Orocos Real-Time Toolkit  2.6.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                   if(ret.isError()) {
00300                     ff->reportError();
00301                     ret.checkError();
00302                   }
00303                   SequenceFactory::update(args);
00304                   return true;
00305               }
00306 
00307               value_t get() const
00308               {
00309                   evaluate();
00310                   return ret.result();
00311               }
00312 
00313               virtual FusedMCallDataSource<Signature>* clone() const
00314               {
00315                   return new FusedMCallDataSource<Signature> (ff, args);
00316               }
00317               virtual FusedMCallDataSource<Signature>* copy(
00318                                                           std::map<
00319                                                                   const base::DataSourceBase*,
00320                                                                   base::DataSourceBase*>& alreadyCloned) const
00321               {
00322                   return new FusedMCallDataSource<Signature> (ff, SequenceFactory::copy(args, alreadyCloned));
00323               }
00324           };
00325 
00330         template<typename Signature>
00331         struct FusedMSendDataSource
00332         : public DataSource<SendHandle<Signature> >
00333           {
00334               typedef SendHandle<Signature> result_type;
00335               typedef result_type value_t;
00336               typedef typename DataSource<value_t>::const_reference_t const_reference_t;
00337               typedef create_sequence<
00338                       typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00339               typedef typename SequenceFactory::type DataSourceSequence;
00340               typename base::OperationCallerBase<Signature>::shared_ptr ff;
00341               DataSourceSequence args;
00342               mutable SendHandle<Signature> sh; // mutable because of get() const
00343           public:
00344               typedef boost::intrusive_ptr<FusedMSendDataSource<Signature> >
00345                       shared_ptr;
00346 
00347               FusedMSendDataSource(typename base::OperationCallerBase<Signature>::shared_ptr g,
00348                                      const DataSourceSequence& s = DataSourceSequence() ) :
00349                   ff(g), args(s)
00350               {
00351               }
00352 
00353               void setArguments(const DataSourceSequence& a1)
00354               {
00355                   args = a1;
00356               }
00357 
00358               value_t value() const
00359               {
00360                   return sh;
00361               }
00362 
00363               const_reference_t rvalue() const
00364               {
00365                   return sh;
00366               }
00367 
00368               value_t get() const
00369               {
00370                   // put the member's object as first since SequenceFactory does not know about the OperationCallerBase type.
00371                   sh = bf::invoke(&base::OperationCallerBase<Signature>::send, bf::cons<base::OperationCallerBase<Signature>*, typename SequenceFactory::data_type>(ff.get(), SequenceFactory::data(args)));
00372                   return sh;
00373               }
00374 
00375               virtual FusedMSendDataSource<Signature>* clone() const
00376               {
00377                   return new FusedMSendDataSource<Signature> (ff, args);
00378               }
00379               virtual FusedMSendDataSource<Signature>* copy(
00380                                                           std::map<
00381                                                                   const base::DataSourceBase*,
00382                                                                   base::DataSourceBase*>& alreadyCloned) const
00383               {
00384                   return new FusedMSendDataSource<Signature> (ff, SequenceFactory::copy(args, alreadyCloned));
00385               }
00386           };
00387 
00394         template<typename Signature>
00395         struct FusedMCollectDataSource
00396         : public DataSource<SendStatus>
00397           {
00398               typedef SendStatus result_type;
00399               typedef result_type value_t;
00400               typedef DataSource<SendStatus>::const_reference_t const_reference_t;
00401               // push the SendHandle pointer in front.
00402               typedef typename CollectType<Signature>::type CollectSignature;
00403               typedef typename boost::function_types::parameter_types<CollectSignature>::type arg_types;
00404               typedef typename mpl::push_front<arg_types, SendHandle<Signature>& >::type handle_and_arg_types;
00405               typedef create_sequence< handle_and_arg_types
00406                       > SequenceFactory;
00407               typedef typename SequenceFactory::type DataSourceSequence;
00408               DataSourceSequence args;
00409               DataSource<bool>::shared_ptr isblocking;
00410               mutable SendStatus ss; // because of get() const
00411           public:
00412               typedef boost::intrusive_ptr<FusedMCollectDataSource<Signature> >
00413                       shared_ptr;
00414 
00415               FusedMCollectDataSource(
00416                                      const DataSourceSequence& s, DataSource<bool>::shared_ptr blocking ) :
00417                   args(s), isblocking(blocking), ss(SendFailure)
00418               {
00419               }
00420 
00421               void setArguments(const DataSourceSequence& a1)
00422               {
00423                   args = a1;
00424               }
00425 
00426               value_t value() const
00427               {
00428                   return ss;
00429               }
00430 
00431               const_reference_t rvalue() const
00432               {
00433                   return ss;
00434               }
00435 
00436               value_t get() const
00437               {
00438                   // put the member's object as first since SequenceFactory does not know about the OperationCallerBase type.
00439                   if (isblocking->get())
00440                       ss = bf::invoke(&SendHandle<Signature>::CBase::collect, SequenceFactory::data(args));
00441                   else
00442                       ss = bf::invoke(&SendHandle<Signature>::CBase::collectIfDone, SequenceFactory::data(args));
00443                   SequenceFactory::update(args);
00444                   return ss;
00445               }
00446 
00447               virtual FusedMCollectDataSource<Signature>* clone() const
00448               {
00449                   return new FusedMCollectDataSource<Signature> ( args, isblocking);
00450               }
00451               virtual FusedMCollectDataSource<Signature>* copy(
00452                                                           std::map<
00453                                                                   const base::DataSourceBase*,
00454                                                                   base::DataSourceBase*>& alreadyCloned) const
00455               {
00456                   return new FusedMCollectDataSource<Signature> ( SequenceFactory::copy(args, alreadyCloned), isblocking);
00457               }
00458           };
00459 
00464         template<typename Signature>
00465         struct FusedMSignal
00466         {
00467             typedef typename boost::function_traits<Signature>::result_type
00468                     result_type;
00469             typedef result_type value_t;
00470             typedef create_sequence<
00471                     typename boost::function_types::parameter_types<Signature>::type> SequenceFactory;
00472             typedef typename SequenceFactory::atype DataSourceSequence;
00473             base::ActionInterface* mact;
00474             DataSourceSequence args;
00475         public:
00476               typedef boost::shared_ptr<FusedMSignal<Signature> >
00477                       shared_ptr;
00478 
00479               FusedMSignal(base::ActionInterface* act,
00480                            const DataSourceSequence& s = DataSourceSequence() ) :
00481                   mact(act), args(s)
00482               {
00483               }
00484 
00490               result_type invoke(typename SequenceFactory::data_type seq) {
00491                   SequenceFactory::set( seq, args );
00492                   mact->execute();
00493                   return NA<result_type>::na();
00494               }
00495 
00496               void setArguments(const DataSourceSequence& a1)
00497               {
00498                   args = a1;
00499               }
00500           };
00501 
00502     }
00503 }
00504 
00505 #endif /* ORO_FUSEDFUNCTORDATASOURCE_HPP_ */