00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #if !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
00020
00021 # ifndef IN_QGLIB_CONNECT_H
00022 # error "This file must not be included directly"
00023 # endif
00024
00025 # include "value.h"
00026 # include "refpointer.h"
00027 # include <QtCore/QList>
00028 # include <stdexcept>
00029 # include <boost/type_traits.hpp>
00030
00031
00032 namespace QGlib {
00033 namespace Private {
00034
00035
00036
00037 template <typename Function, typename Signature>
00038 struct CppClosure {};
00039
00040
00041
00042
00043 template <typename Function, typename R>
00044 struct invoker
00045 {
00046 static inline void invoke(const Function & f, Value & result) { ValueImpl<R>::set(result, f()); }
00047 };
00048
00049 template <typename Function>
00050 struct invoker<Function, void>
00051 {
00052 static inline void invoke(const Function & f, Value &) { f(); }
00053 };
00054
00055
00056
00057 }
00058 }
00059
00060
00061 # if QGLIB_HAVE_CXX0X
00062
00063 namespace QGlib {
00064 namespace Private {
00065
00066
00067
00068 template <typename T, typename R, typename... Args>
00069 class MemberFunction
00070 {
00071 public:
00072 inline MemberFunction(R (T::*fn)(Args...), T *obj)
00073 : m_function(fn), m_object(obj) {}
00074
00075 inline R operator()(Args&&... args) const
00076 {
00077 return (m_object->*m_function)(std::forward<Args>(args)...);
00078 }
00079
00080 private:
00081 R (T::*m_function)(Args...);
00082 T *m_object;
00083 };
00084
00085 template <typename T, typename R, typename... Args>
00086 MemberFunction<T, R, Args...> mem_fn(R (T::*fn)(Args...), T *obj)
00087 {
00088 return MemberFunction<T, R, Args...>(fn, obj);
00089 }
00090
00091
00092
00093
00094 template <typename ParentFunction, typename R, typename Arg1, typename... Args>
00095 class BoundArgumentFunction
00096 {
00097 public:
00098 inline BoundArgumentFunction(ParentFunction && fn, Arg1 && arg)
00099 : m_function(std::forward<ParentFunction>(fn)),
00100 m_firstArg(std::forward<Arg1>(arg)) {}
00101
00102 inline R operator()(Args&&... args) const
00103 {
00104 return m_function(std::forward<Arg1>(m_firstArg), std::forward<Args>(args)...);
00105 }
00106
00107 private:
00108 ParentFunction && m_function;
00109 Arg1 && m_firstArg;
00110 };
00111
00112 template <typename F, typename R, typename Arg1, typename... Args>
00113 inline BoundArgumentFunction<F, R, Arg1, Args...> partial_bind(F && f, Arg1 && a1)
00114 {
00115 return BoundArgumentFunction<F, R, Arg1, Args...>(std::forward<F>(f), std::forward<Arg1>(a1));
00116 }
00117
00118
00119
00120
00121 template <typename F, typename R>
00122 inline void unpackAndInvoke(F && function, Value & result,
00123 QList<Value>::const_iterator &&,
00124 QList<Value>::const_iterator &&)
00125 {
00126 invoker<F, R>::invoke(function, result);
00127 }
00128
00129 template <typename F, typename R, typename Arg1, typename... Args>
00130 inline void unpackAndInvoke(F && function, Value & result,
00131 QList<Value>::const_iterator && argsBegin,
00132 QList<Value>::const_iterator && argsEnd)
00133 {
00134 typedef typename boost::remove_const<
00135 typename boost::remove_reference<Arg1>::type
00136 >::type CleanArg1;
00137 typedef BoundArgumentFunction<F, R, Arg1, Args...> F1;
00138
00139 CleanArg1 && boundArg = ValueImpl<CleanArg1>::get(*argsBegin);
00140 F1 && f = partial_bind<F, R, Arg1, Args...>(std::forward<F>(function), std::forward<Arg1>(boundArg));
00141
00142 unpackAndInvoke< F1, R, Args... >(std::forward<F1>(f), result,
00143 std::forward<QList<Value>::const_iterator>(++argsBegin),
00144 std::forward<QList<Value>::const_iterator>(argsEnd));
00145 }
00146
00147
00148
00149
00150 template <typename F, typename R, typename... Args>
00151 struct CppClosure<F, R (Args...)>
00152 {
00153 class ClosureData : public ClosureDataBase
00154 {
00155 public:
00156 inline ClosureData(const F & func, bool passSender)
00157 : ClosureDataBase(passSender), m_function(func) {}
00158
00159 virtual void marshaller(Value & result, const QList<Value> & params)
00160 {
00161 if (static_cast<unsigned int>(params.size()) < sizeof...(Args)) {
00162 throw std::logic_error("The signal provides less arguments than what the closure expects");
00163 }
00164
00165 unpackAndInvoke<F, R, Args...>(std::forward<F>(m_function), result,
00166 params.constBegin(), params.constEnd());
00167 }
00168
00169 private:
00170 F m_function;
00171 };
00172
00173 static inline ClosureDataBase *create(const F & function, bool passSender)
00174 {
00175 return new ClosureData(function, passSender);
00176 }
00177 };
00178
00179
00180
00181 }
00182
00183
00184
00185 template <typename T, typename R, typename... Args>
00186 bool connect(void *instance, const char *detailedSignal,
00187 T *receiver, R (T::*slot)(Args...), ConnectFlags flags = 0)
00188 {
00189 typedef Private::MemberFunction<T, R, Args...> F;
00190
00191 F && f = Private::mem_fn(slot, receiver);
00192 Private::ClosureDataBase* && closure
00193 = Private::CppClosure<F, R (Args...)>::create(f, flags & PassSender);
00194
00195 return Private::connect(instance, detailedSignal, Quark(),
00196 receiver, Private::GetDestroyNotifier<T>(),
00197 Private::hashMfp(slot), closure, flags);
00198 }
00199
00200
00201
00202 }
00203
00204 # else //QGLIB_HAVE_CXX0X
00205
00206 # include <boost/function.hpp>
00207 # include <boost/preprocessor.hpp>
00208 # include <boost/bind.hpp>
00209
00210
00211 # define BOOST_PP_ITERATION_PARAMS_1 (3,(0, QGLIB_CONNECT_MAX_ARGS, "QGlib/connectimpl.h"))
00212 # include BOOST_PP_ITERATE()
00213
00214 # undef BOOST_PP_ITERATION_PARAMS_1
00215 # undef QGLIB_CONNECT_MAX_ARGS
00216
00217 # endif //QGLIB_HAVE_CXX0X
00218
00219
00220 #else // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 # define QGLIB_CONNECT_IMPL_NUM_ARGS \
00232 BOOST_PP_ITERATION()
00233
00234 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS \
00235 BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, typename A)
00236
00237 # define QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS \
00238 BOOST_PP_ENUM_TRAILING_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
00239
00240 # define QGLIB_CONNECT_IMPL_TEMPLATE_ARGS \
00241 BOOST_PP_ENUM_PARAMS(QGLIB_CONNECT_IMPL_NUM_ARGS, A)
00242
00243 namespace QGlib {
00244 namespace Private {
00245
00246
00247
00248 # define QGLIB_CONNECT_IMPL_CPPCLOSUREN \
00249 BOOST_PP_CAT(CppClosure, QGLIB_CONNECT_IMPL_NUM_ARGS)
00250
00251 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP(z, n, list) \
00252 ,ValueImpl< \
00253 typename boost::remove_const< \
00254 typename boost::remove_reference<A ##n>::type \
00255 >::type \
00256 >::get(list.at(n))
00257
00258 # define QGLIB_CONNECT_IMPL_UNPACK_ARGS(list) \
00259 BOOST_PP_REPEAT(QGLIB_CONNECT_IMPL_NUM_ARGS, QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP, list)
00260
00261 template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
00262 struct QGLIB_CONNECT_IMPL_CPPCLOSUREN
00263 {
00264 class ClosureData : public ClosureDataBase
00265 {
00266 public:
00267 inline ClosureData(const F & func, bool passSender)
00268 : ClosureDataBase(passSender), m_function(func) {}
00269
00270 virtual void marshaller(Value & result, const QList<Value> & params)
00271 {
00272 if (params.size() < QGLIB_CONNECT_IMPL_NUM_ARGS) {
00273 throw std::logic_error("The signal provides less arguments than what the closure expects");
00274 }
00275
00276 # if QGLIB_CONNECT_IMPL_NUM_ARGS > 0
00277 boost::function<R ()> callback = boost::bind<R>(m_function
00278 QGLIB_CONNECT_IMPL_UNPACK_ARGS(params));
00279 invoker< boost::function<R ()>, R >::invoke(callback, result);
00280 # else
00281 invoker< F, R >::invoke(m_function, result);
00282 # endif
00283 }
00284
00285 private:
00286 F m_function;
00287 };
00288
00289 static ClosureDataBase *create(const F & function, bool passSender)
00290 {
00291 return new ClosureData(function, passSender);
00292 }
00293 };
00294
00295
00296 template <typename F, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
00297 struct CppClosure<F, R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>
00298 : public QGLIB_CONNECT_IMPL_CPPCLOSUREN< F, R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS >
00299 {
00300 };
00301
00302 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS
00303 # undef QGLIB_CONNECT_IMPL_UNPACK_ARGS_STEP
00304 # undef QGLIB_CONNECT_IMPL_CPPCLOSUREN
00305
00306
00307
00308 }
00309
00310
00311
00312 # define QGLIB_CONNECT_IMPL_BIND_ARGS \
00313 BOOST_PP_COMMA_IF(QGLIB_CONNECT_IMPL_NUM_ARGS) \
00314 BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(QGLIB_CONNECT_IMPL_NUM_ARGS), _)
00315
00316 template <typename T, typename R QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS>
00317 bool connect(void *instance, const char *detailedSignal,
00318 T *receiver, R (T::*slot)(QGLIB_CONNECT_IMPL_TEMPLATE_ARGS), ConnectFlags flags = 0)
00319 {
00320 boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)> f
00321 = boost::bind(slot, receiver QGLIB_CONNECT_IMPL_BIND_ARGS);
00322
00323 Private::ClosureDataBase *closure = Private::CppClosure<
00324 boost::function<R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)>,
00325 R (QGLIB_CONNECT_IMPL_TEMPLATE_ARGS)
00326 >::create(f, flags & PassSender);
00327
00328 return Private::connect(instance, detailedSignal, Quark(),
00329 receiver, Private::GetDestroyNotifier<T>(),
00330 Private::hashMfp(slot), closure, flags);
00331 }
00332
00333 # undef QGLIB_CONNECT_IMPL_BIND_ARGS
00334
00335
00336
00337 }
00338
00339 # undef QGLIB_CONNECT_IMPL_TEMPLATE_ARGS
00340 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_ARGS
00341 # undef QGLIB_CONNECT_IMPL_TRAILING_TEMPLATE_PARAMS
00342 # undef QGLIB_CONNECT_IMPL_NUM_ARGS
00343
00344 #endif // !defined(BOOST_PP_IS_ITERATING) || !BOOST_PP_IS_ITERATING