QtGStreamer  1.2.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
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 # include <boost/type_traits.hpp>
30 
31 
32 namespace QGlib {
33 namespace Private {
34 
35 //BEGIN ******** CppClosure prototype ********
36 
37 template <typename Function, typename Signature>
38 struct CppClosure {};
39 
40 //END ******** CppClosure prototype ********
41 //BEGIN ******** invoker ********
42 
43 template <typename Function, typename R>
44 struct invoker
45 {
46  static inline void invoke(const Function & f, Value & result) { ValueImpl<R>::set(result, f()); }
47 };
48 
49 template <typename Function>
50 struct invoker<Function, void>
51 {
52  static inline void invoke(const Function & f, Value &) { f(); }
53 };
54 
55 //END ******** invoker ********
56 
57 } //namespace Private
58 } //namespace QGlib
59 
60 
61 # if QGLIB_HAVE_CXX0X
62 
63 namespace QGlib {
64 namespace Private {
65 
66 //BEGIN ******** MemberFunction ********
67 
68 template <typename T, typename R, typename... Args>
69 class MemberFunction
70 {
71 public:
72  inline MemberFunction(R (T::*fn)(Args...), T *obj)
73  : m_function(fn), m_object(obj) {}
74 
75  inline R operator()(Args&&... args) const
76  {
77  return (m_object->*m_function)(std::forward<Args>(args)...);
78  }
79 
80 private:
81  R (T::*m_function)(Args...);
82  T *m_object;
83 };
84 
85 template <typename T, typename R, typename... Args>
86 MemberFunction<T, R, Args...> mem_fn(R (T::*fn)(Args...), T *obj)
87 {
88  return MemberFunction<T, R, Args...>(fn, obj);
89 }
90 
91 //END ******** MemberFunction ********
92 //BEGIN ******** BoundArgumentFunction ********
93 
94 template <typename ParentFunction, typename R, typename Arg1, typename... Args>
95 class BoundArgumentFunction
96 {
97 public:
98  inline BoundArgumentFunction(ParentFunction && fn, Arg1 && arg)
99  : m_function(std::forward<ParentFunction>(fn)),
100  m_firstArg(std::forward<Arg1>(arg)) {}
101 
102  inline R operator()(Args&&... args) const
103  {
104  return m_function(std::forward<Arg1>(m_firstArg), std::forward<Args>(args)...);
105  }
106 
107 private:
108  ParentFunction && m_function;
109  Arg1 && m_firstArg;
110 };
111 
112 template <typename F, typename R, typename Arg1, typename... Args>
113 inline BoundArgumentFunction<F, R, Arg1, Args...> partial_bind(F && f, Arg1 && a1)
114 {
115  return BoundArgumentFunction<F, R, Arg1, Args...>(std::forward<F>(f), std::forward<Arg1>(a1));
116 }
117 
118 //END ******** BoundArgumentFunction ********
119 //BEGIN ******** unpackAndInvoke ********
120 
121 template <typename F, typename R>
122 inline void unpackAndInvoke(F && function, Value & result,
123  QList<Value>::const_iterator &&,
124  QList<Value>::const_iterator &&)
125 {
126  invoker<F, R>::invoke(function, result);
127 }
128 
129 template <typename F, typename R, typename Arg1, typename... Args>
130 inline void unpackAndInvoke(F && function, Value & result,
131  QList<Value>::const_iterator && argsBegin,
132  QList<Value>::const_iterator && argsEnd)
133 {
134  typedef typename boost::remove_const<
135  typename boost::remove_reference<Arg1>::type
136  >::type CleanArg1;
137  typedef BoundArgumentFunction<F, R, Arg1, Args...> F1;
138 
139  CleanArg1 && boundArg = ValueImpl<CleanArg1>::get(*argsBegin);
140  F1 && f = partial_bind<F, R, Arg1, Args...>(std::forward<F>(function), std::forward<Arg1>(boundArg));
141 
142  unpackAndInvoke< F1, R, Args... >(std::forward<F1>(f), result,
143  std::forward<QList<Value>::const_iterator>(++argsBegin),
144  std::forward<QList<Value>::const_iterator>(argsEnd));
145 }
146 
147 //END ******** unpackAndInvoke ********
148 //BEGIN ******** CppClosure ********
149 
150 template <typename F, typename R, typename... Args>
151 struct CppClosure<F, R (Args...)>
152 {
153  class ClosureData : public ClosureDataBase
154  {
155  public:
156  inline ClosureData(const F & func, bool passSender)
157  : ClosureDataBase(passSender), m_function(func) {}
158 
159  virtual void marshaller(Value & result, const QList<Value> & params)
160  {
161  if (static_cast<size_t>(params.size()) < sizeof...(Args)) {
162  throw std::logic_error("The signal provides less arguments than what the closure expects");
163  }
164 
165  unpackAndInvoke<F, R, Args...>(std::forward<F>(m_function), result,
166  params.constBegin(), params.constEnd());
167  }
168 
169  private:
170  F m_function;
171  };
172 
173  static inline ClosureDataBase *create(const F & function, bool passSender)
174  {
175  return new ClosureData(function, passSender);
176  }
177 };
178 
179 //END ******** CppClosure ********
180 
181 } //namespace Private
182 
183 //BEGIN ******** QGlib::connect ********
184 
185 template <typename T, typename R, typename... Args>
186 bool connect(void *instance, const char *detailedSignal,
187  T *receiver, R (T::*slot)(Args...), ConnectFlags flags = 0)
188 {
189  typedef Private::MemberFunction<T, R, Args...> F;
190 
191  F && f = Private::mem_fn(slot, receiver);
192  Private::ClosureDataBase* && closure
193  = Private::CppClosure<F, R (Args...)>::create(f, flags & PassSender);
194 
195  return Private::connect(instance, detailedSignal, Quark(),
196  receiver, Private::GetDestroyNotifier<T>(),
197  Private::hashMfp(slot), closure, flags);
198 }
199 
200 //END ******** QGlib::connect ********
201 
202 } //namespace QGlib
203 
204 # else //QGLIB_HAVE_CXX0X
205 
206 # include <boost/function.hpp>
207 # include <boost/preprocessor.hpp>
208 # include <boost/bind.hpp>
209 
210 // include the second part of this file as many times as QGLIB_CONNECT_MAX_ARGS specifies
211 # define BOOST_PP_ITERATION_PARAMS_1 (3,(0, QGLIB_CONNECT_MAX_ARGS, "QGlib/connectimpl.h"))
212 # include BOOST_PP_ITERATE()
213 
214 # undef BOOST_PP_ITERATION_PARAMS_1
215 # undef QGLIB_CONNECT_MAX_ARGS
216 
217 # endif //QGLIB_HAVE_CXX0X
218 
219 
220 #else // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
221 
222 /*
223  This part is included from BOOST_PP_ITERATE(). It defines a CppClosureN class
224  (where N is the number of template arguments it takes) and a specialization for class
225  CppClosure, so that the CppClosure<R (Args...), F> syntax is supported. This part is
226  included multiple times (QGLIB_CONNECT_MAX_ARGS defines how many), and each time
227  it defines those classes with different number of arguments.
228  The concept is based on the implementation of boost::function.
229 */
230 
231 # define QGLIB_CONNECT_IMPL_NUM_ARGS \
232  BOOST_PP_ITERATION()
233 
234 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS \
235  BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, typename A)
236 
237 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS \
238  BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
239 
240 # define QGLIB_CONNECT_IMPL_TEMPLATE_ARGS \
241  BOOST_PP_ENUM_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
242 
243 namespace QGlib {
244 namespace Private {
245 
246 //BEGIN ******** boostpp CppClosure ********
247 
248 # define QGLIB_CONNECT_IMPL_CPPCLOSUREN \
249  BOOST_PP_CAT(CppClosure, QGLIB_CONNECT_IMPL_NUM_ARGS)
250 
251 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP(z, n, list) \
252  ,ValueImpl< \
253  typename boost::remove_const< \
254  typename boost::remove_reference<A ##n>::type \
255  >::type \
256  >::get(list.at(n))
257 
258 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS(list) \
259  BOOST_PP_REPEAT(QGLIB_CONNECT_IMPL_NUM_ARGS, QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP, list)
260 
261 template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
262 struct QGLIB_CONNECT_IMPL_CPPCLOSUREN
263 {
264  class ClosureData : public ClosureDataBase
265  {
266  public:
267  inline ClosureData(const F & func, bool passSender)
268  : ClosureDataBase(passSender), m_function(func) {}
269 
270  virtual void marshaller(Value & result, const QList<Value> & params)
271  {
272  if (params.size() < QGLIB_CONNECT_IMPL_NUM_ARGS) {
273  throw std::logic_error("The signal provides less arguments than what the closure expects");
274  }
275 
276 # if QGLIB_CONNECT_IMPL_NUM_ARGS > 0
277  boost::function<R ()> callback = boost::bind<R>(m_function
278  QGLIB_CONNECT_IMPL_UNPACK_ARGS(params));
279  invoker< boost::function<R ()>, R >::invoke(callback, result);
280 # else
281  invoker< F, R >::invoke(m_function, result);
282 # endif
283  }
284 
285  private:
286  F m_function;
287  };
288 
289  static ClosureDataBase *create(const F & function, bool passSender)
290  {
291  return new ClosureData(function, passSender);
292  }
293 };
294 
295 //partial specialization of struct CppClosure to support the CppClosure<F, R (Args...)> syntax
296 template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
297 struct CppClosure<F, R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>
298  : public QGLIB_CONNECT_IMPL_CPPCLOSUREN< F, R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS >
299 {
300 };
301 
302 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS
303 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP
304 # undef QGLIB_CONNECT_IMPL_CPPCLOSUREN
305 
306 //END ******** boostpp CppClosure ********
307 
308 } //namespace Private
309 
310 //BEGIN ******** bostpp QGlib::connect ********
311 
312 # define QGLIB_CONNECT_IMPL_BIND_ARGS \
313  BOOST_PP_COMMA_IF(QGLIB_CONNECT_IMPL_NUM_ARGS) \
314  BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(QGLIB_CONNECT_IMPL_NUM_ARGS), _)
315 
316 template <typename T, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
317 bool connect(void *instance, const char *detailedSignal,
318  T *receiver, R (T::*slot)(QGLIB_CONNECT_IMPL_TEMPLATE_ARGS), ConnectFlags flags = 0)
319 {
320  boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)> f
321  = boost::bind(slot, receiver QGLIB_CONNECT_IMPL_BIND_ARGS);
322 
323  Private::ClosureDataBase *closure = Private::CppClosure<
324  boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>,
325  R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)
326  >::create(f, flags & PassSender);
327 
328  return Private::connect(instance, detailedSignal, Quark(),
329  receiver, Private::GetDestroyNotifier<T>(),
330  Private::hashMfp(slot), closure, flags);
331 }
332 
333 # undef QGLIB_CONNECT_IMPL_BIND_ARGS
334 
335 //END ******** bostpp QGlib::connect ********
336 
337 } //namespace QGlib
338 
339 # undef QGLIB_CONNECT_IMPL_TEMPLATE_ARGS
340 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS
341 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS
342 # undef QGLIB_CONNECT_IMPL_NUM_ARGS
343 
344 #endif // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
bool connect(void *instance, const char *detailedSignal, T *receiver, R(T::*slot)(Args...), ConnectFlags flags=0)
Definition: connectimpl.h:186
Wrapper class for GQuark.
Definition: quark.h:42