Imported Upstream version 2.99.2
[platform/upstream/libsigc++.git] / sigc++ / functors / slot.h
1 #ifndef _SIGC_FUNCTORS_SLOT_H_
2 #define _SIGC_FUNCTORS_SLOT_H_
3
4 #include <sigc++/trackable.h>
5 #include <sigc++/visit_each.h>
6 #include <sigc++/adaptors/adaptor_trait.h>
7 #include <sigc++/functors/slot_base.h>
8
9 namespace sigc {
10
11 namespace internal {
12
13 /** A typed slot_rep.
14  * A typed slot_rep holds a functor that can be invoked from
15  * slot::operator()(). visit_each() is used to visit the functor's
16  * targets that inherit trackable recursively and register the
17  * notification callback. Consequently the slot_rep object will be
18  * notified when some referred object is destroyed or overwritten.
19  */
20 template <class T_functor>
21 struct typed_slot_rep : public slot_rep
22 {
23 private:
24   using self = typed_slot_rep<T_functor>;
25
26 public:
27   /* Use an adaptor type so that arguments can be passed as const references
28    * through explicit template instantiation from slot_call#::call_it() */
29   using adaptor_type = typename adaptor_trait<T_functor>::adaptor_type;
30
31   /** The functor contained by this slot_rep object. */
32   adaptor_type functor_;
33
34   /** Constructs an invalid typed slot_rep object.
35    * The notification callback is registered using visit_each().
36    * @param functor The functor contained by the new slot_rep object.
37    */
38   inline typed_slot_rep(const T_functor& functor)
39     : slot_rep(nullptr, &destroy, &dup), functor_(functor)
40     { sigc::visit_each_type<trackable*>(slot_do_bind(this), functor_); }
41
42   inline typed_slot_rep(const typed_slot_rep& cl)
43     : slot_rep(cl.call_, &destroy, &dup), functor_(cl.functor_)
44     { sigc::visit_each_type<trackable*>(slot_do_bind(this), functor_); }
45
46   typed_slot_rep& operator=(const typed_slot_rep& src) = delete;
47
48   typed_slot_rep(typed_slot_rep&& src) = delete;
49   typed_slot_rep& operator=(typed_slot_rep&& src) = delete;
50
51   inline ~typed_slot_rep()
52     {
53       call_ = nullptr;
54       destroy_ = nullptr;
55       sigc::visit_each_type<trackable*>(slot_do_unbind(this), functor_);
56     }
57
58 private:
59   /** Detaches the stored functor from the other referred trackables and destroys it.
60    * This does not destroy the base slot_rep object.
61    */
62   static void destroy(notifiable* data)
63     {
64       self* self_ = static_cast<self*>(reinterpret_cast<slot_rep*>(data));
65       self_->call_ = nullptr;
66       self_->destroy_ = nullptr;
67       sigc::visit_each_type<trackable*>(slot_do_unbind(self_), self_->functor_);
68       self_->functor_.~adaptor_type();
69       /* don't call disconnect() here: destroy() is either called
70        * a) from the parent itself (in which case disconnect() leads to a segfault) or
71        * b) from a parentless slot (in which case disconnect() does nothing)
72        */
73     }
74
75   /** Makes a deep copy of the slot_rep object.
76    * Deep copy means that the notification callback of the new
77    * slot_rep object is registered in the referred trackables.
78    * @return A deep copy of the slot_rep object.
79    */
80   static slot_rep* dup(slot_rep* a_rep)
81     {
82       return new self(*static_cast<self*>(a_rep));
83     }
84 };
85
86
87 /** Abstracts functor execution.
88  * call_it() invokes a functor of type @e T_functor with a list of
89  * parameters whose types are given by the template arguments.
90  * address() forms a function pointer from call_it().
91  *
92  * The following template arguments are used:
93  * - @e T_functor The functor type.
94  * - @e T_return The return type of call_it().
95  * - @e T_arg Argument types used in the definition of call_it().
96  *
97  */
98 template<class T_functor, class T_return, class... T_arg>
99 struct slot_call
100 {
101   /** Invokes a functor of type @p T_functor.
102    * @param rep slot_rep object that holds a functor of type @p T_functor.
103    * @param _A_a Arguments to be passed on to the functor.
104    * @return The return values of the functor invocation.
105    */
106   static T_return call_it(slot_rep* rep, type_trait_take_t<T_arg>... a_)
107     {
108       using typed_slot = typed_slot_rep<T_functor>;
109       typed_slot *typed_rep = static_cast<typed_slot*>(rep);
110       return (typed_rep->functor_).template operator()<type_trait_take_t<T_arg>...>
111                (a_...);
112     }
113
114   /** Forms a function pointer from call_it().
115    * @return A function pointer formed from call_it().
116    */
117   static hook address()
118     { return reinterpret_cast<hook>(&call_it); }
119 };
120
121
122 } /* namespace internal */
123
124
125 // Because slot is opaque, visit_each() will not visit its internal members.
126 // Those members are not reachable by visit_each() after the slot has been
127 // constructed. But when a slot contains another slot, the outer slot will become
128 // the parent of the inner slot, with similar results. See the description of
129 // slot's specialization of the visitor struct.
130
131 /** Converts an arbitrary functor to a unified type which is opaque.
132  * sigc::slot itself is a functor or, to be more precise, a closure. It contains
133  * a single, arbitrary functor (or closure) that is executed in operator()().
134  *
135  * The template arguments determine the function signature of operator()():
136  * - @e T_return The return type of operator()().
137  * - @e T_arg Argument types used in the definition of operator()().
138  *
139  * For instance, to declare a slot that returns void and takes two parameters
140  * of bool and int:
141  * @code
142  * sigc::slot<void(bool, int)> some_slot;
143  * @endcode
144  *
145  * To use, simply assign the desired functor to the slot. If the functor
146  * is not compatible with the parameter list defined with the template
147  * arguments then compiler errors are triggered. When called, the slot
148  * will invoke the functor with minimal copies.
149  * block() and unblock() can be used to block the functor's invocation
150  * from operator()() temporarily.
151  *
152  * @ingroup slot
153  */
154 template <class T_return, class... T_arg>
155 class slot;
156
157 template <class T_return, class... T_arg>
158 class slot<T_return(T_arg...)>
159   : public slot_base
160 {
161 public:
162   using result_type = T_return;
163   //TODO: using arg_type_ = type_trait_take_t<T_arg>;
164
165 #ifndef DOXYGEN_SHOULD_SKIP_THIS
166 private:
167   using rep_type = internal::slot_rep;
168 public:
169   using call_type = T_return (*)(rep_type*, type_trait_take_t<T_arg>...);
170 #endif
171
172   /** Invoke the contained functor unless slot is in blocking state.
173    * @param _A_a Arguments to be passed on to the functor.
174    * @return The return value of the functor invocation.
175    */
176   inline T_return operator()(type_trait_take_t<T_arg>... _A_a) const
177     {
178       if (!empty() && !blocked())
179         return (reinterpret_cast<call_type>(slot_base::rep_->call_))(slot_base::rep_, _A_a...);
180       return T_return();
181     }
182
183   inline slot() {}
184
185   /** Constructs a slot from an arbitrary functor.
186    * @param _A_func The desired functor the new slot should be assigned to.
187    */
188   template <class T_functor>
189   slot(const T_functor& _A_func)
190     : slot_base(new internal::typed_slot_rep<T_functor>(_A_func))
191     {
192       //The slot_base:: is necessary to stop the HP-UX aCC compiler from being confused. murrayc.
193       slot_base::rep_->call_ = internal::slot_call<T_functor, T_return, T_arg...>::address();
194     }
195
196   /** Constructs a slot, copying an existing one.
197    * @param src The existing slot to copy.
198    */
199   slot(const slot& src)
200     : slot_base(src)
201     {}
202
203   /** Constructs a slot, moving an existing one.
204    * If @p src is connected to a parent (e.g. a signal), it is copied, not moved.
205    * @param src The existing slot to move or copy.
206    */
207   slot(slot&& src)
208     : slot_base(std::move(src))
209     {}
210
211   /** Overrides this slot, making a copy from another slot.
212    * @param src The slot from which to make a copy.
213    * @return @p this.
214    */
215   slot& operator=(const slot& src)
216   {
217     slot_base::operator=(src);
218     return *this;
219   }
220
221   /** Overrides this slot, making a move from another slot.
222    * If @p src is connected to a parent (e.g. a signal), it is copied, not moved.
223    * @param src The slot from which to move or copy.
224    * @return @p this.
225    */
226   slot& operator=(slot&& src)
227   {
228     slot_base::operator=(std::move(src));
229     return *this;
230   }
231 };
232
233 #ifndef DOXYGEN_SHOULD_SKIP_THIS
234 //template specialization of visitor<>::do_visit_each<>(action, functor):
235 /** Performs a functor on each of the targets of a functor.
236  *
237  * There are three function overloads for sigc::slot.
238  *
239  * The first two overloads are very specialized. They handle the (probably unusual)
240  * case when the functor, stored in a slot, contains a slot. They are invoked from
241  * the constructor, destructor or destroy() method of typed_slot_rep.
242  * The first overload, called from the constructor of the outer slot, sets
243  * the outer slot as the parent of the inner slot. The second overload, called from
244  * the destructor or destroy() of the outer slot, unsets the parent of the inner slot.
245  * When an object referenced from the inner slot is deleted, the inner slot calls
246  * its slot_rep::disconnect(), which calls the outer slot's slot_rep::notify().
247  * The outer slot is informed just as if one of its directly referenced objects
248  * had been deleted. Result: The outer slot is disconnected from its parent,
249  * if any (for instance a sigc::signal).
250  * See https://bugzilla.gnome.org/show_bug.cgi?id=755003
251  *
252  * The third overload is identical to do_visit_each() in visitor's primary template.
253  *
254  * @ingroup slot
255  */
256 template <typename T_return, typename... T_arg>
257 struct visitor<slot<T_return, T_arg...>>
258 {
259   static void do_visit_each(const internal::limit_derived_target<trackable*, internal::slot_do_bind>& _A_action,
260                             const slot<T_return, T_arg...>& _A_target)
261   {
262     if (_A_target.rep_ && _A_target.rep_->parent_ == nullptr)
263     _A_target.rep_->set_parent(_A_action.action_.rep_, &internal::slot_rep::notify);
264   }
265
266   static void do_visit_each(const internal::limit_derived_target<trackable*, internal::slot_do_unbind>& _A_action,
267                             const slot<T_return, T_arg...>& _A_target)
268   {
269     if (_A_target.rep_ && _A_target.rep_->parent_ == _A_action.action_.rep_)
270       _A_target.rep_->set_parent(nullptr, nullptr);
271   }
272
273   template <typename T_action>
274   static void do_visit_each(const T_action& _A_action,
275                             const slot<T_return, T_arg...>& _A_target)
276   {
277     _A_action(_A_target);
278   }
279 };
280 #endif // DOXYGEN_SHOULD_SKIP_THIS
281
282 } /* namespace sigc */
283
284 #endif /* _SIGC_FUNCTORS_SLOT_H_ */