lumiera_/src/lib/meta/tuple.hpp

503 lines
14 KiB
C++

/*
TUPLE.hpp - metaprogramming utilities for type tuples and data tuples
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
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 very simple Tuple 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
** 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 very 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"
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<class T, class TYPES>
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<T01, Types< T02,T03,T04,T05
, T06,T07,T08,T09,T10
, T11,T12,T13,T14,T15
, T16,T17,T18,T19,T20
, IGN
> >
{
typedef Types< T01,T02,T03,T04,T05
, T06,T07,T08,T09,T10
, T11,T12,T13,T14,T15
, T16,T17,T18,T19,T20 > Tuple;
};
/** Helper: separate parts of a type sequence */
template<class TYPES>
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<Types< T01,T02,T03,T04,T05
, T06,T07,T08,T09,T10
, T11,T12,T13,T14,T15
, T16,T17,T18,T19,T20
> >
{
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 TYPES, uint i=1>
class Shifted
{
typedef typename Split<TYPES>::Tail Tail;
public:
typedef typename Shifted<Tail,i-1>::Types Types;
typedef typename Split<Types>::Head Head;
};
template<class TYPES>
struct Shifted<TYPES,0>
{
typedef TYPES Types;
typedef typename Types::List::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
*/
template<class TYPES>
struct Tuple;
template<>
struct Tuple<NullType>
{
typedef NullType HeadType;
typedef Types<> TailType;
typedef Types<> Type;
typedef NullType ArgList;
typedef Tuple<Type> ThisTuple;
typedef Tuple<NullType> Tail;
enum { SIZE = 0 };
NullType getHead() { return NullType(); }
Tail& getTail() { return *this; }
Tuple (HeadType const&, Tail const&) { }
Tuple () { }
};
template<class TY, class TYPES>
struct Tuple<Node<TY,TYPES> >
: Tuple<TYPES>
{
typedef TY HeadType;
typedef typename Tuple<TYPES>::Type TailType;
typedef typename Prepend<TY,TailType>::Tuple Type;
typedef Node<TY,TYPES> ArgList;
typedef Tuple<Type> ThisTuple;
typedef Tuple<TYPES> Tail;
enum { SIZE = count<ArgList>::value };
Tuple ( TY a1 =TY()
, Tail tail =Tail()
)
: Tuple<TYPES> (tail.getHead(), tail.getTail()),
val_(a1)
{ }
TY & getHead() { return val_; }
Tail& getTail() { return static_cast<Tail&> (*this); }
private:
TY val_;
};
template< typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
, typename T7
, typename T8
, typename T9
>
struct Tuple<Types<T1,T2,T3,T4,T5,T6,T7,T8,T9> >
: Tuple<typename Types<T1,T2,T3,T4,T5,T6,T7,T8,T9>::List>
{
typedef T1 HeadType;
typedef Types<T2,T3,T4,T5,T6,T7,T8,T9,NullType> TailType;
typedef Types<T1,T2,T3,T4,T5,T6,T7,T8,T9> Type;
typedef typename Type::List ArgList;
typedef Tuple<Type> ThisTuple;
typedef Tuple<TailType> Tail;
enum { SIZE = count<ArgList>::value };
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<ArgList>(a1, Tuple<TailType>(a2,a3,a4,a5,a6,a7,a8,a9))
{ }
using Tuple<ArgList>::getHead;
using Tuple<ArgList>::getTail;
template<uint i>
class ShiftedTuple
{
typedef typename Tuple::Type OurType_;
typedef typename Shifted<OurType_,i>::Types ShiftedTypes_;
public:
typedef Tuple<typename ShiftedTypes_::List> Type;
};
template<uint i>
typename ShiftedTuple<i>::Type&
getShifted ()
{
typedef typename ShiftedTuple<i>::Type Tail_I;
return static_cast<Tail_I&> (*this);
}
template<uint i>
typename Shifted<Type,i>::Head&
getAt ()
{
return getShifted<i>().getHead();
}
};
namespace tuple { // some convenience access functions
template<uint n, class TUP>
typename TUP::template ShiftedTuple<n>::Type::Head&
element (TUP& tup)
{
return tup.template getAt<n>();
}
inline
Tuple< Types<> >
makeNullTuple ()
{
return Tuple<Types<> > ();
}
template<typename T1>
inline
Tuple< Types<T1> >
make ( T1 a1 =T1()
)
{
return Tuple<Types<T1> > (a1);
}
template< typename T1
, typename T2
>
inline
Tuple< Types<T1,T2> >
make ( T1 a1 =T1()
, T2 a2 =T2()
)
{
return Tuple<Types<T1,T2> > (a1,a2);
}
template< typename T1
, typename T2
, typename T3
>
inline
Tuple< Types<T1,T2,T3> >
make ( T1 a1 =T1()
, T2 a2 =T2()
, T3 a3 =T3()
)
{
return Tuple<Types<T1,T2,T3> > (a1,a2,a3);
}
template< typename T1
, typename T2
, typename T3
, typename T4
>
inline
Tuple< Types<T1,T2,T3,T4> >
make ( T1 a1 =T1()
, T2 a2 =T2()
, T3 a3 =T3()
, T4 a4 =T4()
)
{
return Tuple<Types<T1,T2,T3,T4> > (a1,a2,a3,a4);
}
template< typename T1
, typename T2
, typename T3
, typename T4
, typename T5
>
inline
Tuple< Types<T1,T2,T3,T4,T5> >
make ( T1 a1 =T1()
, T2 a2 =T2()
, T3 a3 =T3()
, T4 a4 =T4()
, T5 a5 =T5()
)
{
return Tuple<Types<T1,T2,T3,T4,T5> > (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<T1,T2,T3,T4,T5,T6,T7,T8,T9> >
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<Types<T1,T2,T3,T4,T5,T6,T7,T8,T9> > (a1,a2,a3,a4,a5,a6,a7,a8,a9);
}
}
/**
* 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<TYPES> ). 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 ///< Type sequence to use within the Accessor (usually the Tuple Types)
, template<class,class,class, uint> class _X_ ///< user provided template<Type, Base, TupleType, arg-No>
, class TUP =Tuple<TYPES> ///< the tuple type to build on
, uint i = 0 ///< tuple element index counter
>
class BuildTupleAccessor
{
typedef Tuple<TYPES> ArgTuple;
typedef typename ArgTuple::HeadType Head;
typedef typename ArgTuple::TailType Tail;
typedef BuildTupleAccessor<Tail,_X_,TUP, i+1> 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,class,class, uint> class _X_
, class TUP
, uint i
>
class BuildTupleAccessor<Types<>, _X_, TUP, i>
{
typedef Tuple<Types<> > ArgTuple;
ArgTuple const& argData_;
public:
typedef _X_<NullType, TUP, TUP, 0> 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