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
14namespace obs {
15
16template<typename T>
17struct is_callable_without_args : std::is_convertible<T, std::function<void()>> { };
18
19class slot_base {
20public:
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
30template<typename Callable>
31class slot { };
32
33template<typename R, typename...Args>
34class slot<R(Args...)> : public slot_base {
35public:
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
55private:
56 std::function<R(Args...)> f;
57};
58
59template<typename...Args>
60class slot<void(Args...)> : public slot_base {
61public:
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
81private:
82 std::function<void(Args...)> f;
83};
84
85} // namespace obs
86
87#endif
88