Commit 936e7260 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Improve iteration over out-/in-neighbours

parent 9e41e054
......@@ -182,11 +182,15 @@ namespace boost {
typedef typename adjacency_iterator_generator<self,
vertex_descriptor, out_edge_iterator>::type adjacency_iterator;
// BidirectionalGraph requirements
typedef filter_iterator<
InEdgePred, typename Traits::in_edge_iterator
> in_edge_iterator;
typedef typename adjacency_iterator_generator<self,
vertex_descriptor, in_edge_iterator>::type in_adjacency_iterator;
// VertexListGraph requirements
typedef filter_iterator<
VertexPredicate, typename Traits::vertex_iterator
......@@ -390,8 +394,8 @@ namespace boost {
inline __attribute__((always_inline))
std::pair<typename filtered_graph<G, EP, VP>::adjacency_iterator,
typename filtered_graph<G, EP, VP>::adjacency_iterator>
adjacent_vertices(typename filtered_graph<G, EP, VP>::vertex_descriptor u,
const filtered_graph<G, EP, VP>& g)
out_neighbours(typename filtered_graph<G, EP, VP>::vertex_descriptor u,
const filtered_graph<G, EP, VP>& g)
{
typedef filtered_graph<G, EP, VP> Graph;
typedef typename Graph::adjacency_iterator adjacency_iterator;
......@@ -400,6 +404,31 @@ namespace boost {
adjacency_iterator(range.second, const_cast<Graph*>(&g)));
}
template <typename G, typename EP, typename VP>
inline __attribute__((always_inline))
std::pair<typename filtered_graph<G, EP, VP>::in_adjacency_iterator,
typename filtered_graph<G, EP, VP>::in_adjacency_iterator>
in_neighbours(typename filtered_graph<G, EP, VP>::vertex_descriptor u,
const filtered_graph<G, EP, VP>& g)
{
typedef filtered_graph<G, EP, VP> Graph;
typedef typename Graph::in_adjacency_iterator adjacency_iterator;
auto range = in_edges(u, g);
return std::make_pair(adjacency_iterator(range.first, const_cast<Graph*>(&g)),
adjacency_iterator(range.second, const_cast<Graph*>(&g)));
}
template <typename G, typename EP, typename VP>
inline __attribute__((always_inline))
std::pair<typename filtered_graph<G, EP, VP>::adjacency_iterator,
typename filtered_graph<G, EP, VP>::adjacency_iterator>
adjacent_vertices(typename filtered_graph<G, EP, VP>::vertex_descriptor u,
const filtered_graph<G, EP, VP>& g)
{
return out_neighbours(u, g);
}
template <typename G, typename EP, typename VP>
inline __attribute__((always_inline))
std::pair<typename filtered_graph<G, EP, VP>::in_edge_iterator,
......
......@@ -89,8 +89,8 @@ class reverse_graph {
typedef transform_iterator<detail::reverse_graph_edge_descriptor_maker<typename Traits::edge_descriptor>, typename Traits::out_edge_iterator> in_edge_iterator;
// AdjacencyGraph requirements
typedef typename adjacency_iterator_generator<Self,
vertex_descriptor, out_edge_iterator>::type adjacency_iterator;
typedef typename BidirectionalGraph::in_adjacency_iterator adjacency_iterator;
typedef typename graph_traits<BidirectionalGraph>::adjacency_iterator in_adjacency_iterator;
// VertexListGraph requirements
typedef typename Traits::vertex_iterator vertex_iterator;
......@@ -250,18 +250,32 @@ in_edges(const typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
template <class BidirectionalGraph, class GRef>
inline std::pair<typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator,
typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator>
typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator>
out_neighbours(typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
const reverse_graph<BidirectionalGraph,GRef>& g)
{
return in_neighbours(u, g.m_g);
}
template <class BidirectionalGraph, class GRef>
inline std::pair<typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator,
typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator>
in_neighbours(typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
const reverse_graph<BidirectionalGraph,GRef>& g)
{
return out_neighbours(u, g.m_g);
}
template <class BidirectionalGraph, class GRef>
inline std::pair<typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator,
typename reverse_graph<BidirectionalGraph,GRef>::adjacency_iterator>
adjacent_vertices(typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
const reverse_graph<BidirectionalGraph,GRef>& g)
{
typedef reverse_graph<BidirectionalGraph,GRef> Graph;
typename graph_traits<Graph>::out_edge_iterator first, last;
boost::tie(first, last) = out_edges(u, g);
typedef typename graph_traits<Graph>::adjacency_iterator adjacency_iterator;
return std::make_pair(adjacency_iterator(first, const_cast<Graph*>(&g)),
adjacency_iterator(last, const_cast<Graph*>(&g)));
return out_neighbours(u, g);
}
template <class BidirectionalGraph, class GRef>
inline typename graph_traits<BidirectionalGraph>::degree_size_type
in_degree(const typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
......@@ -281,14 +295,16 @@ degree(const typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
template <class Edge, class BidirectionalGraph, class GRef>
inline typename graph_traits<BidirectionalGraph>::vertex_descriptor
source(const detail::reverse_graph_edge_descriptor<Edge>& e, const reverse_graph<BidirectionalGraph,GRef>& g)
source(const detail::reverse_graph_edge_descriptor<Edge>& e,
const reverse_graph<BidirectionalGraph,GRef>& g)
{
return target(Edge(e), g.m_g);
}
template <class Edge, class BidirectionalGraph, class GRef>
inline typename graph_traits<BidirectionalGraph>::vertex_descriptor
target(const detail::reverse_graph_edge_descriptor<Edge>& e, const reverse_graph<BidirectionalGraph,GRef>& g)
target(const detail::reverse_graph_edge_descriptor<Edge>& e,
const reverse_graph<BidirectionalGraph,GRef>& g)
{
return source(Edge(e), g.m_g);
}
......
......@@ -99,9 +99,9 @@ struct get_iterator_category
};
template <class Graph, class Inverted = mpl::false_>
template <class Graph>
class joined_edge_iterator
: public boost::iterator_facade<joined_edge_iterator<Graph, Inverted>,
: public boost::iterator_facade<joined_edge_iterator<Graph>,
typename graph_traits<Graph>::edge_descriptor,
typename get_iterator_category<Graph>::type,
typename graph_traits<Graph>::edge_descriptor>
......@@ -110,15 +110,13 @@ class joined_edge_iterator
typedef typename graph_traits<Graph>::in_edge_iterator in_iter_t;
typedef typename graph_traits<Graph>::out_edge_iterator out_iter_t;
typedef typename mpl::if_<Inverted, out_iter_t, in_iter_t>::type iter1_t;
typedef typename mpl::if_<Inverted, in_iter_t, out_iter_t>::type iter2_t;
joined_edge_iterator() {}
explicit joined_edge_iterator(std::pair<iter1_t, iter1_t>&& range1,
std::pair<iter2_t, iter2_t>&& range2,
template <class InRange, class OutRange>
__attribute__((always_inline))
explicit joined_edge_iterator(InRange&& range1, OutRange&& range2,
bool begin)
: _range1(std::forward<std::pair<iter1_t, iter1_t>>(range1)),
_range2(std::forward<std::pair<iter2_t, iter2_t>>(range2))
: _range1(std::forward<InRange>(range1)),
_range2(std::forward<OutRange>(range2))
{
if (!begin)
{
......@@ -129,6 +127,7 @@ class joined_edge_iterator
private:
friend class boost::iterator_core_access;
__attribute__((always_inline))
void increment()
{
if (_range1.first == _range1.second)
......@@ -137,7 +136,8 @@ class joined_edge_iterator
++_range1.first;
}
typedef typename std::iterator_traits<iter1_t>::difference_type diff_t;
typedef typename std::iterator_traits<in_iter_t>::difference_type diff_t;
__attribute__((always_inline))
void advance(diff_t n)
{
diff_t d1 = _range1.second - _range1.first;
......@@ -152,12 +152,14 @@ class joined_edge_iterator
}
}
diff_t distance_to(joined_edge_iterator const& other)
__attribute__((always_inline))
diff_t distance_to(joined_edge_iterator const& other) const
{
return (other._range1.first - _range1.first) +
(other._range2.first - _range2.first);
}
__attribute__((always_inline))
bool equal(joined_edge_iterator const& other) const
{
return (_range2.first == other._range2.first &&
......@@ -165,12 +167,14 @@ class joined_edge_iterator
}
template <class Edge>
Edge inv(Edge&& e) const
__attribute__((always_inline))
Edge inv(Edge e) const
{
e.inv = true;
e.inv ^= true;
return e;
}
__attribute__((always_inline))
typename graph_traits<Graph>::edge_descriptor dereference() const
{
if (_range1.first == _range1.second)
......@@ -179,27 +183,89 @@ class joined_edge_iterator
return inv(*_range1.first);
}
std::pair<iter1_t, iter1_t> _range1;
std::pair<iter2_t, iter2_t> _range2;
std::pair<in_iter_t, in_iter_t> _range1;
std::pair<out_iter_t, out_iter_t> _range2;
};
template <class Graph>
class joined_neighbour_iterator
: public boost::iterator_facade<joined_neighbour_iterator<Graph>,
typename graph_traits<Graph>::vertex_descriptor,
typename get_iterator_category<Graph>::type,
typename graph_traits<Graph>::vertex_descriptor>
{
public:
typedef typename Graph::in_adjacency_iterator in_iter_t;
typedef typename graph_traits<Graph>::adjacency_iterator out_iter_t;
joined_neighbour_iterator() {}
template <class InRange, class OutRange>
explicit joined_neighbour_iterator(InRange&& range1, OutRange&& range2,
bool begin)
: _range1(std::forward<InRange>(range1)),
_range2(std::forward<OutRange>(range2))
{
if (!begin)
{
_range1.first = _range1.second;
_range2.first = _range2.second;
}
}
private:
friend class boost::iterator_core_access;
//==============================================================================
// UndirectedAdaptorAdjacencyIterator
// just keeps an internal reference to out_edge_iterator and calls target() when
// referenced
//==============================================================================
__attribute__((always_inline))
void increment()
{
if (_range1.first == _range1.second)
++_range2.first;
else
++_range1.first;
}
template <class Graph>
struct get_undirected_adjacency_iterator
{
typedef joined_edge_iterator<Graph> out_edge_iter_t;
typedef typename boost::adjacency_iterator_generator<UndirectedAdaptor<Graph>,
typename graph_traits<Graph>::vertex_descriptor,
out_edge_iter_t>::type type;
};
typedef typename std::iterator_traits<in_iter_t>::difference_type diff_t;
__attribute__((always_inline))
void advance(diff_t n)
{
diff_t d1 = _range1.second - _range1.first;
if (n < d1)
{
_range1.first += n;
}
else
{
_range1.first = _range1.second;
_range2.first += n - d1;
}
}
__attribute__((always_inline))
diff_t distance_to(joined_neighbour_iterator const& other) const
{
return (other._range1.first - _range1.first) +
(other._range2.first - _range2.first);
}
__attribute__((always_inline))
bool equal(joined_neighbour_iterator const& other) const
{
return (_range2.first == other._range2.first &&
_range1.first == other._range1.first);
}
__attribute__((always_inline))
typename graph_traits<Graph>::vertex_descriptor dereference() const
{
if (_range1.first == _range1.second)
return *_range2.first;
else
return *_range1.first;
}
std::pair<in_iter_t, in_iter_t> _range1;
std::pair<out_iter_t, out_iter_t> _range2;
};
//==============================================================================
// graph_traits<UndirectedAdaptor>
......@@ -210,9 +276,9 @@ struct graph_traits<UndirectedAdaptor<Graph> > {
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename get_undirected_adjacency_iterator<Graph>::type adjacency_iterator;
typedef joined_edge_iterator<Graph, mpl::false_> out_edge_iterator;
typedef joined_edge_iterator<Graph, mpl::true_> in_edge_iterator;
typedef joined_neighbour_iterator<Graph> adjacency_iterator;
typedef joined_edge_iterator<Graph> out_edge_iterator;
typedef joined_edge_iterator<Graph> in_edge_iterator;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
......@@ -338,15 +404,15 @@ edge(typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor u,
template <class Graph>
inline __attribute__((always_inline))
std::pair<typename graph_traits<UndirectedAdaptor<Graph>>::out_edge_iterator,
typename graph_traits<UndirectedAdaptor<Graph>>::out_edge_iterator >
typename graph_traits<UndirectedAdaptor<Graph>>::out_edge_iterator>
out_edges(typename graph_traits<UndirectedAdaptor<Graph>>::vertex_descriptor u,
const UndirectedAdaptor<Graph>& g)
{
typedef joined_edge_iterator<Graph> iter_t;
return std::make_pair(iter_t(in_edges(u, g.original_graph()),
out_edges(u, g.original_graph()), true),
iter_t(in_edges(u, g.original_graph()),
out_edges(u, g.original_graph()), false));
auto ies = in_edges(u, g.original_graph());
auto oes = out_edges(u, g.original_graph());
return std::make_pair(iter_t(ies, oes, true),
iter_t(ies, oes, false));
}
//==============================================================================
......@@ -359,11 +425,37 @@ std::pair<typename graph_traits<UndirectedAdaptor<Graph>>::in_edge_iterator,
in_edges(typename graph_traits<UndirectedAdaptor<Graph>>::vertex_descriptor u,
const UndirectedAdaptor<Graph>& g)
{
typedef joined_edge_iterator<Graph, mpl::true_> iter_t;
return std::make_pair(iter_t(out_edges(u, g.original_graph()),
in_edges(u, g.original_graph()), true),
iter_t(out_edges(u, g.original_graph()),
in_edges(u, g.original_graph()), false));
return out_edges(u, g);
}
//==============================================================================
// out_neighbours(u, g)
//==============================================================================
template <class Graph>
inline __attribute__((always_inline))
std::pair<typename graph_traits<UndirectedAdaptor<Graph> >::adjacency_iterator,
typename graph_traits<UndirectedAdaptor<Graph> >::adjacency_iterator>
out_neighbours(typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor u,
const UndirectedAdaptor<Graph>& g)
{
typedef joined_neighbour_iterator<Graph> iter_t;
auto ins = in_neighbours(u, g.original_graph());
auto ons = out_neighbours(u, g.original_graph());
return std::make_pair(iter_t(ins, ons, true),
iter_t(ins, ons, false));
}
//==============================================================================
// in_neighbours(u, g)
//==============================================================================
template <class Graph>
inline __attribute__((always_inline))
std::pair<typename graph_traits<UndirectedAdaptor<Graph> >::adjacency_iterator,
typename graph_traits<UndirectedAdaptor<Graph> >::adjacency_iterator>
in_neighbours(typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor u,
const UndirectedAdaptor<Graph>& g)
{
return out_neighbours(u, g);
}
//==============================================================================
......@@ -377,11 +469,7 @@ adjacent_vertices
(typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor u,
const UndirectedAdaptor<Graph>& g)
{
typedef typename graph_traits<UndirectedAdaptor<Graph> >::adjacency_iterator
adjacency_iterator;
auto e_range = out_edges(u, g);
return std::make_pair(adjacency_iterator(e_range.first, &g),
adjacency_iterator(e_range.second, &g));
return out_neighbours(u, g);
}
//==============================================================================
......
......@@ -81,6 +81,16 @@ std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
adjacent_vertices(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
out_neighbours(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
in_neighbours(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
size_t num_vertices(const adj_list<Vertex>& g);
......@@ -178,13 +188,16 @@ public:
{
get_vertex() {}
typedef Vertex result_type;
__attribute__((always_inline))
Vertex operator()(const std::pair<vertex_t, vertex_t>& v) const
{ return v.first; }
};
typedef transform_random_access_iterator<get_vertex, typename edge_list_t::const_iterator>
typedef transform_random_access_iterator<get_vertex,
typename edge_list_t::const_iterator>
adjacency_iterator;
typedef adjacency_iterator in_adjacency_iterator;
template <class Deference>
struct base_edge_iterator:
......@@ -426,6 +439,12 @@ private:
friend std::pair<adjacency_iterator, adjacency_iterator>
adjacent_vertices<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<adjacency_iterator, adjacency_iterator>
out_neighbours<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<adjacency_iterator, adjacency_iterator>
in_neighbours<>(Vertex v, const adj_list<Vertex>& g);
friend size_t num_vertices<>(const adj_list<Vertex>& g);
friend size_t num_edges<>(const adj_list<Vertex>& g);
......@@ -479,6 +498,7 @@ struct graph_traits<adj_list<Vertex> >
typedef size_t degree_size_type;
static Vertex null_vertex() { return adj_list<Vertex>::null_vertex(); }
private:
BOOST_STATIC_ASSERT((is_convertible<typename std::iterator_traits<out_edge_iterator>::iterator_category,
std::random_access_iterator_tag>::value));
......@@ -631,7 +651,7 @@ template <class Vertex>
inline __attribute__((always_inline))
std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
adjacent_vertices(Vertex v, const adj_list<Vertex>& g)
out_neighbours(Vertex v, const adj_list<Vertex>& g)
{
typedef typename adj_list<Vertex>::adjacency_iterator ai_t;
auto& edges = g._out_edges[v];
......@@ -639,6 +659,28 @@ adjacent_vertices(Vertex v, const adj_list<Vertex>& g)
ai_t(edges.end()));
}
template <class Vertex>
inline __attribute__((always_inline))
std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
in_neighbours(Vertex v, const adj_list<Vertex>& g)
{
typedef typename adj_list<Vertex>::adjacency_iterator ai_t;
auto& edges = g._in_edges[v];
return std::make_pair(ai_t(edges.begin()),
ai_t(edges.end()));
}
template <class Vertex>
inline __attribute__((always_inline))
std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
adjacent_vertices(Vertex v, const adj_list<Vertex>& g)
{
return out_neighbours(v, g);
}
template <class Vertex>
inline __attribute__((always_inline))
size_t num_vertices(const adj_list<Vertex>& g)
......
......@@ -404,6 +404,7 @@ struct get_all_edges<Graph,std::false_type>
typedef typename boost::graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef typename boost::graph_traits<Graph>::out_edge_iterator type;
inline __attribute__((always_inline))
static std::pair<type,type> get_edges(vertex_descriptor v,
const Graph& g)
{
......@@ -467,6 +468,179 @@ struct in_or_out_edge_iteratorS
}
};
// helper types for in_neighbour_iteratorS
template <class Graph, class IsDirected>
struct get_in_neighbours
{
BOOST_MPL_ASSERT((is_same<IsDirected,std::true_type>));
BOOST_MPL_ASSERT((is_convertible
<typename boost::graph_traits<Graph>::directed_category,
boost::directed_tag>));
typedef typename boost::graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef typename boost::graph_traits<Graph>::in_neighbour_iterator type;
inline __attribute__((always_inline))
static std::pair<type,type> get_edges(vertex_descriptor v,
const Graph& g)
{
using namespace boost;
return in_neighbours(v, g);
}
};
template <class Graph>
struct get_in_neighbours<Graph,std::false_type>
{
BOOST_MPL_ASSERT((is_convertible
<typename boost::graph_traits<Graph>::directed_category,
boost::undirected_tag>));
typedef typename boost::graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef typename boost::graph_traits<Graph>::out_neighbours_iterator type;
inline __attribute__((always_inline))
static std::pair<type,type> get_neighbours(vertex_descriptor,
const Graph&)
{
return make_pair(type(), type());
}
};
// this in-neighbour iterator selector returns the in-neighbour range for
// directed graphs and an empty out-neighbour range for undirected graphs. The
// iterator type is given by in_neighbour_iteratorS<Graph>::type.
template <class Graph>
struct in_neighbour_iteratorS
{
typedef typename boost::graph_traits<Graph>::directed_category
directed_category;
typedef typename is_convertible<directed_category,
boost::directed_tag>::type is_directed;
typedef typename get_in_edges<Graph,is_directed>::type type;
typedef typename boost::graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
inline __attribute__((always_inline))
static std::pair<type,type> get_neighbours(vertex_descriptor v,
const Graph& g)
{
return get_in_neighbours<Graph,is_directed>::get_neighbours(v, g);
}
};
// out edges selector for completeness
template <class Graph>
struct out_neighbour_iteratorS
{
typedef typename boost::graph_traits<Graph>::out_neighbours_iterator type;
typedef typename boost::graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
inline __attribute__((always_inline))
static std::pair<type,type> get_neighbours(vertex_descriptor v,
const Graph& g)
{
return out_neighbours(v, g);
}
};
// helper types for all_neighbours_iteratorS
template <class Graph, class IsDirected>
struct get_all_neighbours
{
BOOST_MPL_ASSERT((is_same<IsDirected,std::true_type>));
BOOST_MPL_ASSERT((is_convertible
<typename boost::graph_traits<Graph>::directed_category,
boost::directed_tag>));
typedef typename boost::graph_traits<Graph>::vertex_descriptor
vertex_descriptor;