Graph is noexcept where it can be.

master
dmatetelki 10 years ago
parent 8c3e0576ac
commit 721c81c79b

@ -13,6 +13,9 @@
- not directed. There are 2 edges for each connection, both direction - not directed. There are 2 edges for each connection, both direction
- no multi/self edges - 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 expected to be cheap to copy
- V should have operator== and be hashable (for the internal std::unordered_map): - V should have operator== and be hashable (for the internal std::unordered_map):
~~~{.cpp} ~~~{.cpp}
@ -25,6 +28,16 @@
~~~ ~~~
*/ */
// from http://cpptruths.blogspot.de/2011/09/tale-of-noexcept-swap-for-user-defined.html
template<typename... T>
struct is_nothrow_swappable_all
{
static std::tuple<T...> *t;
enum { value = noexcept(t->swap(*t)) };
};
template <typename V> template <typename V>
class Graph { class Graph {
@ -48,11 +61,14 @@ private:
public: public:
struct Edge { struct Edge {
Edge() : source(), destination() {} Edge() noexcept(std::is_default_constructible<value_type>::value) : source(), destination() {}
Edge(const_reference s, const_reference d) : source(s), destination(d) {} Edge(const_reference s, const_reference d) : source(s), destination(d) {}
Edge(const Edge& o) : source(o.source), destination(o.destination) {} Edge(const Edge& o) : source(o.source), destination(o.destination) {}
Edge(Edge&& o) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
: source(std::move(o.source)), destination(std::move(o.destination)) {}
Edge& operator=(Edge o) { swap(o); return *this; } 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<V>::value)
{ std::swap(source, o.source); std::swap(destination, o.destination); }
bool operator==(const Edge& o) const { return source == o.source && destination == o.destination; } bool operator==(const Edge& o) const { return source == o.source && destination == o.destination; }
value_type source; value_type source;
@ -61,14 +77,15 @@ public:
Graph() : m_vertices() {} Graph() : m_vertices() {}
Graph(const Graph<V>& o) : m_vertices(o.m_vertices) {} Graph(const Graph<V>& o) : m_vertices(o.m_vertices) {}
Graph(Graph<V>&& o) : m_vertices(std::move(o.m_vertices)) {} Graph(Graph<V>&& o) : m_vertices(std::move(o.m_vertices)) {} // unordered_map move ctor is noexcept indifferent
Graph(std::initializer_list<V> vertex_list); Graph(std::initializer_list<V> vertex_list);
Graph(const std::vector<V>& vertex_list); Graph(const std::vector<V>& vertex_list);
Graph(std::initializer_list<Edge> edge_list); Graph(std::initializer_list<Edge> edge_list);
Graph(const std::vector<Edge>& edge_list); Graph(const std::vector<Edge>& edge_list);
Graph<V>& operator=(Graph<V> o) { swap(o); return *this; } Graph<V>& operator=(Graph<V> 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<v_container>::value)
{ std::swap(m_vertices, o.m_vertices); }
void addVertex(const_reference data); void addVertex(const_reference data);
void removeVertex(const_reference data); void removeVertex(const_reference data);
@ -81,8 +98,8 @@ public:
std::vector<value_type> vertices() const; std::vector<value_type> vertices() const;
std::vector<Edge> edges() const; std::vector<Edge> edges() const;
void clear() { m_vertices.clear(); } void clear() noexcept { m_vertices.clear(); }
std::vector<value_type> neighboursOf(const_reference data) const; const std::vector<value_type>& neighboursOf(const_reference data) const;
class vertex_iterator : public std::iterator<std::forward_iterator_tag, class vertex_iterator : public std::iterator<std::forward_iterator_tag,
@ -123,12 +140,12 @@ public:
typedef vertex_iterator iterator; typedef vertex_iterator iterator;
typedef const vertex_iterator const_iterator; typedef const vertex_iterator const_iterator;
iterator begin() { return iterator(m_vertices.begin()); } iterator begin() noexcept { return iterator(m_vertices.begin()); }
iterator begin() const { return iterator(m_vertices.begin()); } iterator begin() const noexcept { return iterator(m_vertices.begin()); }
const_iterator cbegin() const { return const_iterator(m_vertices.begin()); } const_iterator cbegin() const noexcept { return const_iterator(m_vertices.begin()); }
iterator end() { return iterator(m_vertices.end()); } iterator end() noexcept { return iterator(m_vertices.end()); }
iterator end() const { return iterator(m_vertices.end()); } iterator end() const noexcept { return iterator(m_vertices.end()); }
const_iterator cend() const { return const_iterator(m_vertices.end()); } const_iterator cend() const noexcept { return const_iterator(m_vertices.end()); }
private: private:
@ -287,11 +304,12 @@ inline std::vector<typename Graph<V>::value_type> Graph<V>::vertices() const
} }
template <typename V> template <typename V>
inline std::vector<V> Graph<V>::neighboursOf(const_reference data) const inline const std::vector<V>& Graph<V>::neighboursOf(const_reference data) const
{ {
static std::vector<V> empty;
auto vertex_it = m_vertices.find(data); auto vertex_it = m_vertices.find(data);
if (vertex_it == m_vertices.end()) if (vertex_it == m_vertices.end())
return std::vector<V>(); return empty;
else else
return vertex_it->second; return vertex_it->second;
} }

Loading…
Cancel
Save