Orocos Real-Time Toolkit  2.5.0
FusedFunctorDataSource.hpp
00001 /***************************************************************************
00002   tag: The SourceWorks  Tue Sep 7 00:55:18 CEST 2010  FusedFunctorDataSource.hpp
00003 
00004                         FusedFunctorDataSource.hpp -  description
00005                            -------------------
00006     begin                : Tue September 07 2010
00007     copyright            : (C) 2010 The SourceWorks
00008     email                : peter@thesourceworks.com
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 #ifndef ORO_FUSEDFUNCTORDATASOURCE_HPP_
00040 #define ORO_FUSEDFUNCTORDATASOURCE_HPP_
00041 
00042 #include "DataSource.hpp"
00043 #include "CreateSequence.hpp"
00044 #include "../SendStatus.hpp"
00045 #include "BindStorage.hpp"
00046 #include <boost/bind.hpp>
00047 #include <boost/type_traits.hpp>
00048 #include <boost/function.hpp>
00049 #include <boost/function_types/function_type.hpp>
00050 #include <boost/fusion/include/invoke.hpp>
00051 #include <boost/fusion/include/invoke_procedure.hpp>
00052 #include <boost/mpl/bool.hpp>
00053 
00054 namespace RTT
00055 {
00056     namespace internal
00057     {
00058         namespace bf = boost::fusion;
00059 
00065         template<typename Signature, class Enable=void>
00066         struct FusedFunctorDataSource
00067         : public DataSource<
00068                   typename remove_cr<typename boost::function_traits<Signature>::result_type>::type >
00069           {
00070               //BOOST_STATIC_ASSERT( boost::mpl::false_::value );
00071               typedef typename boost::function_traits<Signature>::result_type
00072                       result_type;
00073               typedef typename remove_cr<result_type>::type value_t;
00074               typedef typename DataSource<value_t>::const_reference_t const_reference_t;
00075               typedef create_sequence<
00076                       typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00077               typedef typename SequenceFactory::type DataSourceSequence;
00078               typedef boost::function<Signature> call_type;
00079               typedef typename SequenceFactory::data_type arg_type;
00080               boost::function<Signature> ff;
00081               DataSourceSequence args;
00082               mutable RStore<result_type> ret;
00083           public:
00084               typedef boost::intrusive_ptr<FusedFunctorDataSource<Signature> >
00085                       shared_ptr;
00086 
00087               template<class Func>
00088               FusedFunctorDataSource(Func g,
00089                                      const DataSourceSequence& s = DataSourceSequence() ) :
00090                   ff(g), args(s)
00091               {
00092               }
00093 
00094               void setArguments(const DataSourceSequence& a1)
00095               {
00096                   args = a1;
00097               }
00098 
00099               value_t value() const
00100               {
00101                   return ret.result();
00102               }
00103 
00104               const_reference_t rvalue() const
00105               {
00106                   return ret.result();
00107               }
00108 
00109               bool evaluate() const {
00110                   // forward invoke to ret object, which stores return value.
00111                   // this foo pointer dance is because older compilers don't handle using
00112                   // &bf::invoke<call_type,arg_type> directly.
00113                   typedef typename bf::result_of::invoke<call_type,arg_type>::type iret;
00114                   typedef iret(*IType)(call_type, arg_type const&);
00115                   IType foo = &bf::invoke<call_type,arg_type>;
00116                   ret.exec( boost::bind(foo, boost::ref(ff), SequenceFactory::data(args)));
00117                   SequenceFactory::update(args);
00118                   return true;
00119               }
00120 
00121               value_t get() const
00122               {
00123                   FusedFunctorDataSource<Signature>::evaluate();
00124                   return ret.result();
00125               }
00126 
00127               virtual FusedFunctorDataSource<Signature>* clone() const
00128               {
00129                   return new FusedFunctorDataSource<Signature> (ff, args);
00130               }
00131               virtual FusedFunctorDataSource<Signature>* copy(
00132                                                           std::map<
00133                                                                   const base::DataSourceBase*,
00134                                                                   base::DataSourceBase*>& alreadyCloned) const
00135               {
00136                   return new FusedFunctorDataSource<Signature> (ff, SequenceFactory::copy(args, alreadyCloned));
00137               }
00138           };
00139 
00140         template<typename Signature>
00141         struct FusedFunctorDataSource<Signature, typename boost::enable_if< is_pure_reference<typename boost::function_traits<Signature>::result_type> >::type >
00142         : public AssignableDataSource<
00143                   typename remove_cr<typename boost::function_traits<Signature>::result_type>::type >
00144           {
00145             //BOOST_STATIC_ASSERT( boost::mpl::false_::value );
00146               typedef typename boost::function_traits<Signature>::result_type
00147                       result_type;
00148               typedef typename remove_cr<result_type>::type value_t;
00149               typedef typename DataSource<value_t>::const_reference_t const_reference_t;
00150               typedef typename AssignableDataSource<value_t>::reference_t reference_t;
00151               typedef create_sequence<
00152                       typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00153               typedef typename SequenceFactory::type DataSourceSequence;
00154               typedef boost::function<Signature> call_type;
00155               typedef typename SequenceFactory::data_type arg_type;
00156               boost::function<Signature> ff;
00157               DataSourceSequence args;
00158               mutable RStore<result_type> ret;
00159           public:
00160               typedef boost::intrusive_ptr<FusedFunctorDataSource<Signature> >
00161                       shared_ptr;
00162 
00163               template<class Func>
00164               FusedFunctorDataSource(Func g,
00165                                      const DataSourceSequence& s = DataSourceSequence() ) :
00166                   ff(g), args(s)
00167               {
00168               }
00169 
00170               void setArguments(const DataSourceSequence& a1)
00171               {
00172                   args = a1;
00173               }
00174 
00175               value_t value() const
00176               {
00177                   return ret.result();
00178               }
00179 
00180               const_reference_t rvalue() const
00181               {
00182                   return ret.result();
00183               }
00184 
00185               bool evaluate() const {
00186                   // forward invoke to ret object, which stores return value.
00187                   // this foo pointer dance is because older compilers don't handle using
00188                   // &bf::invoke<call_type,arg_type> directly.
00189                   typedef typename bf::result_of::invoke<call_type,arg_type>::type iret;
00190                   typedef iret(*IType)(call_type, arg_type const&);
00191                   IType foo = &bf::invoke<call_type,arg_type>;
00192                   ret.exec( boost::bind(foo, boost::ref(ff), SequenceFactory::data(args)));
00193                   SequenceFactory::update(args);
00194                   return true;
00195               }
00196               value_t get() const
00197               {
00198                   FusedFunctorDataSource<Signature>::evaluate();
00199                   return ret.result();
00200               }
00201 
00202               void set( typename AssignableDataSource<value_t>::param_t arg) {
00203                   // we need to get the new reference before we set the arg.
00204                   get(); ret.result() = arg;
00205               }
00206 
00207               reference_t set() {
00208                   get(); return ret.result();
00209               }
00210 
00211               virtual FusedFunctorDataSource<Signature>* clone() const
00212               {
00213                   return new FusedFunctorDataSource<Signature> (ff, args);
00214               }
00215               virtual FusedFunctorDataSource<Signature>* copy(
00216                                                           std::map<
00217                                                                   const base::DataSourceBase*,
00218                                                                   base::DataSourceBase*>& alreadyCloned) const
00219               {
00220                   return new FusedFunctorDataSource<Signature> (ff, SequenceFactory::copy(args, alreadyCloned));
00221               }
00222           };
00233         template<class Function>
00234         base::DataSourceBase* newFunctorDataSource(Function f, const std::vector<base::DataSourceBase::shared_ptr>& args)
00235         {
00236             typedef typename boost::function_types::function_type<Function>::type Signature;
00237             typedef internal::create_sequence<typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00238             if ( args.size() != boost::function_traits<Signature>::arity )
00239                 throw wrong_number_of_args_exception(boost::function_traits<Signature>::arity, args.size() );
00240             return new FusedFunctorDataSource<Signature>(f, SequenceFactory::sources(args.begin()));
00241         }
00242 
00248         template<typename Signature>
00249         struct FusedMCallDataSource
00250         : public DataSource<
00251               typename remove_cr<typename boost::function_traits<Signature>::result_type>::type >
00252         {
00253               typedef typename boost::function_traits<Signature>::result_type
00254                       result_type;
00255               typedef typename remove_cr<result_type>::type value_t;
00256               typedef typename DataSource<value_t>::const_reference_t const_reference_t;
00257               typedef create_sequence<
00258                       typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00259               typedef typename SequenceFactory::type DataSourceSequence;
00260               typename base::OperationCallerBase<Signature>::shared_ptr ff;
00261               DataSourceSequence args;
00262               mutable RStore<result_type> ret;
00263           public:
00264               typedef boost::intrusive_ptr<FusedMCallDataSource<Signature> >
00265                       shared_ptr;
00266 
00267               FusedMCallDataSource(typename base::OperationCallerBase<Signature>::shared_ptr g,
00268                                      const DataSourceSequence& s = DataSourceSequence() ) :
00269                   ff(g), args(s)
00270               {
00271               }
00272 
00273               void setArguments(const DataSourceSequence& a1)
00274               {
00275                   args = a1;
00276               }
00277 
00278               value_t value() const
00279               {
00280                   return ret.result();
00281               }
00282 
00283               const_reference_t rvalue() const
00284               {
00285                   return ret.result();
00286               }
00287 
00288               bool evaluate() const {
00289                   // put the member's object as first since SequenceFactory does not know about the OperationCallerBase type.
00290                   typedef bf::cons<base::OperationCallerBase<Signature>*, typename SequenceFactory::data_type> arg_type;
00291                   typedef typename AddMember<Signature,base::OperationCallerBase<Signature>* >::type call_type;
00292                   // this foo pointer dance is because older compilers don't handle using
00293                   // &bf::invoke<call_type,arg_type> directly.
00294                   typedef typename bf::result_of::invoke<call_type,arg_type>::type iret;
00295                   typedef iret(*IType)(call_type, arg_type const&);
00296                   IType foo = &bf::invoke<call_type,arg_type>;
00297                   // we need to store the ret value ourselves.
00298                   ret.exec( boost::bind(foo, &base::OperationCallerBase<Signature>::call, arg_type(ff.get(), SequenceFactory::data(args))) );
00299                   SequenceFactory::update(args);
00300                   return true;
00301               }
00302 
00303               value_t get() const
00304               {
00305                   FusedMCallDataSource<Signature>::evaluate();
00306                   return ret.result();
00307               }
00308 
00309               virtual FusedMCallDataSource<Signature>* clone() const
00310               {
00311                   return new FusedMCallDataSource<Signature> (ff, args);
00312               }
00313               virtual FusedMCallDataSource<Signature>* copy(
00314                                                           std::map<
00315                                                                   const base::DataSourceBase*,
00316                                                                   base::DataSourceBase*>& alreadyCloned) const
00317               {
00318                   return new FusedMCallDataSource<Signature> (ff, SequenceFactory::copy(args, alreadyCloned));
00319               }
00320           };
00321 
00326         template<typename Signature>
00327         struct FusedMSendDataSource
00328         : public DataSource<SendHandle<Signature> >
00329           {
00330               typedef SendHandle<Signature> result_type;
00331               typedef result_type value_t;
00332               typedef typename DataSource<value_t>::const_reference_t const_reference_t;
00333               typedef create_sequence<
00334                       typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00335               typedef typename SequenceFactory::type DataSourceSequence;
00336               typename base::OperationCallerBase<Signature>::shared_ptr ff;
00337               DataSourceSequence args;
00338               mutable SendHandle<Signature> sh; // mutable because of get() const
00339           public:
00340               typedef boost::intrusive_ptr<FusedMSendDataSource<Signature> >
00341                       shared_ptr;
00342 
00343               FusedMSendDataSource(typename base::OperationCallerBase<Signature>::shared_ptr g,
00344                                      const DataSourceSequence& s = DataSourceSequence() ) :
00345                   ff(g), args(s)
00346               {
00347               }
00348 
00349               void setArguments(const DataSourceSequence& a1)
00350               {
00351                   args = a1;
00352               }
00353 
00354               value_t value() const
00355               {
00356                   return sh;
00357               }
00358 
00359               const_reference_t rvalue() const
00360               {
00361                   return sh;
00362               }
00363 
00364               value_t get() const
00365               {
00366                   // put the member's object as first since SequenceFactory does not know about the OperationCallerBase type.
00367                   sh = bf::invoke(&base::OperationCallerBase<Signature>::send, bf::cons<base::OperationCallerBase<Signature>*, typename SequenceFactory::data_type>(ff.get(), SequenceFactory::data(args)));
00368                   return sh;
00369               }
00370 
00371               virtual FusedMSendDataSource<Signature>* clone() const
00372               {
00373                   return new FusedMSendDataSource<Signature> (ff, args);
00374               }
00375               virtual FusedMSendDataSource<Signature>* copy(
00376                                                           std::map<
00377                                                                   const base::DataSourceBase*,
00378                                                                   base::DataSourceBase*>& alreadyCloned) const
00379               {
00380                   return new FusedMSendDataSource<Signature> (ff, SequenceFactory::copy(args, alreadyCloned));
00381               }
00382           };
00383 
00390         template<typename Signature>
00391         struct FusedMCollectDataSource
00392         : public DataSource<SendStatus>
00393           {
00394               typedef SendStatus result_type;
00395               typedef result_type value_t;
00396               typedef DataSource<SendStatus>::const_reference_t const_reference_t;
00397               // push the SendHandle pointer in front.
00398               typedef typename CollectType<Signature>::type CollectSignature;
00399               typedef typename boost::function_types::parameter_types<CollectSignature>::type arg_types;
00400               typedef typename mpl::push_front<arg_types, SendHandle<Signature>& >::type handle_and_arg_types;
00401               typedef create_sequence< handle_and_arg_types
00402                       > SequenceFactory;
00403               typedef typename SequenceFactory::type DataSourceSequence;
00404               DataSourceSequence args;
00405               DataSource<bool>::shared_ptr isblocking;
00406               mutable SendStatus ss; // because of get() const
00407           public:
00408               typedef boost::intrusive_ptr<FusedMCollectDataSource<Signature> >
00409                       shared_ptr;
00410 
00411               FusedMCollectDataSource(
00412                                      const DataSourceSequence& s, DataSource<bool>::shared_ptr blocking ) :
00413                   args(s), isblocking(blocking), ss(SendFailure)
00414               {
00415               }
00416 
00417               void setArguments(const DataSourceSequence& a1)
00418               {
00419                   args = a1;
00420               }
00421 
00422               value_t value() const
00423               {
00424                   return ss;
00425               }
00426 
00427               const_reference_t rvalue() const
00428               {
00429                   return ss;
00430               }
00431 
00432               value_t get() const
00433               {
00434                   // put the member's object as first since SequenceFactory does not know about the OperationCallerBase type.
00435                   if (isblocking->get())
00436                       ss = bf::invoke(&SendHandle<Signature>::CBase::collect, SequenceFactory::data(args));
00437                   else
00438                       ss = bf::invoke(&SendHandle<Signature>::CBase::collectIfDone, SequenceFactory::data(args));
00439                   SequenceFactory::update(args);
00440                   return ss;
00441               }
00442 
00443               virtual FusedMCollectDataSource<Signature>* clone() const
00444               {
00445                   return new FusedMCollectDataSource<Signature> ( args, isblocking);
00446               }
00447               virtual FusedMCollectDataSource<Signature>* copy(
00448                                                           std::map<
00449                                                                   const base::DataSourceBase*,
00450                                                                   base::DataSourceBase*>& alreadyCloned) const
00451               {
00452                   return new FusedMCollectDataSource<Signature> ( SequenceFactory::copy(args, alreadyCloned), isblocking);
00453               }
00454           };
00455 
00460         template<typename Signature>
00461         struct FusedMSignal
00462         {
00463             typedef typename boost::function_traits<Signature>::result_type
00464                     result_type;
00465             typedef result_type value_t;
00466             typedef create_sequence<
00467                     typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00468             typedef typename SequenceFactory::atype DataSourceSequence;
00469             base::ActionInterface* mact;
00470             DataSourceSequence args;
00471         public:
00472               typedef boost::shared_ptr<FusedMSignal<Signature> >
00473                       shared_ptr;
00474 
00475               FusedMSignal(base::ActionInterface* act,
00476                            const DataSourceSequence& s = DataSourceSequence() ) :
00477                   mact(act), args(s)
00478               {
00479               }
00480 
00486               result_type invoke(typename SequenceFactory::data_type seq) {
00487                   SequenceFactory::set( seq, args );
00488                   mact->execute();
00489                   return NA<result_type>::na();
00490               }
00491 
00492               void setArguments(const DataSourceSequence& a1)
00493               {
00494                   args = a1;
00495               }
00496           };
00497 
00498     }
00499 }
00500 
00501 #endif /* ORO_FUSEDFUNCTORDATASOURCE_HPP_ */