Commit 0841edbb authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Simplify mpl::nested_for_each()

This modification provides a significant compile-time memory reduction.
parent 5b665fcc
......@@ -284,9 +284,9 @@ struct get_all_graph_views
// filtered graphs
struct filtered_graphs:
boost::mpl::if_<NeverFiltered,
boost::mpl::vector<GraphInterface::multigraph_t>,
boost::mpl::vector<GraphInterface::multigraph_t,
typename get_graph_filtered::apply<FiltType>::type>
boost::mpl::vector1<GraphInterface::multigraph_t>,
boost::mpl::vector2<GraphInterface::multigraph_t,
typename get_graph_filtered::apply<FiltType>::type>
>::type {};
// filtered + reversed graphs
......@@ -324,39 +324,6 @@ struct get_all_graph_views
};
};
// useful metafunction to split sequences in half
struct split
{
template <class Sequence>
struct get_element
{
template <class Index>
struct apply
{
typedef typename boost::mpl::at<Sequence,Index>::type type;
};
};
template <class Sequence>
struct apply
{
typedef typename boost::mpl::size<Sequence>::type size;
typedef typename boost::mpl::divides<size, boost::mpl::int_<2> >::type half_size;
typedef typename boost::mpl::transform<boost::mpl::range_c<int, 0, half_size::value>,
get_element<Sequence>,
boost::mpl::back_inserter<boost::mpl::vector<> > >
::type first_part;
typedef typename boost::mpl::transform<boost::mpl::range_c<int, half_size::value,
size::value>,
get_element<Sequence>,
boost::mpl::back_inserter<boost::mpl::vector<> > >
::type second_part;
typedef typename boost::mpl::pair<first_part,second_part> type;
};
};
typedef uint8_t filt_scalar_type;
// finally, this type should hold all the possible graph views
......@@ -485,10 +452,9 @@ struct graph_action
template <class... Args>
void operator()(Args&&... args) const
{
bool found = false;
boost::any gview = _g.get_graph_view();
boost::mpl::nested_for_each<graph_view_pointers,TRS...>
(boost::mpl::select_types(_a, found, gview, std::forward<Args>(args)...));
bool found = boost::mpl::nested_for_each<graph_view_pointers,TRS...>
(_a, gview, std::forward<Args>(args)...);
if (!found)
{
vector<const std::type_info*> args_t = {(&(args).type())...};
......
......@@ -64,24 +64,24 @@ using namespace std;
// broken, and use a vector<uint8_t> instead!
// see: http://www.gotw.ca/publications/N1211.pdf
typedef boost::mpl::vector<uint8_t, int16_t, int32_t, int64_t, double, long double, string,
vector<uint8_t>, vector<int16_t>, vector<int32_t>, vector<int64_t>,
vector<double>, vector<long double>, vector<string>,
boost::python::object>
typedef boost::mpl::vector15<uint8_t, int16_t, int32_t, int64_t, double, long double, string,
vector<uint8_t>, vector<int16_t>, vector<int32_t>, vector<int64_t>,
vector<double>, vector<long double>, vector<string>,
boost::python::object>
value_types;
extern const char* type_names[]; // respective type names (defined in
// graph_properties.cc)
// scalar types: types contained in value_types which are scalar
typedef boost::mpl::vector<uint8_t, int16_t, int32_t, int64_t, double, long double>
typedef boost::mpl::vector6<uint8_t, int16_t, int32_t, int64_t, double, long double>
scalar_types;
// integer_types: scalar types which are integer
typedef boost::mpl::vector<uint8_t, int16_t, int32_t, int64_t> integer_types;
typedef boost::mpl::vector4<uint8_t, int16_t, int32_t, int64_t> integer_types;
// floating_types: scalar types which are floating point
typedef boost::mpl::vector<double, long double> floating_types;
typedef boost::mpl::vector2<double, long double> floating_types;
struct make_vector
{
......
......@@ -532,103 +532,105 @@ in_or_out_edges_range(typename in_or_out_edge_iteratorS<Graph>::vertex_descripto
// useful type lists
typedef boost::mpl::vector<in_degreeS, out_degreeS, total_degreeS>
degree_selectors;
struct degree_selectors:
boost::mpl::vector<in_degreeS, out_degreeS, total_degreeS> {};
typedef property_map_types::apply<value_types,
GraphInterface::vertex_index_map_t>::type
vertex_properties;
typedef property_map_types::apply<value_types,
struct vertex_properties:
property_map_types::apply<value_types,
GraphInterface::vertex_index_map_t>::type {};
struct writable_vertex_properties:
property_map_types::apply<value_types,
GraphInterface::vertex_index_map_t,
boost::mpl::bool_<false> >::type
writable_vertex_properties;
boost::mpl::bool_<false> >::type {};
struct edge_properties:
property_map_types::apply<value_types,
GraphInterface::edge_index_map_t>::type {};
typedef property_map_types::apply<value_types,
GraphInterface::edge_index_map_t>::type
edge_properties;
typedef property_map_types::apply<value_types,
struct writable_edge_properties:
property_map_types::apply<value_types,
GraphInterface::edge_index_map_t,
boost::mpl::bool_<false> >::type
writable_edge_properties;
boost::mpl::bool_<false> >::type {};
struct vertex_scalar_properties:
property_map_types::apply<scalar_types,
GraphInterface::vertex_index_map_t>::type {};
typedef property_map_types::apply<scalar_types,
GraphInterface::vertex_index_map_t>::type
vertex_scalar_properties;
typedef property_map_types::apply<scalar_types,
struct writable_vertex_scalar_properties:
property_map_types::apply<scalar_types,
GraphInterface::vertex_index_map_t,
boost::mpl::bool_<false> >::type
writable_vertex_scalar_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<integer_types,
GraphInterface::vertex_index_map_t>::type
vertex_integer_properties;
struct vertex_integer_properties:
property_map_types::apply<integer_types,
GraphInterface::vertex_index_map_t>::type {};
typedef property_map_types::apply<floating_types,
struct vertex_floating_properties:
property_map_types::apply<floating_types,
GraphInterface::vertex_index_map_t,
boost::mpl::bool_<false> >::type
vertex_floating_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<scalar_vector_types,
struct vertex_scalar_vector_properties:
property_map_types::apply<scalar_vector_types,
GraphInterface::vertex_index_map_t,
boost::mpl::bool_<false> >::type
vertex_scalar_vector_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<integer_vector_types,
struct vertex_integer_vector_properties:
property_map_types::apply<integer_vector_types,
GraphInterface::vertex_index_map_t,
boost::mpl::bool_<false> >::type
vertex_integer_vector_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<floating_vector_types,
struct vertex_floating_vector_properties:
property_map_types::apply<floating_vector_types,
GraphInterface::vertex_index_map_t,
boost::mpl::bool_<false> >::type
vertex_floating_vector_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<scalar_types,
GraphInterface::edge_index_map_t>::type
edge_scalar_properties;
struct edge_scalar_properties:
property_map_types::apply<scalar_types,
GraphInterface::edge_index_map_t>::type {};
typedef property_map_types::apply<scalar_types,
struct writable_edge_scalar_properties:
property_map_types::apply<scalar_types,
GraphInterface::edge_index_map_t,
boost::mpl::bool_<false> >::type
writable_edge_scalar_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<integer_types,
GraphInterface::edge_index_map_t>::type
edge_integer_properties;
struct edge_integer_properties:
property_map_types::apply<integer_types,
GraphInterface::edge_index_map_t>::type {};
typedef property_map_types::apply<floating_types,
struct edge_floating_properties:
property_map_types::apply<floating_types,
GraphInterface::edge_index_map_t,
boost::mpl::bool_<false> >::type
edge_floating_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<scalar_vector_types,
struct edge_scalar_vector_properties:
property_map_types::apply<scalar_vector_types,
GraphInterface::edge_index_map_t,
boost::mpl::bool_<false> >::type
edge_scalar_vector_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<integer_vector_types,
struct edge_integer_vector_properties:
property_map_types::apply<integer_vector_types,
GraphInterface::edge_index_map_t,
boost::mpl::bool_<false> >::type
edge_integer_vector_properties;
boost::mpl::bool_<false> >::type {};
typedef property_map_types::apply<floating_vector_types,
struct edge_floating_vector_properties:
property_map_types::apply<floating_vector_types,
GraphInterface::edge_index_map_t,
boost::mpl::bool_<false> >::type
edge_floating_vector_properties;
boost::mpl::bool_<false> >::type {};
struct vertex_scalar_selectors:
boost::mpl::transform<vertex_scalar_properties,
scalar_selector_type>::type {};
boost::mpl::transform<vertex_scalar_properties,
scalar_selector_type>::type {};
struct all_selectors:
boost::mpl::transform<vertex_properties,
scalar_selector_type,
boost::mpl::back_inserter<degree_selectors> >::type {};
boost::mpl::transform<vertex_properties,
scalar_selector_type,
boost::mpl::back_inserter<degree_selectors> >::type {};
struct scalar_selectors:
boost::mpl::transform<vertex_scalar_properties,
scalar_selector_type,
boost::mpl::back_inserter<degree_selectors> >::type {};
boost::mpl::transform<vertex_scalar_properties,
scalar_selector_type,
boost::mpl::back_inserter<degree_selectors> >::type {};
} //namespace graph_tool
......
......@@ -46,37 +46,108 @@ namespace mpl
// typedef mpl::vector<string,double> r2;
// typedef mpl::vector<size_t,char> r3;
//
// nested_for_each<r1,r2,r3>(foo());
// any x = float(2);
// any y = string("foo");
// any z = size_t(42);
//
// 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().
// bool found = nested_for_each<r1,r2,r3>(foo(), x, y, z);
//
// The code above will run iterate through all combinations of foo::operator(T1,
// T2, T3) and call the one that corresponds to the actual types stored in x, y,
// and z. If the types are not found during iteration, we have found = true,
// otherwise found = false. This provides a more general compile-time to
// run-time bridge than the simpler mpl::for_each().
template <class Action, class T>
struct bind_arg
{
bind_arg(Action a, any& arg, bool& found)
: _a(a), _arg(arg), _found(found) {}
template <class... Ts>
__attribute__((always_inline))
void operator()(Ts&&... args) const
{
T* v = const_cast<T*>(any_cast<T>(&_arg));
if (v != 0)
_a(*v, args...);
}
__attribute__((always_inline))
void operator()() const
{
T* v = const_cast<T*>(any_cast<T>(&_arg));
if (v != 0)
{
_a(*v);
_found = true;
}
}
Action _a;
any& _arg;
bool& _found;
};
template <class Action, class... Args>
template <class Action>
struct dispatch
{
dispatch(Action a): _a(a) {}
dispatch(Action a, any* args, bool& found)
: _a(a), _args(args), _found(found) {}
template <class T>
dispatch<Action, Args..., T> join() const
__attribute__((always_inline))
auto get_next() const
{
return dispatch<Action, Args..., T>(_a);
bind_arg<Action, T> a(_a, *_args, _found);
return dispatch<bind_arg<Action, T>>(a, _args + 1, _found);
}
template <class T>
__attribute__((always_inline))
void operator()(T) const
{
_a(Args()..., T());
bind_arg<Action, T> a(_a, *_args, _found);
a();
}
__attribute__((always_inline))
void operator()() const
{
_a(Args()...);
_a();
}
Action _a;
any* _args;
bool& _found;
};
template <class F>
inline void for_each_pack(F)
{};
template <class F, class T, class... Ts>
inline void for_each_pack(F f)
{
f(T());
for_each_pack<F, Ts...>(f);
};
template <class F, class Seq, class Iter, class... Ts>
inline void for_each_alt(F f, Iter)
{
for_each_alt<F, Seq, typename next<Iter>::type, Ts...,
typename deref<Iter>::type>
(f, typename next<Iter>::type());
}
template <class F, class Seq, class Iter, class... Ts>
inline void for_each_alt(F f, typename end<Seq>::type)
{
for_each_pack<F, Ts...>(f);
}
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a);
......@@ -86,18 +157,20 @@ struct inner_loop
inner_loop(Action a): _a(a) {}
template <class T>
__attribute__((always_inline))
void operator()(T) const
{
nested_for_each_imp<TRS...>(_a.template join<T>());
nested_for_each_imp<TRS...>(_a.template get_next<T>());
}
Action _a;
};
template <class TR1, class... TRS, class Action>
void nested_for_each_imp(Action a)
{
for_each<TR1>(inner_loop<Action, TRS...>(a));
for_each_alt<inner_loop<Action, TRS...>,
TR1, typename begin<TR1>::type>
(inner_loop<Action, TRS...>(a), typename begin<TR1>::type());
}
template <class Action>
......@@ -106,86 +179,16 @@ void nested_for_each_imp(Action a)
a();
}
template <class... TRS, class Action>
void nested_for_each(Action a)
template <class... TRS, class Action, class... Args>
bool nested_for_each(Action a, Args... args)
{
auto b = dispatch<Action>(a);
bool found = false;
std::array<any, sizeof...(args)> as{args...};
auto b = dispatch<Action>(a, &as[0], found);
nested_for_each_imp<TRS...>(b);
return found;
}
// The functor below wraps another functor Action, but only calls it for the
// correct argument types, determined at runtime. Together with
// nested_for_each() above, it provides general means of selecting static
// polymorphic implementation of algorithms at run-time, as such:
//
// struct foo
// {
// template <class T1, class T2>
// void operator()(T1 x, T2 y) const
// {
// ... do something with x and y ...
// }x
// };
//
// typedef mpl::vector<double,std::string,int> types;
//
// any x = double(1.0) // determined at run-time
// any y = std::string("user input") // determined at run-time
//
// bool found;
// mpl::nested_for_each<types,types>(mpl::select_types(foo, x, y));
//
// The last line will call foo::operator()(double, std::string) passing the
// values of x and y, and the found variable will contain the value 'true'.
template <class Action> struct selected_types; // forward decl.
template <class Action, class... Args>
selected_types<Action>
select_types(Action a, bool& found, Args... args)
{
return selected_types<Action>(a, found, args...);
}
template <class Action>
struct selected_types
{
template <class... Args>
selected_types(Action a, bool& found, Args&&... args)
: _a(a), _found(found)
{
_args = {args...};
}
template <class... Args, class T, class... Ts>
void dispatch(unsigned int i, std::tuple<T, Ts...>, Args&&... args) const
{
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... Args>
void dispatch(unsigned int, std::tuple<>, Args&&... args) const
{
_a(std::forward<Args>(args)...);
_found = true;
}
template <class... Ts>
void operator()(Ts&&...) const
{
dispatch(0, std::tuple<Ts...>());
}
Action _a;
bool& _found;
std::vector<any> _args;
};
} // mpl namespace
} // boost 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