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