Commit 6b062a27 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Merge branch 'speedup/remove-dispatch-exceptions' into 'master'

Remove exception throwing from hot path in dispatch

See merge request count0/graph-tool!24
parents 77c95cc2 bf16ec13
Pipeline #607 failed with stage
in 547 minutes and 31 seconds
...@@ -59,11 +59,9 @@ namespace mpl ...@@ -59,11 +59,9 @@ namespace mpl
// run-time bridge than the simpler mpl::for_each(). // run-time bridge than the simpler mpl::for_each().
struct stop_iteration: public std::exception {};
// this is a functor wrapper that will perform an any_cast<> in each in an array // this is a functor wrapper that will perform an any_cast<> in each in an array
// of arguments according to the called types. If the cast is successful, the // of arguments according to the called types. If the cast is successful, the
// function will be called with those types, and stop_iteration will be thrown. // function will be called with those types, and true will be returned.
template <class Action, std::size_t N> template <class Action, std::size_t N>
struct all_any_cast struct all_any_cast
{ {
...@@ -72,45 +70,45 @@ struct all_any_cast ...@@ -72,45 +70,45 @@ struct all_any_cast
template <class... Ts> template <class... Ts>
[[gnu::always_inline]] [[gnu::always_inline]]
void operator()(Ts*... vs) const bool operator()(Ts*... vs) const
{ {
dispatch(std::make_index_sequence<sizeof...(Ts)>(), vs...); return dispatch(std::make_index_sequence<sizeof...(Ts)>(), vs...);
} }
struct fail_cast {};
template <class T> template <class T>
T& try_any_cast(boost::any& a) const T* try_any_cast(boost::any& a) const
{ {
try T * t = any_cast<T>(&a);
if (t)
{ {
return any_cast<T&>(a); return t;
} }
catch (bad_any_cast&)
std::reference_wrapper<T> * tr = any_cast<std::reference_wrapper<T>>(&a);
if (tr)
{ {
try return &(tr->get());
{
return any_cast<std::reference_wrapper<T>>(a);
}
catch (bad_any_cast&)
{
throw fail_cast();
}
} }
return nullptr;
} }
template <std::size_t... Idx, class... Ts> template <std::size_t... Idx, class... Ts>
[[gnu::always_inline]] [[gnu::always_inline]]
void dispatch(std::index_sequence<Idx...>, Ts*...) const bool dispatch(std::index_sequence<Idx...>, Ts*...) const
{ {
try 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])) && ...))
{ {
static_assert(sizeof...(Idx) == N, // successful set of casts. Dereference and call action.
"all_any_cast: wrong number of arguments"); std::apply([this](auto*... arg){ _a(*arg...); }, args);
_a(try_any_cast<Ts>(*_args[Idx])...); return true;
throw stop_iteration();
} }
catch (fail_cast) {}
return false;
} }
Action _a; Action _a;
...@@ -124,10 +122,10 @@ struct for_each_variadic; ...@@ -124,10 +122,10 @@ struct for_each_variadic;
template <class F, class... Ts> template <class F, class... Ts>
struct for_each_variadic<F,std::tuple<Ts...>> struct for_each_variadic<F,std::tuple<Ts...>>
{ {
void operator()(F f) bool operator()(F f)
{ {
auto call = [&](auto&& arg){f(std::forward<decltype(arg)>(arg)); return 0;}; auto call = [&](auto&& arg) -> bool {return f(std::forward<decltype(arg)>(arg));};
(void) std::initializer_list<int> {call(typename std::add_pointer<Ts>::type())...}; return (call(typename std::add_pointer<Ts>::type()) || ...);
} }
}; };
...@@ -160,9 +158,9 @@ struct inner_loop<Action, std::tuple<Ts...>> ...@@ -160,9 +158,9 @@ struct inner_loop<Action, std::tuple<Ts...>>
template <class T> template <class T>
[[gnu::always_inline]] [[gnu::always_inline]]
void operator()(T*) const bool operator()(T*) const
{ _a(typename std::add_pointer<Ts>::type()..., { return _a(typename std::add_pointer<Ts>::type()...,
typename std::add_pointer<T>::type()); } // innermost loop typename std::add_pointer<T>::type()); } // innermost loop
Action _a; Action _a;
}; };
...@@ -173,11 +171,11 @@ struct inner_loop<Action, std::tuple<Ts...>, TR1, TRS...> ...@@ -173,11 +171,11 @@ struct inner_loop<Action, std::tuple<Ts...>, TR1, TRS...>
template <class T> template <class T>
[[gnu::always_inline]] [[gnu::always_inline]]
void operator()(T*) const bool operator()(T*) const
{ {
typedef inner_loop<Action, std::tuple<Ts..., T>, TRS...> inner_loop_t; typedef inner_loop<Action, std::tuple<Ts..., T>, TRS...> inner_loop_t;
typedef typename to_tuple<TR1>::type tr_tuple; typedef typename to_tuple<TR1>::type tr_tuple;
for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(_a)); return for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(_a));
} }
Action _a; Action _a;
}; };
...@@ -189,30 +187,22 @@ bool nested_for_each(Action a, Args&&... args) ...@@ -189,30 +187,22 @@ bool nested_for_each(Action a, Args&&... args)
{ {
std::array<any*, sizeof...(args)> as{{&args...}}; std::array<any*, sizeof...(args)> as{{&args...}};
auto b = all_any_cast<Action, sizeof...(args)>(a, as); auto b = all_any_cast<Action, sizeof...(args)>(a, as);
try typedef decltype(b) action_t;
{ typedef typename to_tuple<TR1>::type tr_tuple;
typedef decltype(b) action_t; typedef inner_loop<action_t, std::tuple<>, TRS...> inner_loop_t;
typedef typename to_tuple<TR1>::type tr_tuple; return for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(b));
typedef inner_loop<action_t, std::tuple<>, TRS...> inner_loop_t;
for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(b));
return false;
}
catch (stop_iteration&)
{
return true;
}
} }
template <class TR1, class... TRS, class Action> template <class TR1, class... TRS, class Action>
void nested_for_each(Action a) void nested_for_each(Action a)
{ {
try typedef typename to_tuple<TR1>::type tr_tuple;
{
typedef typename to_tuple<TR1>::type tr_tuple; // wrap action into a bool-returning function
typedef inner_loop<Action, std::tuple<>, TRS...> inner_loop_t; auto ab = [=](auto*... args) -> bool { a(args...); return true; };
for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(a));
} typedef inner_loop<decltype(ab), std::tuple<>, TRS...> inner_loop_t;
catch (stop_iteration&) {} for_each_variadic<inner_loop_t, tr_tuple>()(inner_loop_t(ab));
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment