Commit 7a84d0f3 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Switch to variadic template implementation of mpl_nested_loop() and run_action()

parent c212db96
......@@ -46,7 +46,8 @@ get_vertex_avg_combined_correlation(GraphInterface& gi,
(avg, dev, bins, ret_bins),
scalar_selectors(), scalar_selectors(),
boost::mpl::vector<dummy_weight>())
(degree_selector(deg1), degree_selector(deg2), dummy_weight());
(any(degree_selector(deg1)), any(degree_selector(deg2)),
any(dummy_weight()));
return boost::python::make_tuple(avg, dev, ret_bins);
}
......
......@@ -50,7 +50,7 @@ get_vertex_combined_correlation_histogram(GraphInterface& gi,
ret_bins),
scalar_selectors(), scalar_selectors(),
boost::mpl::vector<dummy_weight>())
(degree_selector(deg1), degree_selector(deg2),
(any(degree_selector(deg1)), any(degree_selector(deg2)),
boost::any(dummy_weight()));
return boost::python::make_tuple(hist, ret_bins);
......
......@@ -48,8 +48,7 @@ namespace detail
{
// Generic graph_action functor. See graph_filtering.hh for details.
template <class Action, class GraphViews, class Wrap = boost::mpl::false_,
class TR1=boost::mpl::vector<>, class TR2=boost::mpl::vector<>,
class TR3=boost::mpl::vector<>, class TR4=boost::mpl::vector<> >
class... TRS>
struct graph_action;
}
......
......@@ -16,7 +16,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "graph_filtering.hh"
#include <boost/python/type_id.hpp>
#include <cxxabi.h>
using namespace graph_tool;
using namespace graph_tool::detail;
......@@ -31,6 +31,15 @@ bool graph_tool::graph_filtering_enabled()
#endif
}
string name_demangle(string name)
{
int status = 0;
char *realname = abi::__cxa_demangle(name.c_str(), 0, 0, &status);
string ret(realname);
free(realname);
return ret;
}
// Whenever no implementation is called, the following exception is thrown
graph_tool::ActionNotFound::ActionNotFound(const boost::any& graph_view,
const type_info& action,
......@@ -48,14 +57,12 @@ const char * graph_tool::ActionNotFound::what () const throw ()
"instructions at " PACKAGE_BUGREPORT ". What follows is debug "
"information.\n\n";
error += "Graph view: " + string(gcc_demangle(_graph_view.type().name()))
+ "\n\n";
error += "Action: " + string(gcc_demangle(_action.name())) + "\n\n";
error += "Graph view: " + name_demangle(_graph_view.type().name()) + "\n\n";
error += "Action: " + name_demangle(_action.name()) + "\n\n";
for (size_t i = 0; i < _args.size(); ++i)
{
error += "Arg " + lexical_cast<string>(i+1) + ": " +
string(gcc_demangle(_args[i]->name())) + "\n\n";
name_demangle(_args[i]->name()) + "\n\n";
}
return error.c_str();
}
......
......@@ -558,23 +558,16 @@ struct action_wrap
Type& uncheck(Type& a, DoWrap) const { return a; }
void operator()() const {};
template <class T1> void operator()(T1* a1) const
{ _a(*a1); }
template <class T1, class T2>
void operator()(T1* a1, T2& a2) const
{ _a(*a1, uncheck(a2, Wrap())); }
template <class T1, class T2, class T3>
void operator()(T1* a1, T2& a2, T3& a3) const
{ _a(*a1, uncheck(a2, Wrap()), uncheck(a3, Wrap())); }
template <class T1, class T2, class T3, class T4>
void operator()(T1* a1, T2& a2, T3& a3, T4& a4)
const
{ _a(*a1, uncheck(a2, Wrap()), uncheck(a3, Wrap()),
uncheck(a4, Wrap())); }
template <class T1, class T2, class T3, class T4, class T5>
void operator()(T1* a1, T2& a2, T3& a3, T4& a4, T5& a5) const
{ _a(*a1, uncheck(a2, Wrap()), uncheck(a3, Wrap()),
uncheck(a4, Wrap()), uncheck(a5, Wrap())); }
template <class T1, class... Ts>
void operator()(T1* a1, Ts&&... as) const
{
_a(*a1, uncheck(std::forward<Ts>(as), Wrap())...);
}
Action _a;
reference_wrapper<GraphInterface> _g;
......@@ -583,8 +576,7 @@ struct action_wrap
// this functor encapsulates another functor Action, which takes a pointer to a
// graph view as first argument
template <class Action, class GraphViews, class Wrap, class TR1, class TR2,
class TR3, class TR4 >
template <class Action, class GraphViews, class Wrap, class... TRS>
struct graph_action
{
struct graph_view_pointers:
......@@ -594,79 +586,17 @@ struct graph_action
: _g(g), _a(a, g, num_vertices(*g._mg),
max(g._mg->get_last_index(), size_t(1))) {}
void operator()() const
{
bool found = false;
boost::any gview = _g.GetGraphView();
boost::mpl::for_each<graph_view_pointers>
(boost::mpl::select_types(_a, found, gview));
if (!found)
{
throw ActionNotFound(gview, typeid(Action),
vector<const std::type_info*>());
}
}
void operator()(boost::any a1) const
template <class... Args>
void operator()(Args&&... args) const
{
bool found = false;
boost::any gview = _g.GetGraphView();
boost::mpl::nested_for_each<graph_view_pointers,TR1>()
(boost::mpl::select_types(_a, found, gview, a1));
boost::mpl::nested_for_each<graph_view_pointers,TRS...>
(boost::mpl::select_types(_a, found, gview, std::forward<Args>(args)...));
if (!found)
{
vector<const std::type_info*> args;
args.push_back(&a1.type());
throw ActionNotFound(gview, typeid(Action), args);
}
}
void operator()(boost::any a1, boost::any a2) const
{
bool found = false;
boost::any gview = _g.GetGraphView();
boost::mpl::nested_for_each<graph_view_pointers,TR1,TR2>()
(boost::mpl::select_types(_a, found, gview, a1, a2));
if (!found)
{
vector<const std::type_info*> args;
args.push_back(&a1.type());
args.push_back(&a2.type());
throw ActionNotFound(gview, typeid(Action), args);
}
}
void operator()(boost::any a1, boost::any a2, boost::any a3) const
{
bool found = false;
boost::any gview = _g.GetGraphView();
boost::mpl::nested_for_each<graph_view_pointers,TR1,TR2,TR3>()
(boost::mpl::select_types(_a, found, gview, a1, a2, a3));
if (!found)
{
vector<const std::type_info*> args;
args.push_back(&a1.type());
args.push_back(&a2.type());
args.push_back(&a3.type());
throw ActionNotFound(gview, typeid(Action), args);
}
}
void operator()(boost::any a1, boost::any a2, boost::any a3,
boost::any a4) const
{
bool found = false;
boost::any gview = _g.GetGraphView();
boost::mpl::nested_for_each<graph_view_pointers,TR1,TR2,TR3,TR4>()
(boost::mpl::select_types(_a, found, gview, a1, a2, a3, a4));
if (!found)
{
vector<const std::type_info*> args;
args.push_back(&a1.type());
args.push_back(&a2.type());
args.push_back(&a3.type());
args.push_back(&a4.type());
throw ActionNotFound(gview, typeid(Action), args);
vector<const std::type_info*> args_t = {(&(args).type())...};
throw ActionNotFound(gview, typeid(Action), args_t);
}
}
......@@ -680,39 +610,11 @@ struct graph_action
template <class GraphViews = detail::all_graph_views, class Wrap = boost::mpl::false_>
struct run_action
{
template <class Action>
detail::graph_action<Action,GraphViews,Wrap>
operator()(GraphInterface &g, Action a)
{
return detail::graph_action<Action,GraphViews,Wrap>(g, a);
}
template <class Action, class TR1>
detail::graph_action<Action,GraphViews,Wrap,TR1>
operator()(GraphInterface &g, Action a, TR1)
{
return detail::graph_action<Action,GraphViews,Wrap,TR1>(g, a);
}
template <class Action, class TR1, class TR2>
detail::graph_action<Action,GraphViews,Wrap,TR1,TR2>
operator()(GraphInterface &g, Action a, TR1, TR2)
{
return detail::graph_action<Action,GraphViews,Wrap,TR1,TR2>(g, a);
}
template <class Action, class TR1, class TR2, class TR3>
detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3>
operator()(GraphInterface &g, Action a, TR1, TR2, TR3)
{
return detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3>(g, a);
}
template <class Action, class TR1, class TR2, class TR3, class TR4>
detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3,TR4>
operator()(GraphInterface &g, Action a, TR1, TR2, TR3, TR4)
template <class Action, class... TRS>
detail::graph_action<Action,GraphViews,Wrap,TRS...>
operator()(GraphInterface &g, Action&& a, TRS...)
{
return detail::graph_action<Action,GraphViews,Wrap,TR1,TR2,TR3,TR4>(g, a);
return detail::graph_action<Action,GraphViews,Wrap,TRS...>(g, std::forward<Action>(a));
}
};
......
......@@ -51,164 +51,68 @@ namespace mpl
// The code above will run foo::operator(T1, T2, T3) for all combinations given
// by r1, r2 and r3. This provides a more general compile-time to run-time
// meta-programming than the more simple mpl::for_each().
//
// Implementation notes: This supports up to 5 nested type ranges. In principle
// this could be generalized, and a lot of the boiler plate code in the
// implementation could be eliminated, by making more thorough use of MPL's
// meta-functions. My attempts to do this, however, tried to make use of
// lambda's bind function, which requires the arity of the function being bound
// to be known in advance. I tried to implement a bind_last() function, which
// always binds the last argument of a given functor, independently of its exact
// arity, but it made use of the typeof operator a lot, and at a given point
// caused GCC (4.2.2) to ICE... Thus, I decided to write the inner loops by
// hand, and wait before GCC implements the auto and typedecl functionality of
// c++0x, making the life of C++ template meta-programmers less horrible.
//
// In any case, "five nested levels should be enough for everybody".
template <class TR1, class TR2, class TR3, class TR4, class TR5>
struct nested_for_each
template <class Action, class... Args>
struct dispatch
{
template <class Action>
void operator()(Action a) const
{
for_each<TR1>(inner_loop1<Action>(a));
}
template <class Action>
struct inner_loop1
{
inner_loop1(Action a): _a(a) {}
template <class T1>
void operator()(T1) const
{
typedef typename mpl::if_<mpl::empty<TR3>,
TR2,
mpl::vector<> >::type eval_range;
if(mpl::empty<TR3>::type::value)
for_each<eval_range>(eval_action2<Action,T1>(_a));
else
for_each<TR2>(inner_loop2<Action,T1>(_a));
}
Action _a;
};
template<class Action, class T1>
struct inner_loop2
{
inner_loop2(Action a): _a(a) {}
template <class T2>
void operator()(T2) const
{
typedef typename mpl::if_<mpl::empty<TR4>,
TR3,
mpl::vector<> >::type eval_range;
if(mpl::empty<TR4>::type::value)
for_each<eval_range>(eval_action3<Action,T1,T2>(_a));
else
for_each<TR3>(inner_loop3<Action, T1, T2>(_a));
}
Action _a;
};
dispatch(Action a): _a(a) {}
template<class Action, class T1, class T2>
struct inner_loop3
template <class T>
dispatch<Action, Args..., T> join() const
{
inner_loop3(Action a): _a(a) {}
template <class T3>
void operator()(T3) const
{
typedef typename mpl::if_<mpl::empty<TR5>,
TR4,
mpl::vector<> >::type eval_range;
if(mpl::empty<TR5>::type::value)
for_each<eval_range>(eval_action4<Action,T1,T2,T3>(_a));
else
for_each<TR4>(inner_loop4<Action, T1, T2, T3>(_a));
}
Action _a;
};
return dispatch<Action, Args..., T>(_a);
}
template<class Action, class T1, class T2, class T3>
struct inner_loop4
template <class T>
void operator()(T) const
{
inner_loop4(Action a): _a(a) {}
template <class T4>
void operator()(T4) const
{
for_each<TR5>(eval_action5<Action, T1, T2, T3, T4>(_a));
}
Action _a;
};
_a(Args()..., T());
}
template<class Action, class T1>
struct eval_action2
void operator()() const
{
eval_action2(Action a): _a(a) {}
template <class T2>
void operator()(T2) const
{
_a(T1(), T2());
}
Action _a;
};
_a(Args()...);
}
template<class Action, class T1, class T2>
struct eval_action3
{
eval_action3(Action a): _a(a) {}
Action _a;
};
template <class T3>
void operator()(T3) const
{
_a(T1(), T2(), T3());
}
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a);
Action _a;
};
template <class Action, class... TRS>
struct inner_loop
{
inner_loop(Action a): _a(a) {}
template<class Action, class T1, class T2, class T3>
struct eval_action4
template <class T>
void operator()(T) const
{
eval_action4(Action a): _a(a) {}
template <class T4>
void operator()(T4) const
{
_a(T1(), T2(), T3(), T4());
}
nested_for_each_imp<TRS...>(_a.join<T>());
}
Action _a;
};
Action _a;
};
template<class Action, class T1, class T2, class T3, class T4>
struct eval_action5
{
eval_action5(Action a): _a(a) {}
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a)
{
for_each<TR1>(inner_loop<Action, TRS...>(a));
}
template <class T5>
void operator()(T5) const
{
_a(T1(), T2(), T3(), T4(), T5());
}
template <class Action>
void nested_for_each_imp(Action a)
{
a();
}
Action _a;
};
};
template <class... TRS, class Action>
void nested_for_each(Action a)
{
auto b = dispatch<Action>(a);
nested_for_each_imp<TRS...>(b);
}
template <class TR1, class TR2, class TR3 = mpl::vector<>,
class TR4 = mpl::vector<>, class TR5 = mpl::vector<> >
struct nested_for_each;
// The functor below wraps another functor Action, but only calls it for the
// correct argument types, determined at runtime. Together with
......@@ -237,93 +141,49 @@ struct nested_for_each;
template <class Action> struct selected_types; // forward decl.
template <class Action>
template <class Action, class... Args>
selected_types<Action>
select_types(Action a, bool& found, any a1 = any(), any a2 = any(),
any a3 = any(), any a4 = any(), any a5 = any())
select_types(Action a, bool& found, Args... args)
{
return selected_types<Action>(a, found, a1, a2, a3, a4, a5);
return selected_types<Action>(a, found, args...);
}
template <class Action>
struct selected_types
{
selected_types(Action a, bool& found, any a1, any a2, any a3, any a4,
any a5)
: _a(a), _found(found), _a1(a1), _a2(a2), _a3(a3), _a4(a4), _a5(a5) {}
template <class T1>
void operator()(T1) const
template <class... Args>
selected_types(Action a, bool& found, Args&&... args)
: _a(a), _found(found)
{
T1* a1 = const_cast<T1*>(any_cast<T1>(&_a1));
if (a1 != 0)
{
_a(*a1);
_found = true;
}
_args = {args...};
}
template <class T1, class T2>
void operator()(T1, T2) const
{
T1* a1 = const_cast<T1*>(any_cast<T1>(&_a1));
T2* a2 = const_cast<T2*>(any_cast<T2>(&_a2));
if (a1 != 0 && a2 != 0)
{
_a(*a1, *a2);
_found = true;
}
}
template <class T1, class T2, class T3>
void operator()(T1, T2, T3) const
template <class... Args, class T, class... Ts>
void dispatch(unsigned int i, std::tuple<T, Ts...>, Args&&... args) const
{
T1* a1 = const_cast<T1*>(any_cast<T1>(&_a1));
T2* a2 = const_cast<T2*>(any_cast<T2>(&_a2));
T3* a3 = const_cast<T3*>(any_cast<T3>(&_a3));
if (a1 != 0 && a2 != 0 && a3 != 0)
{
_a(*a1, *a2, *a3);
_found = true;
}
assert(i < _args.size());
T* a = const_cast<T*>(any_cast<T>(&_args[i]));
if (a != 0)
dispatch(i + 1, std::tuple<Ts...>(), std::forward<Args>(args)..., *a);
}
template <class T1, class T2, class T3, class T4>
void operator()(T1, T2, T3, T4) const
template <class... Args>
void dispatch(unsigned int i, std::tuple<>, Args&&... args) const
{
T1* a1 = const_cast<T1*>(any_cast<T1>(&_a1));
T2* a2 = const_cast<T2*>(any_cast<T2>(&_a2));
T3* a3 = const_cast<T3*>(any_cast<T3>(&_a3));
T4* a4 = const_cast<T4*>(any_cast<T4>(&_a4));
if (a1 != 0 && a2 != 0 && a3 != 0 && a4 != 0)
{
_a(*a1, *a2, *a3, *a4);
_found = true;
}
_a(std::forward<Args>(args)...);
_found = true;
}
template <class T1, class T2, class T3, class T4, class T5>
void operator()(T1, T2, T3, T4, T5) const
template <class... Ts>
void operator()(Ts&&... ts) const
{
T1* a1 = const_cast<T1*>(any_cast<T1>(&_a1));
T2* a2 = const_cast<T2*>(any_cast<T2>(&_a2));
T3* a3 = const_cast<T3*>(any_cast<T3>(&_a3));
T4* a4 = const_cast<T4*>(any_cast<T4>(&_a4));
T5* a5 = const_cast<T5*>(any_cast<T5>(&_a5));
if (a1 != 0 && a2 != 0 && a3 != 0 && a4 != 0 && a5 != 0)
{
_a(*a1, *a2, *a3, *a4, *a5);
_found = true;
}
dispatch(0, std::tuple<Ts...>());
}
Action _a;
bool& _found;
any _a1, _a2, _a3, _a4, _a5;
std::vector<any> _args;
};
} // mpl namespace
......
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