diff --git a/src/lib/meta/tuple.hpp b/src/lib/meta/tuple.hpp index 84559216a..38d5def29 100644 --- a/src/lib/meta/tuple.hpp +++ b/src/lib/meta/tuple.hpp @@ -48,7 +48,7 @@ #define LUMIERA_META_TUPLE_H #include "lib/meta/typelist.hpp" -#include "lib/meta/typelist-manip.hpp" +#include "lib/meta/typelist-util.hpp" #include "lib/meta/typeseq-util.hpp" #include "lib/meta/util.hpp" diff --git a/src/lib/meta/typelist-manip.hpp b/src/lib/meta/typelist-manip.hpp index 428c23f97..b0d789a76 100644 --- a/src/lib/meta/typelist-manip.hpp +++ b/src/lib/meta/typelist-manip.hpp @@ -1,5 +1,5 @@ /* - TYPELIST-UTIL.hpp - Utils for working with lists-of-types + TYPELIST-MANIP.hpp - Utils for working with lists-of-types Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -21,8 +21,8 @@ */ -/** @file typelist-util.hpp - ** Metaprogramming: Helpers for manipulating lists-of-types. +/** @file typelist-manip.hpp + ** Metaprogramming: Helpers for manipulating lists-of-types. ** Sometimes, we use metaprogramming to generate a variation of concrete ** implementations by combining some basic building blocks. Typically, there ** is a number of similar, but not suitably related types involved. We want to @@ -49,54 +49,17 @@ */ -#ifndef LUMIERA_META_TYPELIST_UTIL_H -#define LUMIERA_META_TYPELIST_UTIL_H +#ifndef LUMIERA_META_TYPELIST_MANIP_H +#define LUMIERA_META_TYPELIST_MANIP_H + - #include "lib/meta/typelist.hpp" namespace lumiera { namespace typelist{ - /** - * Metafunction counting the number of Types in the collection - * @return an embedded constant \c value holding the result - */ - template - struct count; - template<> - struct count - { - enum{ value = 0 }; - }; - template - struct count > - { - enum{ value = 1 + count::value }; - }; - - /** - * Metafunction " max( sizeof(T) ) for T in TYPES " - */ - template - struct maxSize; - template<> - struct maxSize - { - enum{ value = 0 }; - }; - template - struct maxSize > - { - enum{ thisval = sizeof(TY) - , nextval = maxSize::value - , value = nextval > thisval? nextval:thisval - }; - }; - - /** pick the n-th element from a typelist */ template struct Pick @@ -111,7 +74,7 @@ namespace typelist{ template struct Pick, i> { - typedef typename Pick::Type Type; + typedef typename Pick::Type Type; }; @@ -240,7 +203,7 @@ namespace typelist{ /** * Allows to access various parts of a given typelist: - * Start and End, Prefix and Tail.. + * Start and End, Prefix and Tail... */ template struct Dissect; @@ -356,7 +319,7 @@ namespace typelist{ template struct CombineFlags { - typedef typename Combine::List List; + typedef typename Combine::List List; }; diff --git a/src/lib/meta/typelist-util.hpp b/src/lib/meta/typelist-util.hpp index 428c23f97..c699855ad 100644 --- a/src/lib/meta/typelist-util.hpp +++ b/src/lib/meta/typelist-util.hpp @@ -1,5 +1,5 @@ /* - TYPELIST-UTIL.hpp - Utils for working with lists-of-types + TYPELIST-UTIL.hpp - simple helpers for working with lists-of-types Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -22,28 +22,21 @@ /** @file typelist-util.hpp - ** Metaprogramming: Helpers for manipulating lists-of-types. - ** Sometimes, we use metaprogramming to generate a variation of concrete - ** implementations by combining some basic building blocks. Typically, there - ** is a number of similar, but not suitably related types involved. We want to - ** process those types using a common scheme, without being forced to squeeze - ** all those types into a artificial inheritance relationship. Now, generating - ** some kind of common factory or adapter, while mixing in pieces of code tailored - ** specifically to the individual types, allows still to build a common processing - ** in such situations. + ** Metaprogramming: simple helpers for working with lists-of-types. + ** This header provides some very basic "meta functions" for extracting + ** some informations from a list-of-types. In Lumiera, we use template + ** metaprogramming and especially such lists-of-types, whenever we build + ** some common implementation backbone, without being able to subsume all + ** participating types (classes) into a single inheritance hierarchy. ** - ** The facilities in this header provide the basics of simple functional list - ** processing (mostly with tail recursion). Usually, there is one template parameter - ** TYPES, which accepts a \em Type-list. The result of the processing step is then - ** accessible as an embedded typedef named \c List . Here, all of the 'processing' - ** to calculate this result is performed by the compiler, as a side-effect of - ** figuring out the resulting concrete type. At run time, in the generated - ** code, typically the resulting classes are empty, maybe just - ** exposing a specifically built-up function. + ** The "meta functions" defined here are templates; to access the "result" of + ** such a meta function, we instantiate the template and then access one of the + ** embedded constant definitions (usually the enum constant named \c value) ** ** @see generator.hpp - ** @see typelist-manip-test.cpp - ** @see TimeControl_test usage example + ** @see TypelistUtil_test + ** @see lib::SimpleAllocator usage example (for isInList) + ** @see TypelistManip_test ** @see typelist.hpp ** */ @@ -53,7 +46,7 @@ #define LUMIERA_META_TYPELIST_UTIL_H - + #include "lib/meta/typelist.hpp" namespace lumiera { @@ -77,6 +70,7 @@ namespace typelist{ enum{ value = 1 + count::value }; }; + /** * Metafunction " max( sizeof(T) ) for T in TYPES " */ @@ -97,268 +91,35 @@ namespace typelist{ }; - /** pick the n-th element from a typelist */ - template - struct Pick - { - typedef NullType Type; - }; - template - struct Pick, 0> - { - typedef TY Type; - }; - template - struct Pick, i> - { - typedef typename Pick::Type Type; - }; - - - - - /** apply a transformation (template) to each type in the list */ - template class _TRANS_> - struct Apply { typedef TY List; }; - - template< class TY, class TYPES - , template class _TRANS_ - > - struct Apply, _TRANS_ > { typedef Node< typename _TRANS_::Type - , typename Apply::List - > List; }; - - - /** conditional node: skip an element based on evaluating a predicate */ - template - struct CondNode { typedef TAIL Next; }; - - template - struct CondNode { typedef Node Next; }; - - /** filter away those types which don't fulfil a predicate metafunction */ - template< class TYPES - , template class _P_ ///< a template providing a boolean member \c ::value - > - struct Filter; - - template class _P_> - struct Filter { typedef NullType List; }; - - template< class TY, class TYPES - , template class _P_ - > - struct Filter,_P_> { typedef typename CondNode< _P_::value - , TY - , typename Filter::List - >::Next - List; }; - - - /** append lists-of-types */ - template - struct Append { typedef Node::List> List; }; - - template< class TY, class TYPES - , class TAIL - > - struct Append, TAIL> { typedef Node::List> List; }; - - template - struct Append > { typedef Node List; }; - - template - struct Append, NullType> { typedef Node List; }; - - template - struct Append { typedef Node List; }; - - template - struct Append { typedef Node List; }; - - template<> - struct Append { typedef NullType List; }; - - - - - /** access the last list element */ - template - struct SplitLast; - - template<> - struct SplitLast { typedef NullType Type; - typedef NullType List; }; - template - struct SplitLast > { typedef TY Type; - typedef NullType List; }; - - template - struct SplitLast > { typedef typename SplitLast::Type Type; - typedef typename Append< TY, - typename SplitLast::List - >::List - List; }; - - - - /** - * splice a typelist like an overlay - * into an base typelist, starting at given index. - * @return either the combined (spliced) List, or - * the Front/Back part before or after the Overlay - * @note using a NullType as OVERLAY allows to extract - * an arbitrary Front/Back part of the list - */ - template - struct Splice; - - template - struct Splice, OVERLAY, i> { typedef Node::List> List; - typedef Node::Front> Front; - typedef typename Splice::Back Back; }; - - template - struct Splice,Node,0> { typedef Node::List> List; - typedef NullType Front; - typedef typename Splice::Back Back; }; - - template - struct Splice, NullType, 0> { typedef Node List; - typedef NullType Front; - typedef Node Back; }; - - template - struct Splice { typedef NullType List; - typedef NullType Front; - typedef NullType Back; }; - - - - /** - * Allows to access various parts of a given typelist: - * Start and End, Prefix and Tail.. + * Metafunction to check if a specific type is contained + * in a given typelist. Only exact match is detected. */ - template - struct Dissect; - - template - struct Dissect > + template + struct IsInList { - typedef Node List; ///< the complete list - typedef T Head; ///< first element - typedef Node First; ///< a list containing the first element - typedef TYPES Tail; ///< remainder of the list starting with the second elm. - typedef typename SplitLast::List Prefix;///< all of the list, up to but excluding the last element - typedef typename SplitLast::Type End; ///< the last element - typedef Node Last; ///< a list containing the last element + enum{ value = false }; }; - template<> - struct Dissect + template + struct IsInList > { - typedef NullType List; - typedef NullType Head; - typedef NullType First; - typedef NullType Tail; - typedef NullType Prefix; - typedef NullType End; - typedef NullType Last; + enum{ value = true }; }; - - - - /** - * prefix each of the elements, - * yielding a list-of lists-of-types - */ - template - struct PrefixAll { typedef Node< typename Append::List, NullType> List; }; - - template - struct PrefixAll { typedef NullType List; }; - - template - struct PrefixAll { typedef Node< typename Append::List, NullType> List; }; - - template< class T - , class TY, class TYPES - > - struct PrefixAll > { typedef Node< typename Append::List - , typename PrefixAll::List - > List; }; - - - - - /** - * build a list-of lists, where each element of the first arg list - * gets in turn prepended to all elements of the second arg list. - * Can be used to build all possible combinations from two - * sources, i.e. the Cartesian product. - */ - template - struct Distribute { typedef typename PrefixAll::List List; }; - - template - struct Distribute { typedef NullType List; }; - - template< class TY, class TYPES - , class TAIL - > - struct Distribute,TAIL> { typedef typename Append< typename PrefixAll::List - , typename Distribute::List - >::List - List; }; - - - - /** - * build all possible combinations, based on a enumeration of the basic cases. - * For each of the types in the argument list, an "enumeration generator" template is invoked, - * yielding a list of the possible base cases. These base cases are then combined with all the - * combinations of the rest, yielding all ordered combinations of all cases. Here, "ordered" - * means that the base cases of the n-th element will appear in the n-th position of the - * resulting lists, - * - * For the typical example, the "base cases" are {flag(on), flag(off)}, so we get a - * list-of-lists, featuring all possibilities to combine these distinct toggles. - */ - template< class X - , template class _ENUM_> - struct Combine { typedef typename Distribute< typename _ENUM_::List - , Node - >::List List; }; - template< template class _ENUM_> - struct Combine { typedef NodeNull List; }; - - template< class TY, class TYPES - , template class _ENUM_> - struct Combine,_ENUM_> { typedef typename Distribute< typename _ENUM_::List - , typename Combine::List - >::List List; }; - - /** enumeration generator for the Combine metafunction, - * yielding an "on" and "off" case - */ - template - struct FlagOnOff - { - typedef Node > List; - }; - - - /** generate all possible on-off combinations of the given flags */ - template - struct CombineFlags - { - typedef typename Combine::List List; + template + struct IsInList > + { + enum{ value = IsInList::value }; }; + /** convenience shortcut: query function */ + template + bool + isInList() + { + return IsInList::value; + } diff --git a/src/lib/meta/typelist.hpp b/src/lib/meta/typelist.hpp index 5d0e11bc0..3de24176f 100644 --- a/src/lib/meta/typelist.hpp +++ b/src/lib/meta/typelist.hpp @@ -40,15 +40,25 @@ This code is heavily inspired by /** @file typelist.hpp ** A template metaprogramming technique for manipulating collections of types. - ** Effectively this is a taylored and simplified version of what can be found in the Loki library. + ** Effectively this is a tailored and simplified version of what can be found in the Loki library. ** We use it in other generic library-style code to generate repetitive code. If you tend to find ** template metaprogramming (or functional programming in general) offending, please ignore the - ** technical details and just consider the benefit of such an simplification for the user code. - ** - ** Interface for using this facility is the template Types(.....) for up to 20 Type parameters + ** technical details and just consider the benefit of such an simplification for the client code. ** + ** Interface for using this facility is the template Types(.....) for up to 20 Type parameters. + ** To start typelist processing, other templates typically pick up the Types<...>::List type. + ** This allows for LISP-style list processing, with a pattern match on either Node + ** or NullType to terminate recursion. In C++ template metaprogramming, "pattern match" + ** is done by partial template specialisations (the compiler will pick up and thus + ** match the template parameters). A typedef acts like a declaration in normal + ** programming. Because such a "declaration" can't be changed after the fact, + ** effectively this is a flavour of functional programming. Just the + ** "execution environment" is the compiler, during compilation. + ** ** @see lumiera::visitor::Applicable usage example - ** @see typelisttest.cpp + ** @see control::CommandSignature more elaborate usage example (dissecting a functor signature) + ** @see TypeList_test + ** @see TypeListManip_test ** */ diff --git a/src/lib/simple-allocator.hpp b/src/lib/simple-allocator.hpp index 71b0438fa..0cbf6b5c9 100644 --- a/src/lib/simple-allocator.hpp +++ b/src/lib/simple-allocator.hpp @@ -49,6 +49,7 @@ //#include "pre.hpp" #include "lib/error.hpp" #include "lib/meta/generator.hpp" +#include "lib/meta/typelist-util.hpp" #include "lib/format.hpp" //#include "lib/typed-counter.hpp" #include "include/logging.h" @@ -63,31 +64,11 @@ namespace lib { // using std::tr1::shared_ptr; - using lumiera::typelist::InstantiateForEach; using lumiera::typelist::Types; + using lumiera::typelist::IsInList; + using lumiera::typelist::InstantiateForEach; namespace { - using lumiera::typelist::Node; - using lumiera::typelist::NullType; - - template - struct IsInList - { - enum{ value = false }; - }; - - template - struct IsInList, TY> - { - enum{ value = true }; - }; - - template - struct IsInList, TY> - { - enum{ value = IsInList::value }; - }; - } @@ -141,9 +122,9 @@ namespace lib { ___assertSupportedType() { typedef typename TYPES::List PreconfiguredTypes; - typedef IsInList IsPreconfiguredType; + typedef IsInList IsSupportedType; - BOOST_STATIC_ASSERT (IsPreconfiguredType::value); + BOOST_STATIC_ASSERT (IsSupportedType::value); } diff --git a/src/lib/variant.hpp b/src/lib/variant.hpp index 7b30ba63c..b4eef9b76 100644 --- a/src/lib/variant.hpp +++ b/src/lib/variant.hpp @@ -45,7 +45,7 @@ #define LIB_VARIANT_H -#include "lib/meta/typelist-manip.hpp" +#include "lib/meta/typelist-util.hpp" #include "lib/meta/generator.hpp" #include diff --git a/src/proc/control/command-signature.hpp b/src/proc/control/command-signature.hpp index 52e4dcf19..44354c300 100644 --- a/src/proc/control/command-signature.hpp +++ b/src/proc/control/command-signature.hpp @@ -30,7 +30,7 @@ ** we need to accept functor objects with a very specific and predetermined ** signature, thus allowing for strict type checking by the compiler. ** - ** \par Relation of function signatures + ** \par Relation of function signatures (MEM = type of the "memento" for Undo) ** - operation: void(P1,..PN) ** - captureUndo: MEM(P1,..PN) ** - undoOperation void(P1,..PN,MEM) @@ -59,24 +59,20 @@ namespace control { -// using lib::Symbol; -// using std::tr1::shared_ptr; using std::tr1::function; using lumiera::typelist::FunctionSignature; using lumiera::typelist::FunctionTypedef; using lumiera::typelist::Types; -//using lumiera::typelist::NullType; -//using lumiera::typelist::Tuple; using lumiera::typelist::Append; using lumiera::typelist::SplitLast; - + /** - * Metaprogramming helper for building Command function signatures. + * Metaprogramming helper for building Command function signatures. * The complete definition context of any command is templated to the signature * of the actual command operation and to the memento type. The typedefs embedded - * within CommandSignature allows accepting suitable typed functions + * within CommandSignature allows for accepting suitable typed functions * to implement the command in question. */ template @@ -90,7 +86,7 @@ namespace control { public: typedef typename FunctionTypedef::Sig OperateSig; - typedef typename FunctionTypedef::Sig CaptureSig; + typedef typename FunctionTypedef::Sig CaptureSig; typedef typename FunctionTypedef::Sig UndoOp_Sig; typedef Args CmdArgs; typedef MEM Memento; @@ -100,16 +96,23 @@ namespace control { /** - * Type analysis helper template. + * Type analysis helper template. * Used for dissecting a given type signature to derive * the related basic operation signature, the signature of a possible Undo-function * and the signature necessary for capturing undo information. The implementation * relies on re-binding an embedded type defining template, based on the actual * case, as identified by the structure of the given parameter signature. + * + * To use this template, it is instantiated with the signature of a functor object + * in question. Depending on the actual situation, the compiler will then either + * pick Case1 or Case2 -- thus allowing the client in any case to pick up the + * correct signatures for Operation, Capture and Undo-function from the + * public typedefs within \c UndoSignature */ template class UndoSignature { + // preparation: dissect the function signature into arguments and result typedef typename FunctionSignature< function >::Args Args; typedef typename FunctionSignature< function >::Ret Ret; diff --git a/tests/40components.tests b/tests/40components.tests index 9dfaffd74..d0f849145 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -801,6 +801,11 @@ return: 0 END +TEST "simple typelist utils" TypeListUtil_test < > out: ctor DoIt > diff --git a/tests/lib/meta/typelist-util-test.cpp b/tests/lib/meta/typelist-util-test.cpp new file mode 100644 index 000000000..22a8c62e8 --- /dev/null +++ b/tests/lib/meta/typelist-util-test.cpp @@ -0,0 +1,83 @@ +/* + TypeListUtil(Test) - check the simple typelist metaprogramming helpers + + Copyright (C) Lumiera.org + 2011, 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/meta/typelist-util.hpp" + + + +namespace lumiera { +namespace typelist{ +namespace test { + + + + typedef Types< int + , uint + , int64_t + , uint64_t + >::List TheList; + + typedef Types< >::List EmptyList; + + + + /************************************************************************* + * @test verify the simple helpers for working with lists-of-types. + * These are simple metafunctions to count the number of elements, + * calculate the maximum size or check for inclusion. + * + * Because these metafunctions will be computed during compilation, + * mostly the function is already verified when it passes compilation. + * All we can do here, at runtime, is to verify some of the (expected) + * constant results. + */ + class TypeListUtil_test : public Test + { + void + run (Arg) + { + CHECK (4 == count::value); + CHECK (0 == count::value); + + CHECK (sizeof(int64_t) == maxSize::value); + CHECK (0 == maxSize::value); + + CHECK ( bool(IsInList::value)); + CHECK ( bool(IsInList::value)); + CHECK ( bool(IsInList::value)); + CHECK ( bool(IsInList::value)); + + CHECK (!bool(IsInList::value)); + CHECK (!bool(IsInList::value)); + CHECK (!bool(IsInList::value)); // Note: not-a-typelist yields false too + } + }; + + + /** Register this test class... */ + LAUNCHER (TypeListUtil_test, "unit common"); + + + +}}} // namespace lumiera::typelist::test