EnTT 4.0.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 "../config/config.h"
5#include "../core/iterator.hpp"
6#include "../stl/concepts.hpp"
7#include "../stl/cstddef.hpp"
8#include "../stl/iterator.hpp"
9#include "../stl/memory.hpp"
10#include "../stl/type_traits.hpp"
11#include "../stl/utility.hpp"
12#include "../stl/vector.hpp"
13#include "fwd.hpp"
14
15namespace entt {
16
18namespace internal {
19
20template<typename It>
21class edge_iterator {
22 using size_type = stl::size_t;
23
24 void find_next() noexcept {
25 for(; pos != last && !it[static_cast<It::difference_type>(pos)]; pos += offset) {}
26 }
27
28public:
29 using value_type = stl::pair<size_type, size_type>;
30 using pointer = input_iterator_pointer<value_type>;
31 using reference = value_type;
32 using difference_type = stl::ptrdiff_t;
33 using iterator_category = stl::input_iterator_tag;
34 using iterator_concept = stl::forward_iterator_tag;
35
36 constexpr edge_iterator() noexcept = default;
37
38 // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
39 constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept
40 : it{stl::move(base)},
41 vert{vertices},
42 pos{from},
43 last{to},
44 offset{step} {
45 find_next();
46 }
47
48 constexpr edge_iterator &operator++() noexcept {
49 pos += offset;
50 find_next();
51 return *this;
52 }
53
54 constexpr edge_iterator operator++(int) noexcept {
55 const edge_iterator orig = *this;
56 return ++(*this), orig;
57 }
58
59 [[nodiscard]] constexpr reference operator*() const noexcept {
60 return *operator->();
61 }
62
63 [[nodiscard]] constexpr pointer operator->() const noexcept {
64 return stl::make_pair<size_type>(pos / vert, pos % vert);
65 }
66
67 [[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept {
68 return pos == other.pos;
69 }
70
71private:
72 It it{};
73 size_type vert{};
74 size_type pos{};
75 size_type last{};
76 size_type offset{};
77};
78
79} // namespace internal
81
87template<stl::derived_from<directed_tag> Category, typename Allocator>
89 using alloc_traits = stl::allocator_traits<Allocator>;
90 static_assert(stl::is_same_v<typename alloc_traits::value_type, stl::size_t>, "Invalid value type");
91 using container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
92
93public:
95 using allocator_type = Allocator;
97 using size_type = stl::size_t;
101 using edge_type = stl::pair<vertex_type, vertex_type>;
105 using edge_iterator = internal::edge_iterator<typename container_type::const_iterator>;
111 using graph_category = Category;
112
114 adjacency_matrix() noexcept(noexcept(allocator_type{}))
115 : adjacency_matrix{0u} {
116 }
117
122 explicit adjacency_matrix(const allocator_type &allocator) noexcept
123 : adjacency_matrix{0u, allocator} {}
124
132 : matrix{vertices * vertices, allocator},
133 vert{vertices} {}
134
137
143 adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator)
144 : matrix{other.matrix, allocator},
145 vert{other.vert} {}
146
148 adjacency_matrix(adjacency_matrix &&) noexcept = default;
149
156 : matrix{stl::move(other.matrix), allocator},
157 vert{other.vert} {}
158
160 ~adjacency_matrix() = default;
161
167
173
178 void swap(adjacency_matrix &other) noexcept {
179 using stl::swap;
180 swap(matrix, other.matrix);
181 swap(vert, other.vert);
182 }
183
188 [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
189 return matrix.get_allocator();
190 }
191
193 void clear() noexcept {
194 matrix.clear();
195 vert = {};
196 }
197
206 [[nodiscard]] bool empty() const noexcept {
207 const auto iterable = edges();
208 return (iterable.begin() == iterable.end());
209 }
210
215 [[nodiscard]] size_type size() const noexcept {
216 return vert;
217 }
218
223 [[nodiscard]] iterable_adaptor<vertex_iterator> vertices() const noexcept {
224 return {0u, vert};
225 }
226
231 [[nodiscard]] iterable_adaptor<edge_iterator> edges() const noexcept {
232 const auto it = matrix.cbegin();
233 const auto sz = matrix.size();
234 return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}};
235 }
236
242 [[nodiscard]] iterable_adaptor<out_edge_iterator> out_edges(const vertex_type vertex) const noexcept {
243 const auto it = matrix.cbegin();
244 const auto from = vertex * vert;
245 const auto to = from + vert;
246 return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}};
247 }
248
254 [[nodiscard]] iterable_adaptor<in_edge_iterator> in_edges(const vertex_type vertex) const noexcept {
255 const auto it = matrix.cbegin();
256 const auto from = vertex;
257 const auto to = vert * vert + from;
258 return {{it, vert, from, to, vert}, {it, vert, to, to, vert}};
259 }
260
267
268 for(auto [lhs, rhs]: edges()) {
269 other.insert(lhs, rhs);
270 }
271
272 other.swap(*this);
273 }
274
283 stl::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
284 const auto pos = lhs * vert + rhs;
285
286 if constexpr(stl::is_same_v<graph_category, undirected_tag>) {
287 const auto rev = rhs * vert + lhs;
288 ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
289 matrix[rev] = 1u;
290 }
291
292 const auto inserted = !stl::exchange(matrix[pos], 1u);
293 return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted};
294 }
295
302 size_type erase(const vertex_type lhs, const vertex_type rhs) {
303 const auto pos = lhs * vert + rhs;
304
305 if constexpr(stl::is_same_v<graph_category, undirected_tag>) {
306 const auto rev = rhs * vert + lhs;
307 ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
308 matrix[rev] = 0u;
309 }
310
311 return stl::exchange(matrix[pos], 0u);
312 }
313
320 [[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const {
321 const auto pos = lhs * vert + rhs;
322 return pos < matrix.size() && matrix[pos];
323 }
324
325private:
326 container_type matrix;
327 size_type vert;
328};
329
330} // namespace entt
331
332#endif
Basic implementation of a directed adjacency matrix.
adjacency_matrix(const adjacency_matrix &)=default
Default copy constructor.
iota_iterator< vertex_type > vertex_iterator
Vertex iterator type.
adjacency_matrix() noexcept(noexcept(allocator_type{}))
Default constructor.
Category graph_category
Graph category tag.
bool empty() const noexcept
Returns true if an adjacency matrix is empty, false otherwise.
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.
stl::pair< vertex_type, vertex_type > edge_type
Edge type.
size_type size() const noexcept
Returns the number of vertices.
Allocator allocator_type
Allocator type.
adjacency_matrix & operator=(adjacency_matrix &&) noexcept=default
Default move assignment operator.
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.
~adjacency_matrix()=default
Default destructor.
adjacency_matrix & operator=(const adjacency_matrix &)=default
Default copy assignment operator.
iterable_adaptor< edge_iterator > edges() const noexcept
Returns an iterable object to visit all edges of a matrix.
stl::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.
stl::size_t size_type
Unsigned integer type.
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(const adjacency_matrix &other, const allocator_type &allocator)
Allocator-extended copy constructor.
adjacency_matrix(adjacency_matrix &&) noexcept=default
Default 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.
EnTT default namespace.
Definition dense_map.hpp:25
Plain iota iterator (waiting for C++20).
Definition iterator.hpp:58
Utility class to create an iterable object from a pair of iterators.
Definition iterator.hpp:125