LeviLamina
Loading...
Searching...
No Matches
associative_adapter.h
1#pragma once
2
3#include "mc/_HeaderOutputPredefine.h"
4
5#include "mc/platform/brstd/no_mapped_container_t.h"
6#include "mc/platform/brstd/no_value_t.h"
7
8#include <algorithm>
9#include <compare>
10#include <cstddef>
11#include <iterator>
12#include <type_traits>
13#include <utility>
14
15namespace brstd {
16
17template <typename Key, typename T, typename Compare, typename KeyContainer, typename MappedContainer>
19public:
20 static constexpr bool no_mapped_container = std::is_same_v<MappedContainer, ::brstd::no_mapped_container_t>;
21
22 using key_type = Key;
23 using mapped_type = std::conditional_t<no_mapped_container, Key, T>;
24 using key_compare = Compare;
25 using key_container_type = KeyContainer;
26 using mapped_container_type = MappedContainer;
27 using size_type = typename key_container_type::size_type;
28 using difference_type = typename std::iterator_traits<typename key_container_type::iterator>::difference_type;
29
30private:
31 struct no_mapped_iterator {
32 public:
33 using difference_type = std::ptrdiff_t;
34 using value_type = ::brstd::no_value_t;
35 using reference = ::brstd::no_value_t&;
36 using iterator_category = std::random_access_iterator_tag;
37
38 public:
39 reference operator*() const {
40 static ::brstd::no_value_t value{};
41 return value;
42 }
43
44 no_mapped_iterator& operator++() { return *this; }
45 no_mapped_iterator operator++(int) { return *this; }
46 no_mapped_iterator& operator--() { return *this; }
47 no_mapped_iterator operator--(int) { return *this; }
48 no_mapped_iterator& operator+=(difference_type) { return *this; }
49 no_mapped_iterator& operator-=(difference_type) { return *this; }
50 no_mapped_iterator operator+(difference_type) const { return *this; }
51 no_mapped_iterator operator-(difference_type) const { return *this; }
52 difference_type operator-(no_mapped_iterator const&) const { return 0; }
53 bool operator==(no_mapped_iterator const&) const = default;
54 std::strong_ordering operator<=>(no_mapped_iterator const&) const = default;
55 };
56
57 using mapped_iterator =
58 std::conditional_t<no_mapped_container, no_mapped_iterator, typename mapped_container_type::iterator>;
59 using mapped_const_iterator =
60 std::conditional_t<no_mapped_container, no_mapped_iterator, typename mapped_container_type::const_iterator>;
61
62public:
63 template <typename KeysIterator, typename ValuesIterator, typename Reference>
64 class iterator_impl {
65 public:
66 using difference_type = typename std::iterator_traits<KeysIterator>::difference_type;
67 using reference = Reference;
68 using iterator_category = typename std::iterator_traits<KeysIterator>::iterator_category;
69
70 public:
71 iterator_impl() = default;
72 iterator_impl(KeysIterator keysIt, ValuesIterator valuesIt) : mKeysIt(keysIt), mValuesIt(valuesIt) {}
73
74 reference operator*() const {
75 if constexpr (no_mapped_container) {
76 return *mKeysIt;
77 } else {
78 return reference(*mKeysIt, *mValuesIt);
79 }
80 }
81
82 iterator_impl& operator++() {
83 ++mKeysIt;
84 ++mValuesIt;
85 return *this;
86 }
87
88 iterator_impl operator++(int) {
89 auto copy = *this;
90 ++(*this);
91 return copy;
92 }
93
94 iterator_impl& operator--() {
95 --mKeysIt;
96 --mValuesIt;
97 return *this;
98 }
99
100 iterator_impl operator--(int) {
101 auto copy = *this;
102 --(*this);
103 return copy;
104 }
105
106 iterator_impl& operator+=(difference_type offset) {
107 mKeysIt += offset;
108 mValuesIt += offset;
109 return *this;
110 }
111
112 iterator_impl& operator-=(difference_type offset) {
113 mKeysIt -= offset;
114 mValuesIt -= offset;
115 return *this;
116 }
117
118 iterator_impl operator+(difference_type offset) const {
119 return iterator_impl(mKeysIt + offset, mValuesIt + offset);
120 }
121
122 iterator_impl operator-(difference_type offset) const {
123 return iterator_impl(mKeysIt - offset, mValuesIt - offset);
124 }
125
126 difference_type operator-(iterator_impl const& other) const { return mKeysIt - other.mKeysIt; }
127 bool operator==(iterator_impl const& other) const { return mKeysIt == other.mKeysIt; }
128 std::strong_ordering operator<=>(iterator_impl const& other) const { return mKeysIt <=> other.mKeysIt; }
129
130 private:
131 KeysIterator mKeysIt{};
132 ValuesIterator mValuesIt{};
133 };
134
135public:
136 using zip_iterator = iterator_impl<
137 typename key_container_type::iterator,
138 mapped_iterator,
139 std::conditional_t<no_mapped_container, key_type const&, std::pair<key_type const&, T&>>>;
140 using const_zip_iterator = iterator_impl<
141 typename key_container_type::const_iterator,
142 mapped_const_iterator,
143 std::conditional_t<no_mapped_container, key_type const&, std::pair<key_type const&, T const&>>>;
144
145 using iterator = zip_iterator;
146 using const_iterator = const_zip_iterator;
147
148 struct containers {
149 key_container_type keys;
150 LL_NO_UNIQUE_ADDRESS mapped_container_type values;
151 };
152
153public:
154 // mContainers is private, so the key container has to be exposed through an accessor of its own.
155 [[nodiscard]] key_container_type const& keys() const noexcept { return mContainers.keys; }
156
157 // In the original it is private and only reachable through an inlined public wrapper, which is why it is exposed
158 // here next to `emplace_hint`.
159 template <class K, class V>
160 std::pair<iterator, bool>
161 _emplace_before(typename key_container_type::const_iterator position, K&& key, V&& value) {
162 auto const offset = static_cast<size_t>(position - mContainers.keys.cbegin());
163 auto const keyIt = mContainers.keys.insert(mContainers.keys.cbegin() + offset, ::std::forward<K>(key));
164 auto const valIt = mContainers.values.insert(mContainers.values.cbegin() + offset, ::std::forward<V>(value));
165 return {iterator(keyIt, valIt), true};
166 }
167
170 template <class K, class V>
171 std::pair<iterator, bool> emplace_hint(typename key_container_type::const_iterator position, K&& key, V&& value) {
172 return _emplace_before(position, ::std::forward<K>(key), ::std::forward<V>(value));
173 }
174
175 iterator begin() noexcept { return iterator(mContainers.keys.begin(), mContainers.values.begin()); }
176 const_iterator begin() const noexcept {
177 return const_iterator(mContainers.keys.begin(), mContainers.values.begin());
178 }
179 iterator end() noexcept { return iterator(mContainers.keys.end(), mContainers.values.end()); }
180 const_iterator end() const noexcept { return const_iterator(mContainers.keys.end(), mContainers.values.end()); }
181 const_iterator cbegin() const noexcept { return begin(); }
182 const_iterator cend() const noexcept { return end(); }
183
184 iterator find(key_type const& key) {
185 auto first = mContainers.keys.begin();
186 auto last = mContainers.keys.end();
187 auto it = std::lower_bound(first, last, key, mCompare);
188 if (it != last && !mCompare(*it, key) && !mCompare(key, *it)) {
189 auto offset = static_cast<difference_type>(it - first);
190 return iterator(it, mContainers.values.begin() + offset);
191 }
192 return end();
193 }
194
195 const_iterator find(key_type const& key) const {
196 auto first = mContainers.keys.begin();
197 auto last = mContainers.keys.end();
198 auto it = std::lower_bound(first, last, key, mCompare);
199 if (it != last && !mCompare(*it, key) && !mCompare(key, *it)) {
200 auto offset = static_cast<difference_type>(it - first);
201 return const_iterator(it, mContainers.values.begin() + offset);
202 }
203 return end();
204 }
205
206private:
207 containers mContainers{};
208 LL_NO_UNIQUE_ADDRESS key_compare mCompare{};
209};
210
211} // namespace brstd
Definition associative_adapter.h:64
Definition associative_adapter.h:18
std::pair< iterator, bool > emplace_hint(typename key_container_type::const_iterator position, K &&key, V &&value)
Inserts key/value at position, which the caller must have located using this container's own ordering...
Definition associative_adapter.h:171
Definition associative_adapter.h:148
Definition no_value_t.h:7