QtGStreamer 1.2.0
Loading...
Searching...
No Matches
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
34namespace QGlib {
35namespace Private {
36
37//BEGIN ******** CppClosure prototype ********
38
39template <typename Function, typename Signature>
40struct CppClosure {};
41
42//END ******** CppClosure prototype ********
43//BEGIN ******** invoker ********
44
45template <typename Function, typename R>
46struct invoker
47{
48 static inline void invoke(const Function & f, Value & result) { ValueImpl<R>::set(result, f()); }
49};
50
51template <typename Function>
52struct 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
65namespace QGlib {
66namespace Private {
67
68//BEGIN ******** MemberFunction ********
69
70template <typename T, typename R, typename... Args>
71class MemberFunction
72{
73public:
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
82private:
83 R (T::*m_function)(Args...);
84 T *m_object;
85};
86
87template <typename T, typename R, typename... Args>
88MemberFunction<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
96template <typename ParentFunction, typename R, typename Arg1, typename... Args>
97class BoundArgumentFunction
98{
99public:
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
109private:
110 ParentFunction && m_function;
111 Arg1 && m_firstArg;
112};
113
114template <typename F, typename R, typename Arg1, typename... Args>
115inline 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
123template <typename F, typename R>
124inline 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
131template <typename F, typename R, typename Arg1, typename... Args>
132inline 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
152template <typename F, typename R, typename... Args>
153struct 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
187template <typename T, typename R, typename... Args>
188bool 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
245namespace QGlib {
246namespace 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
263template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
264struct 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
298template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
299struct 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
318template <typename T, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
319bool 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)
@ PassSender
Definition connect.h:52