QtGStreamer  0.10.2
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
connectimpl.h
00001 /*
00002     Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
00003     Copyright (C) 2010 Collabora Ltd.
00004       @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>
00005 
00006     This library is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU Lesser General Public License as published
00008     by the Free Software Foundation; either version 2.1 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU Lesser General Public License for more details.
00015 
00016     You should have received a copy of the GNU Lesser General Public License
00017     along with this program.  If not, see <http://www.gnu.org/licenses/>.
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 //BEGIN ******** CppClosure prototype ********
00036 
00037 template <typename Function, typename Signature>
00038 struct CppClosure {};
00039 
00040 //END ******** CppClosure prototype ********
00041 //BEGIN ******** invoker ********
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 //END ******** invoker ********
00056 
00057 } //namespace Private
00058 } //namespace QGlib
00059 
00060 
00061 # if QGLIB_HAVE_CXX0X
00062 
00063 namespace QGlib {
00064 namespace Private {
00065 
00066 //BEGIN ******** MemberFunction ********
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 //END ******** MemberFunction ********
00092 //BEGIN ******** BoundArgumentFunction ********
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 //END ******** BoundArgumentFunction ********
00119 //BEGIN ******** unpackAndInvoke ********
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 //END ******** unpackAndInvoke ********
00148 //BEGIN ******** CppClosure ********
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 //END ******** CppClosure ********
00180 
00181 } //namespace Private
00182 
00183 //BEGIN ******** QGlib::connect ********
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 //END ******** QGlib::connect ********
00201 
00202 } //namespace QGlib
00203 
00204 # else //QGLIB_HAVE_CXX0X
00205 
00206 #  include <boost/function.hpp>
00207 #  include <boost/preprocessor.hpp>
00208 #  include <boost/bind.hpp>
00209 
00210 // include the second part of this file as many times as QGLIB_CONNECT_MAX_ARGS specifies
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     This part is included from BOOST_PP_ITERATE(). It defines a CppClosureN class
00224     (where N is the number of template arguments it takes) and a specialization for class
00225     CppClosure, so that the CppClosure<R (Args...), F> syntax is supported. This part is
00226     included multiple times (QGLIB_CONNECT_MAX_ARGS defines how many), and each time
00227     it defines those classes with different number of arguments.
00228     The concept is based on the implementation of boost::function.
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 //BEGIN ******** boostpp CppClosure ********
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 //partial specialization of struct CppClosure to support the CppClosure<F, R (Args...)> syntax
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 //END ******** boostpp CppClosure ********
00307 
00308 } //namespace Private
00309 
00310 //BEGIN ******** bostpp QGlib::connect ********
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 //END ******** bostpp QGlib::connect ********
00336 
00337 } //namespace QGlib
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