From ab4b4c71e61869ffb90e7443666962c525585af5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 16 Jun 2009 11:39:36 +0200 Subject: [PATCH] WIP: start extacting new headers --- src/lib/meta/function.hpp | 534 ++++++++++++++++++ .../proc/control/command-basic-test.cpp | 476 +--------------- 2 files changed, 535 insertions(+), 475 deletions(-) create mode 100644 src/lib/meta/function.hpp diff --git a/src/lib/meta/function.hpp b/src/lib/meta/function.hpp new file mode 100644 index 000000000..9cdb8e89d --- /dev/null +++ b/src/lib/meta/function.hpp @@ -0,0 +1,534 @@ +/* + FUNCTION.hpp - metaprogramming utilities for transforming function types + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file function.hpp + ** Metaprogramming tools for transforming functor types. + ** Sometimes it is necessary to build and remould a function signature, e.g. for + ** creating a functor or a closure based on an existing function of function pointer. + ** This is a core task of functional programming, but sadly C++ in its current shape + ** is still lacking in this area. (C++0X will significantly improve this situation). + ** As an \em pragmatic fix, we define here a collection of templates, specialising + ** them in a very repetitive way for up to 9 function arguments. Doing so enables + ** us to capture a function, access the return type and argument types as a typelist, + ** eventually to manipulate them and re-build a different signature, or to create + ** specifically tailored bindings. + ** + ** If the following code makes you feel like vomiting, please look away, + ** and rest assured: you aren't alone. + ** + ** @see control::CommandDef usage example + ** @see typelist.hpp + ** @see tuple.hpp + ** + */ + + +#ifndef LUMIERA_META_FUNCTION_H +#define LUMIERA_META_FUNCTION_H + +#include "lib/meta/typelist.hpp" +#include "lib/meta/generator.hpp" +#include "lib/meta/typelistutil.hpp" + +#include + + + +namespace lumiera { +namespace typelist{ + + using std::tr1::bind; + //using std::tr1::placeholders::_1; + //using std::tr1::placeholders::_2; + using std::tr1::function; + + + template< typename SIG> + struct FunctionSignature; + + template< typename RET> + struct FunctionSignature< function > + { + typedef RET Ret; + typedef Types<> Args; + }; + + template< typename RET + , typename A1 + > + struct FunctionSignature< function > + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET + , typename A1 + , typename A2 + > + struct FunctionSignature< function > + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET + , typename A1 + , typename A2 + , typename A3 + > + struct FunctionSignature< function > + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET + , typename A1 + , typename A2 + , typename A3 + , typename A4 + > + struct FunctionSignature< function > + { + typedef RET Ret; + typedef Types Args; + }; + + template< typename RET + , typename A1 + , typename A2 + , typename A3 + , typename A4 + , typename A5 + > + struct FunctionSignature< function > + { + typedef RET Ret; + typedef Types Args; + }; + + + template + struct FunctionTypedef; + + template< typename RET> + struct FunctionTypedef > + { + typedef function Func; + typedef RET Sig(); + }; + + template< typename RET + , typename A1 + > + struct FunctionTypedef > + { + typedef function Func; + typedef RET Sig(A1); + }; + + template< typename RET + , typename A1 + , typename A2 + > + struct FunctionTypedef > + { + typedef function Func; + typedef RET Sig(A1,A2); + }; + + template< typename RET + , typename A1 + , typename A2 + , typename A3 + > + struct FunctionTypedef > + { + typedef function Func; + typedef RET Sig(A1,A2,A3); + }; + + template< typename RET + , typename A1 + , typename A2 + , typename A3 + , typename A4 + > + struct FunctionTypedef > + { + typedef function Func; + typedef RET Sig(A1,A2,A3,A4); + }; + + template< typename RET + , typename A1 + , typename A2 + , typename A3 + , typename A4 + , typename A5 + > + struct FunctionTypedef > + { + typedef function Func; + typedef RET Sig(A1,A2,A3,A4,A5); + }; + + + + /////////////////////////very basic facility: Typed tuples + + template + struct Prepend; + + template< typename A1 + , typename A2 + , typename A3 + , typename A4 + , typename A5 + , typename IGN + > + struct Prepend > + { + typedef Types Tuple; + }; + + template + struct Tuple; + + template<> + struct Tuple + { + typedef NullType HeadType; + typedef Types<> TailType; + typedef Types<> Type; + + typedef NullType ArgList_; + typedef Tuple ThisTuple; + typedef Tuple Tail; + enum { SIZE = 0 }; + + NullType getHead() { return NullType(); } + Tail& getTail() { return *this; } + + Tuple (HeadType const&, Tail const&) { } + Tuple () { } + }; + + template + struct Tuple > + : Tuple + { + typedef TY HeadType; + typedef typename Tuple::Type TailType; + typedef typename Prepend::Tuple Type; + + typedef Node ArgList_; + typedef Tuple ThisTuple; + typedef Tuple Tail; + enum { SIZE = count::value }; + + Tuple ( TY a1 =TY() + , Tail tail =Tail() + ) + : Tuple (tail.getHead(), tail.getTail()), + val_(a1) + { } + + TY & getHead() { return val_; } + Tail& getTail() { return static_cast (*this); } + + private: + TY val_; + }; + + ////TODO move in sub-scope + template + struct Shifted + { + typedef typename TUP::Tail Tail; + typedef typename Shifted::TupleType TupleType; + }; + template + struct Shifted + { + typedef Tuple TupleType; + }; + + + template< typename T1 + , typename T2 + , typename T3 + , typename T4 + , typename T5 + > + struct Tuple > + : Tuple::List> + { + typedef T1 HeadType; + typedef Types TailType; + typedef Types Type; + + typedef typename Type::List ArgList_; + typedef Tuple ThisTuple; + typedef Tuple Tail; + enum { SIZE = count::value }; + + Tuple ( T1 a1 =T1() + , T2 a2 =T2() + , T3 a3 =T3() + , T4 a4 =T4() + , T5 a5 =T5() + ) + : Tuple(a1, Tuple(a2,a3,a4,a5)) + { } + + using Tuple::getHead; + using Tuple::getTail; + + template + typename Shifted::TupleType& + getShifted () + { + typedef typename Shifted::TupleType Tail_I; + return static_cast (*this); + } + + template + typename Shifted::TupleType::HeadType& + getAt () + { + return getShifted().getHead(); + } + + NullType& + getNull() + { + static NullType nix; + return nix; + } + }; + + + /** + * Decorating a tuple type with auxiliary data access operations. + * This helper template builds up a subclass of the given BASE type + * (which is assumed to be a Tuple or at least need to be copy constructible + * from \c Tuple ). The purpose is to use the Tuple as storage, but + * to add a layer of access functions, which in turn might rely on the exact + * type of the individual elements within the Tuple. To achieve this, for each + * type within the Tuple, the BASE type is decorated with an instance of the + * template passed in as template template parameter _X_. Each of these + * decorating instances is provided with a member pointer to access "his" + * specific element within the underlying tuple. + * + * The decorating template _X_ need to take its own base class as template + * parameter. Typically, operations on _X_ will be defined in a recursive fashion, + * calling down into this templated base class. To support this, an instantiation + * of _X_ with the 0 member ptr is generated for detecting recursion end + * (built as innermost decorator, i.e. immediate subclass of BASE) + */ + template + < typename TYPES + , template class _X_ + , class BASE =Tuple + , uint i = 0 + > + class BuildTupleAccessor + { + typedef Tuple ArgTuple; + typedef typename ArgTuple::HeadType Head; + typedef typename ArgTuple::TailType Tail; +// typedef Head ArgTuple::*getElm(); + typedef BuildTupleAccessor NextBuilder; + typedef typename NextBuilder::Accessor NextAccessor; + + ArgTuple& argData_; + + public: + + /** type of the product created by this template. + * Will be a subclass of BASE */ + typedef _X_ Accessor; + + BuildTupleAccessor (ArgTuple& tup) + : argData_(tup) + { } + + operator Accessor() { return Accessor(argData_); } + + }; + + template + < class BASE + , template class _X_ + , uint i + > + class BuildTupleAccessor, _X_, BASE, i> + { + typedef Tuple > ArgTuple; +// typedef NullType BASE::*getElm(); + + public: + typedef _X_ Accessor; + }; + + + ///////////////////////// creating functional closures + + namespace tuple { + template + struct Apply; + + template<> + struct Apply<1> + { + template + static RET + invoke (FUN f, TUP & arg) + { + return f (arg.template getAt<1>()); + } + + template + static RET + bind (FUN f, TUP & arg) + { + return std::tr1::bind (f, arg.template getAt<1>()); + } + }; + + template<> + struct Apply<2> + { + template + static RET + invoke (FUN f, TUP & arg) + { + return f ( arg.template getAt<1>() + , arg.template getAt<2>() + ); + } + + template + static RET + bind (FUN f, TUP & arg) + { + return std::tr1::bind (f, arg.template getAt<1>() + , arg.template getAt<2>() + ); + } + }; + } // (END) sub-namespace + + template + class TupleApplicator + { + typedef typename FunctionSignature< function >::Args Args; + typedef typename FunctionSignature< function >::Ret Ret; + + enum { ARG_CNT = count::value }; + + + /** storing a ref to the parameter tuple */ + Tuple& params_; + + public: + TupleApplicator (Tuple& args) + : params_(args) + { } + + function bind (SIG& f) { return tuple::Apply::bind (f, params_); } + function bind (function const& f) { return tuple::Apply::bind (f, params_); } + + Ret operator() (SIG& f) { return tuple::Apply::invoke (f, params_); } + Ret operator() (function const& f) { return tuple::Apply::invoke (f, params_); } + }; + + + /** + * Closing a function over its arguments. + * This is a small usage example or spin-off, + * having almost the same effect than invoking tr1::bind. + * The notable difference is that the function arguments for + * creating the closure are passed in as one compound tuple. + */ + template + class FunctionClosure + { + typedef typename FunctionSignature< function >::Args Args; + typedef typename FunctionSignature< function >::Ret Ret; + + function closure_; + + public: + FunctionClosure (SIG& f, Tuple& arg) + : closure_(TupleApplicator(arg).bind(f)) + { } + FunctionClosure (function const& f, Tuple& arg) + : closure_(TupleApplicator(arg).bind(f)) + { } + + Ret operator() () { return closure_(); } + }; + + +/* + template + struct BuildClosure + : InstantiateWithIndex + { + + }; +*/ + + ///////////////////////// additional typelist manipulators + + template + struct SplitLast; + + template<> + struct SplitLast + { + typedef NullType Type; + typedef NullType Prefix; + }; + + template + struct SplitLast > + { + typedef TY Type; + typedef NullType Prefix; + }; + + template + struct SplitLast > + { + typedef typename SplitLast::Type Type; + typedef typename Append::Prefix>::List Prefix; + }; + + + +}} // namespace lumiera::typelist +#endif diff --git a/tests/components/proc/control/command-basic-test.cpp b/tests/components/proc/control/command-basic-test.cpp index 15c551834..7d74708a6 100644 --- a/tests/components/proc/control/command-basic-test.cpp +++ b/tests/components/proc/control/command-basic-test.cpp @@ -39,6 +39,7 @@ #include "lib/meta/typelist.hpp" #include "lib/meta/typelistutil.hpp" #include "lib/meta/generator.hpp" +#include "lib/meta/function.hpp" #include //#include @@ -57,481 +58,6 @@ using std::cout; using std::endl; -namespace lumiera { -namespace typelist{ - - - ////////////////////////////////////////////TODO braindump - - template< typename SIG> - struct FunctionSignature; - - template< typename RET> - struct FunctionSignature< function > - { - typedef RET Ret; - typedef Types<> Args; - }; - - template< typename RET - , typename A1 - > - struct FunctionSignature< function > - { - typedef RET Ret; - typedef Types Args; - }; - - template< typename RET - , typename A1 - , typename A2 - > - struct FunctionSignature< function > - { - typedef RET Ret; - typedef Types Args; - }; - - template< typename RET - , typename A1 - , typename A2 - , typename A3 - > - struct FunctionSignature< function > - { - typedef RET Ret; - typedef Types Args; - }; - - template< typename RET - , typename A1 - , typename A2 - , typename A3 - , typename A4 - > - struct FunctionSignature< function > - { - typedef RET Ret; - typedef Types Args; - }; - - template< typename RET - , typename A1 - , typename A2 - , typename A3 - , typename A4 - , typename A5 - > - struct FunctionSignature< function > - { - typedef RET Ret; - typedef Types Args; - }; - - - template - struct FunctionTypedef; - - template< typename RET> - struct FunctionTypedef > - { - typedef function Func; - typedef RET Sig(); - }; - - template< typename RET - , typename A1 - > - struct FunctionTypedef > - { - typedef function Func; - typedef RET Sig(A1); - }; - - template< typename RET - , typename A1 - , typename A2 - > - struct FunctionTypedef > - { - typedef function Func; - typedef RET Sig(A1,A2); - }; - - template< typename RET - , typename A1 - , typename A2 - , typename A3 - > - struct FunctionTypedef > - { - typedef function Func; - typedef RET Sig(A1,A2,A3); - }; - - template< typename RET - , typename A1 - , typename A2 - , typename A3 - , typename A4 - > - struct FunctionTypedef > - { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4); - }; - - template< typename RET - , typename A1 - , typename A2 - , typename A3 - , typename A4 - , typename A5 - > - struct FunctionTypedef > - { - typedef function Func; - typedef RET Sig(A1,A2,A3,A4,A5); - }; - - - - /////////////////////////very basic facility: Typed tuples - - template - struct Prepend; - - template< typename A1 - , typename A2 - , typename A3 - , typename A4 - , typename A5 - , typename IGN - > - struct Prepend > - { - typedef Types Tuple; - }; - - template - struct Tuple; - - template<> - struct Tuple - { - typedef NullType HeadType; - typedef Types<> TailType; - typedef Types<> Type; - - typedef NullType ArgList_; - typedef Tuple ThisTuple; - typedef Tuple Tail; - enum { SIZE = 0 }; - - NullType getHead() { return NullType(); } - Tail& getTail() { return *this; } - - Tuple (HeadType const&, Tail const&) { } - Tuple () { } - }; - - template - struct Tuple > - : Tuple - { - typedef TY HeadType; - typedef typename Tuple::Type TailType; - typedef typename Prepend::Tuple Type; - - typedef Node ArgList_; - typedef Tuple ThisTuple; - typedef Tuple Tail; - enum { SIZE = count::value }; - - Tuple ( TY a1 =TY() - , Tail tail =Tail() - ) - : Tuple (tail.getHead(), tail.getTail()), - val_(a1) - { } - - TY & getHead() { return val_; } - Tail& getTail() { return static_cast (*this); } - - private: - TY val_; - }; - - ////TODO move in sub-scope - template - struct Shifted - { - typedef typename TUP::Tail Tail; - typedef typename Shifted::TupleType TupleType; - }; - template - struct Shifted - { - typedef Tuple TupleType; - }; - - - template< typename T1 - , typename T2 - , typename T3 - , typename T4 - , typename T5 - > - struct Tuple > - : Tuple::List> - { - typedef T1 HeadType; - typedef Types TailType; - typedef Types Type; - - typedef typename Type::List ArgList_; - typedef Tuple ThisTuple; - typedef Tuple Tail; - enum { SIZE = count::value }; - - Tuple ( T1 a1 =T1() - , T2 a2 =T2() - , T3 a3 =T3() - , T4 a4 =T4() - , T5 a5 =T5() - ) - : Tuple(a1, Tuple(a2,a3,a4,a5)) - { } - - using Tuple::getHead; - using Tuple::getTail; - - template - typename Shifted::TupleType& - getShifted () - { - typedef typename Shifted::TupleType Tail_I; - return static_cast (*this); - } - - template - typename Shifted::TupleType::HeadType& - getAt () - { - return getShifted().getHead(); - } - - NullType& - getNull() - { - static NullType nix; - return nix; - } - }; - - - /** - * Decorating a tuple type with auxiliary data access operations. - * This helper template builds up a subclass of the given BASE type - * (which is assumed to be a Tuple or at least need to be copy constructible - * from \c Tuple ). The purpose is to use the Tuple as storage, but - * to add a layer of access functions, which in turn might rely on the exact - * type of the individual elements within the Tuple. To achieve this, for each - * type within the Tuple, the BASE type is decorated with an instance of the - * template passed in as template template parameter _X_. Each of these - * decorating instances is provided with a member pointer to access "his" - * specific element within the underlying tuple. - * - * The decorating template _X_ need to take its own base class as template - * parameter. Typically, operations on _X_ will be defined in a recursive fashion, - * calling down into this templated base class. To support this, an instantiation - * of _X_ with the 0 member ptr is generated for detecting recursion end - * (built as innermost decorator, i.e. immediate subclass of BASE) - */ - template - < typename TYPES - , template class _X_ - , class BASE =Tuple - , uint i = 0 - > - class BuildTupleAccessor - { - typedef Tuple ArgTuple; - typedef typename ArgTuple::HeadType Head; - typedef typename ArgTuple::TailType Tail; -// typedef Head ArgTuple::*getElm(); - typedef BuildTupleAccessor NextBuilder; - typedef typename NextBuilder::Accessor NextAccessor; - - ArgTuple& argData_; - - public: - - /** type of the product created by this template. - * Will be a subclass of BASE */ - typedef _X_ Accessor; - - BuildTupleAccessor (ArgTuple& tup) - : argData_(tup) - { } - - operator Accessor() { return Accessor(argData_); } - - }; - - template - < class BASE - , template class _X_ - , uint i - > - class BuildTupleAccessor, _X_, BASE, i> - { - typedef Tuple > ArgTuple; -// typedef NullType BASE::*getElm(); - - public: - typedef _X_ Accessor; - }; - - - ///////////////////////// creating functional closures - - namespace tuple { - template - struct Apply; - - template<> - struct Apply<1> - { - template - static RET - invoke (FUN f, TUP & arg) - { - return f (arg.template getAt<1>()); - } - - template - static RET - bind (FUN f, TUP & arg) - { - return std::tr1::bind (f, arg.template getAt<1>()); - } - }; - - template<> - struct Apply<2> - { - template - static RET - invoke (FUN f, TUP & arg) - { - return f ( arg.template getAt<1>() - , arg.template getAt<2>() - ); - } - - template - static RET - bind (FUN f, TUP & arg) - { - return std::tr1::bind (f, arg.template getAt<1>() - , arg.template getAt<2>() - ); - } - }; - } // (END) sub-namespace - - template - class TupleApplicator - { - typedef typename FunctionSignature< function >::Args Args; - typedef typename FunctionSignature< function >::Ret Ret; - - enum { ARG_CNT = count::value }; - - - /** storing a ref to the parameter tuple */ - Tuple& params_; - - public: - TupleApplicator (Tuple& args) - : params_(args) - { } - - function bind (SIG& f) { return tuple::Apply::bind (f, params_); } - function bind (function const& f) { return tuple::Apply::bind (f, params_); } - - Ret operator() (SIG& f) { return tuple::Apply::invoke (f, params_); } - Ret operator() (function const& f) { return tuple::Apply::invoke (f, params_); } - }; - - - /** - * Closing a function over its arguments. - * This is a small usage example or spin-off, - * having almost the same effect than invoking tr1::bind. - * The notable difference is that the function arguments for - * creating the closure are passed in as one compound tuple. - */ - template - class FunctionClosure - { - typedef typename FunctionSignature< function >::Args Args; - typedef typename FunctionSignature< function >::Ret Ret; - - function closure_; - - public: - FunctionClosure (SIG& f, Tuple& arg) - : closure_(TupleApplicator(arg).bind(f)) - { } - FunctionClosure (function const& f, Tuple& arg) - : closure_(TupleApplicator(arg).bind(f)) - { } - - Ret operator() () { return closure_(); } - }; - - -/* - template - struct BuildClosure - : InstantiateWithIndex - { - - }; -*/ - - ///////////////////////// additional typelist manipulators - - template - struct SplitLast; - - template<> - struct SplitLast - { - typedef NullType Type; - typedef NullType Prefix; - }; - - template - struct SplitLast > - { - typedef TY Type; - typedef NullType Prefix; - }; - - template - struct SplitLast > - { - typedef typename SplitLast::Type Type; - typedef typename Append::Prefix>::List Prefix; - }; - - - -}} // namespace lumiera::typelist - namespace control { namespace test {