959 lines
32 KiB
C++
959 lines
32 KiB
C++
/*
|
|
FUNCTION-CLOSURE.hpp - metaprogramming tools for closing a function over given arguments
|
|
|
|
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 function-closure.hpp
|
|
** Partial function application and building a complete function closure.
|
|
** This is a addendum to (and thin wrapper for) `<functional>`, supporting
|
|
** the case when a function should be _closed_ over (partially or all) arguments,
|
|
** where especially the parameter values to close on are provided as a tuple.
|
|
** Additionally, we allow for composing (chaining) of two functions.
|
|
**
|
|
** Because we have to deal with arbitrary functions and arbitrary parameter types,
|
|
** we need a lot of repetitive code to "catch" functions from zero to nine arguments.
|
|
** At the bottom of this header, you'll find a function-style interface, which
|
|
** wraps up all these technicalities.
|
|
**
|
|
** @todo the implementation is able to handle partial application with N arguments,
|
|
** but currently we need just one argument, thus only this case was wrapped
|
|
** up into a convenient functions func::applyFirst and func::applyLast
|
|
**
|
|
** @see control::CommandDef usage example
|
|
** @see function.hpp
|
|
**
|
|
*/
|
|
|
|
|
|
#ifndef LIB_META_FUNCTION_CLOSURE_H
|
|
#define LIB_META_FUNCTION_CLOSURE_H
|
|
|
|
#include "lib/meta/function.hpp"
|
|
#include "lib/meta/tuple-helper.hpp"
|
|
|
|
#include <functional>
|
|
#include <tuple>
|
|
|
|
|
|
|
|
namespace lib {
|
|
namespace meta{
|
|
namespace func{
|
|
|
|
using std::function;
|
|
using std::tuple;
|
|
|
|
|
|
|
|
|
|
namespace { // helpers for binding and applying a function to an argument tuple
|
|
|
|
using std::get;
|
|
|
|
/**
|
|
* this Helper with repetitive specialisations for up to nine arguments
|
|
* is used either to apply a function to arguments given as a tuple, or
|
|
* to create the actual closure (functor) over all function arguments.
|
|
*/
|
|
template<uint n>
|
|
struct Apply;
|
|
|
|
|
|
template<> //__________________________________
|
|
struct Apply<0> ///< Apply function without Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP&)
|
|
{
|
|
return f ();
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP&)
|
|
{
|
|
return std::bind (f);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<1> ///< Apply function with 1 Argument
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f (get<0>(arg));
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg));
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<2> ///< Apply function with 2 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<3> ///< Apply function with 3 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<4> ///< Apply function with 4 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<5> ///< Apply function with 5 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<6> ///< Apply function with 6 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<7> ///< Apply function with 7 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
, get<6>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
, get<6>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<8> ///< Apply function with 8 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
, get<6>(arg)
|
|
, get<7>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
, get<6>(arg)
|
|
, get<7>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
template<> //_________________________________
|
|
struct Apply<9> ///< Apply function with 9 Arguments
|
|
{
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
invoke (FUN& f, TUP & arg)
|
|
{
|
|
return f ( get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
, get<6>(arg)
|
|
, get<7>(arg)
|
|
, get<8>(arg)
|
|
);
|
|
}
|
|
|
|
template<typename RET, class FUN, class TUP>
|
|
static RET
|
|
bind (FUN& f, TUP & arg)
|
|
{
|
|
return std::bind (f, get<0>(arg)
|
|
, get<1>(arg)
|
|
, get<2>(arg)
|
|
, get<3>(arg)
|
|
, get<4>(arg)
|
|
, get<5>(arg)
|
|
, get<6>(arg)
|
|
, get<7>(arg)
|
|
, get<8>(arg)
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ===== Helpers for partial function application ===== */
|
|
|
|
/** @note relying on the implementation type
|
|
* since we need to _build_ placeholders */
|
|
using std::_Placeholder;
|
|
|
|
|
|
/**
|
|
* Build a list of standard function argument placeholder types.
|
|
* For each of the elements of the provided reference list,
|
|
* a Placeholder is added, numbers counting up starting with 1 (!)
|
|
*/
|
|
template<typename TYPES, size_t i=1>
|
|
struct PlaceholderTuple
|
|
: PlaceholderTuple<typename TYPES::List>
|
|
{ };
|
|
|
|
template<typename X, typename TAIL, size_t i>
|
|
struct PlaceholderTuple<Node<X,TAIL>, i>
|
|
{
|
|
using TailPlaceholders = typename PlaceholderTuple<TAIL,i+1>::List;
|
|
|
|
using List = Node<_Placeholder<i>, TailPlaceholders>;
|
|
};
|
|
|
|
template<size_t i>
|
|
struct PlaceholderTuple<NullType, i>
|
|
{
|
|
using List = NullType;
|
|
};
|
|
|
|
|
|
|
|
using std::tuple_element;
|
|
using std::tuple_size;
|
|
using std::get;
|
|
|
|
|
|
/**
|
|
* Builder for a tuple instance, where only some ctor parameters are supplied,
|
|
* while the remaining arguments will be default constructed. The use case is
|
|
* creating of a function binder, where some arguments shall be passed through
|
|
* (and thus be stored in the resulting closure), while other arguments are just
|
|
* marked as "Placeholder" with `std::_Placeholder<i>`.
|
|
* These placeholder marker terms just need to be default constructed, and will
|
|
* then be stored into the desired positions. Later on, when actually invoking
|
|
* such a partially closed function, only the arguments marked with placeholders
|
|
* need to be supplied, while the other arguments will use the values hereby
|
|
* "baked" into the closure.
|
|
* @tparam TAR full target tuple type. Some oft the elements within this tuple will
|
|
* be default constructed, some will be initialised from the SRC tuple
|
|
* @tparam SRC argument tuple type, for the values _actually to be initialised_ here.
|
|
* @tparam start position within TYPES, at which the sequence of init-arguments starts;
|
|
* all other positions will just be default initialised
|
|
* @see lib::meta::TupleConstructor
|
|
*/
|
|
template<typename SRC, typename TAR, size_t start>
|
|
struct PartiallyInitTuple
|
|
{
|
|
template<size_t i>
|
|
using DestType = typename std::tuple_element<i, TAR>::type;
|
|
|
|
|
|
/**
|
|
* define those index positions in the target tuple,
|
|
* where init arguments shall be used on construction.
|
|
* All other arguments will just be default initialised.
|
|
*/
|
|
static constexpr bool
|
|
useArg (size_t idx)
|
|
{
|
|
return (start <= idx)
|
|
and (idx < start + std::tuple_size<SRC>());
|
|
}
|
|
|
|
|
|
|
|
template<size_t idx, bool doPick = PartiallyInitTuple::useArg(idx)>
|
|
struct IndexMapper
|
|
{
|
|
SRC const& initArgs;
|
|
|
|
operator DestType<idx>()
|
|
{
|
|
return std::get<idx-start> (initArgs);
|
|
}
|
|
};
|
|
|
|
template<size_t idx>
|
|
struct IndexMapper<idx, false>
|
|
{
|
|
SRC const& initArgs;
|
|
|
|
operator DestType<idx>()
|
|
{
|
|
return DestType<idx>();
|
|
}
|
|
};
|
|
};
|
|
|
|
} // (END) impl-namespace
|
|
|
|
|
|
|
|
|
|
/* ======= core operations: closures and partial application ========= */
|
|
|
|
/**
|
|
* Closure-creating template.
|
|
* @note we take functor objects \em and parameters by reference
|
|
*/
|
|
template<typename SIG>
|
|
class TupleApplicator
|
|
{
|
|
typedef typename FunctionSignature< function<SIG> >::Args Args;
|
|
typedef typename FunctionSignature< function<SIG> >::Ret Ret;
|
|
|
|
typedef function<Ret()> BoundFunc;
|
|
|
|
enum { ARG_CNT = count<typename Args::List>::value };
|
|
|
|
|
|
/** storing a ref to the parameter tuple */
|
|
Tuple<Args>& params_;
|
|
|
|
public:
|
|
TupleApplicator (Tuple<Args>& args)
|
|
: params_(args)
|
|
{ }
|
|
|
|
BoundFunc bind (SIG& f) { return Apply<ARG_CNT>::template bind<BoundFunc> (f, params_); }
|
|
BoundFunc bind (function<SIG> const& f) { return Apply<ARG_CNT>::template bind<BoundFunc> (f, params_); }
|
|
|
|
Ret operator() (SIG& f) { return Apply<ARG_CNT>::template invoke<Ret> (f, params_); }
|
|
Ret operator() (function<SIG>& f) { return Apply<ARG_CNT>::template invoke<Ret> (f, params_); }
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Closing a function over its arguments.
|
|
* This is a small usage example or spin-off,
|
|
* having almost the same effect than invoking tr1::bind.
|
|
* The notable difference is that the function arguments for
|
|
* creating the closure are passed in as one tuple compound.
|
|
*/
|
|
template<typename SIG>
|
|
class FunctionClosure
|
|
{
|
|
typedef typename _Fun<SIG>::Args Args;
|
|
typedef typename _Fun<SIG>::Ret Ret;
|
|
|
|
function<Ret(void)> closure_;
|
|
|
|
public:
|
|
FunctionClosure (SIG& f, Tuple<Args>& arg)
|
|
: closure_(TupleApplicator<SIG>(arg).bind(f))
|
|
{ }
|
|
FunctionClosure (function<SIG> const& f, Tuple<Args>& arg)
|
|
: closure_(TupleApplicator<SIG>(arg).bind(f))
|
|
{ }
|
|
|
|
Ret operator() () { return closure_(); }
|
|
|
|
typedef Ret result_type; ///< for STL use
|
|
typedef void argument_type;
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Partial function application
|
|
* Takes a function and a value tuple,
|
|
* using the latter to close function arguments
|
|
* either from the front (left) or aligned to the end
|
|
* of the function argument list. Result is a "reduced" function,
|
|
* expecting only the remaining "un-closed" arguments at invocation.
|
|
* @tparam SIG signature of the function to be closed, either as
|
|
* function reference type or `std::function` object
|
|
* @tparam VAL type sequence describing the tuple of values
|
|
* used for closing arguments
|
|
* @note the construction of this helper template does not verify or
|
|
* match types to to the signature. In case of mismatch, you'll get
|
|
* a compilation failure from `std::bind` (which can be confusing)
|
|
*/
|
|
template<typename SIG, typename VAL>
|
|
class PApply
|
|
{
|
|
typedef typename _Fun<SIG>::Args Args;
|
|
typedef typename _Fun<SIG>::Ret Ret;
|
|
typedef typename Args::List ArgsList;
|
|
typedef typename VAL::List ValList;
|
|
typedef typename Types<ValList>::Seq ValTypes;
|
|
|
|
enum { ARG_CNT = count<ArgsList>::value
|
|
, VAL_CNT = count<ValList> ::value
|
|
, ROFFSET = (VAL_CNT < ARG_CNT)? ARG_CNT-VAL_CNT : 0
|
|
};
|
|
|
|
|
|
// create list of the *remaining* arguments, after applying the ValList
|
|
typedef typename Splice<ArgsList, ValList>::Back LeftReduced;
|
|
typedef typename Splice<ArgsList, ValList, ROFFSET>::Front RightReduced;
|
|
|
|
typedef typename Types<LeftReduced>::Seq ArgsL;
|
|
typedef typename Types<RightReduced>::Seq ArgsR;
|
|
|
|
|
|
// build a list, where each of the *remaining* arguments is replaced by a placeholder marker
|
|
typedef typename func::PlaceholderTuple<LeftReduced>::List TrailingPlaceholders;
|
|
typedef typename func::PlaceholderTuple<RightReduced>::List LeadingPlaceholders;
|
|
|
|
// ... and splice these placeholders on top of the original argument type list,
|
|
// thus retaining the types to be closed, but setting a placeholder for each remaining argument
|
|
typedef typename Splice<ArgsList, TrailingPlaceholders, VAL_CNT>::List LeftReplaced;
|
|
typedef typename Splice<ArgsList, LeadingPlaceholders, 0 >::List RightReplaced;
|
|
|
|
typedef typename Types<LeftReplaced>::Seq LeftReplacedTypes;
|
|
typedef typename Types<RightReplaced>::Seq RightReplacedTypes;
|
|
|
|
// create a "builder" helper, which accepts exactly the value tuple elements
|
|
// and puts them at the right location, while default-constructing the remaining
|
|
// (=placeholder)-arguments. Using this builder helper, we can finally set up
|
|
// the argument tuples (Left/RightReplacedArgs) used for the std::bind call
|
|
template<class SRC, class TAR, size_t i>
|
|
using IdxSelectorL = typename PartiallyInitTuple<SRC, TAR, 0>::template IndexMapper<i>;
|
|
|
|
template<class SRC, class TAR, size_t i>
|
|
using IdxSelectorR = typename PartiallyInitTuple<SRC, TAR, ROFFSET>::template IndexMapper<i>;
|
|
|
|
using BuildL = TupleConstructor<LeftReplacedTypes, IdxSelectorL>;
|
|
using BuildR = TupleConstructor<RightReplacedTypes, IdxSelectorR>;
|
|
|
|
|
|
/** Tuple to hold all argument values, starting from left.
|
|
* Any remaining positions behind the substitute values are occupied by binding placeholders */
|
|
using LeftReplacedArgs = Tuple<LeftReplacedTypes>;
|
|
|
|
/** Tuple to hold all argument values, aligned to the end of the function argument list.
|
|
* Any remaining positions before the substitute values are occupied by binding placeholders */
|
|
using RightReplacedArgs = Tuple<RightReplacedTypes>;
|
|
|
|
|
|
public:
|
|
typedef function<typename FunctionTypedef<Ret,ArgsL>::Sig> LeftReducedFunc;
|
|
typedef function<typename FunctionTypedef<Ret,ArgsR>::Sig> RightReducedFunc;
|
|
|
|
|
|
/** do a partial function application, closing the first arguments</br>
|
|
* `f(a,b,c)->res + (a,b)` yields `f(c)->res`
|
|
*
|
|
* @param f function, function pointer or functor
|
|
* @param arg value tuple, used to close function arguments starting from left
|
|
* @return new function object, holding copies of the values and using them at the
|
|
* closed arguments; on invocation, only the remaining arguments need to be supplied.
|
|
*/
|
|
static LeftReducedFunc
|
|
bindFront (SIG& f, Tuple<ValTypes> const& arg)
|
|
{
|
|
LeftReplacedArgs params {BuildL(arg)};
|
|
return func::Apply<ARG_CNT>::template bind<LeftReducedFunc> (f, params);
|
|
}
|
|
|
|
/** do a partial function application, closing the last arguments</br>
|
|
* `f(a,b,c)->res + (b,c)` yields `f(a)->res`
|
|
*
|
|
* @param f function, function pointer or functor
|
|
* @param arg value tuple, used to close function arguments starting from right
|
|
* @return new function object, holding copies of the values and using them at the
|
|
* closed arguments; on invocation, only the remaining arguments need to be supplied.
|
|
*/
|
|
static RightReducedFunc
|
|
bindBack (SIG& f, Tuple<ValTypes> const& arg)
|
|
{
|
|
RightReplacedArgs params {BuildR(arg)};
|
|
return func::Apply<ARG_CNT>::template bind<RightReducedFunc> (f, params);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace _composed { // repetitive impl.code for function composition
|
|
using std::bind;
|
|
using std::function;
|
|
using std::placeholders::_1;
|
|
using std::placeholders::_2;
|
|
using std::placeholders::_3;
|
|
using std::placeholders::_4;
|
|
using std::placeholders::_5;
|
|
using std::placeholders::_6;
|
|
using std::placeholders::_7;
|
|
using std::placeholders::_8;
|
|
using std::placeholders::_9;
|
|
|
|
template<typename RES, typename F1, typename F2, uint n>
|
|
struct Build;
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 0 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 1 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 2 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 3 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 4 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 5 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 6 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 7 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6,_7)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 8 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6,_7,_8)); }
|
|
};
|
|
|
|
template<typename RES, typename F1, typename F2>
|
|
struct Build<RES,F1,F2, 9 >
|
|
{
|
|
static function<RES> func(F1& f1, F2& f2) { return bind (f2, bind (f1,_1,_2,_3,_4,_5,_6,_7,_8,_9)); }
|
|
};
|
|
} // (End) impl namespace (_composed)
|
|
|
|
|
|
|
|
/**
|
|
* Functional composition. Create a functor, which
|
|
* on invocation will execute two functions chained,
|
|
* i.e. fed the result of invoking the first function
|
|
* as argument into the second function.
|
|
*/
|
|
template<typename F1, typename RET>
|
|
class FunctionComposition
|
|
{
|
|
typedef typename _Fun<F1>::Args Args;
|
|
typedef typename _Fun<F1>::Ret Ret1;
|
|
|
|
typedef Types<Ret1> ArgsF2;
|
|
typedef typename FunctionTypedef<RET, ArgsF2>::Sig SigF2;
|
|
typedef typename FunctionTypedef<RET, Args>::Sig ChainedSig;
|
|
|
|
enum { ARG_CNT = count<typename Args::List>::value };
|
|
|
|
|
|
public:
|
|
static function<ChainedSig>
|
|
chain (F1& f1, SigF2& f2)
|
|
{
|
|
return _composed::Build<ChainedSig,F1,SigF2, ARG_CNT>::func (f1,f2);
|
|
}
|
|
static function<ChainedSig>
|
|
chain (F1& f1, function<SigF2>& f2)
|
|
{
|
|
return _composed::Build<ChainedSig,F1,function<SigF2>, ARG_CNT>::func (f1,f2);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Bind a specific argument to an arbitrary value.
|
|
* Especially, this "value" might be another binder.
|
|
*/
|
|
template<typename SIG, typename X, uint pos>
|
|
class BindToArgument
|
|
{
|
|
typedef typename _Fun<SIG>::Args Args;
|
|
typedef typename _Fun<SIG>::Ret Ret;
|
|
typedef typename Args::List ArgsList;
|
|
typedef typename Types<X>::List ValList;
|
|
|
|
enum { ARG_CNT = count<ArgsList>::value };
|
|
|
|
typedef typename Splice<ArgsList, ValList, pos>::Front RemainingFront;
|
|
typedef typename Splice<ArgsList, ValList, pos>::Back RemainingBack;
|
|
typedef typename func::PlaceholderTuple<RemainingFront>::List PlaceholdersBefore;
|
|
typedef typename func::PlaceholderTuple<RemainingBack,pos+1>::List PlaceholdersBehind;
|
|
typedef typename Append< typename Append< PlaceholdersBefore
|
|
, ValList >::List
|
|
, PlaceholdersBehind >::List PreparedArgs;
|
|
typedef typename Append<RemainingFront, RemainingBack>::List ReducedArgs;
|
|
|
|
using PreparedArgTypes = typename Types<PreparedArgs>::Seq;
|
|
using RemainingArgs = typename Types<ReducedArgs>::Seq;
|
|
|
|
using ReducedSig = typename FunctionTypedef<Ret,RemainingArgs>::Sig;
|
|
|
|
template<class SRC, class TAR, size_t i>
|
|
using IdxSelector = typename PartiallyInitTuple<SRC, TAR, pos>::template IndexMapper<i>;
|
|
|
|
using BuildPreparedArgs = TupleConstructor<PreparedArgTypes, IdxSelector>;
|
|
|
|
|
|
|
|
public:
|
|
typedef function<ReducedSig> ReducedFunc;
|
|
|
|
static ReducedFunc
|
|
reduced (SIG& f, Tuple<Types<X>> const& val)
|
|
{
|
|
Tuple<PreparedArgTypes> params {BuildPreparedArgs(val)};
|
|
return func::Apply<ARG_CNT>::template bind<ReducedFunc> (f, params);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
namespace { // ...helpers for specifying types in function declarations....
|
|
|
|
template<typename RET, typename ARG>
|
|
struct _Sig
|
|
{
|
|
typedef typename FunctionTypedef<RET, ARG>::Sig Type;
|
|
typedef TupleApplicator<Type> Applicator;
|
|
};
|
|
|
|
template<typename SIG, typename ARG>
|
|
struct _Clo
|
|
{
|
|
typedef typename _Fun<SIG>::Ret Ret;
|
|
typedef typename _Sig<Ret,ARG>::Type Signature;
|
|
typedef FunctionClosure<Signature> Type;
|
|
};
|
|
|
|
template<typename SIG1, typename SIG2>
|
|
struct _Chain
|
|
{
|
|
typedef typename _Fun<SIG1>::Args Args;
|
|
typedef typename _Fun<SIG2>::Ret Ret;
|
|
typedef typename FunctionTypedef<Ret, Args>::Sig Chained;
|
|
typedef function<Chained> Function;
|
|
};
|
|
|
|
template<typename SIG>
|
|
struct _PapS
|
|
{
|
|
typedef typename _Fun<SIG>::Ret Ret;
|
|
typedef typename _Fun<SIG>::Args Args;
|
|
typedef typename Split<Args>::Head Arg;
|
|
typedef typename Split<Args>::Tail Rest;
|
|
typedef typename _Sig<Ret,Rest>::Type Signature;
|
|
typedef function<Signature> Function;
|
|
};
|
|
|
|
template<typename SIG>
|
|
struct _PapE
|
|
{
|
|
typedef typename _Fun<SIG>::Ret Ret;
|
|
typedef typename _Fun<SIG>::Args Args;
|
|
typedef typename Split<Args>::End Arg;
|
|
typedef typename Split<Args>::Prefix Rest;
|
|
typedef typename _Sig<Ret,Rest>::Type Signature;
|
|
typedef function<Signature> Function;
|
|
};
|
|
|
|
} // (End) argument type shortcuts
|
|
|
|
|
|
|
|
|
|
/* ========== function-style interface ============= */
|
|
|
|
/** build a TupleApplicator, which embodies the given
|
|
* argument tuple and can be used to apply them
|
|
* to various functions repeatedly.
|
|
*/
|
|
template<typename...ARG>
|
|
inline
|
|
typename _Sig<void, Types<ARG...>>::Applicator
|
|
tupleApplicator (std::tuple<ARG...>& args)
|
|
{
|
|
typedef typename _Sig<void,Types<ARG...>>::Type Signature;
|
|
return TupleApplicator<Signature> (args);
|
|
}
|
|
|
|
|
|
/** apply the given function to the argument tuple */
|
|
template<typename SIG, typename...ARG>
|
|
inline
|
|
typename _Fun<SIG>::Ret
|
|
apply (SIG& f, std::tuple<ARG...>& args)
|
|
{
|
|
typedef typename _Fun<SIG>::Ret Ret; //
|
|
typedef typename _Sig<Ret,Types<ARG...>>::Type Signature; // Note: deliberately re-building the Signature Type
|
|
return TupleApplicator<Signature> (args) (f); // in order to get better error messages here
|
|
}
|
|
|
|
/** close the given function over all arguments,
|
|
* using the values from the argument tuple.
|
|
* @return a closure object, which can be
|
|
* invoked later to yield the
|
|
* function result. */
|
|
template<typename SIG, typename...ARG>
|
|
inline
|
|
typename _Clo<SIG,Types<ARG...>>::Type
|
|
closure (SIG& f, std::tuple<ARG...>& args)
|
|
{
|
|
typedef typename _Clo<SIG,Types<ARG...>>::Type Closure;
|
|
return Closure (f,args);
|
|
}
|
|
|
|
|
|
/** close the given function over the first argument */
|
|
template<typename SIG, typename ARG>
|
|
inline
|
|
typename _PapS<SIG>::Function
|
|
applyFirst (SIG& f, ARG arg)
|
|
{
|
|
typedef typename _PapS<SIG>::Arg ArgType;
|
|
typedef Types<ArgType> ArgTypeSeq;
|
|
typedef Tuple<ArgTypeSeq> ArgTuple;
|
|
ArgTuple val(arg);
|
|
return PApply<SIG,ArgTypeSeq>::bindFront (f, val);
|
|
}
|
|
|
|
/** close the given function over the last argument */
|
|
template<typename SIG, typename ARG>
|
|
inline
|
|
typename _PapE<SIG>::Function
|
|
applyLast (SIG& f, ARG arg)
|
|
{
|
|
typedef typename _PapE<SIG>::Arg ArgType;
|
|
typedef Types<ArgType> ArgTypeSeq;
|
|
typedef Tuple<ArgTypeSeq> ArgTuple;
|
|
ArgTuple val(arg);
|
|
return PApply<SIG,ArgTypeSeq>::bindBack (f, val);
|
|
}
|
|
|
|
|
|
/** bind the last function argument to an arbitrary term,
|
|
* which especially might be a (nested) binder... */
|
|
template<typename SIG, typename TERM>
|
|
inline
|
|
typename _PapE<SIG>::Function
|
|
bindLast (SIG& f, TERM const& arg)
|
|
{
|
|
typedef Types<TERM> ArgTypeSeq;
|
|
typedef Tuple<ArgTypeSeq> ArgTuple;
|
|
ArgTuple argT(arg);
|
|
enum { LAST_POS = -1 + count<typename _Fun<SIG>::Args::List>::value };
|
|
return BindToArgument<SIG,TERM,LAST_POS>::reduced (f, argT);
|
|
}
|
|
|
|
|
|
/** build a functor chaining the given functions */
|
|
template<typename SIG1, typename SIG2>
|
|
inline
|
|
typename _Chain<SIG1,SIG2>::Function
|
|
chained (SIG1& f1, SIG2& f2)
|
|
{
|
|
typedef typename _Chain<SIG1,SIG2>::Ret Ret;
|
|
return FunctionComposition<SIG1,Ret>::chain (f1, f2);
|
|
}
|
|
|
|
|
|
|
|
}}} // namespace lib::meta::func
|
|
#endif
|