/* TUPLE.hpp - metaprogramming utilities for type tuples and data tuples 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 tuple.hpp ** Metaprogramming with tuples-of-types and a simple Tuple (record) datatype. ** The metaprogramming part of this header complements typelist.hpp and allows ** to re-build a new tuple-of-types from an existing typelist. Such a finite ** sequence or tuple of types can at times be more handy than a typelist, ** especially when capturing specific types to use as template parameter. ** ** Additionally, this header augments the Tuple template into a simple Tuple ** (run time) datatype. This isn't meant as competing with std::tr1::tuple, which is ** much more capable, but also has the downside of pulling in a lot of other headers. ** But when all we need is to define a generic typed record of N data elements and ** later re-accessing them (but no further advanced processing), the Tuple template ** might come in handy. ** ** @see control::CommandDef usage example ** @see tuple-test.cpp ** @see typelist.hpp ** @see function.hpp ** @see generator.hpp ** */ #ifndef LUMIERA_META_TUPLE_H #define LUMIERA_META_TUPLE_H #include "lib/meta/typelist.hpp" #include "lib/meta/typelistutil.hpp" #include "lib/meta/util.hpp" namespace lumiera { namespace typelist{ /** * Helper: prepend a type to an existing type sequence, * thus shifting all elements within the sequence * to the right, eventually dropping the last element */ template struct Prepend; template< typename T01 , typename T02 , typename T03 , typename T04 , typename T05 , typename T06 , typename T07 , typename T08 , typename T09 , typename T10 , typename T11 , typename T12 , typename T13 , typename T14 , typename T15 , typename T16 , typename T17 , typename T18 , typename T19 , typename T20 , typename IGN > struct Prepend > { typedef Types< T01,T02,T03,T04,T05 , T06,T07,T08,T09,T10 , T11,T12,T13,T14,T15 , T16,T17,T18,T19,T20 > Tuple; typedef typename Tuple::List List; }; /** Helper: separate parts of a type sequence */ template struct Split; template< typename T01 , typename T02 , typename T03 , typename T04 , typename T05 , typename T06 , typename T07 , typename T08 , typename T09 , typename T10 , typename T11 , typename T12 , typename T13 , typename T14 , typename T15 , typename T16 , typename T17 , typename T18 , typename T19 , typename T20 > struct Split > { typedef T01 Head; typedef Types< T01 > First; typedef Types< T01,T02,T03,T04,T05 , T06,T07,T08,T09,T10 , T11,T12,T13,T14,T15 , T16,T17,T18,T19 > Prefix; typedef Types< T02,T03,T04,T05 , T06,T07,T08,T09,T10 , T11,T12,T13,T14,T15 , T16,T17,T18,T19,T20 > Tail; typedef Types< T20 > Last; typedef T20 End; }; /** * Helper: generate a type sequence left shifted * by i steps, filling in NullType at the end */ template class Shifted { typedef typename Split::Tail Tail; public: typedef typename Shifted::Type Type; typedef typename Split::Head Head; }; template struct Shifted { typedef TYPES Type; typedef typename Split::Head Head; }; /** * simple generic Tuple datatype. * Usable both for metaprogramming and as a generic record. * The types within this tuple can either be specified * as Type sequence or as typelist. Default and canonical * is the type-sequence based tuple form \c Tuple> * The secondary from of specifying a tuple is based on a typelist * (and this form is used actually to implement the storage, while * the plain-flat (type sequence based) form acts as interface. * * Irrespective of the flavour actually used, you can always * - get the canonical TupleType (sequence based) * - get the types of head and tail, and a list version of the types * - access the head element and the tail tuple * - access the Nth element and a shifted-b-N sub (tail) tuple */ template struct Tuple; template<> struct Tuple { typedef NullType HeadType; typedef Types<> TailType; typedef Types<> Type; typedef NullType ArgList; typedef Tuple TupleType; typedef Tuple ThisType; typedef Tuple Tail; enum { SIZE = 0 }; NullType getHead() { return NullType(); } Tail& getTail() { return *this; } Tuple (HeadType const&, Tail const&) { } Tuple () { } template struct ShiftedTuple { typedef Tail Type;}; template Tail& getShifted () { return *this; } template NullType& getAt () { return getHead(); } TupleType& tupleCast () { return reinterpret_cast (*this); } }; template struct Tuple > : Tuple { typedef TY HeadType; typedef typename Tuple::Type TailType; typedef typename Prepend::Tuple Type; typedef Node ArgList; typedef Tuple TupleType; typedef Tuple ThisType; typedef Tuple Tail; enum { SIZE = count::value }; Tuple ( TY a1 =TY() , Tail tail =Tail() ) : Tail (tail.getHead(), tail.getTail()), val_(a1) { } TY & getHead() { return val_; } Tail& getTail() { return static_cast (*this); } template class ShiftedTuple { typedef typename Tuple::Type OurType_; typedef typename Shifted::Type ShiftedTypes_; public: typedef Tuple Type; }; template typename ShiftedTuple::Type& getShifted () { typedef typename ShiftedTuple::Type Tail_I; return static_cast (*this); } TupleType& tupleCast () ///< note makes this List-style Tuple appear as plain-flat Tuple { return reinterpret_cast (*this); } template typename Shifted::Head& getAt () { return getShifted().getHead(); } private: TY val_; }; template< typename T1 , typename T2 , typename T3 , typename T4 , typename T5 , typename T6 , typename T7 , typename T8 , typename T9 > struct Tuple > : Tuple::List> { typedef T1 HeadType; typedef Types TailType; typedef Types Type; typedef typename Type::List ArgList; typedef Tuple TupleType; typedef Tuple ThisType; typedef Tuple Tail; enum { SIZE = count::value }; /** standard ctor: create from values */ Tuple ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() , T4 a4 =T4() , T5 a5 =T5() , T6 a6 =T6() , T7 a7 =T7() , T8 a8 =T8() , T9 a9 =T9() ) : Tuple(a1, Tuple(a2,a3,a4,a5,a6,a7,a8,a9)) { } /** shortcut: allow copy construction from a tuple * which is rather defined by a list type */ Tuple (Tuple const& listTuple) : Tuple (listTuple) { } using Tuple::getHead; Tail& getTail() ///< note makes the Tail appear as plain-flat shifted tuple { return Tuple::getTail().tupleCast(); } }; template<> struct Tuple > : Tuple { enum { SIZE = 0 }; typedef Tuple TupNilList; typedef Tuple > ThisType; typedef ThisType Tail; Tuple ( NullType =NullType() , NullType =NullType() , NullType =NullType() , NullType =NullType() , NullType =NullType() , NullType =NullType() , NullType =NullType() , NullType =NullType() , NullType =NullType() ) { } ///< end recursion of chained ctor calls /** shortcut: allow copy construction from a tuple * which is rather defined by a list type */ Tuple (TupNilList const&) { } }; /** specialisation to shift plain tuple types */ template struct Shifted,i> { typedef typename Shifted::Type Type; typedef typename Shifted::Head Head; typedef Tuple TupleType; }; template struct Shifted, 0> { typedef typename Tuple::Type Type; typedef typename Tuple::HeadType Head; typedef Tuple TupleType; }; /* ====== Helpers for working with Tuples ========= */ namespace tuple { // some convenience access functions template typename Shifted::Head& element (TUP& tup) { return tup.template getAt(); } inline Tuple< Types<> > makeNullTuple () { return Tuple > (); } template inline Tuple< Types > make ( T1 a1 =T1() ) { return Tuple > (a1); } template< typename T1 , typename T2 > inline Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() ) { return Tuple > (a1,a2); } template< typename T1 , typename T2 , typename T3 > inline Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() ) { return Tuple > (a1,a2,a3); } template< typename T1 , typename T2 , typename T3 , typename T4 > inline Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() , T4 a4 =T4() ) { return Tuple > (a1,a2,a3,a4); } template< typename T1 , typename T2 , typename T3 , typename T4 , typename T5 > inline Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() , T4 a4 =T4() , T5 a5 =T5() ) { return Tuple > (a1,a2,a3,a4,a5); } template< typename T1 , typename T2 , typename T3 , typename T4 , typename T5 , typename T6 , typename T7 , typename T8 , typename T9 > inline Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() , T4 a4 =T4() , T5 a5 =T5() , T6 a6 =T6() , T7 a7 =T7() , T8 a8 =T8() , T9 a9 =T9() ) { return Tuple > (a1,a2,a3,a4,a5,a6,a7,a8,a9); } } // (END) access / tuple building helper functions (namespace tuple) /** Trait template for detecting a type tuple */ template class is_Tuple { template struct Check { typedef No_t It; }; template struct Check > { typedef Yes_t It; }; public: static const bool value = (sizeof(Yes_t)==sizeof(typename Check::It)); }; /** Trait template detecting especially tuples * built directly on top of a Typelist */ template class is_TupleListType { template struct Check { enum{ result = sizeof(No_t)}; }; template struct Check > { template Yes_t static check(Node*); Yes_t static check(NullType*); No_t static check(...); enum{ result = sizeof(check( (N*)0)) }; }; public: static const bool value = (sizeof(Yes_t)== Check::result); }; /** Trait template to discern plain tuples and list-type tuples */ template struct is_TuplePlain { static const bool value = is_Tuple::value && !is_TupleListType::value; }; /** Trait template detecting an empty tuple type */ template class is_NullTuple { template struct Check { enum{ result = sizeof(No_t)}; }; template struct Check > { Yes_t static check(Types<>*); Yes_t static check(NullType*); No_t static check(...); enum{ result = sizeof(check( (TY*)0)) }; }; public: static const bool value = (sizeof(Yes_t)== Check::result); }; /** * 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 index allowing 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 empty type sequence is generated for detecting recursion end * (built as innermost decorator, i.e. immediate subclass of BASE) */ template < typename TYPES ///< Type sequence to use within the Accessor (usually the Tuple Types) , template class _X_ ///< user provided template , class TUP =Tuple ///< the tuple type to build on , uint i = 0 ///< tuple element index counter > class BuildTupleAccessor { typedef Tuple ArgTuple; typedef typename ArgTuple::HeadType Head; typedef typename ArgTuple::TailType Tail; typedef BuildTupleAccessor NextBuilder; typedef typename NextBuilder::Accessor NextAccessor; ArgTuple const& argData_; public: /** type of the product created by this template. * Will be a subclass of TUP */ typedef _X_< Head // the type to use for this accessor , NextAccessor // the base type to inherit from , TUP // the tuple type we build upon , i // current element index > Accessor; BuildTupleAccessor (ArgTuple const& tup) : argData_(tup) { } /** used to get the product of this builder template... */ operator Accessor() { return Accessor(argData_); } }; template < template class _X_ , class TUP , uint i > class BuildTupleAccessor, _X_, TUP, i> { typedef Tuple > ArgTuple; ArgTuple const& argData_; public: typedef _X_ Accessor; BuildTupleAccessor (ArgTuple const& tup) : argData_(tup) { } /** used to get the product of this builder template... */ operator Accessor() { return Accessor(argData_); } }; }} // namespace lumiera::typelist #endif