Commit e1c811ad authored by Tiago Peixoto's avatar Tiago Peixoto

Fix bug in all_edges_range() for directed graphs.

This fixes issue #375
parent c4ff2303
......@@ -55,6 +55,9 @@ public:
typedef allow_parallel_edge_tag edge_parallel_category;
typedef typename graph_traits<Graph>::traversal_category traversal_category;
typedef typename Graph::out_edge_iterator all_edge_iterator;
typedef typename Graph::out_edge_iterator all_edge_iterator_reversed;
const Graph& original_graph() const {return _g;}
Graph& original_graph() {return _g;}
......@@ -229,6 +232,15 @@ in_edges(typename graph_traits<undirected_adaptor<Graph>>::vertex_descriptor u,
return _all_edges_in(u, g.original_graph());
}
template <class Graph>
inline __attribute__((always_inline)) __attribute__((flatten))
auto
all_edges(typename graph_traits<undirected_adaptor<Graph>>::vertex_descriptor u,
const undirected_adaptor<Graph>& g)
{
return out_edges(u, g);
}
//==============================================================================
// out_neighbours(u, g)
//==============================================================================
......
......@@ -89,6 +89,16 @@ std::pair<typename adj_list<Vertex>::in_edge_iterator,
typename adj_list<Vertex>::in_edge_iterator>
_all_edges_in(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::all_edge_iterator,
typename adj_list<Vertex>::all_edge_iterator>
all_edges(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::all_edge_iterator_reversed,
typename adj_list<Vertex>::all_edge_iterator_reversed>
_all_edges_reversed(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
......@@ -250,30 +260,84 @@ public:
__attribute__((always_inline)) __attribute__((flatten))
edge_descriptor dereference() const
{
return Deference::def(_v, *_iter);
return Deference::def(_v, *_iter, *this);
}
protected:
vertex_t _v;
typename edge_list_t::const_iterator _iter;
};
struct make_out_edge
{
template <class Iter>
static edge_descriptor def(vertex_t src,
const std::pair<vertex_t, vertex_t>& v)
const std::pair<vertex_t, vertex_t>& v,
Iter&&)
{ return edge_descriptor(src, v.first, v.second); }
static edge_descriptor def(vertex_t src,
const std::pair<vertex_t, vertex_t>& v)
{ return def(src, v, nullptr); }
};
struct make_in_edge
{
template <class Iter>
static edge_descriptor def(vertex_t tgt,
const std::pair<vertex_t, vertex_t>& v)
const std::pair<vertex_t, vertex_t>& v,
Iter&&)
{ return edge_descriptor(v.first, tgt, v.second); }
static edge_descriptor def(vertex_t tgt,
const std::pair<vertex_t, vertex_t>& v)
{ return def(tgt, v, nullptr); }
};
typedef base_edge_iterator<make_out_edge> out_edge_iterator;
typedef base_edge_iterator<make_in_edge> in_edge_iterator;
template <class Iter, bool reversed>
struct make_in_or_out_edge
{
template <class I>
static edge_descriptor def(vertex_t u,
const std::pair<vertex_t, vertex_t>& v,
const I& i)
{
const Iter& iter = reinterpret_cast<const Iter&>(i);
if ((iter._iter < iter._pos) != reversed)
return edge_descriptor(u, v.first, v.second);
else
return edge_descriptor(v.first, u, v.second);
}
};
template <bool reversed>
struct all_edge_iterator_base:
public base_edge_iterator<make_in_or_out_edge<all_edge_iterator_base<reversed>,
reversed>>
{
all_edge_iterator_base() {}
all_edge_iterator_base(vertex_t v,
typename edge_list_t::const_iterator&& iter,
const typename edge_list_t::const_iterator& pos)
: base_edge_iterator<make_in_or_out_edge<all_edge_iterator_base,
reversed>>
(v, std::forward<typename edge_list_t::const_iterator>(iter)),
_pos(pos)
{}
private:
friend struct make_in_or_out_edge<all_edge_iterator_base<reversed>,
reversed>;
typename edge_list_t::const_iterator _pos;
};
typedef all_edge_iterator_base<false> all_edge_iterator;
typedef all_edge_iterator_base<true> all_edge_iterator_reversed;
class edge_iterator:
public boost::iterator_facade<edge_iterator,
edge_descriptor,
......@@ -480,6 +544,12 @@ private:
friend std::pair<in_edge_iterator, in_edge_iterator>
_all_edges_in<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<all_edge_iterator, all_edge_iterator>
all_edges<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<all_edge_iterator_reversed, all_edge_iterator_reversed>
_all_edges_reversed<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<adjacency_iterator, adjacency_iterator>
adjacent_vertices<>(Vertex v, const adj_list<Vertex>& g);
......@@ -726,6 +796,32 @@ _all_edges_in(Vertex v, const adj_list<Vertex>& g)
return {ei_t(v, es.begin()), ei_t(v, es.end())};
}
template <class Vertex>
inline __attribute__((always_inline)) __attribute__((flatten))
std::pair<typename adj_list<Vertex>::all_edge_iterator,
typename adj_list<Vertex>::all_edge_iterator>
all_edges(Vertex v, const adj_list<Vertex>& g)
{
typedef typename adj_list<Vertex>::all_edge_iterator ei_t;
const auto& pes = g._edges[v];
auto& es = pes.second;
auto pos = es.begin() + pes.first;
return {ei_t(v, es.begin(), pos), ei_t(v, es.end(), pos)};
}
template <class Vertex>
inline __attribute__((always_inline)) __attribute__((flatten))
std::pair<typename adj_list<Vertex>::all_edge_iterator_reversed,
typename adj_list<Vertex>::all_edge_iterator_reversed>
_all_edges_reversed(Vertex v, const adj_list<Vertex>& g)
{
typedef typename adj_list<Vertex>::all_edge_iterator_reversed ei_t;
const auto& pes = g._edges[v];
auto& es = pes.second;
auto pos = es.begin() + pes.first;
return {ei_t(v, es.begin(), pos), ei_t(v, es.end(), pos)};
}
template <class Vertex>
inline __attribute__((always_inline)) __attribute__((flatten))
std::pair<typename adj_list<Vertex>::adjacency_iterator,
......
......@@ -172,6 +172,14 @@ public:
InEdgePred, typename Traits::in_edge_iterator
> in_edge_iterator;
typedef filter_iterator<
EdgePred, typename Graph::all_edge_iterator
> all_edge_iterator;
typedef filter_iterator<
EdgePred, typename Graph::all_edge_iterator_reversed
> all_edge_iterator_reversed;
typedef typename adjacency_iterator_generator<self,
vertex_descriptor,
in_edge_iterator>::type
......@@ -497,6 +505,20 @@ in_degree(typename filt_graph<G, EP, VP>::vertex_descriptor u,
return n;
}
template <typename G, typename EP, typename VP>
inline __attribute__((always_inline)) __attribute__((flatten))
std::pair<typename filt_graph<G, EP, VP>::all_edge_iterator,
typename filt_graph<G, EP, VP>::all_edge_iterator>
all_edges(typename filt_graph<G, EP, VP>::vertex_descriptor u,
const filt_graph<G, EP, VP>& g)
{
typedef typename filt_graph<G, EP, VP>::all_edge_iterator iter;
auto range = all_edges(u, g._g);
return std::make_pair(iter(g._all_edge_pred, range.first, range.second),
iter(g._all_edge_pred, range.second, range.second));
}
template <typename G, typename EP, typename VP>
inline
std::pair<typename filt_graph<G, EP, VP>::edge_descriptor, bool>
......
......@@ -64,6 +64,9 @@ class reversed_graph {
// BidirectionalGraph requirements
typedef typename Traits::out_edge_iterator in_edge_iterator;
typedef typename BidirectionalGraph::all_edge_iterator_reversed all_edge_iterator;
typedef typename BidirectionalGraph::all_edge_iterator all_edge_iterator_reversed;
// AdjacencyGraph requirements
typedef typename BidirectionalGraph::in_adjacency_iterator adjacency_iterator;
typedef typename graph_traits<BidirectionalGraph>::adjacency_iterator in_adjacency_iterator;
......@@ -191,6 +194,15 @@ in_edges(const typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
return out_edges(u, g._g);
}
template <class BidirectionalGraph, class GRef>
inline std::pair<typename reversed_graph<BidirectionalGraph>::all_edge_iterator,
typename reversed_graph<BidirectionalGraph>::all_edge_iterator>
all_edges(const typename graph_traits<BidirectionalGraph>::vertex_descriptor u,
const reversed_graph<BidirectionalGraph,GRef>& g)
{
return _all_edges_reversed(u, g._g);
}
template <class BidirectionalGraph, class GRef>
inline std::pair<typename reversed_graph<BidirectionalGraph,GRef>::adjacency_iterator,
typename reversed_graph<BidirectionalGraph,GRef>::adjacency_iterator>
......
......@@ -326,7 +326,6 @@ struct get_in_edges
static std::pair<type,type> get_edges(vertex_descriptor v,
const Graph& g)
{
using namespace boost;
return in_edges(v, g);
}
};
......@@ -386,100 +385,35 @@ struct out_edge_iteratorS
}
};
// helper types for all_edges_iteratorS
template <class Graph, class IsDirected>
struct get_all_edges
{
BOOST_MPL_ASSERT((std::is_same<IsDirected,std::true_type>));
BOOST_MPL_ASSERT((std::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<boost::undirected_adaptor<Graph> >::out_edge_iterator
type;
inline __attribute__((always_inline))
static std::pair<type,type> get_edges(vertex_descriptor v,
const Graph& g)
{
using namespace boost;
const boost::undirected_adaptor<Graph> ug(g);
return out_edges(v, ug);
}
};
template <class Graph>
struct get_all_edges<Graph,std::false_type>
{
BOOST_MPL_ASSERT((std::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_edge_iterator type;
inline __attribute__((always_inline))
static std::pair<type,type> get_edges(vertex_descriptor v,
const Graph& g)
{
using namespace boost;
return out_edges(v, g);
}
};
// this "all edges" iterator selector returns the in-edge + out-edge ranges for
// directed graphs and the out-edge range for undirected graphs. The
// iterator type is given by all_edges_iteratorS<Graph>::type.
template <class Graph>
struct all_edges_iteratorS
{
typedef typename boost::graph_traits<Graph>::directed_category
directed_category;
typedef typename std::is_convertible<directed_category,
boost::directed_tag>::type is_directed;
typedef typename get_all_edges<Graph,is_directed>::type type;
typedef typename Graph::all_edge_iterator type;
typedef typename boost::graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
inline __attribute__((always_inline))
static std::pair<type,type> get_edges(vertex_descriptor v,
const Graph& g)
static std::pair<type, type> get_edges(vertex_descriptor v, const Graph& g)
{
return get_all_edges<Graph,is_directed>::get_edges(v, g);
return all_edges(v, g);
}
};
// helper types for in_or_out_edge_iteratorS
template <class Graph, class IsDirected>
struct get_in_or_out_edges
: public get_in_edges<Graph,IsDirected>
{};
template <class Graph>
struct get_in_or_out_edges<Graph,std::false_type>
: public get_all_edges<Graph,std::false_type>
{};
// this "in or out" iterator selector returns the in-edge range for directed
// graphs and the out-edge range for undirected graphs. The iterator type is
// given by in_or_out_edges_iteratorS<Graph>::type
template <class Graph>
struct in_or_out_edge_iteratorS
{
typedef typename boost::graph_traits<Graph>::directed_category
directed_category;
typedef typename std::is_convertible<directed_category,
boost::directed_tag>::type is_directed;
typedef typename get_in_or_out_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_edges(vertex_descriptor v,
const Graph& g)
{
return get_in_or_out_edges<Graph,is_directed>::get_edges(v, g);
}
};
: public std::conditional
<std::is_convertible
<typename boost::graph_traits<Graph>::directed_category,
boost::directed_tag>::value,
in_edge_iteratorS<Graph>,
out_edge_iteratorS<Graph>>::type
{};
// helper types for in_neighbour_iteratorS
......@@ -497,7 +431,6 @@ struct get_in_neighbours
static std::pair<type,type> get_edges(vertex_descriptor v,
const Graph& g)
{
using namespace boost;
return in_neighbours(v, g);
}
};
......@@ -575,38 +508,18 @@ struct all_neighbours_iteratorS
}
};
// helper types for in_or_out_neighbours_iteratorS
template <class Graph, class IsDirected>
struct get_in_or_out_neighbours
: public in_neighbour_iteratorS<Graph>
{};
template <class Graph>
struct get_in_or_out_neighbours<Graph, std::false_type>
: public out_neighbour_iteratorS<Graph>
{};
// this "in or out" iterator selector returns the in-neighbour range for
// directed graphs and the out-neighbour range for undirected graphs. The
// iterator type is given by in_or_adjacency_iteratorS<Graph>::type
template <class Graph>
struct in_or_out_neighbours_iteratorS
{
typedef typename boost::graph_traits<Graph>::directed_category
directed_category;
typedef typename std::is_convertible<directed_category,
boost::directed_tag>::type is_directed;
typedef typename get_in_or_out_neighbours<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_or_out_neighbours<Graph,is_directed>::get_neighbours(v, g);
}
};
: public std::conditional
<std::is_convertible
<typename boost::graph_traits<Graph>::directed_category,
boost::directed_tag>::value,
in_neighbour_iteratorS<Graph>,
out_neighbour_iteratorS<Graph>>::type
{};
// range adaptors
......@@ -690,7 +603,7 @@ inline __attribute__((always_inline)) __attribute__((flatten))
auto all_edges_range(typename all_edges_iteratorS<Graph>::vertex_descriptor v,
const Graph& g)
{
return mk_range(all_edges_iteratorS<Graph>::get_edges(v, g));
return mk_range(all_edges(v, g));
}
template <class Graph>
......@@ -698,7 +611,7 @@ inline __attribute__((always_inline)) __attribute__((flatten))
auto all_neighbours_range(typename all_neighbours_iteratorS<Graph>::vertex_descriptor v,
const Graph& g)
{
return mk_range(all_neighbours_iteratorS<Graph>::get_neighbours(v, g));
return mk_range(all_neighbours(v, g));
}
template <class Graph>
......
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