FastLED 3.9.15
Loading...
Searching...
No Matches
multi_set.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/type_traits.h" // IWYU pragma: keep
8#include "fl/stl/allocator.h"
9#include "fl/stl/noexcept.h"
10
11namespace fl {
12
13// Forward declaration for drop-in std::multiset replacement
14template <typename Key, typename Compare = less<Key>, typename Allocator = allocator<Key>>
16
17// Specialized Red-Black Tree for multisets (allows duplicate keys)
18// Based on SetRedBlackTree but with modified insert logic
19template <typename Key, typename Compare = less<Key>, typename Allocator = allocator<Key>>
21public:
22 using key_type = Key;
23 using value_type = Key;
24 using size_type = fl::size;
26 using key_compare = Compare;
27 using value_compare = Compare;
28 using reference = const value_type&;
30 using pointer = const value_type*;
31 using const_pointer = const value_type*;
32 using allocator_type = Allocator;
33
34private:
35 // Forward declare iterator wrapper classes
38
39 // Store keys along with unique IDs to allow duplicate keys
40 struct ValueWithId {
42 fl::size unique_id;
43
45 ValueWithId(const Key& v, fl::size id) : value(v), unique_id(id) {}
46 ValueWithId(Key&& v, fl::size id) : value(fl::move(v)), unique_id(id) {}
47
48 // For comparisons - only compare keys, not IDs
49 const Key& get_key() const { return value; }
50 };
51
52 // Comparator that compares only keys
54 Compare mComp;
55
56 KeyCompareWithId(const Compare& comp = Compare()) : mComp(comp) {}
57
58 bool operator()(const ValueWithId& a, const ValueWithId& b) const {
59 // Compare keys; if keys are equal, compare IDs to maintain stable order
60 if (mComp(a.value, b.value)) {
61 return true;
62 }
63 if (mComp(b.value, a.value)) {
64 return false;
65 }
66 // Keys are equal - use ID for ordering
67 return a.unique_id < b.unique_id;
68 }
69 };
70
73 fl::size mNextId = 0;
74
75 // Convert tree iterator to our iterator
77 private:
78 friend class MultiSetTree;
79 typename TreeType::const_iterator mTreeIt;
80
81 public:
83 explicit ConstIteratorWrapper(typename TreeType::const_iterator it) : mTreeIt(it) {}
84
85 const value_type& operator*() const {
86 return (*mTreeIt).value;
87 }
88 const value_type* operator->() const {
89 return &((*mTreeIt).value);
90 }
91
93 ++mTreeIt;
94 return *this;
95 }
96
98 ConstIteratorWrapper tmp = *this;
99 ++mTreeIt;
100 return tmp;
101 }
102
104 --mTreeIt;
105 return *this;
106 }
107
109 ConstIteratorWrapper tmp = *this;
110 --mTreeIt;
111 return tmp;
112 }
113
114 bool operator==(const ConstIteratorWrapper& other) const { return mTreeIt == other.mTreeIt; }
115 bool operator!=(const ConstIteratorWrapper& other) const { return mTreeIt != other.mTreeIt; }
116 };
117
119 private:
120 friend class MultiSetTree;
121 typename TreeType::const_reverse_iterator mTreeRIt;
122
123 public:
126
127 const value_type& operator*() const {
128 return (*mTreeRIt).value;
129 }
130 const value_type* operator->() const {
131 return &((*mTreeRIt).value);
132 }
133
135 ++mTreeRIt;
136 return *this;
137 }
138
140 ConstReverseIteratorWrapper tmp = *this;
141 ++mTreeRIt;
142 return tmp;
143 }
144
146 --mTreeRIt;
147 return *this;
148 }
149
151 ConstReverseIteratorWrapper tmp = *this;
152 --mTreeRIt;
153 return tmp;
154 }
155
156 bool operator==(const ConstReverseIteratorWrapper& other) const { return mTreeRIt == other.mTreeRIt; }
157 bool operator!=(const ConstReverseIteratorWrapper& other) const { return mTreeRIt != other.mTreeRIt; }
158 };
159
160public:
165
166 // Constructors and destructor
167 MultiSetTree(const Compare& comp = Compare(), const Allocator& alloc = Allocator())
168 : mTree(KeyCompareWithId(comp), alloc) {}
169
170 MultiSetTree(const MultiSetTree& other) FL_NOEXCEPT = default;
172
175
176 // Initializer list constructor
177 MultiSetTree(fl::initializer_list<value_type> init,
178 const Compare& comp = Compare(),
179 const Allocator& alloc = Allocator())
180 : mTree(KeyCompareWithId(comp), alloc) {
181 for (const auto& value : init) {
182 insert(value);
183 }
184 }
185
187
188 // Iterators
189 iterator begin() { return iterator(mTree.begin()); }
190 const_iterator begin() const { return const_iterator(mTree.begin()); }
191 const_iterator cbegin() const { return const_iterator(mTree.cbegin()); }
192 iterator end() { return iterator(mTree.end()); }
193 const_iterator end() const { return const_iterator(mTree.end()); }
194 const_iterator cend() const { return const_iterator(mTree.cend()); }
195
196 // Reverse iterators
201
202 // Capacity
203 bool empty() const { return mTree.empty(); }
204 fl::size size() const { return mTree.size(); }
205 fl::size max_size() const { return mTree.max_size(); }
206
207 // Modifiers
208 void clear() { mTree.clear(); mNextId = 0; }
209
210 // Insert always succeeds for multiset
212 ValueWithId vwid(value, mNextId++);
213 auto result = mTree.insert(vwid);
214 return iterator(result.first);
215 }
216
218 ValueWithId vwid(fl::move(value), mNextId++);
219 auto result = mTree.insert(fl::move(vwid));
220 return iterator(result.first);
221 }
222
223 template<typename... Args>
224 iterator emplace(Args&&... args) {
226 ValueWithId vwid(fl::move(temp), mNextId++);
227 auto result = mTree.insert(fl::move(vwid));
228 return iterator(result.first);
229 }
230
231 // Range insert
232 template <typename InputIt>
233 void insert(InputIt first, InputIt last) {
234 for (InputIt it = first; it != last; ++it) {
235 insert(*it);
236 }
237 }
238
239 // Initializer list insert
240 void insert(fl::initializer_list<value_type> ilist) {
241 for (const auto& value : ilist) {
242 insert(value);
243 }
244 }
245
246 // Erase by iterator
248 return iterator(mTree.erase(pos.mTreeIt));
249 }
250
251 // Erase all elements with the given key
252 fl::size erase(const Key& key) {
253 auto range = equal_range(key);
254 fl::size count = 0;
255 auto it = range.first;
256 while (it != range.second) {
257 it = erase(it);
258 ++count;
259 }
260 return count;
261 }
262
263 // Range erase
265 // Erase each element in the range [first, last)
266 iterator result = begin(); // Default return
267
268 while (first != last) {
269 result = erase(first); // erase(const_iterator pos) returns iterator to next element
270 // Update first to point to the next element (which is now at the erased position)
271 first = ConstIteratorWrapper(result.mTreeIt);
272 }
273
274 return result;
275 }
276
277 void swap(MultiSetTree& other) {
278 mTree.swap(other.mTree);
279 fl::swap(mNextId, other.mNextId);
280 }
281
282 // Lookup
283 fl::size count(const Key& key) const {
284 auto range = equal_range(key);
285 fl::size count = 0;
286 for (auto it = range.first; it != range.second; ++it) {
287 ++count;
288 }
289 return count;
290 }
291
292 iterator find(const Key& key) {
293 ValueWithId search_key(key, 0);
294 auto it = mTree.lower_bound(search_key);
295 if (it != mTree.end() && it->value == key) {
296 return iterator(it);
297 }
298 return end();
299 }
300
301 const_iterator find(const Key& key) const {
302 ValueWithId search_key(key, 0);
303 auto it = mTree.lower_bound(search_key);
304 if (it != mTree.end() && it->value == key) {
305 return const_iterator(it);
306 }
307 return end();
308 }
309
310 bool contains(const Key& key) const {
311 return find(key) != end();
312 }
313
314 // equal_range returns [lower_bound, upper_bound) for the given key
316 iterator lower = lower_bound(key);
317 iterator upper = upper_bound(key);
318 return fl::pair<iterator, iterator>(lower, upper);
319 }
320
326
328 ValueWithId search_key(key, 0);
329 return iterator(mTree.lower_bound(search_key));
330 }
331
332 const_iterator lower_bound(const Key& key) const {
333 ValueWithId search_key(key, 0);
334 return const_iterator(mTree.lower_bound(search_key));
335 }
336
338 ValueWithId search_key(key, mNextId); // Use mNextId to get upper bound
339 return iterator(mTree.upper_bound(search_key));
340 }
341
342 const_iterator upper_bound(const Key& key) const {
343 ValueWithId search_key(key, mNextId);
344 return const_iterator(mTree.upper_bound(search_key));
345 }
346
347 // Observers
348 key_compare key_comp() const { return key_compare(); }
349
351 return value_compare();
352 }
353
355 return mTree.get_allocator();
356 }
357
358 // Comparison operators
359 bool operator==(const MultiSetTree& other) const {
360 if (size() != other.size()) return false;
361 for (auto it1 = begin(), it2 = other.begin(); it1 != end(); ++it1, ++it2) {
362 if (*it1 != *it2) {
363 return false;
364 }
365 }
366 return true;
367 }
368
369 bool operator!=(const MultiSetTree& other) const {
370 return !(*this == other);
371 }
372
373 bool operator<(const MultiSetTree& other) const {
374 for (auto it1 = begin(), it2 = other.begin(); it1 != end() && it2 != other.end(); ++it1, ++it2) {
375 if (*it1 < *it2) return true;
376 if (*it2 < *it1) return false;
377 }
378 return size() < other.size();
379 }
380
381 bool operator<=(const MultiSetTree& other) const {
382 return *this < other || *this == other;
383 }
384
385 bool operator>(const MultiSetTree& other) const {
386 return other < *this;
387 }
388
389 bool operator>=(const MultiSetTree& other) const {
390 return other <= *this;
391 }
392};
393
394} // namespace fl
395
396// Drop-in replacement for std::multiset
397namespace fl {
398
399// Default multiset uses slab allocator for better performance
400template <typename Key, typename Compare = fl::less<Key>>
402
403} // namespace fl
uint8_t pos
Definition Blur.ino:11
bool operator!=(const ConstIteratorWrapper &other) const
Definition multi_set.h:115
ConstIteratorWrapper operator--(int)
Definition multi_set.h:108
bool operator==(const ConstIteratorWrapper &other) const
Definition multi_set.h:114
TreeType::const_iterator mTreeIt
Definition multi_set.h:79
ConstIteratorWrapper operator++(int)
Definition multi_set.h:97
const value_type & operator*() const
Definition multi_set.h:85
ConstIteratorWrapper() FL_NOEXCEPT=default
const value_type * operator->() const
Definition multi_set.h:88
ConstIteratorWrapper & operator++()
Definition multi_set.h:92
ConstIteratorWrapper & operator--()
Definition multi_set.h:103
ConstReverseIteratorWrapper & operator--()
Definition multi_set.h:145
ConstReverseIteratorWrapper operator++(int)
Definition multi_set.h:139
const value_type * operator->() const
Definition multi_set.h:130
bool operator==(const ConstReverseIteratorWrapper &other) const
Definition multi_set.h:156
bool operator!=(const ConstReverseIteratorWrapper &other) const
Definition multi_set.h:157
ConstReverseIteratorWrapper & operator++()
Definition multi_set.h:134
TreeType::const_reverse_iterator mTreeRIt
Definition multi_set.h:121
ConstReverseIteratorWrapper operator--(int)
Definition multi_set.h:150
void insert(InputIt first, InputIt last)
Definition multi_set.h:233
reverse_iterator rend()
Definition multi_set.h:198
bool empty() const
Definition multi_set.h:203
const_reverse_iterator rend() const
Definition multi_set.h:200
const_iterator upper_bound(const Key &key) const
Definition multi_set.h:342
const_iterator end() const
Definition multi_set.h:193
Compare value_compare
Definition multi_set.h:27
const value_type * const_pointer
Definition multi_set.h:31
const value_type & reference
Definition multi_set.h:28
Compare key_compare
Definition multi_set.h:26
ConstReverseIteratorWrapper reverse_iterator
Definition multi_set.h:163
iterator erase(const_iterator pos)
Definition multi_set.h:247
bool operator<(const MultiSetTree &other) const
Definition multi_set.h:373
bool operator>=(const MultiSetTree &other) const
Definition multi_set.h:389
const value_type * pointer
Definition multi_set.h:30
MultiSetTree & operator=(MultiSetTree &&other) FL_NOEXCEPT=default
bool contains(const Key &key) const
Definition multi_set.h:310
const_iterator find(const Key &key) const
Definition multi_set.h:301
RedBlackTree< ValueWithId, KeyCompareWithId, Allocator > TreeType
Definition multi_set.h:71
const_iterator cbegin() const
Definition multi_set.h:191
const value_type & const_reference
Definition multi_set.h:29
reverse_iterator rbegin()
Definition multi_set.h:197
~MultiSetTree() FL_NOEXCEPT=default
ConstReverseIteratorWrapper const_reverse_iterator
Definition multi_set.h:164
bool operator!=(const MultiSetTree &other) const
Definition multi_set.h:369
iterator end()
Definition multi_set.h:192
allocator_type get_allocator() const
Definition multi_set.h:354
ConstIteratorWrapper const_iterator
Definition multi_set.h:162
const_iterator begin() const
Definition multi_set.h:190
fl::pair< const_iterator, const_iterator > equal_range(const Key &key) const
Definition multi_set.h:321
ptrdiff_t difference_type
Definition multi_set.h:25
iterator upper_bound(const Key &key)
Definition multi_set.h:337
fl::size erase(const Key &key)
Definition multi_set.h:252
iterator insert(const value_type &value)
Definition multi_set.h:211
MultiSetTree(const Compare &comp=Compare(), const Allocator &alloc=Allocator())
Definition multi_set.h:167
void swap(MultiSetTree &other)
Definition multi_set.h:277
const_reverse_iterator rbegin() const
Definition multi_set.h:199
key_compare key_comp() const
Definition multi_set.h:348
value_compare value_comp() const
Definition multi_set.h:350
MultiSetTree(const MultiSetTree &other) FL_NOEXCEPT=default
MultiSetTree(MultiSetTree &&other) FL_NOEXCEPT=default
iterator erase(const_iterator first, const_iterator last)
Definition multi_set.h:264
MultiSetTree(fl::initializer_list< value_type > init, const Compare &comp=Compare(), const Allocator &alloc=Allocator())
Definition multi_set.h:177
fl::size max_size() const
Definition multi_set.h:205
iterator find(const Key &key)
Definition multi_set.h:292
iterator insert(value_type &&value)
Definition multi_set.h:217
MultiSetTree & operator=(const MultiSetTree &other) FL_NOEXCEPT=default
const_iterator lower_bound(const Key &key) const
Definition multi_set.h:332
Allocator allocator_type
Definition multi_set.h:32
fl::size size() const
Definition multi_set.h:204
fl::pair< iterator, iterator > equal_range(const Key &key)
Definition multi_set.h:315
bool operator>(const MultiSetTree &other) const
Definition multi_set.h:385
bool operator==(const MultiSetTree &other) const
Definition multi_set.h:359
bool operator<=(const MultiSetTree &other) const
Definition multi_set.h:381
const_iterator cend() const
Definition multi_set.h:194
void insert(fl::initializer_list< value_type > ilist)
Definition multi_set.h:240
ConstIteratorWrapper iterator
Definition multi_set.h:161
iterator lower_bound(const Key &key)
Definition multi_set.h:327
iterator emplace(Args &&... args)
Definition multi_set.h:224
fl::size size_type
Definition multi_set.h:24
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
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
Definition move.h:28
MultiSetTree< Key, Compare, fl::allocator_slab< char > > multi_set
Definition multi_set.h:401
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_set.h:58
KeyCompareWithId(const Compare &comp=Compare())
Definition multi_set.h:56
ValueWithId(Key &&v, fl::size id)
Definition multi_set.h:46
ValueWithId() FL_NOEXCEPT=default
const Key & get_key() const
Definition multi_set.h:49