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
18namespace obs {
19
20class signal_base {
21public:
22 virtual ~signal_base() { }
23 virtual void disconnect_slot(slot_base* slot) = 0;
24};
25
26// Signal for any kind of functions
27template<typename Callable>
28class signal { };
29
30template<typename R, typename...Args>
31class signal<R(Args...)> : public signal_base {
32public:
33 typedef R result_type;
34 typedef slot<R(Args...)> slot_type;
35 typedef safe_list<slot_type> slot_list;
36
37 signal() { }
38 ~signal() {
39 for (auto slot : m_slots)
40 delete slot;
41 }
42
43 signal(const signal&) { }
44 signal& operator=(const signal&) { return *this; }
45
46 connection add_slot(slot_type* s) {
47 m_slots.push_back(s);
48 return connection(this, s);
49 }
50
51 template<typename Function>
52 connection connect(Function&& f) {
53 return add_slot(new slot_type(std::forward<Function>(f)));
54 }
55
56 template<class Class>
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
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
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
78protected:
79 slot_list m_slots;
80};
81
82template<typename...Args>
83class signal<void(Args...)> : public signal_base {
84public:
85 typedef slot<void(Args...)> slot_type;
86 typedef safe_list<slot_type> slot_list;
87
88 signal() { }
89 ~signal() {
90 for (auto slot : m_slots)
91 delete slot;
92 }
93
94 signal(const signal&) { }
95 signal& operator=(const signal&) { return *this; }
96
97 connection add_slot(slot_type* s) {
98 m_slots.push_back(s);
99 return connection(this, s);
100 }
101
102 template<typename Function>
103 connection connect(Function&& f) {
104 return add_slot(new slot_type(std::forward<Function>(f)));
105 }
106
107 template<class Class>
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
115 virtual void disconnect_slot(slot_base* slot) override {
116 m_slots.erase(static_cast<slot_type*>(slot));
117 }
118
119 template<typename...Args2>
120 void operator()(Args2&&...args) {
121 for (auto slot : m_slots)
122 if (slot)
123 (*slot)(std::forward<Args2>(args)...);
124 }
125
126protected:
127 slot_list m_slots;
128};
129
130} // namespace obs
131
132#endif
133