...
 
......@@ -440,9 +440,82 @@ struct action_wrap
Action _a;
};
// this takes a functor and type ranges and iterates through the type
// combinations when called with boost::any parameters, and calls the correct
// function
//
// action_dispatch machinery
//
// a lightweight class for holding a list of types
template <class... T>
struct typelist {};
template <class... T>
constexpr auto to_typelist(std::tuple<T...>) -> typelist<T...>;
template <class Tuple>
using to_typelist_t = decltype(to_typelist(std::declval<Tuple>()));
// handling one typelist/value
// select a binding from the current list
template<class F, // function to bind
class... Ts, // current typelist
class... TRS, // remaining typelists
class Arg,
class... Args>
bool dispatch_loop(
F f,
typelist<typelist<Ts...>, TRS...>,
Arg&& arg,
Args&&... args) // remaining args
{
using namespace boost::mpl;
// determine which one of the Ts we are looking at
// then recurse with the first argument of F bound accordingly
void *farg; // pointer to extracted value from boost::any
// we always will know what its type is
if constexpr (sizeof...(TRS) == 0)
// just one argument remains to be bound
return (
// iterate over types, trying each
((farg = boost::any_cast<Ts>(&arg))
? (f(*static_cast<Ts*>(farg)), true)
// try reference_wrapper instead
: ((farg = boost::any_cast<std::reference_wrapper<Ts>>(&arg))
? (f(static_cast<std::reference_wrapper<Ts>*>(farg)->get()), true)
: false)) || ...);
else
{
// helper function for setting up recursion
auto dl =
[f = std::move(f)](auto * a, // extracted value from boost::any
auto&&... args) // boost::any's yet to be processed
{
return dispatch_loop(
// create the new F with N-1 arguments
[f = std::move(f), a](auto &&... fargs){
f(*a,
std::forward<decltype(fargs)>(fargs)...);
},
typelist<TRS...>{},
std::forward<decltype(args)>(args)...);
};
return (
((farg = boost::any_cast<Ts>(&arg))
? dl(static_cast<Ts*>(farg),
std::forward<Args>(args)...)
: ((farg = boost::any_cast<std::reference_wrapper<Ts>>(&arg))
? dl(&static_cast<std::reference_wrapper<Ts>*>(farg)->get(),
std::forward<Args>(args)...)
: false))
|| ...); // iterate over Ts...
}
}
// this takes a functor and type ranges, locates the correct combination
// from the boost::any parameters, and calls the correct function
template <class Action, class Wrap, class... TRS>
struct action_dispatch
{
......@@ -451,8 +524,11 @@ struct action_dispatch
template <class... Args>
void operator()(Args&&... args) const
{
bool found =
boost::mpl::nested_for_each<TRS...>(_a, std::forward<Args>(args)...);
using namespace boost::mpl;
bool found = dispatch_loop(_a, typelist<to_typelist_t<to_tuple_t<TRS>>...>{},
std::forward<Args>(args)...);
if (!found)
{
std::vector<const std::type_info*> args_t = {(&(args).type())...};
......
......@@ -63,55 +63,6 @@ namespace mpl
// of arguments according to the called types. If the cast is successful, the
// function will be called with those types, and true will be returned.
template <class Action, std::size_t N>
struct all_any_cast
{
all_any_cast(Action a, std::array<any*, N>& args)
: _a(a), _args(args) {}
template <class... Ts>
[[gnu::always_inline]]
bool operator()(Ts*... vs) const
{
return dispatch(std::make_index_sequence<sizeof...(Ts)>(), vs...);
}
template <class T>
T* try_any_cast(boost::any& a) const
{
T* t = any_cast<T>(&a);
if (t != nullptr)
return t;
std::reference_wrapper<T>* tr = any_cast<std::reference_wrapper<T>>(&a);
if (tr != nullptr)
return &(tr->get());
return nullptr;
}
template <std::size_t... Idx, class... Ts>
[[gnu::always_inline]]
bool dispatch(std::index_sequence<Idx...>, Ts*...) const
{
static_assert(sizeof...(Idx) == N,
"all_any_cast: wrong number of arguments");
std::tuple<std::add_pointer_t<Ts>...> args;
if (((std::get<Idx>(args) = try_any_cast<Ts>(*_args[Idx])) && ...))
{
// successful set of casts. Dereference and call action.
std::apply([this](auto*... arg){ _a(*arg...); }, args);
return true;
}
return false;
}
Action _a;
std::array<any*, N>& _args;
};
// recursion-free variadic version of for_each
template <class...>
struct for_each_variadic;
......@@ -143,6 +94,9 @@ struct to_tuple
to_tuple_imp<mpl::_1, mpl::_2>>::type type;
};
template <class Seq>
using to_tuple_t = typename to_tuple<Seq>::type;
// nested type loops via variadic templates
template <class...>
......@@ -179,17 +133,6 @@ struct inner_loop<Action, std::tuple<Ts...>, TR1, TRS...>
// final function
template <class TR1, class... TRS, class Action, class... Args>
bool nested_for_each(Action a, Args&&... args)
{
std::array<any*, sizeof...(args)> as{{&args...}};
auto b = all_any_cast<Action, sizeof...(args)>(a, as);
typedef decltype(b) action_t;
typedef typename to_tuple<TR1>::type tr_tuple;
typedef inner_loop<action_t, std::tuple<>, TRS...> inner_loop_t;
return for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(b));
}
template <class TR1, class... TRS, class Action>
void nested_for_each(Action a)
{
......