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