kblib 0.2.3
General utilities library for modern C++
direct_map.h
Go to the documentation of this file.
1/* *****************************************************************************
2 * kblib is a general utility library for C++14 and C++17, intended to provide
3 * performant high-level abstractions and more expressive ways to do simple
4 * things.
5 *
6 * Copyright (c) 2021 killerbee
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * ****************************************************************************/
21
31#ifndef DIRECT_MAP_H
32#define DIRECT_MAP_H
33
34#include <kblib/fakestd.h>
35#include <kblib/iterators.h>
36#include <kblib/tdecl.h>
37
38#include <array>
39#include <bitset>
40#include <cinttypes>
41#include <climits>
42#include <limits>
43#include <new>
44#include <optional>
45
46namespace kblib {
47
53
54 template <typename T>
56 = (std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed
57 < std::numeric_limits<std::uintmax_t>::digits)
58 ? static_cast<std::uintmax_t>(1)
59 << to_unsigned(std::numeric_limits<T>::digits
60 + std::numeric_limits<T>::is_signed)
61 : 0;
62 static_assert(range_of<unsigned char> == 1u << to_unsigned(CHAR_BIT), "");
63 static_assert(range_of<signed char> == 1u << to_unsigned(CHAR_BIT), "");
64
65 template <typename T, bool
66 = std::is_trivially_default_constructible<T>::value and
67 std::is_trivially_destructible<T>::value>
68 struct alignas(T) storage_for : private std::array<byte, sizeof(T)> {
69 template <
70 typename... Args,
71 enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
72 constexpr auto construct(Args&&... args) noexcept(
73 std::is_nothrow_constructible<T, Args&&...>::value) -> T& {
74 return *new (this->data()) T(std::forward<Args>(args)...);
75 }
76 storage_for() = default;
77 storage_for(const storage_for&) = delete;
79
80 auto operator=(const storage_for&) -> storage_for& = delete;
81 auto operator=(storage_for&&) -> storage_for& = delete;
82
83 ~storage_for() = default;
84
85 constexpr auto destroy() noexcept -> void { get()->~T(); }
86
87#if __cpp_lib_launder
88# define LAUNDER(x) std::launder(x)
89#else
90# define LAUNDER(x) (x)
91#endif
92 KBLIB_NODISCARD constexpr auto get() & noexcept -> T* {
93 return LAUNDER(reinterpret_cast<T*>(this->data()));
94 }
95 KBLIB_NODISCARD constexpr auto get() const& noexcept -> const T* {
96 return LAUNDER(reinterpret_cast<const T*>(this->data()));
97 }
98#undef LAUNDER
99 };
100 template <typename T>
101 struct alignas(T) storage_for<T, true> {
102 private:
103 T t;
104
105 public:
106 template <
107 typename... Args,
108 enable_if_t<std::is_constructible<T, Args&&...>::value, int> = 0>
109 constexpr auto construct(Args&&... args) noexcept(
110 std::is_nothrow_constructible<T, Args&&...>::value) -> T& {
111 return *new (&t) T(std::forward<Args>(args)...);
112 }
113
114 constexpr auto destroy() noexcept -> void {}
115
116 KBLIB_NODISCARD constexpr auto get() & noexcept -> T* { return &t; }
117 KBLIB_NODISCARD constexpr auto get() const& noexcept -> const T* {
118 return &t;
119 }
120 };
121
122} // namespace detail_direct_map
123
124template <typename Key, typename T, typename allocator = void>
126 // Allocating direct_map
127 public:
128 using key_type = Key;
129 using mapped_type = T;
130 using value_type = std::pair<const Key, T>;
131 using size_type = std::size_t;
132 using difference_type = std::ptrdiff_t;
133
137 using const_pointer = const value_type*;
138
139 private:
140 constexpr static std::ptrdiff_t key_range{detail_direct_map::range_of<Key>};
142
143 using held_type
144 = std::pair<std::bitset<key_range>, std::array<storage_type, key_range>>;
145
146 template <typename V>
147 class iter {
148 public:
150 std::ptrdiff_t pos;
151
152 using value_type = typename direct_map::value_type;
153 using difference_type = typename direct_map::difference_type;
154 using reference = copy_const_t<V, value_type>&;
155 using pointer = copy_const_t<V, value_type>*;
156 using iterator_category = std::bidirectional_iterator_tag;
157
158 KBLIB_NODISCARD constexpr auto operator*() const noexcept -> reference {
159 return *storage->second[kblib::to_unsigned(pos)].get();
160 }
161 KBLIB_NODISCARD constexpr auto operator->() const noexcept -> pointer {
162 return storage->second[kblib::to_unsigned(pos)].get();
163 }
164
165 constexpr auto operator++() noexcept -> iter& {
166 if (pos == key_range) {
167 // not required in general, but direct_map::iterator guarantees that
168 // ++end() == end() because it simplifies the implementation and is
169 // unlikely to be a significant performance impact
170 return *this;
171 }
172 for (auto i : range(++pos, key_range)) {
173 if (storage->first.test(kblib::to_unsigned(i))) {
174 pos = i;
175 return *this;
176 }
177 }
178 pos = key_range;
179 return *this;
180 }
181 constexpr auto operator++(int) noexcept -> iter {
182 iter it = *this;
183 ++*this;
184 return it;
185 }
186
187 constexpr auto operator--() noexcept -> iter& {
188 for (auto i : range(pos - 1, std::ptrdiff_t(-1))) {
189 if (storage->first.test(kblib::to_unsigned(i))) {
190 pos = i;
191 return *this;
192 }
193 }
194 // going past the beginning is UB
195 __builtin_unreachable();
196 }
197 constexpr auto operator--(int) noexcept -> iter {
198 iter it = *this;
199 --*this;
200 return it;
201 }
202
203 KBLIB_NODISCARD friend constexpr auto operator==(iter l, iter r) noexcept
204 -> bool {
205 return l.storage == r.storage and l.pos == r.pos;
206 }
207 KBLIB_NODISCARD friend constexpr auto operator!=(iter l, iter r) noexcept
208 -> bool {
209 return not (l == r);
210 }
211#define DECL_OP(op) \
212 KBLIB_NODISCARD friend constexpr auto operator op(iter l, \
213 iter r) noexcept->bool { \
214 assert(l.storage == r.storage); \
215 return l.pos op r.pos; \
216 }
217 DECL_OP(<)
218 DECL_OP(>)
219 DECL_OP(>=)
220 DECL_OP(<=)
221#undef DECL_OP
222
223 constexpr auto swap(iter& other) noexcept -> void {
224 kblib::swap(storage, other.storage);
225 kblib::swap(pos, other.pos);
226 }
227 };
228
229 public:
230 using iterator = iter<value_type>;
231 using const_iterator = iter<const value_type>;
232 using reverse_iterator = std::reverse_iterator<iterator>;
233 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
234
235 constexpr direct_map() noexcept = default;
236
237 template <typename InputIt>
238 constexpr direct_map(InputIt first, InputIt last)
239 : storage(in_place_agg) {
240 for (auto v : indirect(first, last)) {
241 construct(v.first, v.second);
242 }
243 }
244 // TODO(killerbee13): copy construction for allocating direct_map
245 constexpr direct_map(const direct_map& other)
246 : storage(in_place_agg, other.storage->first)
247 , _size(other._size) {
248 for (auto k : range(+min(), max() + 1)) {
249 if (contains(k)) { // the bitmap is already copied from other
250 do_construct(k, other.at(k));
251 ++_size;
252 }
253 }
254 }
255
256 constexpr direct_map(direct_map&& other) noexcept
257 : storage(std::move(other.storage))
258 , _size(std::exchange(other._size, 0)) {}
259
260 constexpr direct_map(std::initializer_list<value_type> init)
261 : direct_map(init.begin(), init.end()) {}
262
266 KBLIB_CXX20(constexpr) ~direct_map() { clear(); }
267
268 constexpr auto operator=(const direct_map& other) -> direct_map& {
269 if (this == &other) {
270 return *this;
271 }
272 clear();
273 storage.assign(in_place_agg, other.storage->first);
274 for (auto k : range(+min(), max() + 1)) {
275 if (contains(k)) { // the bitmap is already copied from other
276 do_construct(k, other.at(k));
277 ++_size;
278 bitmap().set(index(k));
279 }
280 }
281 return *this;
282 }
283 constexpr auto operator=(direct_map&& other) noexcept
284 -> direct_map& = default;
285 constexpr auto operator=(std::initializer_list<value_type> init)
286 -> direct_map& {
287 clear();
288 for (auto it : init) {
289 construct(it->first, it->second);
290 }
291 return *this;
292 }
293
294 KBLIB_NODISCARD constexpr auto at(Key key) & -> T& {
295 if (contains(key)) {
296 return unsafe_at(key).get()->second;
297 } else {
298 throw std::out_of_range("direct_map: key out of range");
299 }
300 }
301 KBLIB_NODISCARD constexpr auto at(Key key) && -> T&& {
302 if (contains(key)) {
303 return std::move(unsafe_at(key).get()->second);
304 } else {
305 throw std::out_of_range("direct_map: key out of range");
306 }
307 }
308 KBLIB_NODISCARD constexpr auto at(Key key) const& -> const T& {
309 if (contains(key)) {
310 return unsafe_at(key).get()->second;
311 } else {
312 throw std::out_of_range("direct_map: key out of range");
313 }
314 }
315 KBLIB_NODISCARD constexpr auto at(Key key) const&& -> const T&& {
316 if (contains(key)) {
317 return std::move(unsafe_at(key).get()->second);
318 } else {
319 throw std::out_of_range("direct_map: key out of range");
320 }
321 }
322
323 KBLIB_NODISCARD constexpr T& operator[](Key key) noexcept(
324 std::is_nothrow_default_constructible<T>::value) {
325 return try_emplace(key).first->second;
326 }
327
328 KBLIB_NODISCARD constexpr auto begin() & noexcept -> iterator {
329 return {storage.get(), cbegin().pos};
330 }
331 KBLIB_NODISCARD constexpr auto begin() const& noexcept -> const_iterator {
332 return {storage.get(), cbegin().pos};
333 }
334 KBLIB_NODISCARD constexpr auto cbegin() const& noexcept -> const_iterator {
335 if (not empty()) {
336 if (contains(to_key(0))) {
337 return {storage.get(), 0};
338 } else {
339 return ++const_iterator{storage.get(), 0};
340 }
341 } else {
342 return {storage.get(), key_range};
343 }
344 }
345
346 KBLIB_NODISCARD constexpr auto end() & noexcept -> iterator {
347 return {storage.get(), key_range};
348 }
349 KBLIB_NODISCARD constexpr auto end() const& noexcept -> const_iterator {
350 return {storage.get(), key_range};
351 }
352 KBLIB_NODISCARD constexpr auto cend() const& noexcept -> const_iterator {
353 return {storage.get(), key_range};
354 }
355
356 KBLIB_NODISCARD constexpr auto rbegin() & noexcept -> auto {
357 return std::make_reverse_iterator(end());
358 }
359 KBLIB_NODISCARD constexpr auto rbegin() const& noexcept -> auto {
360 return std::make_reverse_iterator(end());
361 }
362 KBLIB_NODISCARD constexpr auto crbegin() const& noexcept -> auto {
363 return std::make_reverse_iterator(cend());
364 }
365
366 KBLIB_NODISCARD constexpr auto rend() & noexcept -> auto {
367 return std::make_reverse_iterator(begin());
368 }
369 KBLIB_NODISCARD constexpr auto rend() const& noexcept -> auto {
370 return std::make_reverse_iterator(begin());
371 }
372 KBLIB_NODISCARD constexpr auto crend() const& noexcept -> auto {
373 return std::make_reverse_iterator(cbegin());
374 }
375
376 KBLIB_NODISCARD constexpr auto empty() const& noexcept -> bool {
377 return _size == 0;
378 }
379
380 KBLIB_NODISCARD constexpr auto size() const& noexcept -> std::size_t {
381 return _size;
382 }
383 KBLIB_NODISCARD constexpr auto ssize() const& noexcept -> std::ptrdiff_t {
384 return _size;
385 }
386
387 KBLIB_NODISCARD constexpr static auto max_size() noexcept -> std::size_t {
388 return key_range;
389 }
390
391 constexpr auto clear() noexcept -> void {
392 for (auto i : range(+min(), max() + 1)) {
393 auto j = static_cast<Key>(i);
394 if (contains(j)) {
395 unsafe_at(j).destroy();
396 }
397 }
398 storage.reset();
399 _size = 0;
400 }
401
402 constexpr auto insert(const value_type& value) -> std::pair<iterator, bool> {
403 if (not contains(value.first)) {
404 construct(value.first, value.second);
405 return {{storage.get(), index(value.first)}, true};
406 } else {
407 return {{storage.get(), index(value.first)}, false};
408 }
409 }
410 template <typename U>
411 constexpr auto insert(U&& value)
413 std::pair<iterator, bool>> {
414 if (not contains(value.first)) {
415 construct(value.first, std::forward<U>(value.second));
416 return {{storage.get(), index(value.first)}, true};
417 } else {
418 return {{storage.get(), index(value.first)}, false};
419 }
420 }
421 constexpr auto insert(value_type&& value) -> std::pair<iterator, bool> {
422 if (not contains(value.first)) {
423 construct(value.first, std::move(value.second));
424 return {{storage.get(), index(value.first)}, true};
425 } else {
426 return {{storage.get(), index(value.first)}, false};
427 }
428 }
429
430 template <typename U>
431 constexpr auto insert_or_assign(Key key, U&& value)
432 -> std::pair<iterator, bool> {
433 if (not contains(key)) {
434 construct(key, std::forward<U>(value));
435 return {{storage.get(), index(key)}, true};
436 } else {
437 *unsafe_at(key).get() = std::forward<U>(value);
438 return {{storage.get(), index(key)}, false};
439 }
440 }
441 template <typename... Args>
442 constexpr auto try_emplace(Key key, Args&&... args)
443 -> std::pair<iterator, bool> {
444 if (not contains(key)) {
445 construct(key, std::forward<Args>(args)...);
446 return {{storage.get(), index(key)}, true};
447 } else {
448 return {{storage.get(), index(key)}, false};
449 }
450 }
451
452 constexpr auto erase(iterator pos) noexcept -> iterator {
453 bitmap().reset(pos.pos);
454 unsafe_at(to_key(pos.pos)).destroy();
455 --_size;
456 return ++pos;
457 }
458 constexpr auto erase(const_iterator pos) noexcept -> iterator {
459 bitmap().reset(pos.pos);
460 unsafe_at(to_key(pos.pos)).destroy();
461 --_size;
462 return ++pos;
463 }
464
465 constexpr auto erase(iterator first, iterator last) noexcept -> iterator {
466 for (auto i : range(first.pos, last.pos)) {
467 if (contains(to_key(i))) {
468 bitmap().reset(i);
469 unsafe_at(to_key(i)).destroy();
470 --_size;
471 }
472 }
473 return ++last;
474 }
475
476 constexpr auto erase(Key key) noexcept -> std::size_t {
477 if (contains(key)) {
478 bitmap().reset(index(key));
479 unsafe_at(key).destroy();
480 --_size;
481 return 1;
482 } else {
483 return 0;
484 }
485 }
486
487 constexpr auto swap(direct_map& other) noexcept -> void {
488 using std::swap;
489 swap(storage, other.storage);
490 swap(_size, other._size);
491 }
492
493 KBLIB_NODISCARD constexpr auto contains(Key key) const noexcept -> bool {
494 return storage and bitmap().test(uindex(key));
495 }
496 KBLIB_NODISCARD constexpr auto count(Key key) const noexcept -> std::size_t {
497 return contains(key);
498 }
499
500 KBLIB_NODISCARD constexpr auto find(Key key) & noexcept -> iterator {
501 return contains(key) ? iterator{storage.get(), index(key)}
502 : iterator{storage.get(), key_range};
503 }
504 KBLIB_NODISCARD constexpr auto find(Key key) const& noexcept
505 -> const_iterator {
506 return contains(key) ? iterator{storage.get(), index(key)}
507 : iterator{storage.get(), key_range};
508 }
509
510 KBLIB_NODISCARD constexpr auto equal_range(Key key) & noexcept
511 -> std::pair<iterator, iterator> {
512 return {lower_bound(key), upper_bound(key)};
513 }
514 KBLIB_NODISCARD constexpr auto equal_range(Key key) const& noexcept
515 -> std::pair<const_iterator, const_iterator> {
516 return {lower_bound(key), upper_bound(key)};
517 }
518
519 KBLIB_NODISCARD constexpr auto lower_bound(Key key) & noexcept -> iterator {
520 if (contains(key)) {
521 return find(key);
522 } else {
523 return ++iterator{storage.get(), index(key)};
524 }
525 }
526 KBLIB_NODISCARD constexpr auto lower_bound(Key key) const& noexcept
527 -> const_iterator {
528 if (contains(key)) {
529 return find(key);
530 } else {
531 return ++iterator{storage.get(), index(key)};
532 }
533 }
534
535 KBLIB_NODISCARD constexpr auto upper_bound(Key key) & noexcept -> iterator {
536 // if the key exists, upper_bound is the next one
537 auto l = lower_bound(key);
538 if (l.pos == index(key)) {
539 return ++l;
540 // otherwise upper_bound == lower_bound
541 } else {
542 return l;
543 }
544 }
545 KBLIB_NODISCARD constexpr auto upper_bound(Key key) const& noexcept
546 -> const_iterator {
547 // if the key exists, upper_bound is the next one
548 auto l = lower_bound(key);
549 if (l.pos == index(key)) {
550 return ++l;
551 // otherwise upper_bound == lower_bound
552 } else {
553 return l;
554 }
555 }
556
557 KBLIB_NODISCARD constexpr static auto min() noexcept -> Key {
559 }
560 KBLIB_NODISCARD constexpr static auto max() noexcept -> Key {
562 }
563
564 KBLIB_NODISCARD friend constexpr auto operator==(
565 const direct_map& l,
566 const direct_map& r) noexcept(noexcept(std::declval<T&>()
567 == std::declval<T&>())) -> bool {
568 if (l.size() != r.size()) {
569 return false;
570 }
571 for (auto i : kblib::range(+min(), max() + 1)) {
572 if (l.contains(i) != r.contains(i)) {
573 return false;
574 } else if (l.contains(i)) {
575 if (l.at(i) != r.at(i)) {
576 return false;
577 }
578 }
579 }
580 return true;
581 }
582
583 KBLIB_NODISCARD friend constexpr auto operator!=(
584 const direct_map& l,
585 const direct_map& r) noexcept(noexcept(std::declval<T&>()
586 == std::declval<T&>())) -> bool {
587 return not (l == r);
588 }
589
590 KBLIB_NODISCARD friend constexpr auto operator<(
591 const direct_map& l,
592 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
593 std::declval<T&>())) -> bool {
594 return kblib::lexicographical_compare(l.begin(), l.end(), r.begin(),
595 r.end());
596 }
597 KBLIB_NODISCARD friend constexpr auto operator>(
598 const direct_map& l,
599 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
600 std::declval<T&>())) -> bool {
601 return r < l;
602 }
603 KBLIB_NODISCARD friend constexpr auto operator<=(
604 const direct_map& l,
605 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
606 std::declval<T&>())) -> bool {
607 return not (r < l);
608 }
609 KBLIB_NODISCARD friend constexpr auto operator>=(
610 const direct_map& l,
611 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
612 std::declval<T&>())) -> bool {
613 return not (l < r);
614 }
615
616 KBLIB_NODISCARD constexpr static auto index(Key key) noexcept
617 -> std::ptrdiff_t {
618 return to_unsigned(key);
619 }
620 KBLIB_NODISCARD constexpr static auto uindex(Key key) noexcept
621 -> std::size_t {
622 return to_unsigned(key);
623 }
624 KBLIB_NODISCARD constexpr static auto to_key(std::ptrdiff_t i) noexcept
625 -> Key {
626 return Key(i);
627 }
628
629 private:
630 KBLIB_NODISCARD constexpr auto bitmap() noexcept -> std::bitset<key_range>& {
631 return storage->first;
632 }
633 KBLIB_NODISCARD constexpr const std::bitset<key_range>& bitmap()
634 const noexcept {
635 return storage->first;
636 }
637
638 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) & -> storage_type& {
639 return storage->second[uindex(key)];
640 }
641 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) && -> storage_type&& {
642 return storage->second[uindex(key)];
643 }
644 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) const& -> const
645 storage_type& {
646 return storage->second[uindex(key)];
647 }
648 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) const&& -> const
649 storage_type&& {
650 return storage->second[uindex(key)];
651 }
652
653 auto allocate() -> void {
654 if (not storage) {
655 storage.assign();
656 }
657 }
658
659 template <typename... Args>
660 constexpr void construct(Key key, Args&&... args) noexcept(
661 std::is_nothrow_constructible<value_type, Args&&...>::value) {
662 allocate();
663 if (not storage->first.test(uindex(key))) {
664 do_construct(key, std::forward<Args>(args)...);
665 // doing these after construction maintains exception safety.
666 storage->first.set(uindex(key));
667 ++_size;
668 }
669 }
670
671 template <typename... Args>
672 constexpr void do_construct(Key key, Args&&... args) noexcept(
673 std::is_nothrow_constructible<value_type, Args&&...>::value) {
674 storage->second[uindex(key)].construct(
675 std::piecewise_construct, std::forward_as_tuple(key),
676 std::forward_as_tuple(std::forward<Args>(args)...));
677 }
678
679 // TODO(killerbee13): Implement, test, and document direct_map
680 // TODO(killerbee13): allocator support for direct_map
682 std::size_t _size{};
683};
684
685template <typename Key, typename T>
686class direct_map<Key, T, void> {
687 // Non-allocating direct_map
688 public:
689 using key_type = Key;
690 using mapped_type = T;
691 using value_type = std::pair<const Key, T>;
692 using size_type = std::size_t;
693 using difference_type = std::ptrdiff_t;
694
698 using const_pointer = const value_type*;
699
700 private:
701 constexpr static std::ptrdiff_t key_range{detail_direct_map::range_of<Key>};
703
704 template <typename V>
705 class iter {
706 public:
708 std::ptrdiff_t pos;
709
710 using value_type = typename direct_map::value_type;
711 using difference_type = typename direct_map::difference_type;
712 using reference = copy_const_t<V, value_type>&;
713 using pointer = copy_const_t<V, value_type>*;
714 using iterator_category = std::bidirectional_iterator_tag;
715
716 KBLIB_NODISCARD constexpr auto operator*() const -> reference {
717 return *map->elems[kblib::to_unsigned(pos)].get();
718 }
719 KBLIB_NODISCARD constexpr auto operator->() const -> pointer {
720 return map->elems[kblib::to_unsigned(pos)].get();
721 }
722
723 constexpr auto operator++() -> iter& {
724 if (pos == key_range) {
725 // not required in general, but direct_map::iterator guarantees that
726 // ++end() == end() because it simplifies the implementation and is
727 // unlikely to be a significant performance impact
728 return *this;
729 }
730 for (auto i : range(++pos, key_range)) {
731 if (map->active_elems.test(kblib::to_unsigned(i))) {
732 pos = i;
733 return *this;
734 }
735 }
736 pos = key_range;
737 return *this;
738 }
739 constexpr auto operator++(int) -> iter {
740 iter it = *this;
741 ++*this;
742 return it;
743 }
744
745 constexpr auto operator--() -> iter& {
746 for (auto i : range(pos - 1, std::ptrdiff_t(-1))) {
747 if (map->active_elems.test(kblib::to_unsigned(i))) {
748 pos = i;
749 return *this;
750 }
751 }
752 // going past the beginning is UB
753 __builtin_unreachable();
754 }
755 constexpr auto operator--(int) -> iter {
756 iter it = *this;
757 --*this;
758 return it;
759 }
760
761 KBLIB_NODISCARD friend constexpr auto operator==(iter l, iter r) noexcept
762 -> bool {
763 return l.map == r.map and l.pos == r.pos;
764 }
765 KBLIB_NODISCARD friend constexpr auto operator!=(iter l, iter r) noexcept
766 -> bool {
767 return not (l == r);
768 }
769
770#define DECL_OP(op) \
771 KBLIB_NODISCARD friend constexpr auto operator op(iter l, \
772 iter r) noexcept->bool { \
773 assert(l.map == r.map); \
774 return l.pos op r.pos; \
775 }
776 DECL_OP(<)
777 DECL_OP(>)
778 DECL_OP(>=)
779 DECL_OP(<=)
780#undef DECL_OP
781
782 constexpr auto swap(iter& other) noexcept -> void {
783 kblib::swap(map, other.map);
784 kblib::swap(pos, other.pos);
785 }
786 };
787
788 public:
789 using iterator = iter<value_type>;
790 using const_iterator = iter<const value_type>;
791 using reverse_iterator = std::reverse_iterator<iterator>;
792 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
793
794 constexpr direct_map() noexcept = default;
795
796 template <typename InputIt>
797 constexpr direct_map(InputIt first, InputIt last) {
798 for (auto&& v : indirect(first, last)) {
799 construct(std::forward<decltype(v)>(v).first,
800 std::forward<decltype(v)>(v).second);
801 }
802 }
803
804 constexpr direct_map(const direct_map& other)
805 : active_elems{other.active_elems}
806 , _size(other._size) {
807 for (const key_type k : range(+min(), max() + 1)) {
808 if (contains(k)) { // the bitmap is already copied from other
809 construct(k, other.unsafe_at(k).get()->second);
810 ++_size;
811 bitmap().set(uindex(k));
812 }
813 }
814 }
815
816 constexpr direct_map(direct_map&& other) noexcept(
817 std::is_nothrow_move_constructible<value_type>::value)
818 : active_elems{other.active_elems}
819 , _size(other._size) {
820 for (const key_type k : range(+min(), max() + 1)) {
821 if (contains(k)) { // the bitmap is already copied from other
822 construct(k, std::move(other.unsafe_at(k).get()->second));
823 ++_size;
824 bitmap().set(uindex(k));
825 }
826 }
827 }
828
829 constexpr direct_map(std::initializer_list<value_type> init)
830 : direct_map(init.begin(), init.end()) {}
831
832 // TODO(killerbee13): Remove this and allow it to be trivially destructible
833 // for trivial Key and T
834 KBLIB_CXX20(constexpr) ~direct_map() { clear(); }
835
836 constexpr auto operator=(const direct_map& other) -> direct_map& {
837 if (this == &other) {
838 return *this;
839 }
840 clear();
841 active_elems = other.active_elems;
842 for (const key_type k : range(+min(), max() + 1)) {
843 if (contains(k)) { // the bitmap is already copied from other
844 construct(k, other.unsafe_at(k).get()->second);
845 ++_size;
846 bitmap().set(uindex(k));
847 }
848 }
849 return *this;
850 }
851 constexpr auto operator=(direct_map&& other) noexcept(
852 std::is_nothrow_move_constructible<T>::value) -> direct_map& {
853 if (this == &other) {
854 return *this;
855 }
856 active_elems = other.active_elems;
857 for (const key_type k : range(+min(), max() + 1)) {
858 if (contains(k)) { // the bitmap is already copied from other
859 construct(k, std::move(other.unsafe_at(k).get()->second));
860 ++_size;
861 bitmap().set(uindex(k));
862 }
863 }
864 return *this;
865 }
866 constexpr auto operator=(std::initializer_list<value_type> init)
867 -> direct_map& {
868 clear();
869 for (auto it : init) {
870 construct(it->first, it->second);
871 }
872 return *this;
873 }
874
875 KBLIB_NODISCARD constexpr auto at(Key key) & -> T& {
876 if (contains(key)) {
877 return unsafe_at(key).get()->second;
878 } else {
879 throw std::out_of_range("direct_map: key out of range");
880 }
881 }
882 KBLIB_NODISCARD constexpr auto at(Key key) && -> T&& {
883 if (contains(key)) {
884 return std::move(unsafe_at(key).get()->second);
885 } else {
886 throw std::out_of_range("direct_map: key out of range");
887 }
888 }
889 KBLIB_NODISCARD constexpr auto at(Key key) const& -> const T& {
890 if (contains(key)) {
891 return unsafe_at(key).get()->second;
892 } else {
893 throw std::out_of_range("direct_map: key out of range");
894 }
895 }
896 KBLIB_NODISCARD constexpr auto at(Key key) const&& -> const T&& {
897 if (contains(key)) {
898 return std::move(unsafe_at(key).get()->second);
899 } else {
900 throw std::out_of_range("direct_map: key out of range");
901 }
902 }
903
904 KBLIB_NODISCARD constexpr T& operator[](Key key) noexcept(
905 std::is_nothrow_default_constructible<T>::value) {
906 return try_emplace(key).first->second;
907 }
908
909 KBLIB_NODISCARD constexpr auto begin() & noexcept -> iterator {
910 return {this, cbegin().pos};
911 }
912 KBLIB_NODISCARD constexpr auto begin() const& noexcept -> const_iterator {
913 return {this, cbegin().pos};
914 }
915 KBLIB_NODISCARD constexpr auto cbegin() const& noexcept -> const_iterator {
916 if (not empty()) {
917 if (contains(to_key(0))) {
918 return {this, 0};
919 } else {
920 return ++const_iterator{this, 0};
921 }
922 } else {
923 return {this, key_range};
924 }
925 }
926
927 KBLIB_NODISCARD constexpr auto end() & noexcept -> iterator {
928 return {this, key_range};
929 }
930 KBLIB_NODISCARD constexpr auto end() const& noexcept -> const_iterator {
931 return {this, key_range};
932 }
933 KBLIB_NODISCARD constexpr auto cend() const& noexcept -> const_iterator {
934 return {this, key_range};
935 }
936
937 KBLIB_NODISCARD constexpr auto rbegin() & noexcept -> reverse_iterator {
938 return std::make_reverse_iterator(end());
939 }
940 KBLIB_NODISCARD constexpr auto rbegin() const& noexcept
942 return std::make_reverse_iterator(end());
943 }
944 KBLIB_NODISCARD constexpr auto crbegin() const& noexcept
946 return std::make_reverse_iterator(crend());
947 }
948
949 KBLIB_NODISCARD constexpr auto rend() & noexcept -> reverse_iterator {
950 return std::make_reverse_iterator(begin());
951 }
952 KBLIB_NODISCARD constexpr auto rend() const& noexcept
954 return std::make_reverse_iterator(begin());
955 }
956 KBLIB_NODISCARD constexpr auto crend() const& noexcept
958 return std::make_reverse_iterator(cbegin());
959 }
960
961 KBLIB_NODISCARD constexpr auto empty() const& noexcept -> bool {
962 return _size == 0;
963 }
964
965 KBLIB_NODISCARD constexpr auto size() const& noexcept -> std::size_t {
966 return _size;
967 }
968 KBLIB_NODISCARD constexpr auto ssize() const& noexcept -> std::ptrdiff_t {
969 return _size;
970 }
971
972 KBLIB_NODISCARD constexpr static auto max_size() noexcept -> std::size_t {
973 return key_range;
974 }
975
976 constexpr auto clear() noexcept -> void {
977 for (auto i : range(+min(), max() + 1)) {
978 auto j = static_cast<Key>(i);
979 if (contains(j)) {
980 unsafe_at(j).destroy();
981 }
982 }
983 _size = 0;
984 }
985
986 constexpr auto insert(const value_type& value) -> std::pair<iterator, bool> {
987 if (not contains(value.first)) {
988 construct(value.first, value.second);
989 return {{this, index(value.first)}, true};
990 } else {
991 return {{this, index(value.first)}, false};
992 }
993 }
994 template <typename U>
995 constexpr auto insert(U&& value)
997 std::pair<iterator, bool>> {
998 if (not contains(value.first)) {
999 construct(value.first, std::forward<U>(value.second));
1000 return {{this, index(value.first)}, true};
1001 } else {
1002 return {{this, index(value.first)}, false};
1003 }
1004 }
1005 constexpr auto insert(value_type&& value) -> std::pair<iterator, bool> {
1006 if (not contains(value.first)) {
1007 construct(value.first, std::move(value.second));
1008 return {{this, index(value.first)}, true};
1009 } else {
1010 return {{this, index(value.first)}, false};
1011 }
1012 }
1013
1014 template <typename U>
1015 constexpr auto insert_or_assign(Key key, U&& value)
1016 -> std::pair<iterator, bool> {
1017 if (not contains(key)) {
1018 construct(key, std::forward<U>(value));
1019 return {{this, index(key)}, true};
1020 } else {
1021 *unsafe_at(key).get() = std::forward<U>(value);
1022 return {{this, index(key)}, false};
1023 }
1024 }
1025 template <typename... Args>
1026 constexpr auto try_emplace(Key key, Args&&... args)
1027 -> std::pair<iterator, bool> {
1028 if (not contains(key)) {
1029 construct(key, std::forward<Args>(args)...);
1030 return {{this, index(key)}, true};
1031 } else {
1032 return {{this, index(key)}, false};
1033 }
1034 }
1035
1036 constexpr auto erase(iterator pos) noexcept -> iterator {
1037 destroy(to_key(pos.pos));
1038 return ++pos;
1039 }
1040 constexpr auto erase(const_iterator pos) noexcept -> iterator {
1041 destroy(to_key(pos.pos));
1042 return ++pos;
1043 }
1044
1045 constexpr auto erase(iterator first, iterator last) noexcept -> iterator {
1046 for (auto i : range(first.pos, last.pos)) {
1047 if (contains(to_key(i))) {
1048 destroy(to_key(i));
1049 }
1050 }
1051 return ++last;
1052 }
1053
1054 constexpr auto erase(Key key) noexcept -> std::size_t {
1055 if (contains(key)) {
1056 destroy(key);
1057 return 1;
1058 } else {
1059 return 0;
1060 }
1061 }
1062
1063 constexpr auto swap(direct_map& other) noexcept(
1064 std::is_nothrow_move_constructible<value_type>::value and
1066 using std::swap;
1067 for (const key_type k : range(+min(), max() + 1)) {
1068 if (contains(k)) {
1069 if (other.contains(k)) {
1070 kblib::swap(unsafe_at(k).get()->second,
1071 other.unsafe_at(k).get()->second);
1072 } else {
1073 other.construct(k, std::move(unsafe_at(k).get()->second));
1074 destroy(k);
1075 }
1076 } else if (other.contains(k)) {
1077 construct(k, std::move(other.unsafe_at(k).get()->second));
1078 other.destroy(k);
1079 } else {
1080 // do nothing
1081 }
1082 }
1083
1084 swap(active_elems, other.active_elems);
1085 swap(_size, other._size);
1086 }
1087
1088 KBLIB_NODISCARD constexpr auto contains(Key key) const noexcept -> bool {
1089 return bitmap().test(uindex(key));
1090 }
1091 KBLIB_NODISCARD constexpr auto count(Key key) const noexcept -> std::size_t {
1092 return contains(key);
1093 }
1094
1095 KBLIB_NODISCARD constexpr auto find(Key key) & noexcept -> iterator {
1096 return contains(key) ? iterator{this, index(key)}
1097 : iterator{this, key_range};
1098 }
1099 KBLIB_NODISCARD constexpr auto find(Key key) const& noexcept
1100 -> const_iterator {
1101 return contains(key) ? iterator{this, index(key)}
1102 : iterator{this, key_range};
1103 }
1104
1105 KBLIB_NODISCARD constexpr auto equal_range(Key key) & noexcept
1106 -> std::pair<iterator, iterator> {
1107 return {lower_bound(key), upper_bound(key)};
1108 }
1109 KBLIB_NODISCARD constexpr auto equal_range(Key key) const& noexcept
1110 -> std::pair<const_iterator, const_iterator> {
1111 return {lower_bound(key), upper_bound(key)};
1112 }
1113
1114 KBLIB_NODISCARD constexpr auto lower_bound(Key key) & noexcept -> iterator {
1115 if (contains(key)) {
1116 return find(key);
1117 } else {
1118 return ++iterator{this, index(key)};
1119 }
1120 }
1121 KBLIB_NODISCARD constexpr auto lower_bound(Key key) const& noexcept
1122 -> const_iterator {
1123 if (contains(key)) {
1124 return find(key);
1125 } else {
1126 return ++iterator{this, index(key)};
1127 }
1128 }
1129
1130 KBLIB_NODISCARD constexpr auto upper_bound(Key key) & noexcept -> iterator {
1131 // if the key exists, upper_bound is the next one
1132 auto l = lower_bound(key);
1133 if (l.pos == index(key)) {
1134 return ++l;
1135 // otherwise upper_bound == lower_bound
1136 } else {
1137 return l;
1138 }
1139 }
1140 KBLIB_NODISCARD constexpr auto upper_bound(Key key) const& noexcept
1141 -> const_iterator {
1142 // if the key exists, upper_bound is the next one
1143 auto l = lower_bound(key);
1144 if (l.pos == index(key)) {
1145 return ++l;
1146 // otherwise upper_bound == lower_bound
1147 } else {
1148 return l;
1149 }
1150 }
1151
1152 KBLIB_NODISCARD constexpr static auto min() noexcept -> Key {
1154 }
1155 KBLIB_NODISCARD constexpr static auto max() noexcept -> Key {
1157 }
1158
1159 KBLIB_NODISCARD friend constexpr auto operator==(
1160 const direct_map& l,
1161 const direct_map& r) noexcept(noexcept(std::declval<T&>()
1162 == std::declval<T&>())) -> bool {
1163 if (l.size() != r.size()) {
1164 return false;
1165 }
1166 for (const key_type i : kblib::range(+min(), max() + 1)) {
1167 if (l.contains(i) != r.contains(i)) {
1168 return false;
1169 } else if (l.contains(i)) {
1170 if (l.at(i) != r.at(i)) {
1171 return false;
1172 }
1173 }
1174 }
1175 return true;
1176 }
1177
1178 KBLIB_NODISCARD friend constexpr auto operator!=(
1179 const direct_map& l,
1180 const direct_map& r) noexcept(noexcept(std::declval<T&>()
1181 == std::declval<T&>())) -> bool {
1182 return not (l == r);
1183 }
1184
1185 KBLIB_NODISCARD friend constexpr auto operator<(
1186 const direct_map& l,
1187 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
1188 std::declval<T&>())) -> bool {
1189 return kblib::lexicographical_compare(l.begin(), l.end(), r.begin(),
1190 r.end());
1191 }
1192 KBLIB_NODISCARD friend constexpr auto operator>(
1193 const direct_map& l,
1194 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
1195 std::declval<T&>())) -> bool {
1196 return r < l;
1197 }
1198 KBLIB_NODISCARD friend constexpr auto operator<=(
1199 const direct_map& l,
1200 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
1201 std::declval<T&>())) -> bool {
1202 return not (r < l);
1203 }
1204 KBLIB_NODISCARD friend constexpr auto operator>=(
1205 const direct_map& l,
1206 const direct_map& r) noexcept(noexcept(std::declval<T&>(),
1207 std::declval<T&>())) -> bool {
1208 return not (l < r);
1209 }
1210
1211 KBLIB_NODISCARD constexpr static auto index(Key key) noexcept
1212 -> std::ptrdiff_t {
1213 return to_unsigned(key);
1214 }
1215 KBLIB_NODISCARD constexpr static auto uindex(Key key) noexcept
1216 -> std::size_t {
1217 return to_unsigned(key);
1218 }
1219 KBLIB_NODISCARD constexpr static auto to_key(std::ptrdiff_t i) noexcept
1220 -> Key {
1221 return Key(i);
1222 }
1223
1224 private:
1225 KBLIB_NODISCARD constexpr auto bitmap() noexcept -> std::bitset<key_range>& {
1226 return active_elems;
1227 }
1228 KBLIB_NODISCARD constexpr auto bitmap() const noexcept
1229 -> const std::bitset<key_range>& {
1230 return active_elems;
1231 }
1232
1233 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) & -> storage_type& {
1234 return elems[uindex(key)];
1235 }
1236 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) && -> storage_type&& {
1237 return elems[uindex(key)];
1238 }
1239 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) const& -> const
1240 storage_type& {
1241 return elems[uindex(key)];
1242 }
1243 KBLIB_NODISCARD constexpr auto unsafe_at(Key key) const&& -> const
1244 storage_type&& {
1245 return elems[uindex(key)];
1246 }
1247
1248 template <typename... Args>
1249 constexpr auto construct(Key key, Args&&... args) noexcept(
1250 std::is_nothrow_constructible<value_type, Args&&...>::value) -> void {
1251 if (not active_elems.test(uindex(key))) {
1252 do_construct(key, std::forward<Args>(args)...);
1253 // doing these after construction maintains exception safety.
1254 active_elems.set(uindex(key));
1255 ++_size;
1256 }
1257 }
1258
1259 template <typename... Args>
1260 constexpr auto do_construct(Key key, Args&&... args) noexcept(
1261 std::is_nothrow_constructible<value_type, Args&&...>::value) -> void {
1262 elems[uindex(key)].construct(
1263 std::piecewise_construct, std::forward_as_tuple(key),
1264 std::forward_as_tuple(std::forward<Args>(args)...));
1265 }
1266
1267 auto destroy(Key key) -> void {
1268 assert(contains(key));
1269
1270 bitmap().reset(uindex(key));
1271 unsafe_at(key).destroy();
1272 --_size;
1273 }
1274
1275 // TODO(killerbee13): Implement, test, and document direct_map
1276
1277 std::bitset<key_range> active_elems;
1278 std::array<storage_type, key_range> elems;
1279
1280 std::size_t _size{};
1281};
1282
1283} // namespace kblib
1284
1285#endif // DIRECT_MAP_H
KBLIB_NODISCARD constexpr auto count(Key key) const noexcept -> std::size_t
Definition: direct_map.h:1091
KBLIB_NODISCARD constexpr auto equal_range(Key key) &noexcept -> std::pair< iterator, iterator >
Definition: direct_map.h:1105
KBLIB_NODISCARD constexpr auto end() &noexcept -> iterator
Definition: direct_map.h:927
constexpr auto erase(iterator first, iterator last) noexcept -> iterator
Definition: direct_map.h:1045
KBLIB_NODISCARD static constexpr auto max() noexcept -> Key
Definition: direct_map.h:1155
KBLIB_NODISCARD constexpr auto contains(Key key) const noexcept -> bool
Definition: direct_map.h:1088
KBLIB_NODISCARD constexpr auto size() const &noexcept -> std::size_t
Definition: direct_map.h:965
KBLIB_NODISCARD constexpr auto at(Key key) const &-> const T &
Definition: direct_map.h:889
KBLIB_NODISCARD constexpr auto ssize() const &noexcept -> std::ptrdiff_t
Definition: direct_map.h:968
constexpr auto insert_or_assign(Key key, U &&value) -> std::pair< iterator, bool >
Definition: direct_map.h:1015
constexpr auto insert(U &&value) -> return_assert_t< std::is_constructible< value_type, U && >::value, std::pair< iterator, bool > >
Definition: direct_map.h:995
KBLIB_NODISCARD constexpr auto upper_bound(Key key) &noexcept -> iterator
Definition: direct_map.h:1130
KBLIB_NODISCARD static constexpr auto min() noexcept -> Key
Definition: direct_map.h:1152
constexpr auto insert(const value_type &value) -> std::pair< iterator, bool >
Definition: direct_map.h:986
KBLIB_NODISCARD static constexpr auto index(Key key) noexcept -> std::ptrdiff_t
Definition: direct_map.h:1211
KBLIB_NODISCARD constexpr auto rbegin() const &noexcept -> const_reverse_iterator
Definition: direct_map.h:940
iter< const value_type > const_iterator
Definition: direct_map.h:790
KBLIB_NODISCARD constexpr auto upper_bound(Key key) const &noexcept -> const_iterator
Definition: direct_map.h:1140
KBLIB_NODISCARD friend constexpr auto operator==(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >()==std::declval< T & >())) -> bool
Definition: direct_map.h:1159
constexpr auto erase(iterator pos) noexcept -> iterator
Definition: direct_map.h:1036
KBLIB_NODISCARD constexpr auto find(Key key) &noexcept -> iterator
Definition: direct_map.h:1095
KBLIB_NODISCARD constexpr auto find(Key key) const &noexcept -> const_iterator
Definition: direct_map.h:1099
constexpr auto clear() noexcept -> void
Definition: direct_map.h:976
const value_type * const_pointer
Definition: direct_map.h:698
KBLIB_NODISCARD constexpr auto cbegin() const &noexcept -> const_iterator
Definition: direct_map.h:915
KBLIB_NODISCARD friend constexpr auto operator>=(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:1204
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: direct_map.h:792
constexpr auto operator=(direct_map &&other) noexcept(std::is_nothrow_move_constructible< T >::value) -> direct_map &
Definition: direct_map.h:851
KBLIB_NODISCARD constexpr auto rbegin() &noexcept -> reverse_iterator
Definition: direct_map.h:937
KBLIB_NODISCARD constexpr auto at(Key key) &&-> T &&
Definition: direct_map.h:882
KBLIB_NODISCARD constexpr auto crend() const &noexcept -> const_reverse_iterator
Definition: direct_map.h:956
constexpr direct_map(const direct_map &other)
Definition: direct_map.h:804
constexpr direct_map(direct_map &&other) noexcept(std::is_nothrow_move_constructible< value_type >::value)
Definition: direct_map.h:816
KBLIB_NODISCARD constexpr T & operator[](Key key) noexcept(std::is_nothrow_default_constructible< T >::value)
Definition: direct_map.h:904
KBLIB_NODISCARD constexpr auto at(Key key) &-> T &
Definition: direct_map.h:875
KBLIB_NODISCARD constexpr auto at(Key key) const &&-> const T &&
Definition: direct_map.h:896
std::reverse_iterator< iterator > reverse_iterator
Definition: direct_map.h:791
constexpr direct_map() noexcept=default
constexpr auto erase(Key key) noexcept -> std::size_t
Definition: direct_map.h:1054
KBLIB_NODISCARD friend constexpr auto operator>(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:1192
KBLIB_NODISCARD constexpr auto begin() const &noexcept -> const_iterator
Definition: direct_map.h:912
KBLIB_NODISCARD constexpr auto end() const &noexcept -> const_iterator
Definition: direct_map.h:930
constexpr direct_map(std::initializer_list< value_type > init)
Definition: direct_map.h:829
constexpr auto swap(direct_map &other) noexcept(std::is_nothrow_move_constructible< value_type >::value and fakestd::is_nothrow_swappable< T >::value) -> void
Definition: direct_map.h:1063
KBLIB_NODISCARD constexpr auto cend() const &noexcept -> const_iterator
Definition: direct_map.h:933
KBLIB_NODISCARD constexpr auto rend() const &noexcept -> const_reverse_iterator
Definition: direct_map.h:952
KBLIB_NODISCARD static constexpr auto max_size() noexcept -> std::size_t
Definition: direct_map.h:972
KBLIB_NODISCARD constexpr auto lower_bound(Key key) const &noexcept -> const_iterator
Definition: direct_map.h:1121
KBLIB_CXX20(constexpr) ~direct_map()
Definition: direct_map.h:834
KBLIB_NODISCARD friend constexpr auto operator<=(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:1198
KBLIB_NODISCARD static constexpr auto uindex(Key key) noexcept -> std::size_t
Definition: direct_map.h:1215
constexpr auto insert(value_type &&value) -> std::pair< iterator, bool >
Definition: direct_map.h:1005
KBLIB_NODISCARD constexpr auto empty() const &noexcept -> bool
Definition: direct_map.h:961
KBLIB_NODISCARD constexpr auto lower_bound(Key key) &noexcept -> iterator
Definition: direct_map.h:1114
KBLIB_NODISCARD constexpr auto rend() &noexcept -> reverse_iterator
Definition: direct_map.h:949
constexpr auto erase(const_iterator pos) noexcept -> iterator
Definition: direct_map.h:1040
KBLIB_NODISCARD friend constexpr auto operator!=(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >()==std::declval< T & >())) -> bool
Definition: direct_map.h:1178
constexpr auto operator=(const direct_map &other) -> direct_map &
Definition: direct_map.h:836
constexpr auto operator=(std::initializer_list< value_type > init) -> direct_map &
Definition: direct_map.h:866
KBLIB_NODISCARD constexpr auto begin() &noexcept -> iterator
Definition: direct_map.h:909
const value_type & const_reference
Definition: direct_map.h:696
KBLIB_NODISCARD friend constexpr auto operator<(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:1185
std::pair< const Key, T > value_type
Definition: direct_map.h:691
KBLIB_NODISCARD static constexpr auto to_key(std::ptrdiff_t i) noexcept -> Key
Definition: direct_map.h:1219
KBLIB_NODISCARD constexpr auto equal_range(Key key) const &noexcept -> std::pair< const_iterator, const_iterator >
Definition: direct_map.h:1109
constexpr auto try_emplace(Key key, Args &&... args) -> std::pair< iterator, bool >
Definition: direct_map.h:1026
KBLIB_NODISCARD constexpr auto crbegin() const &noexcept -> const_reverse_iterator
Definition: direct_map.h:944
iter< value_type > iterator
Definition: direct_map.h:230
KBLIB_NODISCARD constexpr auto rend() const &noexcept -> auto
Definition: direct_map.h:369
constexpr auto insert(const value_type &value) -> std::pair< iterator, bool >
Definition: direct_map.h:402
KBLIB_NODISCARD constexpr auto begin() const &noexcept -> const_iterator
Definition: direct_map.h:331
constexpr auto insert_or_assign(Key key, U &&value) -> std::pair< iterator, bool >
Definition: direct_map.h:431
constexpr auto clear() noexcept -> void
Definition: direct_map.h:391
constexpr direct_map(const direct_map &other)
Definition: direct_map.h:245
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: direct_map.h:233
KBLIB_NODISCARD constexpr auto size() const &noexcept -> std::size_t
Definition: direct_map.h:380
KBLIB_NODISCARD constexpr auto crbegin() const &noexcept -> auto
Definition: direct_map.h:362
constexpr auto erase(iterator pos) noexcept -> iterator
Definition: direct_map.h:452
KBLIB_NODISCARD constexpr auto at(Key key) const &-> const T &
Definition: direct_map.h:308
KBLIB_NODISCARD constexpr auto rbegin() const &noexcept -> auto
Definition: direct_map.h:359
value_type * pointer
Definition: direct_map.h:136
constexpr auto operator=(const direct_map &other) -> direct_map &
Definition: direct_map.h:268
KBLIB_NODISCARD constexpr auto find(Key key) &noexcept -> iterator
Definition: direct_map.h:500
constexpr auto erase(const_iterator pos) noexcept -> iterator
Definition: direct_map.h:458
KBLIB_NODISCARD constexpr auto upper_bound(Key key) const &noexcept -> const_iterator
Definition: direct_map.h:545
KBLIB_NODISCARD constexpr auto rend() &noexcept -> auto
Definition: direct_map.h:366
KBLIB_NODISCARD friend constexpr auto operator==(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >()==std::declval< T & >())) -> bool
Definition: direct_map.h:564
KBLIB_NODISCARD constexpr auto rbegin() &noexcept -> auto
Definition: direct_map.h:356
KBLIB_NODISCARD constexpr auto equal_range(Key key) const &noexcept -> std::pair< const_iterator, const_iterator >
Definition: direct_map.h:514
KBLIB_NODISCARD constexpr auto end() const &noexcept -> const_iterator
Definition: direct_map.h:349
constexpr auto erase(iterator first, iterator last) noexcept -> iterator
Definition: direct_map.h:465
KBLIB_NODISCARD friend constexpr auto operator>=(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:609
KBLIB_NODISCARD constexpr auto contains(Key key) const noexcept -> bool
Definition: direct_map.h:493
KBLIB_NODISCARD constexpr auto begin() &noexcept -> iterator
Definition: direct_map.h:328
KBLIB_NODISCARD static constexpr auto max_size() noexcept -> std::size_t
Definition: direct_map.h:387
KBLIB_NODISCARD constexpr auto ssize() const &noexcept -> std::ptrdiff_t
Definition: direct_map.h:383
value_type & reference
Definition: direct_map.h:134
std::size_t size_type
Definition: direct_map.h:131
KBLIB_NODISCARD constexpr auto cbegin() const &noexcept -> const_iterator
Definition: direct_map.h:334
constexpr auto try_emplace(Key key, Args &&... args) -> std::pair< iterator, bool >
Definition: direct_map.h:442
KBLIB_NODISCARD static constexpr auto uindex(Key key) noexcept -> std::size_t
Definition: direct_map.h:620
KBLIB_NODISCARD static constexpr auto max() noexcept -> Key
Definition: direct_map.h:560
constexpr auto swap(direct_map &other) noexcept -> void
Definition: direct_map.h:487
KBLIB_NODISCARD constexpr auto empty() const &noexcept -> bool
Definition: direct_map.h:376
KBLIB_NODISCARD friend constexpr auto operator>(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:597
KBLIB_NODISCARD constexpr auto at(Key key) &&-> T &&
Definition: direct_map.h:301
KBLIB_NODISCARD constexpr auto at(Key key) const &&-> const T &&
Definition: direct_map.h:315
KBLIB_NODISCARD constexpr auto end() &noexcept -> iterator
Definition: direct_map.h:346
KBLIB_NODISCARD constexpr auto equal_range(Key key) &noexcept -> std::pair< iterator, iterator >
Definition: direct_map.h:510
std::ptrdiff_t difference_type
Definition: direct_map.h:132
constexpr direct_map(std::initializer_list< value_type > init)
Definition: direct_map.h:260
std::pair< const Key, T > value_type
Definition: direct_map.h:130
KBLIB_NODISCARD constexpr auto upper_bound(Key key) &noexcept -> iterator
Definition: direct_map.h:535
const value_type * const_pointer
Definition: direct_map.h:137
KBLIB_NODISCARD static constexpr auto min() noexcept -> Key
Definition: direct_map.h:557
KBLIB_CXX20(constexpr) ~direct_map()
Definition: direct_map.h:266
KBLIB_NODISCARD friend constexpr auto operator<=(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:603
constexpr auto operator=(direct_map &&other) noexcept -> direct_map &=default
constexpr auto operator=(std::initializer_list< value_type > init) -> direct_map &
Definition: direct_map.h:285
KBLIB_NODISCARD constexpr auto cend() const &noexcept -> const_iterator
Definition: direct_map.h:352
std::reverse_iterator< iterator > reverse_iterator
Definition: direct_map.h:232
KBLIB_NODISCARD constexpr auto crend() const &noexcept -> auto
Definition: direct_map.h:372
KBLIB_NODISCARD constexpr auto find(Key key) const &noexcept -> const_iterator
Definition: direct_map.h:504
constexpr auto erase(Key key) noexcept -> std::size_t
Definition: direct_map.h:476
KBLIB_NODISCARD constexpr auto at(Key key) &-> T &
Definition: direct_map.h:294
KBLIB_NODISCARD friend constexpr auto operator!=(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >()==std::declval< T & >())) -> bool
Definition: direct_map.h:583
KBLIB_NODISCARD constexpr auto lower_bound(Key key) &noexcept -> iterator
Definition: direct_map.h:519
constexpr auto insert(value_type &&value) -> std::pair< iterator, bool >
Definition: direct_map.h:421
KBLIB_NODISCARD constexpr T & operator[](Key key) noexcept(std::is_nothrow_default_constructible< T >::value)
Definition: direct_map.h:323
iter< const value_type > const_iterator
Definition: direct_map.h:231
KBLIB_NODISCARD friend constexpr auto operator<(const direct_map &l, const direct_map &r) noexcept(noexcept(std::declval< T & >(), std::declval< T & >())) -> bool
Definition: direct_map.h:590
KBLIB_NODISCARD static constexpr auto index(Key key) noexcept -> std::ptrdiff_t
Definition: direct_map.h:616
constexpr auto insert(U &&value) -> enable_if_t< std::is_constructible< value_type, U && >::value, std::pair< iterator, bool > >
Definition: direct_map.h:411
constexpr direct_map() noexcept=default
KBLIB_NODISCARD constexpr auto lower_bound(Key key) const &noexcept -> const_iterator
Definition: direct_map.h:526
constexpr direct_map(direct_map &&other) noexcept
Definition: direct_map.h:256
KBLIB_NODISCARD constexpr auto count(Key key) const noexcept -> std::size_t
Definition: direct_map.h:496
KBLIB_NODISCARD static constexpr auto to_key(std::ptrdiff_t i) noexcept -> Key
Definition: direct_map.h:624
const value_type & const_reference
Definition: direct_map.h:135
#define DECL_OP(op)
Definition: direct_map.h:770
#define LAUNDER(x)
Definition: direct_map.h:90
This header provides some features of C++17 <type_traits> and other headers for C++14,...
This file provides some iterators, ranges, iterator/range adapters, and operations that can be perfor...
KBLIB_CONSTANT auto range_of
Definition: direct_map.h:56
constexpr struct kblib::nums::min_t min
constexpr struct kblib::nums::max_t max
The main namespace in which all entities from kblib are defined.
Definition: algorithm.h:44
constexpr auto contains(InputIt begin, InputIt end, const Value &val) noexcept(noexcept(*begin==val)) -> enable_if_t< is_input_iterator< InputIt >::value, bool >
Determine if a range contains a value.
Definition: algorithm.h:1052
constexpr auto exchange(T &obj, U &&new_value) -> T
Definition: fakestd.h:719
auto map(F f, T &&... t) noexcept(noexcept(std::tuple{ kblib::apply(f, std::forward< T >(t))...})) -> enable_if_t< not any_void< decltype(kblib::apply(f, std::forward< T >(t)))... >, decltype(std::tuple{kblib::apply(f, std::forward< T >(t))...})>
Definition: simple.h:75
typename std::enable_if< B, T >::type enable_if_t
Definition: fakestd.h:54
struct kblib::@0 swap
constexpr auto range(Value min, Value max, Delta step=0) -> range_t< Value, Delta >
Constructs a range from beginning, end, and step amount. The range is half-open, that is min is in th...
Definition: iterators.h:621
constexpr auto indirect(Iter1 begin, Iter2 end) noexcept(noexcept(indirect_range< Iter1, Iter2 >{begin, end})) -> indirect_range< Iter1, Iter2 >
Create a range from an iterator pair. Primarily useful for range-for loops.
Definition: iterators.h:1060
auto get(punner< Types... > &p) noexcept -> decltype(auto)
Definition: bits.h:730
constexpr auto find(ForwardIt begin, EndIt end, const Elem &value) noexcept(noexcept(*begin==value)) -> ForwardIt
Finds a value in range [begin, end). If not found, returns end. It also allows for a sentinel end ite...
Definition: algorithm.h:290
typename return_assert< V, T >::type return_assert_t
Definition: fakestd.h:543
constexpr auto operator*(construct_type l, bool r) noexcept -> construct_type
Definition: poly_obj.h:60
constexpr auto lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) -> bool
Definition: fakestd.h:1080
constexpr struct kblib::in_place_agg_t in_place_agg
typename copy_const< C, V >::type copy_const_t
Definition: fakestd.h:871
constexpr auto to_unsigned(I x) -> std::make_unsigned_t< I >
Cast integral argument to corresponding unsigned type.
Definition: fakestd.h:586
Definition: bits.h:714
Definition: traits.cpp:4
constexpr auto destroy() noexcept -> void
Definition: direct_map.h:114
KBLIB_NODISCARD constexpr auto get() &noexcept -> T *
Definition: direct_map.h:116
KBLIB_NODISCARD constexpr auto get() const &noexcept -> const T *
Definition: direct_map.h:117
constexpr auto construct(Args &&... args) noexcept(std::is_nothrow_constructible< T, Args &&... >::value) -> T &
Definition: direct_map.h:109
constexpr auto construct(Args &&... args) noexcept(std::is_nothrow_constructible< T, Args &&... >::value) -> T &
Definition: direct_map.h:72
KBLIB_NODISCARD constexpr auto get() &noexcept -> T *
Definition: direct_map.h:92
auto operator=(storage_for &&) -> storage_for &=delete
storage_for(storage_for &&)=delete
auto operator=(const storage_for &) -> storage_for &=delete
KBLIB_NODISCARD constexpr auto get() const &noexcept -> const T *
Definition: direct_map.h:95
storage_for(const storage_for &)=delete
constexpr auto destroy() noexcept -> void
Definition: direct_map.h:85
Provides macros and basic templates used by the rest of kblib.
#define KBLIB_CONSTANT
Definition: tdecl.h:98
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Definition: tdecl.h:81