Sequoia
Loading...
Searching...
No Matches
NodeStorage.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2018. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
22
23#include <type_traits>
24#include <algorithm>
25
26namespace sequoia::maths
27{
28 //===================================Storage for the list of nodes===================================//
29
30 template<class T>
31 inline constexpr bool has_get_allocator{
32 requires(const T& t) { t.get_allocator(); }
33 };
34
35 template<class Weight, class Container>
37 {
38 public:
39 using weight_type = Weight;
40 using node_weight_container_type = Container;
41 using size_type = typename node_weight_container_type::size_type;
42
43 using iterator = typename node_weight_container_type::iterator;
44 using reverse_iterator = typename node_weight_container_type::reverse_iterator;
45 using node_weights_range = std::ranges::subrange<iterator>;
46
47 using const_iterator = typename node_weight_container_type::const_iterator;
48 using const_reverse_iterator = typename node_weight_container_type::const_reverse_iterator;
49 using const_node_weights_range = std::ranges::subrange<const_iterator>;
50
51 [[nodiscard]]
52 constexpr auto size() const noexcept { return m_NodeWeights.size(); }
53
54 [[nodiscard]]
55 constexpr iterator begin_node_weights() noexcept
56 requires std::indirectly_writable<iterator, std::iter_value_t<iterator>>
57 {
58 return m_NodeWeights.begin();
59 }
60
61 [[nodiscard]]
62 constexpr reverse_iterator rbegin_node_weights() noexcept
63 requires std::indirectly_writable<iterator, std::iter_value_t<iterator>>
64 {
65 return m_NodeWeights.rbegin();
66 }
67
68 [[nodiscard]]
69 constexpr const_iterator cbegin_node_weights() const noexcept
70 {
71 return m_NodeWeights.cbegin();
72 }
73
74 [[nodiscard]]
75 constexpr const_reverse_iterator crbegin_node_weights() const noexcept
76 {
77 return m_NodeWeights.crbegin();
78 }
79
80 [[nodiscard]]
81 constexpr iterator end_node_weights() noexcept
82 requires std::indirectly_writable<iterator, std::iter_value_t<iterator>>
83 {
84 return m_NodeWeights.end();
85 }
86
87 [[nodiscard]]
88 constexpr reverse_iterator rend_node_weights() noexcept
89 requires std::indirectly_writable<iterator, std::iter_value_t<iterator>>
90 {
91 return m_NodeWeights.rend();
92 }
93
94 [[nodiscard]]
95 constexpr const_iterator cend_node_weights() const noexcept
96 {
97 return m_NodeWeights.cend();
98 }
99
100 [[nodiscard]]
101 constexpr const_reverse_iterator crend_node_weights() const noexcept
102 {
103 return m_NodeWeights.crend();
104 }
105
106 [[nodiscard]]
107 constexpr node_weights_range node_weights() noexcept
108 requires std::indirectly_writable<iterator, std::iter_value_t<iterator>>
109 {
110 return {begin_node_weights(), end_node_weights()};
111 }
112
113 [[nodiscard]]
114 constexpr const_node_weights_range node_weights() const noexcept
115 {
116 return {cbegin_node_weights(), cend_node_weights()};
117 }
118
119 [[nodiscard]]
120 constexpr const_node_weights_range cnode_weights() const noexcept
121 {
122 return node_weights();
123 }
124
125 template<class W>
126 constexpr void set_node_weight(const_iterator pos, W w)
127 {
128 if(pos == cend_node_weights()) throw std::out_of_range("node_storage::set_node_weight - index out of range!\n");
129
130 const auto index{std::ranges::distance(cbegin_node_weights(), pos)};
131 m_NodeWeights[index] = std::move(w);
132 }
133
134 template<class Fn>
135 constexpr decltype(auto) mutate_node_weight(const_iterator pos, Fn fn)
136 {
137 if(pos == cend_node_weights()) throw std::out_of_range("node_storage::mutate_node_weight - index out of range!\n");
138
139 const auto index{std::ranges::distance(cbegin_node_weights(), pos)};
140 return fn(m_NodeWeights[index]);
141 }
142
143 [[nodiscard]]
144 friend constexpr bool operator==(const node_storage_base&, const node_storage_base&) noexcept
146 = default;
147 protected:
148 constexpr node_storage_base() = default;
149
150 constexpr explicit node_storage_base(const size_type n)
151 : m_NodeWeights(n)
152 {}
153
154 template<std::size_t N>
155 constexpr node_storage_base(const std::array<weight_type, N>& weights)
156 : m_NodeWeights{weights}
157 {}
158
159 constexpr node_storage_base(std::initializer_list<weight_type> weights)
160 : m_NodeWeights{weights}
161 {}
162
163 template<alloc Allocator>
164 constexpr explicit node_storage_base(const Allocator& allocator)
165 : m_NodeWeights(allocator)
166 {}
167
168 template<alloc Allocator>
169 constexpr node_storage_base(const size_t n, const Allocator& allocator)
170 : m_NodeWeights(n, allocator)
171 {}
172
173 template<alloc Allocator>
174 constexpr node_storage_base(std::initializer_list<weight_type> weights, const Allocator& allocator)
175 : m_NodeWeights{weights, allocator}
176 {}
177
178 constexpr node_storage_base(const node_storage_base&) = default;
179
180 template<alloc Allocator>
181 constexpr node_storage_base(const node_storage_base& other, const Allocator& allocator)
182 : m_NodeWeights{other.m_NodeWeights, allocator}
183 {}
184
185 constexpr node_storage_base(node_storage_base&&) noexcept = default;
186
187 template<alloc Allocator>
188 constexpr node_storage_base(node_storage_base&& s, const Allocator& allocator) noexcept
189 : m_NodeWeights{std::move(s.m_NodeWeights), allocator}
190 {}
191
192 ~node_storage_base() = default;
193
194 constexpr node_storage_base& operator=(const node_storage_base&) = default;
195 constexpr node_storage_base& operator=(node_storage_base&&) noexcept = default;
196
197 constexpr void swap(node_storage_base& rhs)
198 noexcept(noexcept(std::ranges::swap(this->m_NodeWeights, rhs.m_NodeWeights)))
199 {
200 std::ranges::swap(m_NodeWeights, rhs.m_NodeWeights);
201 }
202
203 // TO DO: consider throwing semantics
204 constexpr void swap_nodes(const size_type i, const size_type j)
205 {
206 if((i >= size()) || (j >= size()))
207 throw std::out_of_range("node_storage::swap - index out of range");
208
209 std::ranges::swap(m_NodeWeights[i], m_NodeWeights[j]);
210 }
211
212 auto get_node_allocator() const
213 requires has_get_allocator<node_weight_container_type>
214 {
215 return m_NodeWeights.get_allocator();
216 }
217
218 void reserve(const size_type newCapacity)
219 {
220 m_NodeWeights.reserve(newCapacity);
221 }
222
223 size_type capacity() const noexcept
224 {
225 return m_NodeWeights.capacity();
226 }
227
228 void shrink_to_fit()
229 {
230 m_NodeWeights.shrink_to_fit();
231 }
232
233 template<class... Args>
234 void add_node(Args&&... args)
235 {
236 m_NodeWeights.emplace_back(std::forward<Args>(args)...);
237 }
238
239 template<class... Args>
240 const_iterator insert_node(const_iterator pos, Args&&... args)
241 {
242 auto iter = m_NodeWeights.emplace(pos, std::forward<Args>(args)...);
243
244 return cbegin_node_weights() + std::ranges::distance(m_NodeWeights.begin(), iter);
245 }
246
247 const_iterator erase_node(const_iterator pos)
248 {
249 if(pos == cend_node_weights()) throw std::out_of_range("Attempting to erase a node which does not exist");
250
251 return const_iterator{m_NodeWeights.erase(pos)};
252 }
253
254 const_iterator erase_nodes(const_iterator first, const_iterator last)
255 {
256 if(first > last) throw std::out_of_range("Attempting to erase a range of nodes with first > last");
257
258 return const_iterator{m_NodeWeights.erase(first, last)};
259 }
260
261 void clear() noexcept
262 {
263 m_NodeWeights.clear();
264 }
265
266 private:
267 node_weight_container_type m_NodeWeights;
268 };
269
270 template<class Weight, class Container = std::vector<Weight>>
271 class node_storage : public node_storage_base<Weight, Container>
272 {
274 public:
275 using size_type = typename base_t::size_type;
276 using weight_type = typename base_t::weight_type;
277
278 using node_storage_base<Weight, Container>::node_storage_base;
279
280 node_storage(const node_storage&) = default;
281
282 node_storage& operator=(const node_storage&) noexcept = default;
283 protected:
284 ~node_storage() = default;
285
286 node_storage(node_storage&&) noexcept = default;
287
288 node_storage& operator=(node_storage&&) noexcept = default;
289
290 template<alloc Allocator>
291 constexpr node_storage(node_storage&& s, const Allocator& allocator) noexcept
292 : base_t{std::move(s), allocator}
293 {}
294 };
295
296 template<class Weight, class Container>
297 requires std::is_empty_v<Weight>
298 class node_storage<Weight, Container>
299 {
300 public:
301 using weight_type = Weight;
302 using size_type = std::size_t;
303
304 constexpr node_storage() noexcept = default;
305
306 constexpr node_storage(const node_storage&) noexcept = default;
307
308 constexpr node_storage& operator=(const node_storage&) noexcept = default;
309
310 [[nodiscard]]
311 constexpr friend bool operator==(const node_storage&, const node_storage&) noexcept = default;
312 protected:
313 constexpr node_storage(node_storage&&) noexcept = default;
314
315 ~node_storage() = default;
316
317 constexpr node_storage& operator=(node_storage&&) noexcept = default;
318
319 void swap(node_storage&) noexcept {};
320 };
321}
Utilities for both edges and nodes.
Implementation for an iterator with policies controlling dereferencing and auxiliary data.
Definition: NodeStorage.hpp:37
Definition: NodeStorage.hpp:272
Concept to work around the fact that currently the stl typically underconstrains operator==.
Definition: Concepts.hpp:105