2009-06-28 20:41:33 +02:00
|
|
|
/*
|
2009-06-29 06:33:42 +02:00
|
|
|
FunctionComposition(Test) - functional composition and partial application
|
2009-06-28 20:41:33 +02:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
|
|
|
#include "lib/test/test-helper.hpp"
|
|
|
|
|
#include "lib/meta/typelist.hpp"
|
|
|
|
|
#include "lib/meta/function.hpp"
|
|
|
|
|
#include "lib/meta/function-closure.hpp"
|
|
|
|
|
#include "meta/typelist-diagnostics.hpp"
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
using ::test::Test;
|
|
|
|
|
using std::string;
|
|
|
|
|
using std::cout;
|
|
|
|
|
using std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lumiera {
|
|
|
|
|
namespace typelist{
|
|
|
|
|
namespace test {
|
2009-06-29 06:33:42 +02:00
|
|
|
|
|
|
|
|
using func::applyFirst;
|
|
|
|
|
using func::applyLast;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { // test functions
|
2009-06-28 20:41:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-06-29 06:33:42 +02:00
|
|
|
typedef Types< Num<1> ////////////////////////TODO kill kill kill
|
2009-06-28 20:41:33 +02:00
|
|
|
, Num<2>
|
|
|
|
|
, Num<3>
|
|
|
|
|
>::List List1;
|
|
|
|
|
typedef Types< Num<5>
|
|
|
|
|
, Num<6>
|
|
|
|
|
, Num<7>
|
|
|
|
|
>::List List2;
|
|
|
|
|
|
2009-06-29 06:33:42 +02:00
|
|
|
Num<1> _1_;
|
|
|
|
|
Num<2> _2_;
|
|
|
|
|
Num<3> _3_;
|
|
|
|
|
Num<4> _4_;
|
|
|
|
|
Num<5> _5_;
|
|
|
|
|
Num<6> _6_;
|
|
|
|
|
Num<7> _7_;
|
|
|
|
|
Num<8> _8_;
|
|
|
|
|
Num<9> _9_;
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:33:42 +02:00
|
|
|
/** "Function-1" will be used at the front side, accepting a tuple of values */
|
|
|
|
|
template<char i>
|
|
|
|
|
Num<i>
|
2009-07-01 03:23:26 +02:00
|
|
|
fun11 ( Num<i> val1
|
|
|
|
|
)
|
2009-06-29 06:33:42 +02:00
|
|
|
{
|
|
|
|
|
return val1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<char i, char ii>
|
|
|
|
|
Num<i>
|
2009-07-01 03:23:26 +02:00
|
|
|
fun12 ( Num<i> val1
|
|
|
|
|
, Num<ii> val2
|
|
|
|
|
)
|
2009-06-29 06:33:42 +02:00
|
|
|
{
|
|
|
|
|
val1.o_ += val2.o_;
|
|
|
|
|
return val1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<char i, char ii, char iii>
|
|
|
|
|
Num<i>
|
2009-07-01 03:23:26 +02:00
|
|
|
fun13 ( Num<i> val1
|
|
|
|
|
, Num<ii> val2
|
|
|
|
|
, Num<iii> val3
|
|
|
|
|
)
|
2009-06-29 06:33:42 +02:00
|
|
|
{
|
|
|
|
|
val1.o_ += val2.o_ + val3.o_;
|
|
|
|
|
return val1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<char i, char ii, char iii, char iv>
|
|
|
|
|
Num<i>
|
2009-07-01 03:23:26 +02:00
|
|
|
fun14 ( Num<i> val1
|
|
|
|
|
, Num<ii> val2
|
|
|
|
|
, Num<iii> val3
|
|
|
|
|
, Num<iv> val4
|
|
|
|
|
)
|
2009-06-29 06:33:42 +02:00
|
|
|
{
|
|
|
|
|
val1.o_ += val2.o_ + val3.o_ + val4.o_;
|
|
|
|
|
return val1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<char i, char ii, char iii, char iv, char v>
|
|
|
|
|
Num<i>
|
2009-07-01 03:23:26 +02:00
|
|
|
fun15 ( Num<i> val1
|
|
|
|
|
, Num<ii> val2
|
|
|
|
|
, Num<iii> val3
|
|
|
|
|
, Num<iv> val4
|
|
|
|
|
, Num<v> val5
|
|
|
|
|
)
|
2009-06-28 20:41:33 +02:00
|
|
|
{
|
2009-06-29 06:33:42 +02:00
|
|
|
val1.o_ += val2.o_ + val3.o_ + val4.o_ + val5.o_;
|
|
|
|
|
return val1;
|
2009-06-28 20:41:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-06-29 06:33:42 +02:00
|
|
|
/** "Function-2" can be chained behind fun1 */
|
|
|
|
|
template<class II>
|
|
|
|
|
int
|
|
|
|
|
fun2 (II val)
|
|
|
|
|
{
|
|
|
|
|
return val.o_;
|
|
|
|
|
}
|
2009-06-28 20:41:33 +02:00
|
|
|
|
|
|
|
|
} // (End) test data
|
2009-06-29 06:33:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
|
* @test this test covers some extensions and variations on function closures:
|
|
|
|
|
* - partial application of a function, returning a binder
|
2009-07-01 03:23:26 +02:00
|
|
|
* - chaining of two functions with suitable arguments ("composition")
|
2009-06-28 20:41:33 +02:00
|
|
|
*/
|
2009-06-29 06:33:42 +02:00
|
|
|
class FunctionComposition_test : public Test
|
2009-06-28 20:41:33 +02:00
|
|
|
{
|
|
|
|
|
virtual void
|
|
|
|
|
run (Arg)
|
|
|
|
|
{
|
|
|
|
|
check_diagnostics ();
|
2009-06-29 06:33:42 +02:00
|
|
|
check_partialApplication ();
|
|
|
|
|
check_functionalComposition ();
|
2009-06-28 20:41:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** verify the test input data
|
|
|
|
|
* @see TypeListManipl_test#check_diagnostics()
|
|
|
|
|
* for an explanation of the DISPLAY macro
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
check_diagnostics ()
|
|
|
|
|
{
|
2009-07-01 03:23:26 +02:00
|
|
|
ASSERT (6 == (fun13<1,2,3> (_1_, _2_, _3_)).o_ );
|
|
|
|
|
ASSERT (6 == (fun13<1,1,1> (Num<1>(3), Num<1>(2), Num<1>(1))).o_ );
|
|
|
|
|
|
|
|
|
|
ASSERT ( 1 == fun2 (fun11<1> (_1_)) );
|
|
|
|
|
ASSERT ( 3 == fun2 (fun12<1,2> (_1_, _2_)) );
|
|
|
|
|
ASSERT ( 6 == fun2 (fun13<1,2,3> (_1_, _2_, _3_)) );
|
|
|
|
|
ASSERT (10 == fun2 (fun14<1,2,3,4> (_1_, _2_, _3_, _4_)) );
|
|
|
|
|
ASSERT (15 == fun2 (fun15<1,2,3,4,5> (_1_, _2_, _3_, _4_, _5_)) );
|
|
|
|
|
|
|
|
|
|
ASSERT ( 9 == fun2 (fun13<2,3,4> (_2_, _3_, _4_)) );
|
|
|
|
|
ASSERT (18 == fun2 (fun13<5,6,7> (_5_, _6_, _7_)) );
|
|
|
|
|
ASSERT (24 == fun2 (fun13<9,8,7> (_9_, _8_, _7_)) );
|
2009-06-28 20:41:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2009-06-29 06:34:20 +02:00
|
|
|
check_partialApplication ()
|
2009-06-28 20:41:33 +02:00
|
|
|
{
|
2009-06-29 06:34:20 +02:00
|
|
|
// Because the code of the partial function application is very technical,
|
|
|
|
|
// the following might serve as explanation what actually happens....
|
|
|
|
|
// (and actually it's a leftover from initial debugging)
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
typedef Num<1> Sig123(Num<1>, Num<2>, Num<3>); // signature of the original function
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
typedef Num<1> Sig23(Num<2>, Num<3>); // signature after having closed over the first argument
|
|
|
|
|
typedef function<Sig23> F23; // and a tr1::function object to hold such a function
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-07-01 03:23:26 +02:00
|
|
|
Sig123& f =fun13<1,2,3>; // the actual input: a reference to the bare function
|
2009-06-28 20:41:33 +02:00
|
|
|
|
|
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
// Version1: do a direct argument binding----------------- //
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
typedef std::tr1::_Placeholder<1> PH1; // tr1::function argument placeholders
|
|
|
|
|
typedef std::tr1::_Placeholder<2> PH2;
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
PH1 ph1; // these empty structs are used to mark the arguments to be kept "open"
|
|
|
|
|
PH2 ph2;
|
|
|
|
|
Num<1> num18 (18); // ...and this value is for closing the first function argument
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
F23 fun_23 = std::tr1::bind (f, num18 // do the actual binding (i.e. close the first argument with a constant value)
|
|
|
|
|
, ph1
|
|
|
|
|
, ph2
|
|
|
|
|
);
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
int res = 0;
|
|
|
|
|
res = fun_23 (_2_,_3_).o_; // and invoke the resulting functor ("closure"), providing the remaining arguments
|
|
|
|
|
ASSERT (23 == res);
|
2009-06-28 20:41:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
// Version2: extract the binding arguments from a tuple--- //
|
|
|
|
|
|
|
|
|
|
typedef Tuple<Types<Num<1>, PH1, PH2> > PartialArg; // Tuple type to hold the binding values. Note the placeholder types
|
|
|
|
|
PartialArg arg(num18); // Value for partial application (the placeholders are default constructed)
|
|
|
|
|
|
|
|
|
|
fun_23 = std::tr1::bind (f, tuple::element<0>(arg) // now extract the values to bind from this tuple
|
|
|
|
|
, tuple::element<1>(arg)
|
|
|
|
|
, tuple::element<2>(arg)
|
|
|
|
|
);
|
|
|
|
|
res = 0;
|
|
|
|
|
res = fun_23 (_2_,_3_).o_; // and invoke the resulting functor....
|
|
|
|
|
ASSERT (23 == res);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Version3: let the PApply-template do the work for us--- //
|
|
|
|
|
|
|
|
|
|
typedef Types<Num<1> > ArgTypes; // now package just the argument(s) to be applied into a tuple
|
|
|
|
|
Tuple<ArgTypes> args_to_bind (Num<1>(18));
|
|
|
|
|
|
|
|
|
|
fun_23 = PApply<Sig123, ArgTypes>::bindFront (f , args_to_bind);
|
|
|
|
|
// "bindFront" will close the parameters starting from left....
|
|
|
|
|
res = 0;
|
|
|
|
|
res = fun_23 (_2_,_3_).o_; // invoke the resulting functor...
|
|
|
|
|
ASSERT (23 == res);
|
|
|
|
|
|
|
|
|
|
|
2009-06-28 20:41:33 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Version4: as you'd typically do it in real life-------- //
|
|
|
|
|
|
|
|
|
|
fun_23 = func::applyFirst (f, Num<1>(18)); // use the convenience function API to close over a single value
|
|
|
|
|
|
|
|
|
|
res = 0;
|
|
|
|
|
res = fun_23 (_2_,_3_).o_; // invoke the resulting functor...
|
|
|
|
|
ASSERT (23 == res);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// what follows is the real unit test...
|
2009-07-01 03:23:26 +02:00
|
|
|
function<Sig123> func123 (f); // alternatively do it with an tr1::function object
|
2009-06-29 06:34:20 +02:00
|
|
|
fun_23 = func::applyFirst (func123, Num<1>(19));
|
|
|
|
|
res = fun_23 (_2_,_3_).o_;
|
|
|
|
|
ASSERT (24 == res);
|
2009-07-01 02:29:11 +02:00
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
typedef function<Num<1>(Num<1>, Num<2>)> F12;
|
2009-07-01 03:23:26 +02:00
|
|
|
F12 fun_12 = func::applyLast(f, Num<3>(20)); // close the *last* argument of a function
|
2009-06-29 06:34:20 +02:00
|
|
|
res = fun_12 (_1_,_2_).o_;
|
|
|
|
|
ASSERT (23 == res);
|
|
|
|
|
|
2009-07-01 03:23:26 +02:00
|
|
|
fun_12 = func::applyLast(func123, Num<3>(21)); // alternatively use a function object
|
2009-06-29 06:34:20 +02:00
|
|
|
res = fun_12 (_1_,_2_).o_;
|
|
|
|
|
ASSERT (24 == res);
|
2009-07-01 02:29:11 +02:00
|
|
|
|
2009-07-01 03:23:26 +02:00
|
|
|
Sig123 *fP = &f; // a function pointer works too
|
|
|
|
|
fun_12 = func::applyLast( fP, Num<3>(22));
|
|
|
|
|
res = fun_12 (_1_,_2_).o_;
|
|
|
|
|
ASSERT (25 == res);
|
|
|
|
|
// cover more cases....
|
|
|
|
|
|
|
|
|
|
ASSERT (1 == (func::applyLast (fun11<1> , _1_) ( ) ).o_);
|
|
|
|
|
ASSERT (1+3 == (func::applyLast (fun12<1,3> , _3_) (_1_) ).o_);
|
|
|
|
|
ASSERT (1+3+5 == (func::applyLast (fun13<1,3,5> , _5_) (_1_,_3_) ).o_);
|
|
|
|
|
ASSERT (1+3+5+7 == (func::applyLast (fun14<1,3,5,7> , _7_) (_1_,_3_,_5_) ).o_);
|
|
|
|
|
ASSERT (1+3+5+7+9 == (func::applyLast (fun15<1,3,5,7,9>, _9_) (_1_,_3_,_5_,_7_)).o_);
|
|
|
|
|
|
|
|
|
|
ASSERT (9+8+7+6+5 == (func::applyFirst(fun15<9,8,7,6,5>, _9_) (_8_,_7_,_6_,_5_)).o_);
|
|
|
|
|
ASSERT ( 8+7+6+5 == (func::applyFirst( fun14<8,7,6,5>, _8_) (_7_,_6_,_5_)).o_);
|
|
|
|
|
ASSERT ( 7+6+5 == (func::applyFirst( fun13<7,6,5>, _7_) (_6_,_5_)).o_);
|
|
|
|
|
ASSERT ( 6+5 == (func::applyFirst( fun12<6,5>, _6_) (_5_)).o_);
|
|
|
|
|
ASSERT ( 5 == (func::applyFirst( fun11<5>, _5_) ( )).o_);
|
2009-07-01 04:47:52 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Finally a more convoluted example
|
|
|
|
|
// covering the general case of partial function closure:
|
|
|
|
|
typedef Num<5> Sig54321(Num<5>, Num<4>, Num<3>, Num<2>, Num<1>); // Signature of the 5-argument function
|
|
|
|
|
typedef Num<5> Sig54 (Num<5>, Num<4>); // ...closing the last 3 arguments should yield this 2-argument function
|
|
|
|
|
typedef Types<Num<3>,Num<2>,Num<1> > Args2Close; // Tuple type to hold the 3 argument values used for the closure
|
|
|
|
|
|
|
|
|
|
// Close the trailing 3 arguments of the 5-argument function...
|
|
|
|
|
function<Sig54> fun_54 = PApply<Sig54321, Args2Close>::bindBack(fun15<5,4,3,2,1>,
|
|
|
|
|
tuple::make(_3_,_2_,_1_)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// apply the remaining argument values
|
|
|
|
|
Num<5> resN5 = fun_54 (_5_,_4_);
|
|
|
|
|
ASSERT (5+4+3+2+1 == resN5.o_);
|
2009-06-28 20:41:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-06-29 06:34:20 +02:00
|
|
|
|
2009-06-28 20:41:33 +02:00
|
|
|
void
|
2009-06-29 06:34:20 +02:00
|
|
|
check_functionalComposition ()
|
2009-06-28 20:41:33 +02:00
|
|
|
{
|
2009-07-01 04:47:52 +02:00
|
|
|
typedef Num<1> Sig12(Num<1>,Num<2>);
|
|
|
|
|
typedef int SigF21(Num<1>);
|
|
|
|
|
|
|
|
|
|
Sig12 &f1 = fun12<1,2>;
|
|
|
|
|
SigF21 &f2 = fun2<Num<1> >;
|
|
|
|
|
|
|
|
|
|
typedef function<int(Num<1>,Num<2>)> Chained;
|
|
|
|
|
|
|
|
|
|
Chained funCh = func::chained (f1, f2 );
|
|
|
|
|
ASSERT (1+2 == funCh (_1_,_2_) );
|
|
|
|
|
|
|
|
|
|
#if false
|
|
|
|
|
ASSERT (1 == func::chain(fun11<1> , fun2) (_1_) );
|
|
|
|
|
ASSERT (1+2 == func::chain(fun12<1,2> , fun2<Num<1> > ) (_1_,_2_) );
|
|
|
|
|
ASSERT (1+2+3 == func::chain(fun13<1,2,3> , fun2) (_1_,_2_,_3_) );
|
|
|
|
|
ASSERT (1+2+3+4 == func::chain(fun14<1,2,3,4> , fun2) (_1_,_2_,_3_,_4_) );
|
|
|
|
|
ASSERT (1+2+3+4+5 == func::chain(fun15<1,2,3,4,5>, fun2) (_1_,_2_,_3_,_4_,_5_) );
|
|
|
|
|
#endif
|
2009-06-28 20:41:33 +02:00
|
|
|
}
|
2009-06-29 06:34:20 +02:00
|
|
|
|
2009-06-28 20:41:33 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Register this test class... */
|
2009-06-29 06:34:20 +02:00
|
|
|
LAUNCHER (FunctionComposition_test, "unit common");
|
2009-06-28 20:41:33 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}}} // namespace lumiera::typelist::test
|