From 14f3641f9b9e8d14ddd7ea70629750fcc00980fa Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 28 Jun 2009 20:41:33 +0200 Subject: [PATCH] helper: initialise a tuple from an existing sub-tuple --- src/lib/meta/tuple.hpp | 132 ++++++- tests/40components.tests | 18 + tests/lib/meta/function-composition-test.cpp | 351 +++++++++++++++++++ tests/lib/meta/type-tuple-test.cpp | 69 ++++ 4 files changed, 567 insertions(+), 3 deletions(-) create mode 100644 tests/lib/meta/function-composition-test.cpp diff --git a/src/lib/meta/tuple.hpp b/src/lib/meta/tuple.hpp index d8e4c8d39..cb7309765 100644 --- a/src/lib/meta/tuple.hpp +++ b/src/lib/meta/tuple.hpp @@ -214,9 +214,12 @@ namespace typelist{ Tuple (HeadType const&, Tail const&) { } Tuple () { } - template struct ShiftedTuple { typedef Tail Type;}; - template Tail& getShifted () { return *this; } - template NullType& getAt () { return getHead(); } + template struct ShiftedTuple { typedef Tail Type;}; + template Tail& getShifted () { return *this; } + template NullType& getAt () { return getHead(); } + + const NullType getHead_const() const { return NullType();} + const Tail& getTail_const() const { return *this; } TupleType& tupleCast () @@ -250,6 +253,9 @@ namespace typelist{ TY & getHead() { return val_; } Tail& getTail() { return static_cast (*this); } + TY const& getHead_const() const { return val_; } + Tail const& getTail_const() const { return static_cast (*this); } + template class ShiftedTuple @@ -509,6 +515,126 @@ namespace typelist{ return Tuple > (a1,a2,a3,a4,a5,a6,a7,a8,a9); } + + + /** + * Helper to construct a new tuple, partially using provided argument values. + * Arguments are expected as a tuple, which is assumed to be a sub-tuple of + * the target type to be created. The start index of this sub-tuple may be + * provided as additional parameter, otherwise it is assumed to be zero, + * (i.e. the sub tuple starting left aligned). Any further arguments + * of the target type, which aren't covered by the argument tuple, + * are default initialised. + * @param TYPES type sequence or type list denoting the target tuple type + * @param ARGS type sequence of type list denoting the argument tuple type + * @param pos start index of the ARGS sequence within the TYPES sequence + * + * @note call the embedded #create function to invoke + * @note when types or positions disagree, argument tuple will be ignored + * @see TypeTuple_test#check_build_from_subTuple + */ + template + struct BuildTuple + { + typedef typename Tuple::TupleType ThisTuple; + typedef typename Tuple::ArgList TypeList; + typedef typename Tuple::ArgList ArgTypeList; + + /** + * @param the argument values, contained in a list or flat- tuple + * of the type denoted by ARGS + * @return a plain-flat Tuple instance, initialised with + * the values found within arg + */ + static ThisTuple + create (Tuple const& arg) + { + return BuildTuple + ::create(arg) + .tupleCast(); + } + }; + + template + struct BuildTuple, Tuple, pos> ///< tuples allowed instead of plain type sequences/lists + : BuildTuple + { }; + + + template< typename T + , typename TS + , typename A + , typename AS + , uint pos + > + struct BuildTuple, Node, pos> ///< case: recursion \em before start of arg tuple + { + typedef Tuple > ThisTuple; + typedef Tuple > ThisArg; + + static ThisTuple + create (ThisArg const& arg) + { + return ThisTuple( T() + , BuildTuple, pos-1>::create(arg) + ); + } + }; + + + template< typename A + , typename TS + , typename AS + > + struct BuildTuple, Node, 0> ///< case: start of argument tuple detected + { + typedef Tuple > ThisTuple; + typedef Tuple > ThisArg; + + static ThisTuple + create (ThisArg const& arg) + { + return ThisTuple( arg.getHead_const() + , BuildTuple::create (arg.getTail_const()) + ); + } + }; + + + template< typename ARGS + , uint i + > + struct BuildTuple ///< case: hit end of target typelist + { + typedef Tuple ThisTuple; + typedef Tuple ThisArg; + + static ThisTuple + create (ThisArg const&) + { + return ThisTuple(); + } + }; + + + template< typename T + , typename TS + , uint i + > + struct BuildTuple, NullType, i> ///< case: hit end of argument tuple + { + typedef Tuple > ThisTuple; + typedef Tuple ThisArg; + + static ThisTuple + create (ThisArg const&) + { + return ThisTuple(); + } + }; + + + } // (END) access / tuple building helper functions (namespace tuple) diff --git a/tests/40components.tests b/tests/40components.tests index 72174a526..8c4317699 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -666,6 +666,24 @@ out: nullL :...Tuple\(\) out: nulTcpy :...Tuple\(\) out: nulTref :...Tuple\(\) out: :$ +out: : ---build-from-sub-Tuples--- +out: T1357L :TYPES-\[\]-<1>-<3>-<5>-<7>- +out: T1357T :TYPES-<>-<1>-<3>-<5>-<7>- +out: T135L :TYPES-\[\]-<1>-<3>-<5>- +out: T57T :TYPES-<>-<5>-<7>- +out: T35T :TYPES-<>-<3>-<5>- +out: sub135 :...Tuple\(\(1\),\(3\),\(5\)\) +out: b_135 :...Tuple\(\(1\),\(3\),\(5\),\(7\)\) +out: sub57 :...Tuple\(\(5\),\(7\)\) +out: b_57 :...Tuple\(\(1\),\(3\),\(5\),\(7\)\) +out: sub35 :...Tuple\(\{8\},\{8\}\) +out: b_35 :...Tuple\(\(1\),\{8\},\{8\},\(7\)\) +out: b_35 :...Tuple\(\(1\),\(3\),\(5\),\(7\)\) +out: sub78 :...Tuple\(\{77\},\{88\}\) +out: b_78 :...Tuple\(\(1\),\(3\),\(5\),\{77\}\) +out: b_nul :...Tuple\(\(1\),\(3\),\(5\),\(7\)\) +out: b_nul2 :...Tuple\(\) +out: :$ out: : ---copy-operations--- out: tup1 :...Tuple\(\{11\},\{33\},\(5\)\) out: tup11 :...Tuple\(\{11\},\{33\},\{44\}\) diff --git a/tests/lib/meta/function-composition-test.cpp b/tests/lib/meta/function-composition-test.cpp new file mode 100644 index 000000000..72b458cf8 --- /dev/null +++ b/tests/lib/meta/function-composition-test.cpp @@ -0,0 +1,351 @@ +/* + FunctionClosure(Test) - appending, mixing and filtering typelists + + 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-closure-test.cpp + ** Testing a combination of tr1::function objects and metaprogramming. + ** Argument types will be extracted and represented as typelist, so they + ** can be manipulated at compile time. This test uses some functions with + ** and systematically applies or binds them to corresponding data tuples. + ** Moreover, closure objects will be constructed in various flavours, + ** combining a function object and a set of parameters. + ** + ** @see function-closure.hpp + ** @see control::CmdClosure real world usage example + ** + */ + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "lib/meta/typelist.hpp" +#include "lib/meta/typelistutil.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/function-closure.hpp" +#include "meta/dummy-functions.hpp" +#include "meta/typelist-diagnostics.hpp" +#include "meta/tuple-diagnostics.hpp" + +#include + +using ::test::Test; +using std::string; +using std::cout; +using std::endl; + + +namespace lumiera { +namespace typelist{ +namespace test { + + + namespace { // test data + + + + typedef Types< Num<1> + , Num<2> + , Num<3> + >::List List1; + typedef Types< Num<5> + , Num<6> + , Num<7> + >::List List2; + + + /** special test fun + * accepting the terrific Num types */ + template + int + getNumberz (Num one, Num two, Num three) + { + return one.o_ + two.o_ + three.o_; + } + + + int fun0 () { return -1; } + int fun1 (int i1) { return i1; } + int fun2 (int i1, int i2) { return i1+i2; } + int fun3 (int i1, int i2, int i3) { return i1+i2+i3; } + + } // (End) test data + + + + + + + /************************************************************************* + * @test building a function closure for a given function or functor, + * while arguments are passed in as tuple + * - accessing signatures as typelists + * - apply free function to tuple + * - apply functor to tuple + * - bind free function to tuple + * - bind functor to tuple + * - build a simple "tuple closure" + */ + class FunctionClosure_test : public Test + { + virtual void + run (Arg) + { + check_diagnostics (); + check_signatureTypeManip (); + check_applyFree (); + check_applyFunc (); + check_bindFree (); + check_bindFunc (); + build_closure (); + } + + + /** verify the test input data + * @see TypeListManipl_test#check_diagnostics() + * for an explanation of the DISPLAY macro + */ + void + check_diagnostics () + { + DISPLAY (List1); + DISPLAY (List2); + ; + ASSERT (6 == (getNumberz<1,2,3> (Num<1>(), Num<2>(), Num<3>()))); + ASSERT (6 == (getNumberz<1,1,1> (Num<1>(), Num<1>(2), Num<1>(3)))); + } + + + void + check_signatureTypeManip () + { + typedef int someFunc(Num<5>,Num<9>); + typedef FunctionSignature >::Ret RetType; // should be int + typedef FunctionSignature >::Args Args; + DISPLAY (Args); + + typedef Prepend, Args>::Tuple NewArgs; // manipulate the argument type(s) + DISPLAY (NewArgs); + + typedef FunctionTypedef::Sig NewSig; // re-build a new function signature + + NewSig& fun = getNumberz<1,5,9>; //...which is compatible to an existing real function signature! + + ASSERT (1+5+9 == fun(Num<1>(), Num<5>(), Num<9>())); + } + + + void + check_applyFree () + { + cout << "\t:\n\t: ---Apply---\n"; + + Tuple > tup0 ; + Tuple > tup1 (11); + Tuple > tup2 (11,12); + Tuple > tup3 (11,12,13); + DUMPVAL (tup0); + DUMPVAL (tup1); + DUMPVAL (tup2); + DUMPVAL (tup3); + + ASSERT (-1 == func::Apply<0>::invoke (fun0, tup0) ); + ASSERT (11 == func::Apply<1>::invoke (fun1, tup1) ); + ASSERT (11+12 == func::Apply<2>::invoke (fun2, tup2) ); + ASSERT (11+12+13 == func::Apply<3>::invoke (fun3, tup3) ); + + ASSERT (-1 == TupleApplicator (tup0) (fun0) ); + ASSERT (11 == TupleApplicator (tup1) (fun1) ); + ASSERT (11+12 == TupleApplicator (tup2) (fun2) ); + ASSERT (11+12+13 == TupleApplicator (tup3) (fun3) ); + + ASSERT (-1 == func::apply(fun0, tup0) ); + ASSERT (11 == func::apply(fun1, tup1) ); + ASSERT (11+12 == func::apply(fun2, tup2) ); + ASSERT (11+12+13 == func::apply(fun3, tup3) ); + + } + + + void + check_applyFunc () + { + Tuple > tup0 ; + Tuple > tup1 (11); + Tuple > tup2 (11,12); + Tuple > tup3 (11,12,13); + function functor0 (fun0); + function functor1 (fun1); + function functor2 (fun2); + function functor3 (fun3); + + ASSERT (-1 == func::Apply<0>::invoke (functor0, tup0) ); + ASSERT (11 == func::Apply<1>::invoke (functor1, tup1) ); + ASSERT (11+12 == func::Apply<2>::invoke (functor2, tup2) ); + ASSERT (11+12+13 == func::Apply<3>::invoke (functor3, tup3) ); + + ASSERT (-1 == TupleApplicator (tup0) (functor0) ); + ASSERT (11 == TupleApplicator (tup1) (functor1) ); + ASSERT (11+12 == TupleApplicator (tup2) (functor2) ); + ASSERT (11+12+13 == TupleApplicator (tup3) (functor3) ); + + ASSERT (-1 == func::apply(functor0, tup0) ); + ASSERT (11 == func::apply(functor1, tup1) ); + ASSERT (11+12 == func::apply(functor2, tup2) ); + ASSERT (11+12+13 == func::apply(functor3, tup3) ); + + } + + + void + check_bindFree () + { + cout << "\t:\n\t: ---Bind----\n"; + + Tuple > tup0 ; + Tuple > tup1 (11); + Tuple > tup2 (11,12); + Tuple > tup3 (11,12,13); + + typedef function BoundFun; + + BoundFun functor0 = func::Apply<0>::bind (fun0, tup0); + BoundFun functor1 = func::Apply<1>::bind (fun1, tup1); + BoundFun functor2 = func::Apply<2>::bind (fun2, tup3); + BoundFun functor3 = func::Apply<3>::bind (fun3, tup3); + + ASSERT (-1 == functor0() ); + ASSERT (11 == functor1() ); + ASSERT (11+12 == functor2() ); + ASSERT (11+12+13 == functor3() ); + + functor0 = TupleApplicator (tup0).bind (fun0); + functor1 = TupleApplicator (tup1).bind (fun1); + functor2 = TupleApplicator (tup2).bind (fun2); + functor3 = TupleApplicator (tup3).bind (fun3); + + ASSERT (-1 == functor0() ); + ASSERT (11 == functor1() ); + ASSERT (11+12 == functor2() ); + ASSERT (11+12+13 == functor3() ); + + } + + + void + check_bindFunc () + { + Tuple > tup0 ; + Tuple > tup1 (11); + Tuple > tup2 (11,12); + Tuple > tup3 (11,12,13); + function unbound_functor0 (fun0); + function unbound_functor1 (fun1); + function unbound_functor2 (fun2); + function unbound_functor3 (fun3); + + typedef function BoundFun; + + BoundFun functor0 = func::Apply<0>::bind (unbound_functor0, tup0); + BoundFun functor1 = func::Apply<1>::bind (unbound_functor1, tup1); + BoundFun functor2 = func::Apply<2>::bind (unbound_functor2, tup3); + BoundFun functor3 = func::Apply<3>::bind (unbound_functor3, tup3); + + ASSERT (-1 == functor0() ); + ASSERT (11 == functor1() ); + ASSERT (11+12 == functor2() ); + ASSERT (11+12+13 == functor3() ); + + functor0 = TupleApplicator (tup0).bind (unbound_functor0); + functor1 = TupleApplicator (tup1).bind (unbound_functor1); + functor2 = TupleApplicator (tup2).bind (unbound_functor2); + functor3 = TupleApplicator (tup3).bind (unbound_functor3); + + ASSERT (-1 == functor0() ); + ASSERT (11 == functor1() ); + ASSERT (11+12 == functor2() ); + ASSERT (11+12+13 == functor3() ); + + } + + + void + build_closure () + { + Tuple > tup0 ; + Tuple > tup1 (11); + Tuple > tup2 (11,12); + Tuple > tup3 (11,12,13); + + FunctionClosure clo0 (fun0,tup0); + FunctionClosure clo1 (fun1,tup1); + FunctionClosure clo2 (fun2,tup2); + FunctionClosure clo3 (fun3,tup3); + + ASSERT (-1 == clo0() ); + ASSERT (11 == clo1() ); + ASSERT (11+12 == clo2() ); + ASSERT (11+12+13 == clo3() ); + + function unbound_functor0 (fun0); + function unbound_functor1 (fun1); + function unbound_functor2 (fun2); + function unbound_functor3 (fun3); + + clo0 = FunctionClosure (unbound_functor0,tup0); + clo1 = FunctionClosure (unbound_functor1,tup1); + clo2 = FunctionClosure (unbound_functor2,tup2); + clo3 = FunctionClosure (unbound_functor3,tup3); + + ASSERT (-1 == clo0() ); + ASSERT (11 == clo1() ); + ASSERT (11+12 == clo2() ); + ASSERT (11+12+13 == clo3() ); + + ASSERT (-1 == func::closure(fun0,tup0) () ); + ASSERT (11 == func::closure(fun1,tup1) () ); + ASSERT (11+12 == func::closure(fun2,tup2) () ); + ASSERT (11+12+13 == func::closure(fun3,tup3) () ); + + ASSERT (-1 == func::closure(unbound_functor0,tup0) () ); + ASSERT (11 == func::closure(unbound_functor1,tup1) () ); + ASSERT (11+12 == func::closure(unbound_functor2,tup2) () ); + ASSERT (11+12+13 == func::closure(unbound_functor3,tup3) () ); + + + // finally combine all techniques.... + typedef Tuple::Type NumberzArg; + typedef FunctionTypedef::Sig NumberzSig; + Tuple numberzTup (Num<5>(22), Num<6>(33), Num<7>(44)); + + FunctionClosure numClo (getNumberz<5,6,7>, numberzTup ); + + ASSERT (22+33+44 == numClo() ); + } + }; + + + /** Register this test class... */ + LAUNCHER (FunctionClosure_test, "unit common"); + + + +}}} // namespace lumiera::typelist::test diff --git a/tests/lib/meta/type-tuple-test.cpp b/tests/lib/meta/type-tuple-test.cpp index 80f15929a..932f56572 100644 --- a/tests/lib/meta/type-tuple-test.cpp +++ b/tests/lib/meta/type-tuple-test.cpp @@ -80,6 +80,7 @@ namespace test { * are synthesised by recursion over the related typelist. * - diagnostics through TupleAccessor retrieving stored values * - creating tuples by direct function call, providing values + * - creating tuples partially from an existing sub-argument tuple * - copy and copy construct * - access the "head" and access values by numeric index * - create a tuple with shifted values @@ -94,6 +95,7 @@ namespace test { check_sub_tuple_types(); check_shiftedTuple(); check_tuple_creation(); + check_build_from_subTuple(); check_tuple_copy(); check_value_access(); } @@ -312,6 +314,73 @@ namespace test { } + void + check_build_from_subTuple() + { + cout << "\t:\n\t: ---build-from-sub-Tuples---\n"; + + typedef Append::List TL; + typedef Tuple::Type TT; + typedef Tuple T1357L; + typedef Tuple T1357T; + DISPLAY (T1357L); + DISPLAY (T1357T); + + typedef Tuple T135L; + typedef Tuple,Num<7> > > T57T; + typedef Tuple,Num<5> > > T35T; + DISPLAY (T135L); + DISPLAY (T57T); + DISPLAY (T35T); + + T135L sub135; + T57T sub57; + T35T sub35 (Num<3>(8),Num<5>(8)); + + DUMPVAL (sub135); + T1357T b_135 = tuple::BuildTuple::create(sub135); + DUMPVAL (b_135); + b_135 = tuple::BuildTuple::create(sub135); + DUMPVAL (b_135); + b_135 = tuple::BuildTuple::create(sub135); + DUMPVAL (b_135); + b_135 = tuple::BuildTuple::create(sub135); + DUMPVAL (b_135); // all variations of type specification lead to the same result + + DUMPVAL (sub57); + T1357T b_57 = tuple::BuildTuple::create(sub57); + DUMPVAL (b_57); + + DUMPVAL (sub35); + T1357T b_35 = tuple::BuildTuple::create(sub35); + DUMPVAL (b_35); + + b_35 = tuple::BuildTuple::create(sub35); + DUMPVAL (b_35); // note: wrong start position, argument tuple ignored completely + b_35 = tuple::BuildTuple::create(sub35); + DUMPVAL (b_35); + + // use an argument tuple beyond the last argument of the target tuple... + typedef Tuple,Num<8> > > T78T; + T78T sub78 (Num<7>(77),Num<8>(88)); + DUMPVAL (sub78); + T1357T b_78 = tuple::BuildTuple::create(sub78); + DUMPVAL (b_78); // note: superfluous arguments ignored + + typedef Tuple > NulT; + NulT nult; + T1357T b_nul = tuple::BuildTuple::create(nult); + DUMPVAL (b_nul); + b_nul = tuple::BuildTuple::create(nult); + DUMPVAL (b_nul); + + NulT b_nul2 = tuple::BuildTuple::create(sub78); + DUMPVAL (b_nul2) + b_nul2 = tuple::BuildTuple::create(sub78); + DUMPVAL (b_nul2) + } + + void check_tuple_copy() {