diff --git a/lib/graph/graph.hpp b/lib/graph/graph.hpp index 08d58e7..00bd2b0 100644 --- a/lib/graph/graph.hpp +++ b/lib/graph/graph.hpp @@ -13,6 +13,9 @@ - not directed. There are 2 edges for each connection, both direction - no multi/self edges + - Stored as an unordered map where the keys are vertices and values are arrays of edges. + The multimap is picked since neighboursOf is the most critical operation. + - V expected to be cheap to copy - V should have operator== and be hashable (for the internal std::unordered_map): ~~~{.cpp} @@ -25,6 +28,16 @@ ~~~ */ + +// from http://cpptruths.blogspot.de/2011/09/tale-of-noexcept-swap-for-user-defined.html +template +struct is_nothrow_swappable_all +{ + static std::tuple *t; + enum { value = noexcept(t->swap(*t)) }; +}; + + template class Graph { @@ -48,11 +61,14 @@ private: public: struct Edge { - Edge() : source(), destination() {} + Edge() noexcept(std::is_default_constructible::value) : source(), destination() {} Edge(const_reference s, const_reference d) : source(s), destination(d) {} Edge(const Edge& o) : source(o.source), destination(o.destination) {} + Edge(Edge&& o) noexcept(std::is_nothrow_copy_constructible::value) + : source(std::move(o.source)), destination(std::move(o.destination)) {} Edge& operator=(Edge o) { swap(o); return *this; } - void swap(Edge& o) { std::swap(source, o.source); std::swap(destination, o.destination); } + void swap(Edge& o) noexcept(is_nothrow_swappable_all::value) + { std::swap(source, o.source); std::swap(destination, o.destination); } bool operator==(const Edge& o) const { return source == o.source && destination == o.destination; } value_type source; @@ -61,14 +77,15 @@ public: Graph() : m_vertices() {} Graph(const Graph& o) : m_vertices(o.m_vertices) {} - Graph(Graph&& o) : m_vertices(std::move(o.m_vertices)) {} + Graph(Graph&& o) : m_vertices(std::move(o.m_vertices)) {} // unordered_map move ctor is noexcept indifferent Graph(std::initializer_list vertex_list); Graph(const std::vector& vertex_list); Graph(std::initializer_list edge_list); Graph(const std::vector& edge_list); Graph& operator=(Graph o) { swap(o); return *this; } - void swap(Graph& o) { std::swap(m_vertices, o.m_vertices); } + void swap(Graph& o) noexcept(is_nothrow_swappable_all::value) + { std::swap(m_vertices, o.m_vertices); } void addVertex(const_reference data); void removeVertex(const_reference data); @@ -81,8 +98,8 @@ public: std::vector vertices() const; std::vector edges() const; - void clear() { m_vertices.clear(); } - std::vector neighboursOf(const_reference data) const; + void clear() noexcept { m_vertices.clear(); } + const std::vector& neighboursOf(const_reference data) const; class vertex_iterator : public std::iterator::value_type> Graph::vertices() const } template -inline std::vector Graph::neighboursOf(const_reference data) const +inline const std::vector& Graph::neighboursOf(const_reference data) const { + static std::vector empty; auto vertex_it = m_vertices.find(data); if (vertex_it == m_vertices.end()) - return std::vector(); + return empty; else return vertex_it->second; }