Skip to content

Instantly share code, notes, and snippets.

@Sleepingwell
Last active August 29, 2015 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sleepingwell/e7521d8d88a417bff143 to your computer and use it in GitHub Desktop.
Save Sleepingwell/e7521d8d88a417bff143 to your computer and use it in GitHub Desktop.
Create a sequence of types (std::pair in this dummy example) containing the outer product of two input sequences of types.
/*
* A 'functor descriptor' that can be used to generate a runtime polymorphic functor
* for a set of input/ouput types. To be used to create python extensions in C++ for
* wrapping with boost::python, such that the functors can be configured in Python
* then applied to a number (greater than 1) of non-polymorphic input/output types
* in C++ (the types used in practice will not be those in first_types and second
* types, which are just for convenience).
*/
#include <new> // placement new
#include <typeinfo> // typeid
#include <cstdio> // printf
#include <stdexcept> // runtime_error
#include <boost/mpl/vector.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/accumulate.hpp>
#include <boost/mpl/insert_range.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/inherit.hpp>
#include <boost/mpl/empty_base.hpp>
#include <boost/fusion/sequence.hpp> // at_c
#include <boost/fusion/container/vector.hpp>
// while I think the following is valid syntax, it does not work on msvc 2012
//template<
// typename T0 = boost::fusion::void_,
// typename T1 = boost::fusion::void_,
// typename T2 = boost::fusion::void_,
// typename T3 = boost::fusion::void_,
// typename T4 = boost::fusion::void_,
// typename T5 = boost::fusion::void_,
// typename T6 = boost::fusion::void_,
// typename T7 = boost::fusion::void_,
// typename T8 = boost::fusion::void_,
// typename T9 = boost::fusion::void_
//> using args_ = boost::fusion::vector<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>;
// ... so do this instead
#define args_ boost::fusion::vector
/**
* @brief Virtual base class for all functors.
*/
template<typename InPoint, typename OutPoint>
struct PymeseriesFunctorBase {
virtual ~PymeseriesFunctorBase(void) {}
virtual double operator()(InPoint const& inPoint, OutPoint& outPoint, double weight) {
throw std::runtime_error("Operation not supported");
}
virtual void finaliseTimeSeries(OutPoint& outPoint) { };
};
namespace detail {
// tools for building the base class of all functor descriptors
template<
template<typename, typename> class FuncToWrap
>
struct double_bind_base {
template<typename First>
struct apply {
struct type {
template<typename Second>
struct apply {
typedef FuncToWrap<First, Second> type;
};
};
};
};
template<typename Seq>
struct second_transform_base {
template<typename State, typename Arg2>
struct apply {
struct apply_arg {
template<typename F>
struct apply {
typedef typename F::template apply<Arg2>::type type;
};
};
typedef typename boost::mpl::insert_range<
State,
typename boost::mpl::end<State>::type,
typename boost::mpl::transform<Seq, apply_arg>::type
>::type type;
};
};
// base class for functor descriptors
template<typename InPoint, typename OutPoint>
struct functor_descriptor_base {
typedef PymeseriesFunctorBase<InPoint, OutPoint> abstract_functor_type;
virtual ~functor_descriptor_base(void) {};
virtual abstract_functor_type* makeFunctor(InPoint const&, OutPoint const&) const = 0;
};
template<typename FirstTypes, typename SecondTypes>
struct make_pymeseries_functor_abstract_base {
// wrap the abstruct functor up
typedef typename boost::mpl::transform<FirstTypes, double_bind_base<functor_descriptor_base> >::type abstract_firsts;
typedef typename boost::mpl::accumulate<SecondTypes, boost::mpl::vector0<>, second_transform_base<abstract_firsts> >::type funtor_base_classes;
// make the class with base classes
typedef typename boost::mpl::inherit_linearly<
funtor_base_classes,
boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2>
>::type virtual_base_type;
struct type : virtual_base_type {
typedef FirstTypes first_types;
typedef SecondTypes second_types;
};
};
} // end namespace detail
// list of classes to specialise functors for
typedef boost::mpl::vector2<float, double> first_types;
typedef boost::mpl::vector2<int, long> second_types;
typedef detail::make_pymeseries_functor_abstract_base<first_types, second_types>::type pymeseries_functor_base;
namespace detail {
// tools for building concrete functors.
template<
typename Derived,
template<typename, typename> class FuncToWrap,
template<template<typename, typename> class, typename, typename, typename, typename> class FuncWrapper
>
struct triple_bind_derived {
template<typename First>
struct apply {
struct type {
template<typename Second>
struct apply {
struct type {
template<typename Base>
struct apply {
typedef FuncWrapper<FuncToWrap, First, Second, Derived, Base> type;
};
};
};
};
};
};
template<typename Seq>
struct second_transform_derived {
template<typename State, typename Arg2>
struct apply {
// metafunction class add the second type (second apply in triple_bind_derived).
struct apply_arg {
template<typename F>
struct apply {
typedef typename F::template apply<Arg2>::type type;
};
};
// contains the first and second points
typedef typename boost::mpl::transform<Seq, apply_arg>::type ready_for_base;
// metafunction class to add the base class (third apply in triple_bind_derived).
struct extend {
template<typename Base, typename Derived>
struct apply {
typedef typename Derived::template apply<Base>::type type;
};
};
// now inherit recursively
typedef typename boost::mpl::accumulate<
ready_for_base,
State,
extend
>::type type;
};
};
// class for wrapping functors.
template<
template<typename, typename> class WrappedFunctor,
typename InPoint,
typename OutPoint,
typename Derived,
typename BaseClass
>
struct functor_wrapper : BaseClass {
virtual WrappedFunctor<InPoint, OutPoint>* makeFunctor(InPoint const&, OutPoint const&) const {
return static_cast<Derived const*>(this)->template makeFunctor<InPoint, OutPoint>();
}
};
template<
typename Derived,
template<typename, typename> class HeldFunctor,
typename first_types,
typename second_types
>
struct make_pymeseries_functor_concrete_base {
typedef typename boost::mpl::transform<first_types, detail::triple_bind_derived<Derived, HeldFunctor, detail::functor_wrapper> >::type first_bounds;
typedef typename boost::mpl::accumulate<second_types, pymeseries_functor_base, detail::second_transform_derived<first_bounds> >::type type;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename Args = boost::fusion::vector<>
>
struct Functor : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, Args>,
HeldFunctor,
first_types,
second_types
>::type {
Functor(void) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>();
}
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1> arg_pack_type;
Functor(
T1 const& t1
) : argPack_(t1) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2
) : argPack_(t1, t2) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3
) : argPack_(t1, t2, t3) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3,
typename T4
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3, T4> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3,
T4 const& t4
) : argPack_(t1, t2, t3, t4) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_),
boost::fusion::at_c<3>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3, T4, T5> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3,
T4 const& t4,
T5 const& t5
) : argPack_(t1, t2, t3, t4, t5) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_),
boost::fusion::at_c<3>(argPack_),
boost::fusion::at_c<4>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3, T4, T5, T6> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3,
T4 const& t4,
T5 const& t5,
T6 const& t6
) : argPack_(t1, t2, t3, t4, t5, t6) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_),
boost::fusion::at_c<3>(argPack_),
boost::fusion::at_c<4>(argPack_),
boost::fusion::at_c<5>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3, T4, T5, T6, T7> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3,
T4 const& t4,
T5 const& t5,
T6 const& t6,
T7 const& t7
) : argPack_(t1, t2, t3, t4, t5, t6, t7) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_),
boost::fusion::at_c<3>(argPack_),
boost::fusion::at_c<4>(argPack_),
boost::fusion::at_c<5>(argPack_),
boost::fusion::at_c<6>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename T8
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7, T8> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7, T8> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3, T4, T5, T6, T7, T8> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3,
T4 const& t4,
T5 const& t5,
T6 const& t6,
T7 const& t7,
T8 const& t8
) : argPack_(t1, t2, t3, t4, t5, t6, t7, t8) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_),
boost::fusion::at_c<3>(argPack_),
boost::fusion::at_c<4>(argPack_),
boost::fusion::at_c<5>(argPack_),
boost::fusion::at_c<6>(argPack_),
boost::fusion::at_c<7>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename T8,
typename T9
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7, T8, T9> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7, T8, T9> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3, T4, T5, T6, T7, T8, T9> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3,
T4 const& t4,
T5 const& t5,
T6 const& t6,
T7 const& t7,
T8 const& t8,
T9 const& t9
) : argPack_(t1, t2, t3, t4, t5, t6, t7, t8, t9) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_),
boost::fusion::at_c<3>(argPack_),
boost::fusion::at_c<4>(argPack_),
boost::fusion::at_c<5>(argPack_),
boost::fusion::at_c<6>(argPack_),
boost::fusion::at_c<7>(argPack_),
boost::fusion::at_c<8>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
template<
typename first_types,
typename second_types,
template<typename, typename> class HeldFunctor,
typename T1,
typename T2,
typename T3,
typename T4,
typename T5,
typename T6,
typename T7,
typename T8,
typename T9,
typename T10
>
struct Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> > : make_pymeseries_functor_concrete_base<
Functor<first_types, second_types, HeldFunctor, args_<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> >,
HeldFunctor,
first_types,
second_types
>::type {
typedef args_<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> arg_pack_type;
Functor(
T1 const& t1,
T2 const& t2,
T3 const& t3,
T4 const& t4,
T5 const& t5,
T6 const& t6,
T7 const& t7,
T8 const& t8,
T9 const& t9,
T10 const& t10
) : argPack_(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) { }
template<typename InPoint, typename OutPoint>
HeldFunctor<InPoint, OutPoint>* makeFunctor(void) const {
return new HeldFunctor<InPoint, OutPoint>(
boost::fusion::at_c<0>(argPack_),
boost::fusion::at_c<1>(argPack_),
boost::fusion::at_c<2>(argPack_),
boost::fusion::at_c<3>(argPack_),
boost::fusion::at_c<4>(argPack_),
boost::fusion::at_c<5>(argPack_),
boost::fusion::at_c<6>(argPack_),
boost::fusion::at_c<7>(argPack_),
boost::fusion::at_c<8>(argPack_),
boost::fusion::at_c<9>(argPack_)
);
}
private:
arg_pack_type
argPack_;
};
} // end namespace detail
// metafunction to wrap up a functor
template<template<typename, typename> class FunctorToWrap, typename ConstructorArgs = boost::mpl::na>
struct make_pymeseries_functor {
typedef typename pymeseries_functor_base::first_types first_types;
typedef typename pymeseries_functor_base::second_types second_types;
typedef detail::Functor<first_types, second_types, FunctorToWrap, ConstructorArgs> type;
};
// A test functor with 0 arg constructor
template<typename InPoint, typename OutPoint>
struct TestFunctor0 : PymeseriesFunctorBase<InPoint, OutPoint> {
double operator()(InPoint const& inPoint, OutPoint const& outPoint) {
printf("%s -> %s\n", typeid(InPoint).name(), typeid(OutPoint).name());
return inPoint + outPoint;
}
};
// wrap the test functor up into a descriptor.
typedef make_pymeseries_functor<TestFunctor0>::type test_functor_descriptor0;
// A test functor with 1 arg constructor
template<typename InPoint, typename OutPoint>
struct TestFunctor1 : PymeseriesFunctorBase<InPoint, OutPoint> {
TestFunctor1(double val) : val_(val) {}
double operator()(InPoint const& inPoint, OutPoint& outPoint, double weight) {
printf("%s -> %s with %f\n", typeid(InPoint).name(), typeid(OutPoint).name(), val_);
return inPoint + outPoint;
}
double val_;
};
// wrap the test functor up into a descriptor.
typedef make_pymeseries_functor<TestFunctor1, args_<double> >::type test_functor_descriptor1;
// function to excercise it
template<typename FirstType, typename SecondType>
int test(pymeseries_functor_base const& functorBase) {
typedef detail::functor_descriptor_base<FirstType, SecondType> FuncDesc;
typedef typename FuncDesc::abstract_functor_type abstract_functor_type;
abstract_functor_type* functor(NULL);
int res(0);
SecondType st(21);
try {
functor = static_cast<FuncDesc const&>(functorBase).makeFunctor(FirstType(), SecondType());
printf("and the answer is... %f\n", (*functor)(21, st, 1.0));
} catch(...) {
printf("whoops\n");
res = 1;
}
if(functor) {
delete functor;
}
return res;
}
int main(int argc, char* argv[]) {
test_functor_descriptor0 bc0;
test<float, long>(bc0);
test_functor_descriptor1 bc1(1.0);
test<double, int>(bc1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment