EnTT 3.13.0
Loading...
Searching...
No Matches
adjacency_matrix.hpp
1#ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
2#define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
3
4#include <cstddef>
5#include <iterator>
6#include <memory>
7#include <type_traits>
8#include <utility>
9#include <vector>
10#include "../config/config.h"
11#include "../core/iterator.hpp"
12#include "fwd.hpp"
13
14namespace entt {
15
17namespace internal {
18
19template<typename It>
20class edge_iterator {
21 using size_type = std::size_t;
22
23public:
24 using value_type = std::pair<size_type, size_type>;
25 using pointer = input_iterator_pointer<value_type>;
26 using reference = value_type;
27 using difference_type = std::ptrdiff_t;
28 using iterator_category = std::input_iterator_tag;
29 using iterator_concept = std::forward_iterator_tag;
30
31 constexpr edge_iterator() noexcept
32 : it{},
33 vert{},
34 pos{},
35 last{},
36 offset{} {}
37
38 constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept
39 : it{std::move(base)},
40 vert{vertices},
41 pos{from},
42 last{to},
43 offset{step} {
44 for(; pos != last && !it[pos]; pos += offset) {}
45 }
46
47 constexpr edge_iterator &operator++() noexcept {
48 for(pos += offset; pos != last && !it[pos]; pos += offset) {}
49 return *this;
50 }
51
52 constexpr edge_iterator operator++(int) noexcept {
53 edge_iterator orig = *this;
54 return ++(*this), orig;
55 }
56
57 [[nodiscard]] constexpr reference operator*() const noexcept {
58 return *operator->();
59 }
60
61 [[nodiscard]] constexpr pointer operator->() const noexcept {
62 return std::make_pair<size_type>(pos / vert, pos % vert);
63 }
64
65 template<typename Type>
66 friend constexpr bool operator==(const edge_iterator<Type> &, const edge_iterator<Type> &) noexcept;
67
68private:
69 It it;
70 size_type vert;
71 size_type pos;
72 size_type last;
73 size_type offset{};
74};
75
76template<typename Container>
77[[nodiscard]] inline constexpr bool operator==(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
78 return lhs.pos == rhs.pos;
79}
80
81template<typename Container>
82[[nodiscard]] inline constexpr bool operator!=(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
83 return !(lhs == rhs);
84}
85
86} // namespace internal
94template<typename Category, typename Allocator>
96 using alloc_traits = std::allocator_traits<Allocator>;
97 static_assert(std::is_base_of_v<directed_tag, Category>, "Invalid graph category");
98 static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
99 using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
100
101public:
103 using allocator_type = Allocator;
105 using size_type = std::size_t;
109 using edge_type = std::pair<vertex_type, vertex_type>;
113 using edge_iterator = internal::edge_iterator<typename container_type::const_iterator>;
119 using graph_category = Category;
120
122 adjacency_matrix() noexcept(noexcept(allocator_type{}))
123 : adjacency_matrix{0u} {}
124
129 explicit adjacency_matrix(const allocator_type &allocator) noexcept
130 : adjacency_matrix{0u, allocator} {}
131
139 : matrix{vertices * vertices, allocator},
140 vert{vertices} {}
141
147 : adjacency_matrix{other, other.get_allocator()} {}
148
154 adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator)
155 : matrix{other.matrix, allocator},
156 vert{other.vert} {}
157
163 : adjacency_matrix{std::move(other), other.get_allocator()} {}
164
171 : matrix{std::move(other.matrix), allocator},
172 vert{std::exchange(other.vert, 0u)} {}
173
180 matrix = other.matrix;
181 vert = other.vert;
182 return *this;
183 }
184
191 matrix = std::move(other.matrix);
192 vert = std::exchange(other.vert, 0u);
193 return *this;
194 }
195
200 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
201 return matrix.get_allocator();
202 }
203
205 void clear() noexcept {
206 matrix.clear();
207 vert = {};
208 }
209
214 void swap(adjacency_matrix &other) {
215 using std::swap;
216 swap(matrix, other.matrix);
217 swap(vert, other.vert);
218 }
219
224 [[nodiscard]] size_type size() const noexcept {
225 return vert;
226 }
227
232 [[nodiscard]] iterable_adaptor<vertex_iterator> vertices() const noexcept {
233 return {0u, vert};
234 }
235
240 [[nodiscard]] iterable_adaptor<edge_iterator> edges() const noexcept {
241 const auto it = matrix.cbegin();
242 const auto sz = matrix.size();
243 return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}};
244 }
245
251 [[nodiscard]] iterable_adaptor<out_edge_iterator> out_edges(const vertex_type vertex) const noexcept {
252 const auto it = matrix.cbegin();
253 const auto from = vertex * vert;
254 const auto to = from + vert;
255 return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}};
256 }
257
263 [[nodiscard]] iterable_adaptor<in_edge_iterator> in_edges(const vertex_type vertex) const noexcept {
264 const auto it = matrix.cbegin();
265 const auto from = vertex;
266 const auto to = vert * vert + from;
267 return {{it, vert, from, to, vert}, {it, vert, to, to, vert}};
268 }
269
276
277 for(auto [lhs, rhs]: edges()) {
278 other.insert(lhs, rhs);
279 }
280
281 other.swap(*this);
282 }
283
292 std::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
293 const auto pos = lhs * vert + rhs;
294
295 if constexpr(std::is_same_v<graph_category, undirected_tag>) {
296 const auto rev = rhs * vert + lhs;
297 ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
298 matrix[rev] = 1u;
299 }
300
301 const auto inserted = !std::exchange(matrix[pos], 1u);
302 return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted};
303 }
304
311 size_type erase(const vertex_type lhs, const vertex_type rhs) {
312 const auto pos = lhs * vert + rhs;
313
314 if constexpr(std::is_same_v<graph_category, undirected_tag>) {
315 const auto rev = rhs * vert + lhs;
316 ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
317 matrix[rev] = 0u;
318 }
319
320 return std::exchange(matrix[pos], 0u);
321 }
322
329 [[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const {
330 const auto pos = lhs * vert + rhs;
331 return pos < matrix.size() && matrix[pos];
332 }
333
334private:
335 container_type matrix;
336 size_type vert;
337};
338
339} // namespace entt
340
341#endif
Basic implementation of a directed adjacency matrix.
std::pair< edge_iterator, bool > insert(const vertex_type lhs, const vertex_type rhs)
Inserts an edge into the adjacency matrix, if it does not exist.
adjacency_matrix & operator=(const adjacency_matrix &other)
Default copy assignment operator.
adjacency_matrix() noexcept(noexcept(allocator_type{}))
Default constructor.
Category graph_category
Graph category tag.
iterable_adaptor< out_edge_iterator > out_edges(const vertex_type vertex) const noexcept
Returns an iterable object to visit all out edges of a vertex.
internal::edge_iterator< typename container_type::const_iterator > edge_iterator
Edge iterator type.
size_type size() const noexcept
Returns the number of vertices.
void swap(adjacency_matrix &other)
Exchanges the contents with those of a given adjacency matrix.
adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator)
Allocator-extended move constructor.
std::size_t size_type
Unsigned integer type.
Allocator allocator_type
Allocator type.
bool contains(const vertex_type lhs, const vertex_type rhs) const
Checks if an adjacency matrix contains a given edge.
void clear() noexcept
Clears the adjacency matrix.
adjacency_matrix(const size_type vertices, const allocator_type &allocator=allocator_type{})
Constructs an empty container with a given allocator and user supplied number of vertices.
edge_iterator out_edge_iterator
Out edge iterator type.
iterable_adaptor< in_edge_iterator > in_edges(const vertex_type vertex) const noexcept
Returns an iterable object to visit all in edges of a vertex.
std::pair< vertex_type, vertex_type > edge_type
Edge type.
iterable_adaptor< vertex_iterator > vertices() const noexcept
Returns an iterable object to visit all vertices of a matrix.
iterable_adaptor< edge_iterator > edges() const noexcept
Returns an iterable object to visit all edges of a matrix.
adjacency_matrix(const adjacency_matrix &other)
Copy constructor.
edge_iterator in_edge_iterator
In edge iterator type.
void resize(const size_type vertices)
Resizes an adjacency matrix.
size_type vertex_type
Vertex type.
adjacency_matrix & operator=(adjacency_matrix &&other) noexcept
Default move assignment operator.
adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator)
Allocator-extended copy constructor.
adjacency_matrix(adjacency_matrix &&other) noexcept
Move constructor.
size_type erase(const vertex_type lhs, const vertex_type rhs)
Removes the edge associated with a pair of given vertices.
adjacency_matrix(const allocator_type &allocator) noexcept
Constructs an empty container with a given allocator.
constexpr allocator_type get_allocator() const noexcept
Returns the associated allocator.
Plain iota iterator (waiting for C++20).
Definition iterator.hpp:56
EnTT default namespace.
Definition dense_map.hpp:21
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:141