Imported Upstream version 2.99.2
[platform/upstream/libsigc++.git] / sigc++ / signal_base.h
1 /*
2  * Copyright 2002, The libsigc++ Development Team
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18
19 #ifndef _SIGC_SIGNAL_BASE_H_
20 #define _SIGC_SIGNAL_BASE_H_
21
22 #include <cstddef>
23 #include <list>
24 #include <sigc++config.h>
25 #include <sigc++/type_traits.h>
26 #include <sigc++/trackable.h>
27 #include <sigc++/functors/slot.h>
28 #include <sigc++/functors/mem_fun.h>
29
30 /** The libsigc++ namespace.
31  */
32 namespace sigc
33 {
34
35 namespace internal
36 {
37
38 /** Implementation of the signal interface.
39  * signal_impl manages a list of slots. When a slot becomes
40  * invalid (because some referred object dies), notify() is executed.
41  * notify() either calls slots_.erase() directly or defers the execution of
42  * erase() to sweep() when the signal is being emitted. sweep() removes all
43  * invalid slots from the list.
44  */
45 struct SIGC_API signal_impl : public notifiable
46 {
47   using size_type = std::size_t;
48   using slot_list = std::list<slot_base>;
49   using iterator_type = slot_list::iterator;
50   using const_iterator_type = slot_list::const_iterator;
51
52   signal_impl();
53   ~signal_impl();
54
55   signal_impl(const signal_impl& src) = delete;
56   signal_impl& operator=(const signal_impl& src) = delete;
57
58   signal_impl(signal_impl&& src) = delete;
59   signal_impl& operator=(signal_impl&& src) = delete;
60
61   // only MSVC needs this to guarantee that all new/delete are executed from the DLL module
62 #ifdef SIGC_NEW_DELETE_IN_LIBRARY_ONLY
63   void* operator new(size_t size_);
64   void operator delete(void* p);
65 #endif
66
67   /// Increments the reference counter.
68   inline void reference() noexcept
69     { ++ref_count_; }
70
71   /// Increments the reference and execution counter.
72   inline void reference_exec() noexcept
73     { ++ref_count_; ++exec_count_; }
74
75   /** Decrements the reference counter.
76    * The object is deleted when the reference counter reaches zero.
77    */
78   inline void unreference()
79     { if (!(--ref_count_)) delete this; }
80
81   /** Decrements the reference and execution counter.
82    * Invokes sweep() if the execution counter reaches zero and the
83    * removal of one or more slots has been deferred.
84    */
85   inline void unreference_exec()
86     {
87       if (!(--ref_count_)) delete this;
88       else if (!(--exec_count_) && deferred_) sweep();
89     }
90
91   /** Returns whether the list of slots is empty.
92    * @return @p true if the list of slots is empty.
93    */
94   inline bool empty() const noexcept
95     { return slots_.empty(); }
96
97   /// Empties the list of slots.
98   void clear();
99
100   /** Returns the number of slots in the list.
101    * @return The number of slots in the list.
102    */
103   size_type size() const noexcept;
104
105   /** Returns whether all slots in the list are blocked.
106    * @return @p true if all slots are blocked or the list is empty.
107    *
108    * @newin{2,4}
109    */
110   bool blocked() const noexcept;
111
112   /** Sets the blocking state of all slots in the list.
113    * If @e should_block is @p true then the blocking state is set.
114    * Subsequent emissions of the signal don't invoke the functors
115    * contained in the slots until block() with @e should_block = @p false is called.
116    * sigc::slot_base::block() and sigc::slot_base::unblock() can change the
117    * blocking state of individual slots.
118    * @param should_block Indicates whether the blocking state should be set or unset.
119    *
120    * @newin{2,4}
121    */
122   void block(bool should_block = true) noexcept;
123
124   /** Adds a slot at the bottom of the list of slots.
125    * @param slot_ The slot to add to the list of slots.
126    * @return An iterator pointing to the new slot in the list.
127    */
128   iterator_type connect(const slot_base& slot_);
129
130   /** Adds a slot at the bottom of the list of slots.
131    * @param slot_ The slot to add to the list of slots.
132    * @return An iterator pointing to the new slot in the list.
133    *
134    * @newin{2,8}
135    */
136   iterator_type connect(slot_base&& slot_);
137
138   /** Adds a slot at the given position into the list of slots.
139    * @param i An iterator indicating the position where @p slot_ should be inserted.
140    * @param slot_ The slot to add to the list of slots.
141    * @return An iterator pointing to the new slot in the list.
142    */
143   iterator_type insert(iterator_type i, const slot_base& slot_);
144
145   /** Adds a slot at the given position into the list of slots.
146    * @param i An iterator indicating the position where @p slot_ should be inserted.
147    * @param slot_ The slot to add to the list of slots.
148    * @return An iterator pointing to the new slot in the list.
149    *
150    * @newin{2,8}
151    */
152   iterator_type insert(iterator_type i, slot_base&& slot_);
153
154   /** Removes the slot at the given position from the list of slots.
155    * @param i An iterator pointing to the slot to be removed.
156    * @return An iterator pointing to the slot in the list after the one removed.
157    */
158   iterator_type erase(iterator_type i);
159
160   /// Removes invalid slots from the list of slots.
161   void sweep();
162
163   /** Callback that is executed when some slot becomes invalid.
164    * This callback is registered in every slot when inserted into
165    * the list of slots. It is executed when a slot becomes invalid
166    * because of some referred object being destroyed.
167    * It either calls slots_.erase() directly or defers the execution of
168    * erase() to sweep() when the signal is being emitted.
169    * @param d A local structure, created in insert().
170    */
171   static void notify(notifiable* d);
172
173   /** Reference counter.
174    * The object is destroyed when @em ref_count_ reaches zero.
175    */
176   short ref_count_;
177
178   /** Execution counter.
179    * Indicates whether the signal is being emitted.
180    */
181   short exec_count_;
182
183   /// Indicates whether the execution of sweep() is being deferred.
184   bool deferred_;
185
186   /// The list of slots.
187   std::list<slot_base> slots_;
188 };
189
190 /// Exception safe sweeper for cleaning up invalid slots on the slot list.
191 struct SIGC_API signal_exec
192 {
193   /// The parent sigc::signal_impl object.
194   signal_impl* sig_;
195
196   /** Increments the reference and execution counter of the parent sigc::signal_impl object.
197    * @param sig The parent sigc::signal_impl object.
198    */
199   inline signal_exec(const signal_impl* sig) noexcept
200     : sig_(const_cast<signal_impl*>(sig) )
201     { sig_->reference_exec(); }
202
203   /// Decrements the reference and execution counter of the parent sigc::signal_impl object.
204   inline ~signal_exec()
205     { sig_->unreference_exec(); }
206 };
207
208 /** Temporary slot list used during signal emission.
209  *  Through evolution this class is slightly misnamed.  It is now
210  *  an index into the slot_list passed into it.  It simply keeps track
211  *  of where the end of this list was at construction, and pretends that's
212  *  the end of your list.  This way you may connect during emission without
213  *  inadvertently entering an infinite loop, as well as make other
214  *  modifications to the slot_list at your own risk.
215  */
216 struct temp_slot_list
217 {
218   using slot_list = signal_impl::slot_list;
219   using iterator = signal_impl::iterator_type;
220   using const_iterator = signal_impl::const_iterator_type;
221
222   temp_slot_list(slot_list &slots) : slots_(slots)
223   {
224     placeholder = slots_.insert(slots_.end(), slot_base());
225   }
226
227   ~temp_slot_list()
228   {
229     slots_.erase(placeholder);
230   }
231
232   iterator begin() { return slots_.begin(); }
233   iterator end() { return placeholder; }
234   const_iterator begin() const { return slots_.begin(); }
235   const_iterator end() const { return placeholder; }
236
237 private:
238   slot_list &slots_;
239   slot_list::iterator placeholder;
240 };
241   
242 } /* namespace internal */
243
244
245 /** @defgroup signal Signals
246  * Use sigc::signal::connect() with sigc::mem_fun() and sigc::ptr_fun() to connect a method or function with a signal.
247  *
248  * @code
249  * signal_clicked.connect( sigc::mem_fun(*this, &MyWindow::on_clicked) );
250  * @endcode
251  *
252  * When the signal is emitted your method will be called.
253  *
254  * signal::connect() returns a connection, which you can later use to disconnect your method.
255  * If the type of your object inherits from sigc::trackable the method is disconnected
256  * automatically when your object is destroyed.
257  *
258  * When signals are copied they share the underlying information,
259  * so you can have a protected/private sigc::signal member and a public accessor method.
260  * A sigc::signal is a kind of reference-counting pointer. It's similar to
261  * std::shared_ptr<>, although sigc::signal is restricted to holding a pointer to
262  * a sigc::internal::signal_impl object that contains the implementation of the signal.
263  *
264  * @code
265  * class MyClass
266  * {
267  * public:
268  *   using MySignalType = sigc::signal<void()>;
269  *   MySignalType get_my_signal() { return m_my_signal; }
270  * private:
271  *   MySignalType m_my_signal;
272  * };
273  * @endcode
274  *
275  * signal and slot objects provide the core functionality of this
276  * library. A slot is a container for an arbitrary functor.
277  * A signal is a list of slots that are executed on emission.
278  * For compile time type safety a list of template arguments
279  * must be provided for the signal template that determines the
280  * parameter list for emission. Functors and closures are converted
281  * into slots implicitly on connection, triggering compiler errors
282  * if the given functor or closure cannot be invoked with the
283  * parameter list of the signal to connect to.
284  *
285  * Almost any functor with the correct signature can be converted to a sigc::slot
286  * and connected to a signal. See @ref slot "Slots" and sigc::signal::connect().
287  */
288
289 /** Base class for the sigc::signal# templates.
290  * signal_base integrates most of the interface of the derived sigc::signal#
291  * templates. The implementation, however, resides in sigc::internal::signal_impl.
292  * A sigc::internal::signal_impl object is dynamically allocated from signal_base
293  * when first connecting a slot to the signal. This ensures that empty signals
294  * don't waste memory.
295  *
296  * sigc::internal::signal_impl is reference-counted. When a sigc::signal# object
297  * is copied, the reference count of its sigc::internal::signal_impl object is
298  * incremented. Both sigc::signal# objects then refer to the same
299  * sigc::internal::signal_impl object.
300  *
301  * @ingroup signal
302  */
303 struct SIGC_API signal_base : public trackable
304 {
305   using size_type = std::size_t;
306
307   signal_base() noexcept;
308
309   signal_base(const signal_base& src) noexcept;
310
311   signal_base(signal_base&& src);
312
313   ~signal_base();
314
315   signal_base& operator=(const signal_base& src);
316
317   signal_base& operator=(signal_base&& src);
318
319   /** Returns whether the list of slots is empty.
320    * @return @p true if the list of slots is empty.
321    */
322   inline bool empty() const noexcept
323     { return (!impl_ || impl_->empty()); }
324
325   /// Empties the list of slots.
326   void clear();
327
328   /** Returns the number of slots in the list.
329    * @return The number of slots in the list.
330    */
331   size_type size() const noexcept;
332
333   /** Returns whether all slots in the list are blocked.
334    * @return @p true if all slots are blocked or the list is empty.
335    *
336    * @newin{2,4}
337    */
338   bool blocked() const noexcept;
339
340   /** Sets the blocking state of all slots in the list.
341    * If @e should_block is @p true then the blocking state is set.
342    * Subsequent emissions of the signal don't invoke the functors
343    * contained in the slots until unblock() or block() with
344    * @e should_block = @p false is called.
345    * sigc::slot_base::block() and sigc::slot_base::unblock() can change the
346    * blocking state of individual slots.
347    * @param should_block Indicates whether the blocking state should be set or unset.
348    *
349    * @newin{2,4}
350    */
351   void block(bool should_block = true) noexcept;
352
353   /** Unsets the blocking state of all slots in the list.
354    *
355    * @newin{2,4}
356    */
357   void unblock() noexcept;
358
359 protected:
360   using iterator_type = internal::signal_impl::iterator_type;
361
362   /** Adds a slot at the end of the list of slots.
363    * With connect(), slots can also be added during signal emission.
364    * In this case, they won't be executed until the next emission occurs.
365    * @param slot_ The slot to add to the list of slots.
366    * @return An iterator pointing to the new slot in the list.
367    */
368   iterator_type connect(const slot_base& slot_);
369
370   /** Adds a slot at the end of the list of slots.
371    * With connect(), slots can also be added during signal emission.
372    * In this case, they won't be executed until the next emission occurs.
373    * @param slot_ The slot to add to the list of slots.
374    * @return An iterator pointing to the new slot in the list.
375    *
376    * @newin{2,8}
377    */
378   iterator_type connect(slot_base&& slot_);
379
380   /** Adds a slot at the given position into the list of slots.
381    * Note that this function does not work during signal emission!
382    * @param i An iterator indicating the position where @e slot_ should be inserted.
383    * @param slot_ The slot to add to the list of slots.
384    * @return An iterator pointing to the new slot in the list.
385    */
386   iterator_type insert(iterator_type i, const slot_base& slot_);
387
388   /** Adds a slot at the given position into the list of slots.
389    * Note that this function does not work during signal emission!
390    * @param i An iterator indicating the position where @e slot_ should be inserted.
391    * @param slot_ The slot to add to the list of slots.
392    * @return An iterator pointing to the new slot in the list.
393    *
394    * @newin{2,8}
395    */
396   iterator_type insert(iterator_type i, slot_base&& slot_);
397
398   /** Removes the slot at the given position from the list of slots.
399    * Note that this function does not work during signal emission!
400    * @param i An iterator pointing to the slot to be removed.
401    * @return An iterator pointing to the slot in the list after the one removed.
402    */
403   iterator_type erase(iterator_type i);
404
405   /** Returns the signal_impl object encapsulating the list of slots.
406    * @return The signal_impl object encapsulating the list of slots.
407    */
408   internal::signal_impl* impl() const;
409
410   /// The signal_impl object encapsulating the slot list.
411   mutable internal::signal_impl* impl_;
412 };
413
414 } //namespace sigc
415
416 #endif /* _SIGC_SIGNAL_BASE_H_ */