tetl 0.1.0
Embedded Template Library
Loading...
Searching...
No Matches
flat_set.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSL-1.0
2// SPDX-FileCopyrightText: Copyright (C) 2021 Tobias Hienzsch
3
4#ifndef TETL_FLAT_SET_FLAT_SET_HPP
5#define TETL_FLAT_SET_FLAT_SET_HPP
6
7#include <etl/_config/all.hpp>
8
9#include <etl/_algorithm/equal.hpp>
10#include <etl/_algorithm/equal_range.hpp>
11#include <etl/_algorithm/lexicographical_compare.hpp>
12#include <etl/_algorithm/lower_bound.hpp>
13#include <etl/_algorithm/remove.hpp>
14#include <etl/_algorithm/remove_if.hpp>
15#include <etl/_algorithm/upper_bound.hpp>
16#include <etl/_concepts/emulation.hpp>
17#include <etl/_cstddef/size_t.hpp>
18#include <etl/_flat_set/sorted_unique.hpp>
19#include <etl/_functional/is_transparent.hpp>
20#include <etl/_functional/less.hpp>
21#include <etl/_functional/reference_wrapper.hpp>
22#include <etl/_iterator/begin.hpp>
23#include <etl/_iterator/data.hpp>
24#include <etl/_iterator/distance.hpp>
25#include <etl/_iterator/end.hpp>
26#include <etl/_iterator/rbegin.hpp>
27#include <etl/_iterator/rend.hpp>
28#include <etl/_iterator/reverse_iterator.hpp>
29#include <etl/_iterator/size.hpp>
30#include <etl/_type_traits/is_nothrow_swappable.hpp>
31#include <etl/_utility/forward.hpp>
32#include <etl/_utility/move.hpp>
33#include <etl/_utility/pair.hpp>
34
35namespace etl {
36
37/// \brief A flat_set is a container adaptor that provides an associative
38/// container interface that supports unique keys (contains at most one of each
39/// key value) and provides for fast retrieval of the keys themselves. flat_set
40/// supports random access iterators. Any sequence container supporting random
41/// access iteration can be used to instantiate flat_set
42///
43/// \details A flat_set satisfies all of the requirements of a container and of
44/// a reversible container. flat_set satisfies the requirements of an
45/// associative container, except that:
46///
47/// - it does not meet the requirements related to node handles,
48/// - it does not meet the requirements related to iterator invalidation, and
49/// - the time complexity of the insert, emplace, emplace_hint, and erase
50/// members that respectively insert, emplace or erase a single element from the
51/// set is linear, including the ones that take an insertion position iterator.
52///
53/// - https://isocpp.org/files/papers/P1222R1.pdf
54/// - https://youtu.be/b9ZYM0d6htg
55///
56/// \headerfile etl/flat_set.hpp
57/// \ingroup flat_set
58template <typename Key, typename Container, typename Compare = etl::less<Key>>
59struct flat_set {
60 using key_type = Key;
61 using key_compare = Compare;
62 using value_type = Key;
63 using value_compare = Compare;
64 using reference = value_type&;
65 using const_reference = value_type const&;
66 using size_type = typename Container::size_type;
67 using difference_type = typename Container::difference_type;
68 using iterator = typename Container::iterator;
69 using const_iterator = typename Container::const_iterator;
70 using reverse_iterator = etl::reverse_iterator<iterator>;
71 using const_reverse_iterator = etl::reverse_iterator<const_iterator>;
72 using container_type = Container;
73
74 constexpr flat_set()
75 : flat_set{Compare{}}
76 {
77 }
78
79 /// \brief Initializes c with etl::move(cont), value-initializes compare,
80 /// sorts the range [begin(),end()) with respect to compare, and finally
81 /// erases the range [ranges::unique(*this, compare), end());
82 ///
83 /// Complexity: Linear in N if cont is sorted with respect to compare and
84 /// otherwise N log N, where N is cont.size().
85 explicit constexpr flat_set(container_type const& container)
86 requires(detail::RandomAccessRange<container_type>)
87 : flat_set{etl::begin(container), etl::end(container), Compare()}
88 {
89 }
90
91 constexpr flat_set(etl::sorted_unique_t /*tag*/, container_type cont)
92 : _container{etl::move(cont)}
93 , _compare{Compare()}
94 {
95 }
96
97 explicit constexpr flat_set(Compare const& comp)
98 : _container{}
99 , _compare(comp)
100 {
101 }
102
103 template <typename InputIt>
104 constexpr flat_set(InputIt first, InputIt last, Compare const& comp = Compare())
105 : _container{}
106 , _compare(comp)
107 {
108 insert(first, last);
109 }
110
111 template <typename InputIt>
112 constexpr flat_set(etl::sorted_unique_t /*tag*/, InputIt first, InputIt last, Compare const& comp = Compare())
113 : _container(first, last)
114 , _compare(comp)
115 {
116 }
117
118 [[nodiscard]] constexpr auto begin() noexcept -> iterator
119 {
120 return _container.begin();
121 }
122 [[nodiscard]] constexpr auto begin() const noexcept -> const_iterator
123 {
124 return _container.begin();
125 }
126 [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator
127 {
128 return _container.begin();
129 }
130
131 [[nodiscard]] constexpr auto end() noexcept -> iterator
132 {
133 return _container.end();
134 }
135 [[nodiscard]] constexpr auto end() const noexcept -> const_iterator
136 {
137 return _container.end();
138 }
139 [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator
140 {
141 return _container.end();
142 }
143
144 [[nodiscard]] constexpr auto rbegin() noexcept -> reverse_iterator
145 {
146 return _container.rbegin();
147 }
148 [[nodiscard]] constexpr auto rbegin() const noexcept -> const_reverse_iterator
149 {
150 return _container.rbegin();
151 }
152 [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator
153 {
154 return _container.crbegin();
155 }
156
157 [[nodiscard]] constexpr auto rend() noexcept -> reverse_iterator
158 {
159 return _container.rend();
160 }
161 [[nodiscard]] constexpr auto rend() const noexcept -> const_reverse_iterator
162 {
163 return _container.rend();
164 }
165 [[nodiscard]] constexpr auto crend() const noexcept -> const_reverse_iterator
166 {
167 return _container.crend();
168 }
169
170 /// \brief Returns true if the underlying container is empty.
171 [[nodiscard]] constexpr auto empty() const noexcept -> bool
172 {
173 return _container.empty();
174 }
175
176 /// \brief Returns the size of the underlying container.
177 [[nodiscard]] constexpr auto size() const noexcept -> size_type
178 {
179 return _container.size();
180 }
181
182 /// \brief Returns the max_size of the underlying container.
183 [[nodiscard]] constexpr auto max_size() const noexcept -> size_type
184 {
185 return _container.max_size();
186 }
187
188 // 21.6.5.3, modifiers
189 template <typename... Args>
190 constexpr auto emplace(Args&&... args) -> etl::pair<iterator, bool>
191 {
192 auto key = Key{etl::forward<Args>(args)...};
193 iterator it = lower_bound(key);
194
195 if (it == end() or _compare(key, *it)) {
196 it = _container.emplace(it, etl::move(key));
197 return etl::make_pair(it, true);
198 }
199
200 return etl::make_pair(it, false);
201 }
202
203 template <typename... Args>
204 constexpr auto emplace_hint(const_iterator /*position*/, Args&&... args) -> iterator
205 {
206 return emplace(etl::forward<Args>(args)...).first;
207 }
208
209 constexpr auto insert(value_type const& x) -> etl::pair<iterator, bool>
210 {
211 return emplace(x);
212 }
213
214 constexpr auto insert(value_type&& x) -> etl::pair<iterator, bool>
215 {
216 return emplace(etl::move(x));
217 }
218
219 constexpr auto insert(const_iterator position, value_type const& x) -> iterator
220 {
221 return emplace_hint(position, x);
222 }
223
224 constexpr auto insert(const_iterator position, value_type&& x) -> iterator
225 {
226 return emplace_hint(position, etl::move(x));
227 }
228
229 template <typename InputIt>
230 constexpr auto insert(InputIt first, InputIt last) -> void
231 {
232 while (first != last) {
233 insert(*first);
234 ++first;
235 }
236 }
237
238 template <typename InputIt>
239 constexpr auto insert(etl::sorted_unique_t /*tag*/, InputIt first, InputIt last) -> void;
240
241 constexpr auto extract() && -> container_type
242 {
243 auto&& container = etl::move(_container);
244 clear();
245 return container;
246 }
247
248 constexpr auto replace(container_type&& container) -> void
249 {
250 _container = etl::move(container);
251 }
252
253 constexpr auto erase(iterator position) -> iterator
254 {
255 return _container.erase(position);
256 }
257
258 constexpr auto erase(const_iterator position) -> iterator
259 {
260 return _container.erase(position);
261 }
262
263 constexpr auto erase(key_type const& key) -> size_type
264 {
265 auto const it = etl::remove(begin(), end(), key);
266 auto const r = static_cast<size_type>(etl::distance(it, end()));
267 erase(it, end());
268 return r;
269 }
270
271 constexpr auto erase(const_iterator first, const_iterator last) -> iterator
272 {
273 return _container.erase(first, last);
274 }
275
276 constexpr auto
278 -> void
279 {
280 using etl::swap;
281 swap(_compare, other._compare);
282 swap(_container, other._container);
283 }
284
285 constexpr auto clear() noexcept -> void
286 {
287 _container.clear();
288 }
289
290 // observers
291 [[nodiscard]] constexpr auto key_comp() const -> key_compare
292 {
293 return _compare;
294 }
295
296 [[nodiscard]] constexpr auto value_comp() const -> value_compare
297 {
298 return _compare;
299 }
300
301 // set operations
302 [[nodiscard]] constexpr auto find(key_type const& key) -> iterator
303 {
304 auto const it = lower_bound(key);
305 if (it == end() or _compare(key, *it)) {
306 return end();
307 }
308 return it;
309 }
310
311 [[nodiscard]] constexpr auto find(key_type const& key) const -> const_iterator
312 {
313 auto const it = lower_bound(key);
314 if (it == end() or _compare(key, *it)) {
315 return end();
316 }
317 return it;
318 }
319
320 template <typename K>
321 requires etl::detail::is_transparent_v<Compare>
322 [[nodiscard]] constexpr auto find(K const& key) -> iterator
323 {
324 auto const it = lower_bound(key);
325 if (it == end() or _compare(key, *it)) {
326 return end();
327 }
328 return it;
329 }
330
331 template <typename K>
332 requires etl::detail::is_transparent_v<Compare>
333 [[nodiscard]] constexpr auto find(K const& key) const -> const_iterator
334 {
335 auto const it = lower_bound(key);
336 if (it == end() or _compare(key, *it)) {
337 return end();
338 }
339 return it;
340 }
341
342 [[nodiscard]] constexpr auto count(key_type const& key) const -> size_type
343 {
344 return find(key) == end() ? 0 : 1;
345 }
346
347 template <typename K>
348 requires etl::detail::is_transparent_v<Compare>
349 [[nodiscard]] constexpr auto count(K const& key) const -> size_type
350 {
351 return find(key) == end() ? 0 : 1;
352 }
353
354 [[nodiscard]] constexpr auto contains(key_type const& key) const -> bool
355 {
356 return count(key) == 1;
357 }
358
359 template <typename K>
360 requires etl::detail::is_transparent_v<Compare>
361 [[nodiscard]] constexpr auto contains(K const& key) const -> bool
362 {
363 return count(key) == 1;
364 }
365
366 [[nodiscard]] constexpr auto lower_bound(key_type const& key) -> iterator
367 {
368 return etl::lower_bound(begin(), end(), key, etl::ref(_compare));
369 }
370
371 [[nodiscard]] constexpr auto lower_bound(key_type const& key) const -> const_iterator
372 {
373 return etl::lower_bound(begin(), end(), key, etl::ref(_compare));
374 }
375
376 template <typename K>
377 requires etl::detail::is_transparent_v<Compare>
378 [[nodiscard]] constexpr auto lower_bound(K const& key) -> iterator
379 {
380 return etl::lower_bound(begin(), end(), key, etl::ref(_compare));
381 }
382
383 template <typename K>
384 requires etl::detail::is_transparent_v<Compare>
385 [[nodiscard]] constexpr auto lower_bound(K const& key) const -> const_iterator
386 {
387 return etl::lower_bound(begin(), end(), key, etl::ref(_compare));
388 }
389
390 [[nodiscard]] constexpr auto upper_bound(key_type const& key) -> iterator
391 {
392 return etl::upper_bound(begin(), end(), key, etl::ref(_compare));
393 }
394
395 [[nodiscard]] constexpr auto upper_bound(key_type const& key) const -> const_iterator
396 {
397 return etl::upper_bound(begin(), end(), key, etl::ref(_compare));
398 }
399
400 template <typename K>
401 requires etl::detail::is_transparent_v<Compare>
402 [[nodiscard]] constexpr auto upper_bound(K const& key) -> iterator
403 {
404 return etl::upper_bound(begin(), end(), key, etl::ref(_compare));
405 }
406
407 template <typename K>
408 requires etl::detail::is_transparent_v<Compare>
409 [[nodiscard]] constexpr auto upper_bound(K const& key) const -> const_iterator
410 {
411 return etl::upper_bound(begin(), end(), key, etl::ref(_compare));
412 }
413
414 [[nodiscard]] constexpr auto equal_range(key_type const& key) -> etl::pair<iterator, iterator>
415 {
416 return etl::equal_range(begin(), end(), key, etl::ref(_compare));
417 }
418
419 [[nodiscard]] constexpr auto equal_range(key_type const& key) const -> etl::pair<const_iterator, const_iterator>
420 {
421 return etl::equal_range(begin(), end(), key, etl::ref(_compare));
422 }
423
424 template <typename K>
425 requires etl::detail::is_transparent_v<Compare>
426 [[nodiscard]] constexpr auto equal_range(K const& key) -> etl::pair<iterator, iterator>
427 {
428 return etl::equal_range(begin(), end(), key, etl::ref(_compare));
429 }
430
431 template <typename K>
432 requires etl::detail::is_transparent_v<Compare>
433 [[nodiscard]] constexpr auto equal_range(K const& key) const -> etl::pair<const_iterator, const_iterator>
434 {
435 return etl::equal_range(begin(), end(), key, etl::ref(_compare));
436 }
437
438 friend constexpr auto operator==(flat_set const& lhs, flat_set const& rhs) -> bool
439 {
440 return etl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
441 }
442
443 friend constexpr auto operator<(flat_set const& lhs, flat_set const& rhs) -> bool
444 {
445 return etl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
446 }
447
448 friend constexpr auto operator>(flat_set const& x, flat_set const& y) -> bool
449 {
450 return y < x;
451 }
452
453 friend constexpr auto operator<=(flat_set const& x, flat_set const& y) -> bool
454 {
455 return !(y < x);
456 }
457
458 friend constexpr auto operator>=(flat_set const& x, flat_set const& y) -> bool
459 {
460 return !(x < y);
461 }
462
463 friend constexpr auto swap(flat_set& x, flat_set& y) noexcept(noexcept(x.swap(y))) -> void
464 {
465 return x.swap(y);
466 }
467
468private:
469 TETL_NO_UNIQUE_ADDRESS container_type _container;
470 TETL_NO_UNIQUE_ADDRESS key_compare _compare;
471};
472
473template <typename Key, typename Container, typename Compare, typename Pred>
474constexpr auto erase_if(etl::flat_set<Key, Container, Compare>& c, Pred pred) ->
475 typename etl::flat_set<Key, Container, Compare>::size_type
476{
477 auto const it = etl::remove_if(c.begin(), c.end(), pred);
478 auto const r = etl::distance(it, c.end());
479 c.erase(it, c.end());
480 return static_cast<typename etl::flat_set<Key, Container, Compare>::size_type>(r);
481}
482
483} // namespace etl
484
485#endif // TETL_FLAT_SET_FLAT_SET_HPP
Definition adjacent_find.hpp:9
constexpr auto erase_if(etl::flat_set< Key, Container, Compare > &c, Pred pred) -> typename etl::flat_set< Key, Container, Compare >::size_type
Definition flat_set.hpp:474
A flat_set is a container adaptor that provides an associative container interface that supports uniq...
Definition flat_set.hpp:59
constexpr auto erase(key_type const &key) -> size_type
Definition flat_set.hpp:263
constexpr auto lower_bound(K const &key) const -> const_iterator
Definition flat_set.hpp:385
constexpr auto upper_bound(K const &key) const -> const_iterator
Definition flat_set.hpp:409
constexpr auto erase(const_iterator first, const_iterator last) -> iterator
Definition flat_set.hpp:271
friend constexpr auto operator==(flat_set const &lhs, flat_set const &rhs) -> bool
Definition flat_set.hpp:438
constexpr auto erase(iterator position) -> iterator
Definition flat_set.hpp:253
constexpr auto insert(value_type &&x) -> etl::pair< iterator, bool >
Definition flat_set.hpp:214
constexpr auto find(key_type const &key) const -> const_iterator
Definition flat_set.hpp:311
constexpr auto crbegin() const noexcept -> const_reverse_iterator
Definition flat_set.hpp:152
constexpr auto insert(InputIt first, InputIt last) -> void
Definition flat_set.hpp:230
constexpr auto upper_bound(K const &key) -> iterator
Definition flat_set.hpp:402
constexpr auto upper_bound(key_type const &key) -> iterator
Definition flat_set.hpp:390
constexpr auto contains(key_type const &key) const -> bool
Definition flat_set.hpp:354
constexpr auto rbegin() const noexcept -> const_reverse_iterator
Definition flat_set.hpp:148
constexpr auto contains(K const &key) const -> bool
Definition flat_set.hpp:361
friend constexpr auto operator<=(flat_set const &x, flat_set const &y) -> bool
Definition flat_set.hpp:453
constexpr auto lower_bound(key_type const &key) -> iterator
Definition flat_set.hpp:366
friend constexpr auto operator>(flat_set const &x, flat_set const &y) -> bool
Definition flat_set.hpp:448
constexpr auto equal_range(key_type const &key) -> etl::pair< iterator, iterator >
Definition flat_set.hpp:414
constexpr auto insert(value_type const &x) -> etl::pair< iterator, bool >
Definition flat_set.hpp:209
constexpr auto lower_bound(key_type const &key) const -> const_iterator
Definition flat_set.hpp:371
constexpr auto rend() noexcept -> reverse_iterator
Definition flat_set.hpp:157
constexpr auto begin() noexcept -> iterator
Definition flat_set.hpp:118
constexpr flat_set(etl::sorted_unique_t, container_type cont)
Definition flat_set.hpp:91
constexpr auto end() noexcept -> iterator
Definition flat_set.hpp:131
constexpr auto begin() const noexcept -> const_iterator
Definition flat_set.hpp:122
constexpr auto replace(container_type &&container) -> void
Definition flat_set.hpp:248
constexpr auto cbegin() const noexcept -> const_iterator
Definition flat_set.hpp:126
constexpr auto count(K const &key) const -> size_type
Definition flat_set.hpp:349
constexpr auto find(key_type const &key) -> iterator
Definition flat_set.hpp:302
friend constexpr auto operator<(flat_set const &lhs, flat_set const &rhs) -> bool
Definition flat_set.hpp:443
constexpr flat_set(InputIt first, InputIt last, Compare const &comp=Compare())
Definition flat_set.hpp:104
constexpr auto empty() const noexcept -> bool
Returns true if the underlying container is empty.
Definition flat_set.hpp:171
constexpr auto clear() noexcept -> void
Definition flat_set.hpp:285
constexpr auto lower_bound(K const &key) -> iterator
Definition flat_set.hpp:378
constexpr auto value_comp() const -> value_compare
Definition flat_set.hpp:296
constexpr flat_set(etl::sorted_unique_t, InputIt first, InputIt last, Compare const &comp=Compare())
Definition flat_set.hpp:112
constexpr auto swap(flat_set &other) noexcept(etl::is_nothrow_swappable_v< Container > &&etl::is_nothrow_swappable_v< Compare >) -> void
Definition flat_set.hpp:277
constexpr auto equal_range(key_type const &key) const -> etl::pair< const_iterator, const_iterator >
Definition flat_set.hpp:419
constexpr flat_set(Compare const &comp)
Definition flat_set.hpp:97
constexpr auto max_size() const noexcept -> size_type
Returns the max_size of the underlying container.
Definition flat_set.hpp:183
constexpr auto key_comp() const -> key_compare
Definition flat_set.hpp:291
friend constexpr auto swap(flat_set &x, flat_set &y) noexcept(noexcept(x.swap(y))) -> void
Definition flat_set.hpp:463
constexpr auto find(K const &key) const -> const_iterator
Definition flat_set.hpp:333
constexpr auto end() const noexcept -> const_iterator
Definition flat_set.hpp:135
constexpr auto emplace(Args &&... args) -> etl::pair< iterator, bool >
Definition flat_set.hpp:190
constexpr auto count(key_type const &key) const -> size_type
Definition flat_set.hpp:342
constexpr auto crend() const noexcept -> const_reverse_iterator
Definition flat_set.hpp:165
constexpr auto equal_range(K const &key) -> etl::pair< iterator, iterator >
Definition flat_set.hpp:426
constexpr auto insert(const_iterator position, value_type const &x) -> iterator
Definition flat_set.hpp:219
constexpr auto extract() &&-> container_type
Definition flat_set.hpp:241
constexpr auto upper_bound(key_type const &key) const -> const_iterator
Definition flat_set.hpp:395
constexpr auto rend() const noexcept -> const_reverse_iterator
Definition flat_set.hpp:161
constexpr auto equal_range(K const &key) const -> etl::pair< const_iterator, const_iterator >
Definition flat_set.hpp:433
friend constexpr auto operator>=(flat_set const &x, flat_set const &y) -> bool
Definition flat_set.hpp:458
constexpr auto erase(const_iterator position) -> iterator
Definition flat_set.hpp:258
constexpr auto size() const noexcept -> size_type
Returns the size of the underlying container.
Definition flat_set.hpp:177
constexpr auto cend() const noexcept -> const_iterator
Definition flat_set.hpp:139
constexpr auto find(K const &key) -> iterator
Definition flat_set.hpp:322
constexpr auto insert(const_iterator position, value_type &&x) -> iterator
Definition flat_set.hpp:224
constexpr auto emplace_hint(const_iterator, Args &&... args) -> iterator
Definition flat_set.hpp:204
constexpr auto rbegin() noexcept -> reverse_iterator
Definition flat_set.hpp:144
constexpr flat_set(container_type const &container)
Initializes c with etl::move(cont), value-initializes compare, sorts the range [begin(),...
Definition flat_set.hpp:85
constexpr auto insert(etl::sorted_unique_t, InputIt first, InputIt last) -> void
constexpr flat_set()
Definition flat_set.hpp:74
Function object for performing comparisons. Unless specialised, invokes operator< on type T....
Definition less.hpp:15
etl::pair is a class template that provides a way to store two heterogeneous objects as a single unit...
Definition pair.hpp:37
Definition sorted_unique.hpp:9