FastLED 3.9.15
Loading...
Searching...
No Matches
multi_map.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/stdint.h"
4#include "fl/stl/assert.h" // IWYU pragma: keep
5#include "fl/stl/comparators.h" // IWYU pragma: keep
6#include "fl/stl/pair.h"
7#include "fl/stl/type_traits.h" // IWYU pragma: keep
9#include "fl/stl/allocator.h"
10#include "fl/stl/noexcept.h"
11
12namespace fl {
13
14// Forward declaration for drop-in std::multimap replacement
15template <typename Key, typename Value, typename Compare = less<Key>, typename Allocator = allocator<fl::pair<Key, Value>>>
17
18// Specialized Red-Black Tree for multimaps (allows duplicate keys)
19// Based on MapRedBlackTree but with modified insert logic
20template <typename Key, typename Value, typename Compare = less<Key>, typename Allocator = allocator<fl::pair<Key, Value>>>
22public:
23 using key_type = Key;
24 using mapped_type = Value;
26 using size_type = fl::size;
28 using key_compare = Compare;
32 using const_pointer = const value_type*;
33 using allocator_type = Allocator;
34
35private:
36 // Forward declare iterator wrapper classes
37 class IteratorWrapper;
41
42 // Store pairs along with unique IDs to allow duplicate keys
43 struct ValueWithId {
45 fl::size unique_id;
46
48 ValueWithId(const value_type& v, fl::size id) : value(v), unique_id(id) {}
49 ValueWithId(value_type&& v, fl::size id) : value(fl::move(v)), unique_id(id) {}
50
51 // For comparisons - only compare keys, not IDs
52 const Key& get_key() const { return value.first; }
53 };
54
55 // Comparator that compares only keys
57 Compare mComp;
58
59 PairCompareWithId(const Compare& comp = Compare()) : mComp(comp) {}
60
61 bool operator()(const ValueWithId& a, const ValueWithId& b) const {
62 // Compare keys; if keys are equal, compare IDs to maintain stable order
63 if (mComp(a.value.first, b.value.first)) {
64 return true;
65 }
66 if (mComp(b.value.first, a.value.first)) {
67 return false;
68 }
69 // Keys are equal - use ID for ordering
70 return a.unique_id < b.unique_id;
71 }
72 };
73
76 fl::size mNextId = 0;
77
78 // Convert tree iterator to our iterator
80 private:
81 friend class MultiMapTree;
83 typename TreeType::iterator mTreeIt;
84
85 public:
87 explicit IteratorWrapper(typename TreeType::iterator it) : mTreeIt(it) {}
88
90 return (*mTreeIt).value;
91 }
93 return &((*mTreeIt).value);
94 }
95
97 ++mTreeIt;
98 return *this;
99 }
100
102 IteratorWrapper tmp = *this;
103 ++mTreeIt;
104 return tmp;
105 }
106
108 --mTreeIt;
109 return *this;
110 }
111
113 IteratorWrapper tmp = *this;
114 --mTreeIt;
115 return tmp;
116 }
117
118 bool operator==(const IteratorWrapper& other) const { return mTreeIt == other.mTreeIt; }
119 bool operator!=(const IteratorWrapper& other) const { return mTreeIt != other.mTreeIt; }
120 };
121
123 private:
124 friend class MultiMapTree;
125 friend class IteratorWrapper;
126 typename TreeType::const_iterator mTreeIt;
127
128 public:
130 explicit ConstIteratorWrapper(typename TreeType::const_iterator it) : mTreeIt(it) {}
131 // Allow implicit conversion from non-const iterator
133
134 const value_type& operator*() const {
135 return (*mTreeIt).value;
136 }
137 const value_type* operator->() const {
138 return &((*mTreeIt).value);
139 }
140
142 ++mTreeIt;
143 return *this;
144 }
145
147 ConstIteratorWrapper tmp = *this;
148 ++mTreeIt;
149 return tmp;
150 }
151
153 --mTreeIt;
154 return *this;
155 }
156
158 ConstIteratorWrapper tmp = *this;
159 --mTreeIt;
160 return tmp;
161 }
162
163 bool operator==(const ConstIteratorWrapper& other) const { return mTreeIt == other.mTreeIt; }
164 bool operator!=(const ConstIteratorWrapper& other) const { return mTreeIt != other.mTreeIt; }
165 };
166
168 private:
169 friend class MultiMapTree;
171 typename TreeType::reverse_iterator mTreeRIt;
172
173 public:
176
178 return (*mTreeRIt).value;
179 }
181 return &((*mTreeRIt).value);
182 }
183
185 ++mTreeRIt;
186 return *this;
187 }
188
190 ReverseIteratorWrapper tmp = *this;
191 ++mTreeRIt;
192 return tmp;
193 }
194
196 --mTreeRIt;
197 return *this;
198 }
199
201 ReverseIteratorWrapper tmp = *this;
202 --mTreeRIt;
203 return tmp;
204 }
205
206 bool operator==(const ReverseIteratorWrapper& other) const { return mTreeRIt == other.mTreeRIt; }
207 bool operator!=(const ReverseIteratorWrapper& other) const { return mTreeRIt != other.mTreeRIt; }
208 };
209
211 private:
212 friend class MultiMapTree;
213 typename TreeType::const_reverse_iterator mTreeRIt;
214
215 public:
218 // Allow implicit conversion from non-const reverse iterator
220
221 const value_type& operator*() const {
222 return (*mTreeRIt).value;
223 }
224 const value_type* operator->() const {
225 return &((*mTreeRIt).value);
226 }
227
229 ++mTreeRIt;
230 return *this;
231 }
232
234 ConstReverseIteratorWrapper tmp = *this;
235 ++mTreeRIt;
236 return tmp;
237 }
238
240 --mTreeRIt;
241 return *this;
242 }
243
245 ConstReverseIteratorWrapper tmp = *this;
246 --mTreeRIt;
247 return tmp;
248 }
249
250 bool operator==(const ConstReverseIteratorWrapper& other) const { return mTreeRIt == other.mTreeRIt; }
251 bool operator!=(const ConstReverseIteratorWrapper& other) const { return mTreeRIt != other.mTreeRIt; }
252 };
253
254public:
259
260 // Value comparison class for std::multimap compatibility
262 friend class MultiMapTree;
263 Compare mComp;
264 value_compare(Compare c) : mComp(c) {}
265 public:
266 bool operator()(const value_type& x, const value_type& y) const {
267 return mComp(x.first, y.first);
268 }
269 };
270
271 // Constructors and destructor
272 MultiMapTree(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
273 : mTree(PairCompareWithId(comp), alloc) {}
274
275 MultiMapTree(const MultiMapTree& other) FL_NOEXCEPT = default;
277
280
281 // Initializer list constructor
282 MultiMapTree(fl::initializer_list<value_type> init,
283 const Compare& comp = Compare(),
284 const Allocator& alloc = Allocator())
285 : mTree(PairCompareWithId(comp), alloc) {
286 for (const auto& value : init) {
287 insert(value);
288 }
289 }
290
292
293 // Iterators
294 iterator begin() { return iterator(mTree.begin()); }
295 const_iterator begin() const { return const_iterator(mTree.begin()); }
296 const_iterator cbegin() const { return const_iterator(mTree.cbegin()); }
297 iterator end() { return iterator(mTree.end()); }
298 const_iterator end() const { return const_iterator(mTree.end()); }
299 const_iterator cend() const { return const_iterator(mTree.cend()); }
300
301 // Reverse iterators
306
307 // Capacity
308 bool empty() const { return mTree.empty(); }
309 fl::size size() const { return mTree.size(); }
310 fl::size max_size() const { return mTree.max_size(); }
311
312 // Modifiers
313 void clear() { mTree.clear(); mNextId = 0; }
314
315 // Insert always succeeds for multimap
317 ValueWithId vwid(value, mNextId++);
318 auto result = mTree.insert(vwid);
319 return iterator(result.first);
320 }
321
323 ValueWithId vwid(fl::move(value), mNextId++);
324 auto result = mTree.insert(fl::move(vwid));
325 return iterator(result.first);
326 }
327
328 template<typename... Args>
329 iterator emplace(Args&&... args) {
331 ValueWithId vwid(fl::move(temp), mNextId++);
332 auto result = mTree.insert(fl::move(vwid));
333 return iterator(result.first);
334 }
335
336 // Range insert
337 template <typename InputIt>
338 void insert(InputIt first, InputIt last) {
339 for (InputIt it = first; it != last; ++it) {
340 insert(*it);
341 }
342 }
343
344 // Initializer list insert
345 void insert(fl::initializer_list<value_type> ilist) {
346 for (const auto& value : ilist) {
347 insert(value);
348 }
349 }
350
351 // Erase by iterator
353 return iterator(mTree.erase(pos.mTreeIt));
354 }
355
356 // Also accept const_iterator for STL compatibility
358 return iterator(mTree.erase(pos.mTreeIt));
359 }
360
361 // Erase all elements with the given key
362 fl::size erase(const Key& key) {
363 auto range = equal_range(key);
364 fl::size count = 0;
365 auto it = range.first;
366 while (it != range.second) {
367 it = erase(it);
368 ++count;
369 }
370 return count;
371 }
372
373 // Range erase
375 // Erase each element in the range [first, last)
376 iterator result = begin(); // Default return
377
378 while (first != last) {
379 result = erase(first); // erase(const_iterator pos) returns iterator to next element
380 // Update first to point to the next element (which is now at the erased position)
381 first = ConstIteratorWrapper(result.mTreeIt);
382 }
383
384 return result;
385 }
386
387 void swap(MultiMapTree& other) {
388 mTree.swap(other.mTree);
389 fl::swap(mNextId, other.mNextId);
390 }
391
392 // Lookup
393 fl::size count(const Key& key) const {
394 auto range = equal_range(key);
395 fl::size count = 0;
396 for (auto it = range.first; it != range.second; ++it) {
397 ++count;
398 }
399 return count;
400 }
401
402 iterator find(const Key& key) {
403 ValueWithId search_key(value_type(key, Value()), 0);
404 auto it = mTree.lower_bound(search_key);
405 if (it != mTree.end() && it->value.first == key) {
406 return iterator(it);
407 }
408 return end();
409 }
410
411 const_iterator find(const Key& key) const {
412 ValueWithId search_key(value_type(key, Value()), 0);
413 auto it = mTree.lower_bound(search_key);
414 if (it != mTree.end() && it->value.first == key) {
415 return const_iterator(it);
416 }
417 return end();
418 }
419
420 bool contains(const Key& key) const {
421 return find(key) != end();
422 }
423
424 // equal_range returns [lower_bound, upper_bound) for the given key
426 iterator lower = lower_bound(key);
427 iterator upper = upper_bound(key);
428 return fl::pair<iterator, iterator>(lower, upper);
429 }
430
436
438 ValueWithId search_key(value_type(key, Value()), 0);
439 return iterator(mTree.lower_bound(search_key));
440 }
441
442 const_iterator lower_bound(const Key& key) const {
443 ValueWithId search_key(value_type(key, Value()), 0);
444 return const_iterator(mTree.lower_bound(search_key));
445 }
446
448 ValueWithId search_key(value_type(key, Value()), mNextId); // Use mNextId to get upper bound
449 return iterator(mTree.upper_bound(search_key));
450 }
451
452 const_iterator upper_bound(const Key& key) const {
453 ValueWithId search_key(value_type(key, Value()), mNextId);
454 return const_iterator(mTree.upper_bound(search_key));
455 }
456
457 // Observers
458 key_compare key_comp() const { return key_compare(); }
459
460 value_compare value_comp() const {
461 return value_compare(key_compare());
462 }
463
465 return mTree.get_allocator();
466 }
467
468 // Comparison operators
469 bool operator==(const MultiMapTree& other) const {
470 if (size() != other.size()) return false;
471 for (auto it1 = begin(), it2 = other.begin(); it1 != end(); ++it1, ++it2) {
472 if (it1->first != it2->first || it1->second != it2->second) {
473 return false;
474 }
475 }
476 return true;
477 }
478
479 bool operator!=(const MultiMapTree& other) const {
480 return !(*this == other);
481 }
482
483 bool operator<(const MultiMapTree& other) const {
484 for (auto it1 = begin(), it2 = other.begin(); it1 != end() && it2 != other.end(); ++it1, ++it2) {
485 if (it1->first < it2->first) return true;
486 if (it2->first < it1->first) return false;
487 if (it1->second < it2->second) return true;
488 if (it2->second < it1->second) return false;
489 }
490 return size() < other.size();
491 }
492
493 bool operator<=(const MultiMapTree& other) const {
494 return *this < other || *this == other;
495 }
496
497 bool operator>(const MultiMapTree& other) const {
498 return other < *this;
499 }
500
501 bool operator>=(const MultiMapTree& other) const {
502 return other <= *this;
503 }
504};
505
506} // namespace fl
507
508// Drop-in replacement for std::multimap
509namespace fl {
510
511// Default multimap uses slab allocator for better performance
512// Matches the behavior of fl::map
513template <typename Key, typename T, typename Compare = fl::less<Key>>
515
516} // namespace fl
uint8_t pos
Definition Blur.ino:11
ConstIteratorWrapper & operator++()
Definition multi_map.h:141
TreeType::const_iterator mTreeIt
Definition multi_map.h:126
ConstIteratorWrapper & operator--()
Definition multi_map.h:152
ConstIteratorWrapper operator++(int)
Definition multi_map.h:146
const value_type & operator*() const
Definition multi_map.h:134
bool operator!=(const ConstIteratorWrapper &other) const
Definition multi_map.h:164
ConstIteratorWrapper operator--(int)
Definition multi_map.h:157
bool operator==(const ConstIteratorWrapper &other) const
Definition multi_map.h:163
const value_type * operator->() const
Definition multi_map.h:137
ConstIteratorWrapper(const IteratorWrapper &it)
Definition multi_map.h:132
ConstIteratorWrapper() FL_NOEXCEPT=default
TreeType::const_reverse_iterator mTreeRIt
Definition multi_map.h:213
ConstReverseIteratorWrapper & operator--()
Definition multi_map.h:239
ConstReverseIteratorWrapper operator--(int)
Definition multi_map.h:244
ConstReverseIteratorWrapper(const ReverseIteratorWrapper &it)
Definition multi_map.h:219
ConstReverseIteratorWrapper operator++(int)
Definition multi_map.h:233
ConstReverseIteratorWrapper & operator++()
Definition multi_map.h:228
bool operator==(const ConstReverseIteratorWrapper &other) const
Definition multi_map.h:250
const value_type * operator->() const
Definition multi_map.h:224
bool operator!=(const ConstReverseIteratorWrapper &other) const
Definition multi_map.h:251
IteratorWrapper & operator--()
Definition multi_map.h:107
bool operator!=(const IteratorWrapper &other) const
Definition multi_map.h:119
IteratorWrapper operator--(int)
Definition multi_map.h:112
IteratorWrapper operator++(int)
Definition multi_map.h:101
IteratorWrapper & operator++()
Definition multi_map.h:96
IteratorWrapper() FL_NOEXCEPT=default
bool operator==(const IteratorWrapper &other) const
Definition multi_map.h:118
bool operator==(const ReverseIteratorWrapper &other) const
Definition multi_map.h:206
ReverseIteratorWrapper operator--(int)
Definition multi_map.h:200
ReverseIteratorWrapper & operator++()
Definition multi_map.h:184
bool operator!=(const ReverseIteratorWrapper &other) const
Definition multi_map.h:207
ReverseIteratorWrapper() FL_NOEXCEPT=default
TreeType::reverse_iterator mTreeRIt
Definition multi_map.h:171
ReverseIteratorWrapper operator++(int)
Definition multi_map.h:189
ReverseIteratorWrapper & operator--()
Definition multi_map.h:195
bool operator()(const value_type &x, const value_type &y) const
Definition multi_map.h:266
bool operator<(const MultiMapTree &other) const
Definition multi_map.h:483
iterator erase(const_iterator first, const_iterator last)
Definition multi_map.h:374
MultiMapTree(const Compare &comp=Compare(), const Allocator &alloc=Allocator())
Definition multi_map.h:272
value_type * pointer
Definition multi_map.h:31
fl::pair< Key, Value > value_type
Definition multi_map.h:25
bool operator>(const MultiMapTree &other) const
Definition multi_map.h:497
fl::size erase(const Key &key)
Definition multi_map.h:362
ReverseIteratorWrapper reverse_iterator
Definition multi_map.h:257
ptrdiff_t difference_type
Definition multi_map.h:27
const_iterator find(const Key &key) const
Definition multi_map.h:411
void insert(fl::initializer_list< value_type > ilist)
Definition multi_map.h:345
const value_type * const_pointer
Definition multi_map.h:32
bool contains(const Key &key) const
Definition multi_map.h:420
MultiMapTree & operator=(MultiMapTree &&other) FL_NOEXCEPT=default
const_iterator cend() const
Definition multi_map.h:299
iterator emplace(Args &&... args)
Definition multi_map.h:329
Compare key_compare
Definition multi_map.h:28
const_reverse_iterator rend() const
Definition multi_map.h:305
allocator_type get_allocator() const
Definition multi_map.h:464
key_compare key_comp() const
Definition multi_map.h:458
iterator erase(iterator pos)
Definition multi_map.h:352
reverse_iterator rbegin()
Definition multi_map.h:302
MultiMapTree(fl::initializer_list< value_type > init, const Compare &comp=Compare(), const Allocator &alloc=Allocator())
Definition multi_map.h:282
ConstIteratorWrapper const_iterator
Definition multi_map.h:256
fl::size size_type
Definition multi_map.h:26
iterator upper_bound(const Key &key)
Definition multi_map.h:447
IteratorWrapper iterator
Definition multi_map.h:255
value_type & reference
Definition multi_map.h:29
MultiMapTree(MultiMapTree &&other) FL_NOEXCEPT=default
iterator insert(value_type &&value)
Definition multi_map.h:322
bool operator>=(const MultiMapTree &other) const
Definition multi_map.h:501
const value_type & const_reference
Definition multi_map.h:30
void swap(MultiMapTree &other)
Definition multi_map.h:387
ConstReverseIteratorWrapper const_reverse_iterator
Definition multi_map.h:258
const_iterator cbegin() const
Definition multi_map.h:296
RedBlackTree< ValueWithId, PairCompareWithId, Allocator > TreeType
Definition multi_map.h:74
iterator lower_bound(const Key &key)
Definition multi_map.h:437
Allocator allocator_type
Definition multi_map.h:33
const_iterator upper_bound(const Key &key) const
Definition multi_map.h:452
bool operator==(const MultiMapTree &other) const
Definition multi_map.h:469
const_iterator lower_bound(const Key &key) const
Definition multi_map.h:442
iterator insert(const value_type &value)
Definition multi_map.h:316
iterator end()
Definition multi_map.h:297
iterator find(const Key &key)
Definition multi_map.h:402
bool operator!=(const MultiMapTree &other) const
Definition multi_map.h:479
fl::size max_size() const
Definition multi_map.h:310
fl::pair< const_iterator, const_iterator > equal_range(const Key &key) const
Definition multi_map.h:431
reverse_iterator rend()
Definition multi_map.h:303
bool empty() const
Definition multi_map.h:308
~MultiMapTree() FL_NOEXCEPT=default
const_reverse_iterator rbegin() const
Definition multi_map.h:304
bool operator<=(const MultiMapTree &other) const
Definition multi_map.h:493
fl::size size() const
Definition multi_map.h:309
const_iterator end() const
Definition multi_map.h:298
fl::pair< iterator, iterator > equal_range(const Key &key)
Definition multi_map.h:425
MultiMapTree(const MultiMapTree &other) FL_NOEXCEPT=default
void insert(InputIt first, InputIt last)
Definition multi_map.h:338
value_compare value_comp() const
Definition multi_map.h:460
const_iterator begin() const
Definition multi_map.h:295
iterator erase(const_iterator pos)
Definition multi_map.h:357
MultiMapTree & operator=(const MultiMapTree &other) FL_NOEXCEPT=default
constexpr T && forward(typename remove_reference< T >::type &t) FL_NOEXCEPT
Definition s16x16x4.h:234
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition s16x16x4.h:28
void swap(T &a, T &b) FL_NOEXCEPT
Definition s16x16x4.h:877
MultiMapTree< Key, T, Compare, fl::allocator_slab< char > > multi_map
Definition multi_map.h:514
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition move.h:28
constexpr int type_rank< T >::value
void init(Context &ctx, int w, int h)
Definition engine.h:133
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
fl::ptrdiff ptrdiff_t
Definition s16x16x4.h:226
Base definition for an LED controller.
Definition crgb.hpp:179
corkscrew_args args
Definition old.h:149
#define FL_NOEXCEPT
Definition Keyboard.h:22
bool operator()(const ValueWithId &a, const ValueWithId &b) const
Definition multi_map.h:61
PairCompareWithId(const Compare &comp=Compare())
Definition multi_map.h:59
ValueWithId(value_type &&v, fl::size id)
Definition multi_map.h:49
const Key & get_key() const
Definition multi_map.h:52
ValueWithId() FL_NOEXCEPT=default
T1 first
Definition pair.h:16