From 72630c3d6b632e4555ca4e8dde4aeac8a8c14e9b Mon Sep 17 00:00:00 2001 From: dmatetelki Date: Mon, 23 Jun 2014 13:17:16 +0200 Subject: [PATCH] std::vector iterators get invalidated at grow --- lib/graph/graph.hpp | 70 +++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/lib/graph/graph.hpp b/lib/graph/graph.hpp index 2d79c47..47a80d8 100644 --- a/lib/graph/graph.hpp +++ b/lib/graph/graph.hpp @@ -51,8 +51,7 @@ private: struct Vertex { - // because of parallell accumulate, ctor(int) is needed and that could conflict - // Vertex(const_reference data) : m_data(data), m_edges() {} + Vertex(const_reference data) : m_data(data), m_edges() {} Vertex() : m_data(), m_edges() {} Vertex(const Vertex& o) : m_data(o.m_data), m_edges(o.m_edges) {} @@ -61,12 +60,12 @@ private: bool operator==(const Vertex& o) const; // parallell accumulate requires both - Vertex(int) : Vertex() {} + Vertex(size_type) : Vertex() {} explicit operator int() const { return (int)m_edges.size(); } - void addEdge(v_iterator destination, const_weight_reference weight = weight_type()); - void removeEdge(v_iterator destination, const_weight_reference weight = weight_type()); - void removeAllEdgesTo(v_iterator destination); + void addEdge(v_const_iterator destination, const_weight_reference weight = weight_type()); + void removeEdge(v_const_iterator destination, const_weight_reference weight = weight_type()); + void removeAllEdgesTo(v_const_iterator destination); std::vector edges() const; value_type m_data; @@ -82,6 +81,7 @@ public: Edge() : source(), destination(), weight() {} Edge(const_reference source, const_reference destination, const_weight_reference weight); Edge(const Edge& o); + ~Edge() {} Edge& operator=(Edge o) { swap(o); return *this; } void swap(Edge& o); bool operator==(const Edge& o) const { return source == o.source && destination == o.destination && weight == o.weight; } @@ -115,6 +115,9 @@ public: /// @todo rename Vertex & Edge? // Modifiers + void reserveVertexCapacity(int c) { m_vertices.reserve(c); } + void clear() { m_vertices.clear(); } + void addVertex(const_reference data); void removeVertex(const_reference data); void addEdge(const_reference source, const_reference destination, const_weight_reference weight = weight_type()); @@ -220,7 +223,10 @@ private: v_iterator find(const_reference data); v_const_iterator findAndCheck(const_reference data, bool existence_expected = true) const; v_iterator findAndCheck(const_reference data, bool existence_expected = true); - void adjustEdges(v_iterator vit); + + /// @todo make is a vector specializetion + void adjustIteratorsAfter(v_iterator vit); + void resizeVerticesVector(); const bool m_directed; v_container m_vertices; @@ -362,22 +368,25 @@ inline bool Graph::Vertex::operator==(const Vertex& other) const } template -inline void Graph::Vertex::addEdge(v_iterator destination, const_weight_reference weight) +inline void Graph::Vertex::addEdge(v_const_iterator destination, const_weight_reference weight) { m_edges.push_back(EdgeTo(destination, weight)); } template -inline void Graph::Vertex::removeEdge(v_iterator destination, const_weight_reference weight) +inline void Graph::Vertex::removeEdge(v_const_iterator destination, const_weight_reference weight) { - m_edges.erase( + typename std::list::iterator it = std::find_if(m_edges.begin(), m_edges.end(), [&destination, &weight](const EdgeTo& e) - { return e.m_destination == destination && e.m_weight == weight;})); + { return e.m_destination == destination && e.m_weight == weight;}); + + if (it != m_edges.end()) + m_edges.erase(it); } template -inline void Graph::Vertex::removeAllEdgesTo(v_iterator destination) +inline void Graph::Vertex::removeAllEdgesTo(v_const_iterator destination) { m_edges.erase( std::remove_if(m_edges.begin(), m_edges.end(), @@ -403,6 +412,7 @@ template Graph::Graph(std::initializer_list vertex_list) : Graph() { + reserveVertexCapacity(vertex_list.size()); for(const V& v : vertex_list) addVertex(v); } @@ -411,6 +421,8 @@ template Graph::Graph(std::initializer_list edge_list) : Graph() { +// m_vertices.resize(edge_list.size()); +// m_vertices.resize(2); for (const Edge& e : edge_list ) addEdge(e.source, e.destination, e.weight); } @@ -429,9 +441,10 @@ inline void Graph::addVertex(const_reference data) if (find(data) != m_vertices.end()) return; - Vertex v; - v.m_data = data; - m_vertices.push_back(v); + if (m_vertices.size() == m_vertices.capacity()) + resizeVerticesVector(); + + m_vertices.push_back(Vertex(data)); } template @@ -446,7 +459,7 @@ inline void Graph::removeVertex(const_reference data) { v.removeAllEdgesTo(it); } ); m_vertices.erase(it); - adjustEdges(it); + adjustIteratorsAfter(it); } template @@ -474,9 +487,9 @@ inline void Graph::removeEdge(const_reference source, const_reference dest if (destination_it == m_vertices.end()) return; - source_it->removeEdge(destination, weight); + source_it->removeEdge(destination_it, weight); if (!m_directed) - destination_it->removeEdge(source, weight); + destination_it->removeEdge(source_it, weight); } template @@ -571,7 +584,7 @@ Graph::find(const_reference data) } template -void Graph::adjustEdges(v_iterator deleted_vit) +void Graph::adjustIteratorsAfter(v_iterator deleted_vit) { std::for_each(m_vertices.begin(), m_vertices.end(), [&deleted_vit](Vertex& v) @@ -581,5 +594,24 @@ void Graph::adjustEdges(v_iterator deleted_vit) }); } +template +void Graph::resizeVerticesVector() +{ + const float grow_factor = 1.5; + const int old_size = m_vertices.size(); + const int new_size = old_size == 0 ? 1 : old_size * grow_factor + 0.5; + + std::vector old_vertices = vertices(); + std::vector old_edges = edges(); + + clear(); + reserveVertexCapacity(new_size); + + for(auto v: old_vertices) + addVertex(v); + + for(auto e: old_edges) + addEdge(e.source, e.destination, e.weight); +} #endif // GRAPH_H