1 // Observable Library
2 // Copyright (c) 2016 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_SIGNAL_H_INCLUDED
8 #define OBS_SIGNAL_H_INCLUDED
9 #pragma once
10 
11 #include "obs/connection.h"
12 #include "obs/safe_list.h"
13 #include "obs/slot.h"
14 
15 #include <functional>
16 #include <type_traits>
17 
18 namespace obs {
19 
20 class signal_base {
21 public:
~signal_base()22   virtual ~signal_base() { }
23   virtual void disconnect_slot(slot_base* slot) = 0;
24 };
25 
26 // Signal for any kind of functions
27 template<typename Callable>
28 class signal { };
29 
30 template<typename R, typename...Args>
31 class signal<R(Args...)> : public signal_base {
32 public:
33   typedef R result_type;
34   typedef slot<R(Args...)> slot_type;
35   typedef safe_list<slot_type> slot_list;
36 
signal()37   signal() { }
~signal()38   ~signal() {
39     for (auto slot : m_slots)
40       delete slot;
41   }
42 
signal(const signal &)43   signal(const signal&) { }
44   signal& operator=(const signal&) { return *this; }
45 
add_slot(slot_type * s)46   connection add_slot(slot_type* s) {
47     m_slots.push_back(s);
48     return connection(this, s);
49   }
50 
51   template<typename Function>
connect(Function && f)52   connection connect(Function&& f) {
53     return add_slot(new slot_type(std::forward<Function>(f)));
54   }
55 
56   template<class Class>
connect(result_type (Class::* m)(Args...args),Class * t)57   connection connect(result_type (Class::*m)(Args...args), Class* t) {
58     return add_slot(new slot_type(
59                       [=](Args...args) -> result_type {
60                         return (t->*m)(std::forward<Args>(args)...);
61                       }));
62   }
63 
disconnect_slot(slot_base * slot)64   virtual void disconnect_slot(slot_base* slot) override {
65     m_slots.erase(static_cast<slot_type*>(slot));
66   }
67 
68   template<typename...Args2>
69   typename std::enable_if<!std::is_void<R>::value, R>::type
operator()70   operator()(Args2&&...args) {
71     R result = R();
72     for (auto slot : m_slots)
73       if (slot)
74         result = (*slot)(std::forward<Args2>(args)...);
75     return result;
76   }
77 
78 protected:
79   slot_list m_slots;
80 };
81 
82 template<typename...Args>
83 class signal<void(Args...)> : public signal_base {
84 public:
85   typedef slot<void(Args...)> slot_type;
86   typedef safe_list<slot_type> slot_list;
87 
signal()88   signal() { }
~signal()89   ~signal() {
90     for (auto slot : m_slots)
91       delete slot;
92   }
93 
signal(const signal &)94   signal(const signal&) { }
95   signal& operator=(const signal&) { return *this; }
96 
add_slot(slot_type * s)97   connection add_slot(slot_type* s) {
98     m_slots.push_back(s);
99     return connection(this, s);
100   }
101 
102   template<typename Function>
connect(Function && f)103   connection connect(Function&& f) {
104     return add_slot(new slot_type(std::forward<Function>(f)));
105   }
106 
107   template<class Class>
connect(void (Class::* m)(Args...args),Class * t)108   connection connect(void (Class::*m)(Args...args), Class* t) {
109     return add_slot(new slot_type(
110                       [=](Args...args) {
111                         (t->*m)(std::forward<Args>(args)...);
112                       }));
113   }
114 
disconnect_slot(slot_base * slot)115   virtual void disconnect_slot(slot_base* slot) override {
116     m_slots.erase(static_cast<slot_type*>(slot));
117   }
118 
119   template<typename...Args2>
operator()120   void operator()(Args2&&...args) {
121     for (auto slot : m_slots)
122       if (slot)
123         (*slot)(std::forward<Args2>(args)...);
124   }
125 
126 protected:
127   slot_list m_slots;
128 };
129 
130 } // namespace obs
131 
132 #endif
133