TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / external / process-cpp-minimal / include / core / signal.h
1 /*
2  * Copyright © 2013 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Thomas Voß <thomas.voss@canonical.com>
17  */
18 #ifndef COM_UBUNTU_SIGNAL_H_
19 #define COM_UBUNTU_SIGNAL_H_
20
21 #include <core/connection.h>
22
23 #include <functional>
24 #include <iostream>
25 #include <list>
26 #include <mutex>
27 #include <set>
28
29 namespace core
30 {
31 /**
32  * @brief A signal class that observers can subscribe to.
33  * @tparam Arguments List of argument types passed on to observers when the signal is emitted.
34  */
35 template<typename ...Arguments>
36 class Signal
37 {
38 public:
39     /**
40      * @brief Slot is the function type that observers have to provide to connect to this signal.
41      */
42     typedef std::function<void(Arguments...)> Slot;
43
44 private:
45     struct SlotWrapper
46     {
47         void operator()(Arguments... args)
48         {
49             dispatcher(std::bind(slot, args...));
50         }
51
52         Slot slot;
53         Connection::Dispatcher dispatcher;
54         Connection connection;
55     };
56
57 public:
58     /**
59      * @brief Signal constructs a new instance. Never throws.
60      */
61     inline Signal() noexcept(true) : d(new Private())
62     {
63     }
64
65     inline ~Signal()
66     {
67         std::lock_guard<std::mutex> lg(d->guard);
68         for (auto slot : d->slot_list)
69             slot.connection.reset();
70     }
71
72     // Copy construction, assignment and equality comparison are disabled.
73     Signal(const Signal&) = delete;
74     Signal& operator=(const Signal&) = delete;
75     bool operator==(const Signal&) const = delete;
76
77     /**
78      * @brief Connects the provided slot to this signal instance.
79      *
80      * Calling this method is thread-safe and synchronized with any
81      * other connect, signal emission or disconnect calls.
82      *
83      * @param slot The function to be called when the signal is emitted.
84      * @return A connection object corresponding to the signal-slot connection.
85      */
86     inline Connection connect(const Slot& slot) const
87     {
88         // Helpers to initialize an invalid connection.
89         static const Connection::Disconnector empty_disconnector{};
90         static const Connection::DispatcherInstaller empty_dispatcher_installer{};
91
92         // The default dispatcher immediately executes the function object
93         // provided as argument on whatever thread is currently running.
94         static const Connection::Dispatcher default_dispatcher
95                 = [](const std::function<void()>& handler) { handler(); };
96
97         Connection conn{empty_disconnector, empty_dispatcher_installer};
98
99         std::lock_guard<std::mutex> lg(d->guard);
100
101         auto result = d->slot_list.insert(
102                     d->slot_list.end(),
103                     SlotWrapper{slot, default_dispatcher, conn});
104
105         // We implicitly share our internal state with the connection here
106         // by passing in our private bits contained in 'd' to the std::bind call.
107         // This admittedly uncommon approach allows us to cleanly manage connection
108         // and signal lifetimes without the need to mark everything as mutable.
109         conn.d->disconnector = std::bind(
110                     &Private::disconnect_slot_for_iterator,
111                     d,
112                     result);
113         conn.d->dispatcher_installer = std::bind(
114                     &Private::install_dispatcher_for_iterator,
115                     d,
116                     std::placeholders::_1,
117                     result);
118
119         return conn;
120     }
121
122     /**
123      * @brief operator () emits the signal with the provided parameters.
124      *
125      * Please note that signal emissions might not be delivered immediately to
126      * registered slots, depending on whether the respective connection is dispatched
127      * via a queueing dispatcher. For that reason, the lifetime of the arguments has to
128      * exceed the scope of the call to this operator and its surrounding scope.
129      *
130      * @param args The arguments to be passed on to registered slots.
131      */
132     inline void operator()(Arguments... args)
133     {
134         std::lock_guard<std::mutex> lg(d->guard);
135         for(auto slot : d->slot_list)
136         {
137             slot(args...);
138         }
139     }
140
141 private:
142     struct Private
143     {
144         typedef std::list<SlotWrapper> SlotList;
145
146         inline void disconnect_slot_for_iterator(typename SlotList::iterator it)
147         {
148             std::lock_guard<std::mutex> lg(guard);
149             slot_list.erase(it);
150         }
151
152         inline void install_dispatcher_for_iterator(const Connection::Dispatcher& dispatcher,
153                                                     typename SlotList::iterator it)
154         {
155             std::lock_guard<std::mutex> lg(guard);
156             it->dispatcher = dispatcher;
157         }
158
159         std::mutex guard;
160         SlotList slot_list;
161     };
162     std::shared_ptr<Private> d;
163 };
164
165 /**
166  * @brief A signal class that observers can subscribe to,
167  * template specialization for signals without arguments.
168  */
169 template<>
170 class Signal<void>
171 {
172 public:
173     /**
174      * @brief Slot is the function type that observers have to provide to connect to this signal.
175      */
176     typedef std::function<void()> Slot;
177
178 private:
179     struct SlotWrapper
180     {
181         void operator()()
182         {
183             dispatcher(slot);
184         }
185
186         Slot slot;
187         Connection::Dispatcher dispatcher;
188         Connection connection;
189     };
190
191 public:
192     /**
193      * @brief Signal constructs a new instance. Never throws.
194      */
195     inline Signal() noexcept(true) : d(new Private())
196     {
197     }
198
199     inline ~Signal()
200     {
201         std::lock_guard<std::mutex> lg(d->guard);
202         for (auto slot : d->slot_list)
203             slot.connection.reset();
204     }
205
206     // Copy construction, assignment and equality comparison are disabled.
207     Signal(const Signal&) = delete;
208     Signal& operator=(const Signal&) = delete;
209     bool operator==(const Signal&) const = delete;
210
211     /**
212      * @brief Connects the provided slot to this signal instance.
213      *
214      * Calling this method is thread-safe and synchronized with any
215      * other connect, signal emission or disconnect calls.
216      *
217      * @param slot The function to be called when the signal is emitted.
218      * @return A connection object corresponding to the signal-slot connection.
219      */
220     inline Connection connect(const Slot& slot) const
221     {
222         // Helpers to initialize an invalid connection.
223         static const Connection::Disconnector empty_disconnector{};
224         static const Connection::DispatcherInstaller empty_dispatcher_installer{};
225
226         // The default dispatcher immediately executes the function object
227         // provided as argument on whatever thread is currently running.
228         static const Connection::Dispatcher default_dispatcher
229                 = [](const std::function<void()>& handler) { handler(); };
230
231         Connection conn{empty_disconnector, empty_dispatcher_installer};
232
233         std::lock_guard<std::mutex> lg(d->guard);
234
235         auto result = d->slot_list.insert(
236                     d->slot_list.end(),
237                     SlotWrapper{slot, default_dispatcher, conn});
238
239         // We implicitly share our internal state with the connection here
240         // by passing in our private bits contained in 'd' to the std::bind call.
241         // This admittedly uncommon approach allows us to cleanly manage connection
242         // and signal lifetimes without the need to mark everything as mutable.
243         conn.d->disconnector = std::bind(
244                     &Private::disconnect_slot_for_iterator,
245                     d,
246                     result);
247         conn.d->dispatcher_installer = std::bind(
248                     &Private::install_dispatcher_for_iterator,
249                     d,
250                     std::placeholders::_1,
251                     result);
252
253         return conn;
254     }
255
256     /**
257      * @brief operator () emits the signal.
258      *
259      * Please note that signal emissions might not be delivered immediately to
260      * registered slots, depending on whether the respective connection is dispatched
261      * via a queueing dispatcher.
262      */
263     inline void operator()()
264     {
265         std::lock_guard<std::mutex> lg(d->guard);
266         for(auto slot : d->slot_list)
267         {
268             slot();
269         }
270     }
271
272 private:
273     struct Private
274     {
275         typedef std::list<SlotWrapper> SlotList;
276
277         inline void disconnect_slot_for_iterator(typename SlotList::iterator it)
278         {
279             std::lock_guard<std::mutex> lg(guard);
280             slot_list.erase(it);
281         }
282
283         inline void install_dispatcher_for_iterator(const Connection::Dispatcher& dispatcher,
284                                                     typename SlotList::iterator it)
285         {
286             std::lock_guard<std::mutex> lg(guard);
287             it->dispatcher = dispatcher;
288         }
289
290         std::mutex guard;
291         SlotList slot_list;
292     };
293     std::shared_ptr<Private> d;
294 };
295 }
296
297 #endif // COM_UBUNTU_SIGNAL_H_