Mercurial > irccd
annotate common/signals.h @ 23:03068f5ed79d
Misc: various style issues, #419
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 14 Feb 2016 16:15:48 +0100 |
parents | 1158cffe5a5e |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * signals.h -- synchronous observer mechanism | |
3 * | |
4 * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #ifndef _IRCCD_SIGNALS_H_ | |
20 #define _IRCCD_SIGNALS_H_ | |
21 | |
22 #include <functional> | |
23 #include <stack> | |
24 #include <unordered_map> | |
25 #include <vector> | |
26 | |
27 /** | |
28 * @file Signals.h | |
29 * @brief Similar Qt signal subsystem for irccd | |
30 */ | |
31 | |
32 namespace irccd { | |
33 | |
34 /** | |
35 * @class SignalConnection | |
36 * @brief Stores the reference to the callable | |
37 * | |
38 * This class can be stored to remove a registered function from a Signal, be | |
39 * careful to not mix connections between different signals as they are just | |
40 * referenced by ids. | |
41 */ | |
42 class SignalConnection { | |
43 private: | |
44 unsigned m_id; | |
45 | |
46 public: | |
47 /** | |
48 * Create a signal connection. | |
49 * | |
50 * @param id the id | |
51 */ | |
52 inline SignalConnection(unsigned id) noexcept | |
23
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
53 : m_id(id) |
0 | 54 { |
55 } | |
56 | |
57 /** | |
58 * Get the reference object. | |
59 * | |
60 * @return the id | |
61 */ | |
62 inline unsigned id() const noexcept | |
63 { | |
64 return m_id; | |
65 } | |
66 }; | |
67 | |
68 /** | |
69 * @class Signal | |
70 * @brief Stores and call registered functions | |
71 * | |
72 * This class is intended to be use as a public field in the desired object. | |
73 * | |
74 * The user just have to call one of connect(), disconnect() or the call | |
75 * operator to use this class. | |
76 * | |
77 * It stores the callable as std::function so type-erasure is complete. | |
78 * | |
79 * The user is responsible of taking care that the object is still alive | |
80 * in case that the function takes a reference to the object. | |
81 */ | |
82 template <typename... Args> | |
83 class Signal { | |
84 private: | |
85 using Function = std::function<void (Args...)>; | |
86 using FunctionMap = std::unordered_map<unsigned, Function>; | |
87 using Stack = std::stack<unsigned>; | |
88 | |
89 FunctionMap m_functions; | |
90 Stack m_stack; | |
91 unsigned m_max{0}; | |
92 | |
93 public: | |
94 /** | |
95 * Register a new function to the signal. | |
96 * | |
97 * @param function the function | |
98 * @return the connection in case you want to remove it | |
99 */ | |
100 inline SignalConnection connect(Function function) noexcept | |
101 { | |
102 unsigned id; | |
103 | |
104 if (!m_stack.empty()) { | |
105 id = m_stack.top(); | |
106 m_stack.pop(); | |
107 } else { | |
108 id = m_max ++; | |
109 } | |
110 | |
111 m_functions.emplace(id, std::move(function)); | |
112 | |
113 return SignalConnection{id}; | |
114 } | |
115 | |
116 /** | |
117 * Disconnect a connection. | |
118 * | |
119 * @param connection the connection | |
120 * @warning Be sure that the connection belongs to that signal | |
121 */ | |
122 inline void disconnect(const SignalConnection &connection) noexcept | |
123 { | |
124 auto value = m_functions.find(connection.id()); | |
125 | |
126 if (value != m_functions.end()) { | |
127 m_functions.erase(connection.id()); | |
128 m_stack.push(connection.id()); | |
129 } | |
130 } | |
131 | |
132 /** | |
133 * Remove all registered functions. | |
134 */ | |
135 inline void clear() | |
136 { | |
137 m_functions.clear(); | |
138 m_max = 0; | |
139 | |
140 while (!m_stack.empty()) | |
141 m_stack.pop(); | |
142 } | |
143 | |
144 /** | |
145 * Call every functions. | |
146 * | |
147 * @param args the arguments to pass to the signal | |
148 */ | |
149 void operator()(Args... args) const | |
150 { | |
151 /* | |
152 * Make a copy of the ids before iterating because the callbacks may eventually remove or modify | |
153 * the list. | |
154 */ | |
155 std::vector<unsigned> ids; | |
156 | |
157 for (auto &pair : m_functions) | |
158 ids.push_back(pair.first); | |
159 | |
160 /* | |
161 * Now iterate while checking if the next id is still available, however if any new signals were | |
162 * added while iterating, they will not be called immediately. | |
163 */ | |
164 for (unsigned i : ids) { | |
165 auto it = m_functions.find(i); | |
166 | |
23
03068f5ed79d
Misc: various style issues, #419
David Demelier <markand@malikania.fr>
parents:
0
diff
changeset
|
167 if (it != m_functions.end()) |
0 | 168 it->second(args...); |
169 } | |
170 } | |
171 }; | |
172 | |
173 } // !irccd | |
174 | |
175 #endif // !_IRCCD_SIGNALS_H_ |