Maipa's Standard Library Extension 1.5.6
mstd
Loading...
Searching...
No Matches
bimap.hpp
1/*
2 * mstd - Maipa's Standard Library
3 *
4 * Licensed under the BSD 3-Clause License with Attribution Requirement.
5 * See the LICENSE file for details: https://github.com/MAIPA01/mstd/blob/main/LICENSE
6 *
7 * Copyright (c) 2025, Patryk Antosik (MAIPA01)
8 */
9
10#pragma once
11#ifndef _MSTD_BIMAP_HPP_
12 #define _MSTD_BIMAP_HPP_
13
14 #include <mstd/config.hpp>
15
17_MSTD_WARNING("this is only available for c++17 and greater!");
18 #else
19
20 #include <mstd/assert.hpp>
21 #include <mstd/containers_types.hpp>
22
23namespace mstd {
24 template<class Key, class T, template<class, class, class...> class Map>
25 class bimap {
26 public:
27 using key_type = remove_cvref_t<Key>;
28 using mapped_type = remove_cvref_t<T>;
29 using value_type = std::pair<key_type, mapped_type>;
30 using reference = value_type&;
31 using const_reference = const value_type&;
32
33 private:
34 using _data_type = std::vector<value_type>;
35
36 public:
37 using size_type = _MSTD_TYPENAME17 _data_type::size_type;
38 using difference_type = _MSTD_TYPENAME17 _data_type::difference_type;
39 using iterator = _MSTD_TYPENAME17 _data_type::const_iterator;
40 using const_iterator = _MSTD_TYPENAME17 _data_type::const_iterator;
41 using reverse_iterator = _MSTD_TYPENAME17 _data_type::const_reverse_iterator;
42 using const_reverse_iterator = _MSTD_TYPENAME17 _data_type::const_reverse_iterator;
43
44 private:
45 using _map_type = Map<key_type, size_type>;
46 using _inverted_map_type = Map<mapped_type, size_type>;
47
48 _data_type _data;
49 _map_type _map;
50 _inverted_map_type _invertedMap;
51
52 _MSTD_CONSTEXPR20 void _update_indexes(const size_type from) {
53 for (size_type i = from; i != _data.size(); ++i) {
54 _map[_data[i].first] = i;
55 _invertedMap[_data[i].second] = i;
56 }
57 }
58
59 template<class UK, class U>
60 _MSTD_CONSTEXPR20 mapped_type& _emplace(UK&& key, U&& value) {
61 return _insert(std::make_pair(std::forward<UK>(key), std::forward<U>(value)));
62 }
63
64 template<class U>
65 _MSTD_CONSTEXPR20 mapped_type& _insert(U&& value) {
66 const key_type key = value.first;
67 const mapped_type mappedValue = value.second;
68
69 if (contains(key) && _data[_map.at(key)].second == mappedValue) { return _data[_map.at(key)].second; }
70
71 // add new pair
72 _data.push_back(std::forward<U>(value));
73
74 // get maps iterators
75 size_t minIdx = _data.size() - 1;
76 if (contains(key)) {
77 size_t valueIdx = _map.at(key);
78
79 // set min idx
80 minIdx = std::min(minIdx, valueIdx);
81
82 // erase inverted map
83 _invertedMap.erase(_data[valueIdx].second);
84
85 // erase data
86 _data.erase(std::next(_data.begin(), valueIdx));
87
88 // erase map
89 _map.erase(key);
90 }
91
92 if (contains_value(mappedValue)) {
93 size_t keyIdx = _invertedMap.at(mappedValue);
94
95 // set min idx
96 minIdx = std::min(keyIdx, minIdx);
97
98 // erase map
99 _map.erase(_data[keyIdx].first);
100
101 // erase data
102 _data.erase(std::next(_data.begin(), keyIdx));
103
104 // erase inverted map
105 _invertedMap.erase(mappedValue);
106 }
107
108 _update_indexes(minIdx);
109
110 return _data[_map.at(key)].second;
111 }
112
113 template<class UK>
114 _MSTD_CONSTEXPR20 void _erase(UK&& key) {
115 if (!contains(key)) { return; }
116
117 size_t elementOffset = _map.at(key);
118
119 const iterator& itr = std::next(_data.begin(), elementOffset);
120 mapped_type value = itr->second;
121 _data.erase(itr);
122 _map.erase(std::forward<UK>(key));
123 _invertedMap.erase(value);
124
125 _update_indexes(elementOffset);
126 }
127
128 template<class U>
129 _MSTD_CONSTEXPR20 void _erase_value(U&& value) {
130 if (!contains_value(value)) { return; }
131
132 size_t elementOffset = _invertedMap.at(value);
133
134 const iterator& itr = std::next(_data.begin(), elementOffset);
135 key_type key = itr->first;
136 _data.erase(itr);
137 _invertedMap.erase(std::forward<U>(value));
138 _map.erase(key);
139
140 _update_indexes(elementOffset);
141 }
142
143 template<class UK>
144 [[nodiscard]] _MSTD_CONSTEXPR20 mapped_type& _at(UK&& key) {
145 if _MSTD_CONSTEXPR17 (fmt::is_formattable<key_type>::value) {
146 mstd_assert(contains(key), "Key '{}' not found", key);
147 }
148 else { mstd_assert(contains(key), "Key not found"); }
149 return _data.at(_map.at(std::forward<UK>(key))).second;
150 }
151
152 template<class UK>
153 [[nodiscard]] _MSTD_CONSTEXPR20 const mapped_type& _at(UK&& key) const {
154 if _MSTD_CONSTEXPR17 (fmt::is_formattable<key_type>::value) {
155 mstd_assert(contains(key), "Key '{}' not found", key);
156 }
157 else { mstd_assert(contains(key), "Key not found"); }
158 return _data.at(_map.at(std::forward<UK>(key))).second;
159 }
160
161 template<class U>
162 [[nodiscard]] _MSTD_CONSTEXPR20 key_type& _at_value(U&& value) {
163 if _MSTD_CONSTEXPR17 (fmt::is_formattable<mapped_type>::value) {
164 mstd_assert(contains_value(value), "Value '{}' not found", value);
165 }
166 else { mstd_assert(contains_value(value), "Value not found"); }
167 return _data.at(_invertedMap.at(std::forward<U>(value))).first;
168 }
169
170 template<class U>
171 [[nodiscard]] _MSTD_CONSTEXPR20 const key_type& _at_value(U&& value) const {
172 if _MSTD_CONSTEXPR17 (fmt::is_formattable<mapped_type>::value) {
173 mstd_assert(contains_value(value), "Value '{}' not found", value);
174 }
175 else { mstd_assert(contains_value(value), "Value not found"); }
176 return _data.at(_invertedMap.at(std::forward<U>(value))).first;
177 }
178
179 template<class UK>
180 [[nodiscard]] _MSTD_CONSTEXPR20 bool _contains(UK&& key) const {
182 return _map.contains(std::forward<UK>(key));
183 #else
184 return _map.find(std::forward<UK>(key)) != _map.end();
185 #endif
186 }
187
188 template<class U>
189 [[nodiscard]] _MSTD_CONSTEXPR20 bool _contains_value(U&& value) const {
191 return _invertedMap.contains(std::forward<U>(value));
192 #else
193 return _invertedMap.find(std::forward<U>(value)) != _invertedMap.end();
194 #endif
195 }
196
197 template<class UK>
198 [[nodiscard]] _MSTD_CONSTEXPR20 key_type& _at_with_construct(UK&& key) {
199 if (!contains(key)) { return _emplace(std::forward<UK>(key), mapped_type()); }
200 return _at(std::forward<UK>(key));
201 }
202
203 template<class UK>
204 [[nodiscard]] _MSTD_CONSTEXPR20 iterator _find(UK&& key) {
205 auto it = _map.find(std::forward<UK>(key));
206 return it != _map.end() ? std::next(_data.begin(), it->second) : _data.end();
207 }
208
209 template<class UK>
210 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator _find(UK&& key) const {
211 auto it = _map.find(std::forward<UK>(key));
212 return it != _map.end() ? std::next(_data.cbegin(), it->second) : _data.cend();
213 }
214
215 template<class U>
216 [[nodiscard]] _MSTD_CONSTEXPR20 iterator _find_value(U&& value) {
217 auto it = _invertedMap.find(std::forward<U>(value));
218 return it != _invertedMap.end() ? std::next(_data.begin(), it->second) : _data.end();
219 }
220
221 template<class U>
222 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator _find_value(U&& value) const {
223 auto it = _invertedMap.find(std::forward<U>(value));
224 return it != _invertedMap.end() ? std::next(_data.cbegin(), it->second) : _data.cend();
225 }
226
227 public:
228 _MSTD_CONSTEXPR20 bimap() = default;
229
230 _MSTD_CONSTEXPR20 bimap(std::initializer_list<value_type> init) { insert(init.begin(), init.end()); }
231
232 _MSTD_CONSTEXPR20 bimap(const bimap& other) = default;
233 _MSTD_CONSTEXPR20 bimap(bimap&& other) noexcept = default;
234
236 template<mstd::iterator_of<value_type> Iter>
237 #else
238 template<class Iter, std::enable_if_t<is_iterator_of_v<Iter, value_type>, bool> = true>
239 #endif
240 _MSTD_CONSTEXPR20 bimap(Iter begin, Iter end) {
241 insert(begin, end);
242 }
243
244 _MSTD_CONSTEXPR20 ~bimap() = default;
245
246 _MSTD_CONSTEXPR20 bimap& operator=(const bimap& other) = default;
247 _MSTD_CONSTEXPR20 bimap& operator=(bimap&& other) noexcept = default;
248
249 _MSTD_CONSTEXPR20 mapped_type& emplace(const key_type& key, const mapped_type& value) { return _emplace(key, value); }
250
251 _MSTD_CONSTEXPR20 mapped_type& emplace(key_type&& key, mapped_type&& value) {
252 return _emplace(std::move(key), std::move(value));
253 }
254
255 _MSTD_CONSTEXPR20 mapped_type& insert(const value_type& value) { return _insert(value); }
256
257 _MSTD_CONSTEXPR20 mapped_type& insert(value_type&& value) { return _insert(std::move(value)); }
258
260 template<mstd::iterator_of<value_type> Iter>
261 #else
262 template<class Iter, std::enable_if_t<is_iterator_of_v<Iter, value_type>, bool> = true>
263 #endif
264 _MSTD_CONSTEXPR20 void insert(Iter begin, Iter end) {
265 for (Iter iter = begin; iter != end; ++iter) { insert(*iter); }
266 }
267
268 _MSTD_CONSTEXPR20 void erase(const key_type& key) { _erase(key); }
269
270 _MSTD_CONSTEXPR20 void erase(key_type&& key) { _erase(std::move(key)); }
271
272 _MSTD_CONSTEXPR20 void erase_value(const mapped_type& value) { _erase_value(value); }
273
274 _MSTD_CONSTEXPR20 void erase_value(mapped_type&& value) { _erase_value(std::move(value)); }
275
276 [[nodiscard]] _MSTD_CONSTEXPR20 mapped_type& at(const key_type& key) { return _at(key); }
277
278 [[nodiscard]] _MSTD_CONSTEXPR20 mapped_type& at(key_type&& key) { return _at(std::move(key)); }
279
280 [[nodiscard]] _MSTD_CONSTEXPR20 const mapped_type& at(const key_type& key) const { return _at(key); }
281
282 [[nodiscard]] _MSTD_CONSTEXPR20 const mapped_type& at(key_type&& key) const { return _at(std::move(key)); }
283
284 [[nodiscard]] _MSTD_CONSTEXPR20 key_type& at_value(const mapped_type& value) { return _at_value(value); }
285
286 [[nodiscard]] _MSTD_CONSTEXPR20 key_type& at_value(mapped_type&& value) { return _at_value(std::move(value)); }
287
288 [[nodiscard]] _MSTD_CONSTEXPR20 const key_type& at_value(const mapped_type& value) const { return _at_value(value); }
289
290 [[nodiscard]] _MSTD_CONSTEXPR20 const key_type& at_value(mapped_type&& value) const {
291 return _at_value(std::move(value));
292 }
293
294 [[nodiscard]] _MSTD_CONSTEXPR20 size_t size() const { return _data.size(); }
295
296 [[nodiscard]] _MSTD_CONSTEXPR20 bool empty() const { return _data.empty(); }
297
298 [[nodiscard]] _MSTD_CONSTEXPR20 bool contains(const key_type& key) const { return _contains(key); }
299
300 [[nodiscard]] _MSTD_CONSTEXPR20 bool contains(key_type&& key) const { return _contains(std::move(key)); }
301
302 [[nodiscard]] _MSTD_CONSTEXPR20 bool contains_value(const mapped_type& value) const { return _contains_value(value); }
303
304 [[nodiscard]] _MSTD_CONSTEXPR20 bool contains_value(mapped_type&& value) const {
305 return _contains_value(std::move(value));
306 }
307
308 [[nodiscard]] _MSTD_CONSTEXPR20 iterator find(const key_type& key) { return _find(key); }
309
310 [[nodiscard]] _MSTD_CONSTEXPR20 iterator find(key_type&& key) { return _find(std::move(key)); }
311
312 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator find(const key_type& key) const { return _find(key); }
313
314 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator find(key_type&& key) const { return _find(std::move(key)); }
315
316 [[nodiscard]] _MSTD_CONSTEXPR20 iterator find_value(const mapped_type& value) { return _find_value(value); }
317
318 [[nodiscard]] _MSTD_CONSTEXPR20 iterator find_value(mapped_type&& value) { return _find_value(std::move(value)); }
319
320 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator find_value(const mapped_type& value) const { return _find_value(value); }
321
322 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator find_value(mapped_type&& value) const {
323 return _find_value(std::move(value));
324 }
325
326 _MSTD_CONSTEXPR20 void clear() {
327 _data.clear();
328 _map.clear();
329 _invertedMap.clear();
330 }
331
332 [[nodiscard]] _MSTD_CONSTEXPR20 iterator begin() { return _data.begin(); }
333
334 [[nodiscard]] _MSTD_CONSTEXPR20 iterator end() { return _data.end(); }
335
336 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator begin() const { return _data.cbegin(); }
337
338 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator end() const { return _data.cend(); }
339
340 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator cbegin() const { return _data.cbegin(); }
341
342 [[nodiscard]] _MSTD_CONSTEXPR20 const_iterator cend() const { return _data.cend(); }
343
344 [[nodiscard]] _MSTD_CONSTEXPR20 reverse_iterator rbegin() { return _data.rbegin(); }
345
346 [[nodiscard]] _MSTD_CONSTEXPR20 reverse_iterator rend() { return _data.rend(); }
347
348 [[nodiscard]] _MSTD_CONSTEXPR20 const_reverse_iterator rbegin() const { return _data.crbegin(); }
349
350 [[nodiscard]] _MSTD_CONSTEXPR20 const_reverse_iterator rend() const { return _data.crend(); }
351
352 [[nodiscard]] _MSTD_CONSTEXPR20 const_reverse_iterator crbegin() const { return _data.crbegin(); }
353
354 [[nodiscard]] _MSTD_CONSTEXPR20 const_reverse_iterator crend() const { return _data.crend(); }
355
356 [[nodiscard]] _MSTD_CONSTEXPR20 mapped_type& operator[](const key_type& key) {
357 if _MSTD_CONSTEXPR17 (std::is_default_constructible_v<mapped_type>) { return _at_with_construct(key); }
358 else { return _at(key); }
359 }
360
361 [[nodiscard]] _MSTD_CONSTEXPR20 mapped_type& operator[](key_type&& key) {
362 if _MSTD_CONSTEXPR17 (std::is_default_constructible_v<mapped_type>) { return _at_with_construct(std::move(key)); }
363 else { return _at(std::move(key)); }
364 }
365
366 [[nodiscard]] _MSTD_CONSTEXPR20 const mapped_type& operator[](const key_type& key) const { return _at(key); }
367
368 [[nodiscard]] _MSTD_CONSTEXPR20 const mapped_type& operator[](key_type&& key) const { return _at(std::move(key)); }
369
370 _MSTD_CONSTEXPR20 bool operator==(const bimap& other) const {
371 return _map == other._map && _invertedMap == other._invertedMap && _data == other._data;
372 }
373
374 _MSTD_CONSTEXPR20 bool operator!=(const bimap& other) const { return !(*this == other); }
375 };
376} // namespace mstd
377
378 #endif
379#endif
#define mstd_assert(expression,...)
Definition assert.hpp:29
#define _MSTD_HAS_CXX17
Definition config.hpp:45
#define _MSTD_CONSTEXPR17
Definition config.hpp:76
#define _MSTD_HAS_CXX20
Definition config.hpp:52
#define _MSTD_TYPENAME17
Definition config.hpp:82
#define _MSTD_CONSTEXPR20
Definition config.hpp:84