1 | // Observable Library |
2 | // Copyright (c) 2016-2020 David Capello |
3 | // |
4 | // This file is released under the terms of the MIT license. |
5 | // Read LICENSE.txt for more information. |
6 | |
7 | #ifndef OBS_SLOT_H_INCLUDED |
8 | #define OBS_SLOT_H_INCLUDED |
9 | #pragma once |
10 | |
11 | #include <functional> |
12 | #include <type_traits> |
13 | |
14 | namespace obs { |
15 | |
16 | template<typename T> |
17 | struct is_callable_without_args : std::is_convertible<T, std::function<void()>> { }; |
18 | |
19 | class slot_base { |
20 | public: |
21 | slot_base() { } |
22 | virtual ~slot_base() { } |
23 | |
24 | // Disable copy |
25 | slot_base(const slot_base&) = delete; |
26 | slot_base& operator=(const slot_base&) = delete; |
27 | }; |
28 | |
29 | // Generic slot |
30 | template<typename Callable> |
31 | class slot { }; |
32 | |
33 | template<typename R, typename...Args> |
34 | class slot<R(Args...)> : public slot_base { |
35 | public: |
36 | template<typename F, |
37 | typename = typename std::enable_if<(sizeof...(Args) == 0 || |
38 | !is_callable_without_args<F>::value)>::type> |
39 | slot(F&& f) : f(std::forward<F>(f)) { } |
40 | |
41 | template<typename G, |
42 | typename = typename std::enable_if<(sizeof...(Args) != 0 && |
43 | is_callable_without_args<G>::value)>::type> |
44 | slot(G g) : f([g](Args...) -> R { return g(); }) { } |
45 | |
46 | slot(const slot& s) { (void)s; } |
47 | virtual ~slot() { } |
48 | |
49 | template<typename...Args2> |
50 | R operator()(Args2&&...args) { |
51 | assert(f); |
52 | return f(std::forward<Args2>(args)...); |
53 | } |
54 | |
55 | private: |
56 | std::function<R(Args...)> f; |
57 | }; |
58 | |
59 | template<typename...Args> |
60 | class slot<void(Args...)> : public slot_base { |
61 | public: |
62 | template<typename F, |
63 | typename = typename std::enable_if<(sizeof...(Args) == 0 || |
64 | !is_callable_without_args<F>::value)>::type> |
65 | slot(F&& f) : f(std::forward<F>(f)) { } |
66 | |
67 | template<typename G, |
68 | typename = typename std::enable_if<(sizeof...(Args) != 0 && |
69 | is_callable_without_args<G>::value)>::type> |
70 | slot(G g) : f([g](Args...){ g(); }) { } |
71 | |
72 | slot(const slot& s) { (void)s; } |
73 | virtual ~slot() { } |
74 | |
75 | template<typename...Args2> |
76 | void operator()(Args2&&...args) { |
77 | assert(f); |
78 | f(std::forward<Args2>(args)...); |
79 | } |
80 | |
81 | private: |
82 | std::function<void(Args...)> f; |
83 | }; |
84 | |
85 | } // namespace obs |
86 | |
87 | #endif |
88 | |