QtGStreamer  1.2.0
connectimpl.h
1 /*
2  Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
3  Copyright (C) 2010 Collabora Ltd.
4  @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
5 
6  This library is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published
8  by the Free Software Foundation; either version 2.1 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #if !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
20 
21 # ifndef IN_QGLIB_CONNECT_H
22 # error "This file must not be included directly"
23 # endif
24 
25 # include "value.h"
26 # include "refpointer.h"
27 # include <QtCore/QList>
28 # include <stdexcept>
29 #ifndef Q_MOC_RUN
30 # include <boost/type_traits.hpp>
31 #endif
32 
33 
34 namespace QGlib {
35 namespace Private {
36 
37 //BEGIN ******** CppClosure prototype ********
38 
39 template <typename Function, typename Signature>
40 struct CppClosure {};
41 
42 //END ******** CppClosure prototype ********
43 //BEGIN ******** invoker ********
44 
45 template <typename Function, typename R>
46 struct invoker
47 {
48  static inline void invoke(const Function & f, Value & result) { ValueImpl<R>::set(result, f()); }
49 };
50 
51 template <typename Function>
52 struct invoker<Function, void>
53 {
54  static inline void invoke(const Function & f, Value &) { f(); }
55 };
56 
57 //END ******** invoker ********
58 
59 } //namespace Private
60 } //namespace QGlib
61 
62 
63 # if QGLIB_HAVE_CXX0X
64 
65 namespace QGlib {
66 namespace Private {
67 
68 //BEGIN ******** MemberFunction ********
69 
70 template <typename T, typename R, typename... Args>
71 class MemberFunction
72 {
73 public:
74  inline MemberFunction(R (T::*fn)(Args...), T *obj)
75  : m_function(fn), m_object(obj) {}
76 
77  inline R operator()(Args&&... args) const
78  {
79  return (m_object->*m_function)(std::forward<Args>(args)...);
80  }
81 
82 private:
83  R (T::*m_function)(Args...);
84  T *m_object;
85 };
86 
87 template <typename T, typename R, typename... Args>
88 MemberFunction<T, R, Args...> mem_fn(R (T::*fn)(Args...), T *obj)
89 {
90  return MemberFunction<T, R, Args...>(fn, obj);
91 }
92 
93 //END ******** MemberFunction ********
94 //BEGIN ******** BoundArgumentFunction ********
95 
96 template <typename ParentFunction, typename R, typename Arg1, typename... Args>
97 class BoundArgumentFunction
98 {
99 public:
100  inline BoundArgumentFunction(ParentFunction && fn, Arg1 && arg)
101  : m_function(std::forward<ParentFunction>(fn)),
102  m_firstArg(std::forward<Arg1>(arg)) {}
103 
104  inline R operator()(Args&&... args) const
105  {
106  return m_function(std::forward<Arg1>(m_firstArg), std::forward<Args>(args)...);
107  }
108 
109 private:
110  ParentFunction && m_function;
111  Arg1 && m_firstArg;
112 };
113 
114 template <typename F, typename R, typename Arg1, typename... Args>
115 inline BoundArgumentFunction<F, R, Arg1, Args...> partial_bind(F && f, Arg1 && a1)
116 {
117  return BoundArgumentFunction<F, R, Arg1, Args...>(std::forward<F>(f), std::forward<Arg1>(a1));
118 }
119 
120 //END ******** BoundArgumentFunction ********
121 //BEGIN ******** unpackAndInvoke ********
122 
123 template <typename F, typename R>
124 inline void unpackAndInvoke(F && function, Value & result,
125  QList<Value>::const_iterator &&,
126  QList<Value>::const_iterator &&)
127 {
128  invoker<F, R>::invoke(function, result);
129 }
130 
131 template <typename F, typename R, typename Arg1, typename... Args>
132 inline void unpackAndInvoke(F && function, Value & result,
133  QList<Value>::const_iterator && argsBegin,
134  QList<Value>::const_iterator && argsEnd)
135 {
136  typedef typename boost::remove_const<
137  typename boost::remove_reference<Arg1>::type
138  >::type CleanArg1;
139  typedef BoundArgumentFunction<F, R, Arg1, Args...> F1;
140 
141  CleanArg1 && boundArg = ValueImpl<CleanArg1>::get(*argsBegin);
142  F1 && f = partial_bind<F, R, Arg1, Args...>(std::forward<F>(function), std::forward<Arg1>(boundArg));
143 
144  unpackAndInvoke< F1, R, Args... >(std::forward<F1>(f), result,
145  std::forward<QList<Value>::const_iterator>(++argsBegin),
146  std::forward<QList<Value>::const_iterator>(argsEnd));
147 }
148 
149 //END ******** unpackAndInvoke ********
150 //BEGIN ******** CppClosure ********
151 
152 template <typename F, typename R, typename... Args>
153 struct CppClosure<F, R (Args...)>
154 {
155  class ClosureData : public ClosureDataBase
156  {
157  public:
158  inline ClosureData(const F & func, bool passSender)
159  : ClosureDataBase(passSender), m_function(func) {}
160 
161  virtual void marshaller(Value & result, const QList<Value> & params)
162  {
163  if (static_cast<size_t>(params.size()) < sizeof...(Args)) {
164  throw std::logic_error("The signal provides less arguments than what the closure expects");
165  }
166 
167  unpackAndInvoke<F, R, Args...>(std::forward<F>(m_function), result,
168  params.constBegin(), params.constEnd());
169  }
170 
171  private:
172  F m_function;
173  };
174 
175  static inline ClosureDataBase *create(const F & function, bool passSender)
176  {
177  return new ClosureData(function, passSender);
178  }
179 };
180 
181 //END ******** CppClosure ********
182 
183 } //namespace Private
184 
185 //BEGIN ******** QGlib::connect ********
186 
187 template <typename T, typename R, typename... Args>
188 bool connect(void *instance, const char *detailedSignal,
189  T *receiver, R (T::*slot)(Args...), ConnectFlags flags = 0)
190 {
191  typedef Private::MemberFunction<T, R, Args...> F;
192 
193  F && f = Private::mem_fn(slot, receiver);
194  Private::ClosureDataBase* && closure
195  = Private::CppClosure<F, R (Args...)>::create(f, flags & PassSender);
196 
197  return Private::connect(instance, detailedSignal, Quark(),
198  receiver, Private::GetDestroyNotifier<T>(),
199  Private::hashMfp(slot), closure, flags);
200 }
201 
202 //END ******** QGlib::connect ********
203 
204 } //namespace QGlib
205 
206 # else //QGLIB_HAVE_CXX0X
207 
208 # include <boost/function.hpp>
209 # include <boost/preprocessor.hpp>
210 # include <boost/bind.hpp>
211 
212 // include the second part of this file as many times as QGLIB_CONNECT_MAX_ARGS specifies
213 # define BOOST_PP_ITERATION_PARAMS_1 (3,(0, QGLIB_CONNECT_MAX_ARGS, "QGlib/connectimpl.h"))
214 # include BOOST_PP_ITERATE()
215 
216 # undef BOOST_PP_ITERATION_PARAMS_1
217 # undef QGLIB_CONNECT_MAX_ARGS
218 
219 # endif //QGLIB_HAVE_CXX0X
220 
221 
222 #else // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
223 
224 /*
225  This part is included from BOOST_PP_ITERATE(). It defines a CppClosureN class
226  (where N is the number of template arguments it takes) and a specialization for class
227  CppClosure, so that the CppClosure<R (Args...), F> syntax is supported. This part is
228  included multiple times (QGLIB_CONNECT_MAX_ARGS defines how many), and each time
229  it defines those classes with different number of arguments.
230  The concept is based on the implementation of boost::function.
231 */
232 
233 # define QGLIB_CONNECT_IMPL_NUM_ARGS \
234  BOOST_PP_ITERATION()
235 
236 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS \
237  BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, typename A)
238 
239 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS \
240  BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
241 
242 # define QGLIB_CONNECT_IMPL_TEMPLATE_ARGS \
243  BOOST_PP_ENUM_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
244 
245 namespace QGlib {
246 namespace Private {
247 
248 //BEGIN ******** boostpp CppClosure ********
249 
250 # define QGLIB_CONNECT_IMPL_CPPCLOSUREN \
251  BOOST_PP_CAT(CppClosure, QGLIB_CONNECT_IMPL_NUM_ARGS)
252 
253 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP(z, n, list) \
254  ,ValueImpl< \
255  typename boost::remove_const< \
256  typename boost::remove_reference<A ##n>::type \
257  >::type \
258  >::get(list.at(n))
259 
260 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS(list) \
261  BOOST_PP_REPEAT(QGLIB_CONNECT_IMPL_NUM_ARGS, QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP, list)
262 
263 template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
264 struct QGLIB_CONNECT_IMPL_CPPCLOSUREN
265 {
266  class ClosureData : public ClosureDataBase
267  {
268  public:
269  inline ClosureData(const F & func, bool passSender)
270  : ClosureDataBase(passSender), m_function(func) {}
271 
272  virtual void marshaller(Value & result, const QList<Value> & params)
273  {
274  if (params.size() < QGLIB_CONNECT_IMPL_NUM_ARGS) {
275  throw std::logic_error("The signal provides less arguments than what the closure expects");
276  }
277 
278 # if QGLIB_CONNECT_IMPL_NUM_ARGS > 0
279  boost::function<R ()> callback = boost::bind<R>(m_function
280  QGLIB_CONNECT_IMPL_UNPACK_ARGS(params));
281  invoker< boost::function<R ()>, R >::invoke(callback, result);
282 # else
283  invoker< F, R >::invoke(m_function, result);
284 # endif
285  }
286 
287  private:
288  F m_function;
289  };
290 
291  static ClosureDataBase *create(const F & function, bool passSender)
292  {
293  return new ClosureData(function, passSender);
294  }
295 };
296 
297 //partial specialization of struct CppClosure to support the CppClosure<F, R (Args...)> syntax
298 template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
299 struct CppClosure<F, R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>
300  : public QGLIB_CONNECT_IMPL_CPPCLOSUREN< F, R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS >
301 {
302 };
303 
304 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS
305 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP
306 # undef QGLIB_CONNECT_IMPL_CPPCLOSUREN
307 
308 //END ******** boostpp CppClosure ********
309 
310 } //namespace Private
311 
312 //BEGIN ******** bostpp QGlib::connect ********
313 
314 # define QGLIB_CONNECT_IMPL_BIND_ARGS \
315  BOOST_PP_COMMA_IF(QGLIB_CONNECT_IMPL_NUM_ARGS) \
316  BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(QGLIB_CONNECT_IMPL_NUM_ARGS), _)
317 
318 template <typename T, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
319 bool connect(void *instance, const char *detailedSignal,
320  T *receiver, R (T::*slot)(QGLIB_CONNECT_IMPL_TEMPLATE_ARGS), ConnectFlags flags = 0)
321 {
322  boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)> f
323  = boost::bind(slot, receiver QGLIB_CONNECT_IMPL_BIND_ARGS);
324 
325  Private::ClosureDataBase *closure = Private::CppClosure<
326  boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>,
327  R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)
328  >::create(f, flags & PassSender);
329 
330  return Private::connect(instance, detailedSignal, Quark(),
331  receiver, Private::GetDestroyNotifier<T>(),
332  Private::hashMfp(slot), closure, flags);
333 }
334 
335 # undef QGLIB_CONNECT_IMPL_BIND_ARGS
336 
337 //END ******** bostpp QGlib::connect ********
338 
339 } //namespace QGlib
340 
341 # undef QGLIB_CONNECT_IMPL_TEMPLATE_ARGS
342 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS
343 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS
344 # undef QGLIB_CONNECT_IMPL_NUM_ARGS
345 
346 #endif // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
Wrapper class for GQuark.
Definition: quark.h:43
Wrappers for Glib and GObject classes.
bool connect(void *instance, const char *detailedSignal, T *receiver, R(T::*slot)(Args...), ConnectFlags flags=0)
Definition: connectimpl.h:188
@ PassSender
Definition: connect.h:52