Commit 733ae662 authored by Tiago Peixoto's avatar Tiago Peixoto

Ensure in/out_edge/adjacency_iterator and associated are random access in...

Ensure in/out_edge/adjacency_iterator and associated are random access in adj_ist<> and UndirectedAdaptor<>
parent 86861179
...@@ -57,7 +57,8 @@ libgraph_tool_core_la_include_HEADERS = \ ...@@ -57,7 +57,8 @@ libgraph_tool_core_la_include_HEADERS = \
random.hh \ random.hh \
str_repr.hh \ str_repr.hh \
shared_map.hh \ shared_map.hh \
tr1_include.hh tr1_include.hh \
transform_iterator.hh
libgraph_tool_core_la_workarounddir = $(MOD_DIR)/include/boost-workaround/boost/graph/ libgraph_tool_core_la_workarounddir = $(MOD_DIR)/include/boost-workaround/boost/graph/
libgraph_tool_core_la_workaround_HEADERS = \ libgraph_tool_core_la_workaround_HEADERS = \
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp> #include <boost/graph/properties.hpp>
#include "transform_iterator.hh"
namespace boost { namespace boost {
//============================================================================== //==============================================================================
...@@ -127,98 +129,140 @@ struct make_undirected_edge ...@@ -127,98 +129,140 @@ struct make_undirected_edge
make_undirected_edge(): _inverted(false) {} make_undirected_edge(): _inverted(false) {}
bool _inverted; bool _inverted;
typedef typename graph_traits<Graph>::edge_descriptor original_edge_t; typedef typename graph_traits<Graph>::edge_descriptor original_edge_t;
typedef typename UndirectedAdaptor<Graph>::EdgeDescriptor result_type;
typename UndirectedAdaptor<Graph>::EdgeDescriptor operator()(const original_edge_t& e) const typename UndirectedAdaptor<Graph>::EdgeDescriptor operator()(const original_edge_t& e) const
{ {
return typename UndirectedAdaptor<Graph>::EdgeDescriptor(e, _inverted); return typename UndirectedAdaptor<Graph>::EdgeDescriptor(e, _inverted);
} }
}; };
template <class Graph> template <class Graph, class Iter>
struct transformed_iterator struct transformed_iterator
{ {
typedef transform_iterator<make_undirected_edge<Graph>, typedef typename mpl::if_<std::tr1::is_convertible<typename std::iterator_traits<Iter>::iterator_category,
typename graph_traits<Graph>::edge_iterator, std::random_access_iterator_tag>,
typename UndirectedAdaptor<Graph>::EdgeDescriptor> type; transform_random_access_iterator<make_undirected_edge<Graph>, Iter>,
transform_iterator<make_undirected_edge<Graph>, Iter> >::type type;
typedef is_convertible<typename std::iterator_traits<Iter>::iterator_category,
std::random_access_iterator_tag> is_orig_ra;
typedef is_convertible<typename std::iterator_traits<type>::iterator_category,
std::random_access_iterator_tag> is_ra;
BOOST_STATIC_ASSERT((!is_orig_ra::value || is_ra::value));
}; };
template <class Graph> template <class Graph>
struct get_undirected_edge_iterator struct get_undirected_edge_iterator
{ {
typedef typename transformed_iterator<Graph>::type type; typedef typename graph_traits<Graph>::edge_iterator ei_t;
typedef typename transformed_iterator<Graph, ei_t>::type type;
}; };
// template <typename Graph>
// class UndirectedAdaptorEdgeIterator
// : public transformed_iterator<Graph>::type
// {
// public:
// UndirectedAdaptorEdgeIterator(const typename graph_traits<Graph>::edge_iterator& e):
// transformed_iterator<Graph>::type(e, make_undirected_edge<Graph>())
// {}
// UndirectedAdaptorEdgeIterator(const typename transformed_iterator<Graph>::type& e):
// transformed_iterator<Graph>::type(e) {}
// UndirectedAdaptorEdgeIterator() {}
// };
//============================================================================== //==============================================================================
// UndirectedAdaptorOutEdgeIterator // UndirectedAdaptorOutEdgeIterator
// this will iterate through both in_edges and out_edges of the underlying graph // this will iterate through both in_edges and out_edges of the underlying graph
//============================================================================== //==============================================================================
template <class Graph> template <class Iter1, class Iter2>
struct transformed_out_iterator class joined_iterator
{ : public boost::iterator_facade<joined_iterator<Iter1, Iter2>,
typedef transform_iterator<make_undirected_edge<Graph>, typename std::iterator_traits<Iter1>::value_type,
typename graph_traits<Graph>::out_edge_iterator, typename std::iterator_traits<Iter1>::iterator_category,
typename UndirectedAdaptor<Graph>::EdgeDescriptor> type; typename std::iterator_traits<Iter1>::reference>
}; {
public:
joined_iterator() {}
explicit joined_iterator(const std::pair<Iter1, Iter1>& range1,
const std::pair<Iter2, Iter2>& range2,
const Iter1& pos1, const Iter2& pos2)
: _range1(range1), _range2(range2), _pos1(pos1), _pos2(pos2)
{ _flip = (_pos1 == _range1.second); }
private:
friend class boost::iterator_core_access;
void increment()
{
if (_flip)
{
++_pos2;
}
else
{
++_pos1;
_flip = (_pos1 == _range1.second);
}
}
template <class Graph> void decrement()
struct transformed_in_iterator {
{ if (_flip)
typedef transform_iterator<make_undirected_edge<Graph>, {
typename graph_traits<Graph>::in_edge_iterator, if (_pos2 == _range2.first)
typename UndirectedAdaptor<Graph>::EdgeDescriptor> type; {
}; _flip = false;
--_pos1;
}
else
{
--_pos2;
}
}
else
{
--_pos1;
}
}
typedef typename std::iterator_traits<Iter1>::difference_type diff_t;
void advance(diff_t n)
{
diff_t d1 = _range1.second - _pos1;
if (n < d1)
{
_pos1 += n;
}
else
{
_pos1 = _range1.second;
_pos2 += n - d1;
_flip = true;
}
}
template <class Graph> diff_t distance_to(joined_iterator const& other)
struct transformed_out_range {
{ return (other._pos1 - _pos1) + (other._pos2 - _pos2);
typedef std::pair<typename transformed_out_iterator<Graph>::type, }
typename transformed_out_iterator<Graph>::type> type;
};
template <class Graph> bool equal(joined_iterator const& other) const
struct transformed_in_range {
{ return (_pos2 == other._pos2 && _pos1 == other._pos1);
typedef std::pair<typename transformed_in_iterator<Graph>::type, }
typename transformed_in_iterator<Graph>::type> type;
};
template <class Graph> typename std::iterator_traits<Iter1>::reference dereference() const
struct joined_iterator {
{ if (_flip)
typedef typename range_iterator<joined_range<typename transformed_out_range<Graph>::type, return *_pos2;
typename transformed_in_range<Graph>::type> >::type type; return *_pos1;
}
std::pair<Iter1, Iter1> _range1;
std::pair<Iter2, Iter2> _range2;
Iter1 _pos1;
Iter2 _pos2;
bool _flip;
}; };
template <class Graph> template <class Graph>
struct get_undirected_out_edge_iterator struct get_undirected_out_edge_iterator
{ {
typedef typename joined_iterator<Graph>::type type; typedef typename graph_traits<Graph>::out_edge_iterator eo_t;
typedef typename graph_traits<Graph>::in_edge_iterator ei_t;
typedef typename transformed_iterator<Graph, eo_t>::type teo_t;
typedef typename transformed_iterator<Graph, ei_t>::type tei_t;
typedef joined_iterator<teo_t, tei_t> type;
}; };
// template <typename Graph>
// class UndirectedAdaptorOutEdgeIterator
// : public joined_iterator<Graph>::type
// {
// public:
// UndirectedAdaptorOutEdgeIterator(const typename joined_iterator<Graph>::type &e)
// : joined_iterator<Graph>::type(e) {}
// UndirectedAdaptorOutEdgeIterator() {};
// };
//============================================================================== //==============================================================================
// UndirectedAdaptorAdjacencyIterator // UndirectedAdaptorAdjacencyIterator
...@@ -235,21 +279,6 @@ struct get_undirected_adjacency_iterator ...@@ -235,21 +279,6 @@ struct get_undirected_adjacency_iterator
out_edge_iter_t>::type type; out_edge_iter_t>::type type;
}; };
// template <typename Graph>
// class UndirectedAdaptorAdjacencyIterator
// : public boost::adjacency_iterator_generator<UndirectedAdaptor<Graph>,
// typename graph_traits<Graph>::vertex_descriptor,
// UndirectedAdaptorOutEdgeIterator<Graph> >::type
// {
// public:
// UndirectedAdaptorAdjacencyIterator(){};
// UndirectedAdaptorAdjacencyIterator(const typename graph_traits<UndirectedAdaptor<Graph> >::out_edge_iterator& e,
// const UndirectedAdaptor<Graph>& g)
// : boost::adjacency_iterator_generator<UndirectedAdaptor<Graph>,
// typename graph_traits<Graph>::vertex_descriptor,
// UndirectedAdaptorOutEdgeIterator<Graph> >::type(e, &g)
// {}
// };
//============================================================================== //==============================================================================
// graph_traits<UndirectedAdaptor> // graph_traits<UndirectedAdaptor>
...@@ -260,13 +289,10 @@ struct graph_traits<UndirectedAdaptor<Graph> > { ...@@ -260,13 +289,10 @@ struct graph_traits<UndirectedAdaptor<Graph> > {
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename UndirectedAdaptor<Graph>::EdgeDescriptor edge_descriptor; typedef typename UndirectedAdaptor<Graph>::EdgeDescriptor edge_descriptor;
//typedef UndirectedAdaptorAdjacencyIterator<Graph> adjacency_iterator;
typedef typename get_undirected_adjacency_iterator<Graph>::type adjacency_iterator; typedef typename get_undirected_adjacency_iterator<Graph>::type adjacency_iterator;
//typedef UndirectedAdaptorOutEdgeIterator<Graph> out_edge_iterator;
typedef typename get_undirected_out_edge_iterator<Graph>::type out_edge_iterator; typedef typename get_undirected_out_edge_iterator<Graph>::type out_edge_iterator;
typedef typename graph_traits<Graph>::in_edge_iterator in_edge_iterator; typedef typename graph_traits<Graph>::in_edge_iterator in_edge_iterator;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
//typedef UndirectedAdaptorEdgeIterator<Graph> edge_iterator;
typedef typename get_undirected_edge_iterator<Graph>::type edge_iterator; typedef typename get_undirected_edge_iterator<Graph>::type edge_iterator;
...@@ -281,6 +307,16 @@ struct graph_traits<UndirectedAdaptor<Graph> > { ...@@ -281,6 +307,16 @@ struct graph_traits<UndirectedAdaptor<Graph> > {
{ {
return graph_traits<Graph>::null_vertex(); return graph_traits<Graph>::null_vertex();
} }
private:
typedef is_convertible<typename std::iterator_traits<typename graph_traits<Graph>::out_edge_iterator>::iterator_category,
std::random_access_iterator_tag> is_orig_ra;
typedef is_convertible<typename std::iterator_traits<out_edge_iterator>::iterator_category,
std::random_access_iterator_tag> is_ra;
BOOST_STATIC_ASSERT((!is_orig_ra::value || is_ra::value));
// typedef is_convertible<typename std::iterator_traits<adjacency_iterator>::iterator_category,
// std::random_access_iterator_tag> is_ara;
// BOOST_STATIC_ASSERT((!is_orig_ra::value || is_ara::value));
}; };
template <class Graph> template <class Graph>
...@@ -396,30 +432,27 @@ std::pair<typename graph_traits<UndirectedAdaptor<Graph> >::out_edge_iterator, ...@@ -396,30 +432,27 @@ std::pair<typename graph_traits<UndirectedAdaptor<Graph> >::out_edge_iterator,
out_edges(typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor u, out_edges(typename graph_traits<UndirectedAdaptor<Graph> >::vertex_descriptor u,
const UndirectedAdaptor<Graph>& g) const UndirectedAdaptor<Graph>& g)
{ {
typename std::pair<typename graph_traits<Graph>::out_edge_iterator, typedef typename graph_traits<Graph>::out_edge_iterator eo_t;
typename graph_traits<Graph>::out_edge_iterator> out_range; typedef typename graph_traits<Graph>::in_edge_iterator ei_t;
typename std::pair<typename graph_traits<Graph>::in_edge_iterator,
typename graph_traits<Graph>::in_edge_iterator> in_range; std::pair<eo_t, eo_t> range1 = out_edges(u, g.OriginalGraph());
std::pair<ei_t, ei_t> range2 = in_edges(u, g.OriginalGraph());
out_range = out_edges(u, g.OriginalGraph());
in_range = in_edges(u, g.OriginalGraph()); typedef typename transformed_iterator<Graph, eo_t>::type teo_t;
typedef typename transformed_iterator<Graph, ei_t>::type tei_t;
typename transformed_out_range<Graph>::type trans_out_range =
std::make_pair(typename transformed_out_iterator<Graph>::type(out_range.first, std::pair<teo_t, teo_t> trange1(teo_t(range1.first,
make_undirected_edge<Graph>(false)), make_undirected_edge<Graph>(false)),
typename transformed_out_iterator<Graph>::type(out_range.second, teo_t(range1.second,
make_undirected_edge<Graph>(false))); make_undirected_edge<Graph>(false)));
typename transformed_in_range<Graph>::type trans_in_range = std::pair<tei_t, tei_t> trange2(tei_t(range2.first,
std::make_pair(typename transformed_in_iterator<Graph>::type(in_range.first, make_undirected_edge<Graph>(true)),
make_undirected_edge<Graph>(true)), tei_t(range2.second,
typename transformed_in_iterator<Graph>::type(in_range.second, make_undirected_edge<Graph>(true)));
make_undirected_edge<Graph>(true)));
joined_iterator<teo_t, tei_t> begin(trange1, trange2, trange1.first, trange2.first);
joined_range<typename transformed_out_range<Graph>::type, joined_iterator<teo_t, tei_t> end(trange1, trange2, trange1.second, trange2.second);
typename transformed_in_range<Graph>::type> jrange = join(trans_out_range, return std::make_pair(begin, end);
trans_in_range);
return std::make_pair(begin(jrange), end(jrange));
} }
//============================================================================== //==============================================================================
......
...@@ -31,10 +31,13 @@ ...@@ -31,10 +31,13 @@
#include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/iterator_facade.hpp>
#include "transform_iterator.hh"
#include "tr1_include.hh" #include "tr1_include.hh"
#include TR1_HEADER(tuple) #include TR1_HEADER(tuple)
namespace boost namespace boost
{ {
...@@ -147,7 +150,7 @@ public: ...@@ -147,7 +150,7 @@ public:
{ return v.first; } { return v.first; }
}; };
typedef transform_iterator<get_vertex, typename edge_list_t::const_iterator> typedef transform_random_access_iterator<get_vertex, typename edge_list_t::const_iterator>
adjacency_iterator; adjacency_iterator;
struct make_out_edge struct make_out_edge
...@@ -170,9 +173,9 @@ public: ...@@ -170,9 +173,9 @@ public:
{ return std::tr1::make_tuple(v.first, _tgt, v.second); } { return std::tr1::make_tuple(v.first, _tgt, v.second); }
}; };
typedef transform_iterator<make_out_edge, typename edge_list_t::const_iterator> typedef transform_random_access_iterator<make_out_edge, typename edge_list_t::const_iterator>
out_edge_iterator; out_edge_iterator;
typedef transform_iterator<make_in_edge, typename edge_list_t::const_iterator> typedef transform_random_access_iterator<make_in_edge, typename edge_list_t::const_iterator>
in_edge_iterator; in_edge_iterator;
class edge_iterator: class edge_iterator:
...@@ -339,6 +342,13 @@ struct graph_traits<adj_list<Vertex> > ...@@ -339,6 +342,13 @@ struct graph_traits<adj_list<Vertex> >
typedef size_t degree_size_type; typedef size_t degree_size_type;
static Vertex null_vertex() { return adj_list<Vertex>::null_vertex(); } 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));
BOOST_STATIC_ASSERT((is_convertible<typename std::iterator_traits<in_edge_iterator>::iterator_category,
std::random_access_iterator_tag>::value));
BOOST_STATIC_ASSERT((is_convertible<typename std::iterator_traits<adjacency_iterator>::iterator_category,
std::random_access_iterator_tag>::value));
}; };
template <class Vertex> template <class Vertex>
...@@ -677,6 +687,7 @@ inline void remove_edge(const typename adj_list<Vertex>::edge_descriptor& e, ...@@ -677,6 +687,7 @@ inline void remove_edge(const typename adj_list<Vertex>::edge_descriptor& e,
g._n_edges--; g._n_edges--;
} }
template <class Vertex> template <class Vertex>
inline Vertex source(const typename adj_list<Vertex>::edge_descriptor& e, inline Vertex source(const typename adj_list<Vertex>::edge_descriptor& e,
const adj_list<Vertex>&) const adj_list<Vertex>&)
......
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006-2013 Tiago de Paula Peixoto <tiago@skewed.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef TRANSFORM_ITERATOR_HH
#define TRANSFORM_ITERATOR_HH
#include <iterator>
#include <boost/iterator/transform_iterator.hpp>
template <class Predicate, class Iterator>
class transform_random_access_iterator:
public boost::transform_iterator<Predicate, Iterator>
{
public:
typedef Iterator iter_t;
typedef boost::transform_iterator<Predicate, Iterator> base_t;
transform_random_access_iterator() {}
transform_random_access_iterator(const base_t& iter) :base_t(iter) {}
transform_random_access_iterator(const Iterator& iter, const Predicate& pred = Predicate())
: base_t(iter, pred) {}
};
namespace std
{
template <class Predicate, class Iterator>
struct iterator_traits<transform_random_access_iterator<Predicate, Iterator> >
{
typedef transform_random_access_iterator<Predicate, Iterator> titer_t;
typedef typename titer_t::base_t base_t;
typedef typename iterator_traits<base_t>::difference_type difference_type;
typedef typename iterator_traits<base_t>::value_type value_type;
typedef typename iterator_traits<base_t>::value_type reference;
typedef typename iterator_traits<base_t>::pointer pointer;
typedef typename iterator_traits<typename titer_t::iter_t>::iterator_category iterator_category;
};
}
#endif // TRANSFORM_ITERATOR_HH
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