FastLED 3.9.15
Loading...
Searching...
No Matches
flat_set.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/stdint.h"
4#include "fl/stl/algorithm.h"
6#include "fl/stl/vector.h"
8#include "fl/stl/noexcept.h"
9
10namespace fl {
11
12// A cache-friendly sorted set using contiguous storage.
13//
14// flat_set stores keys in a sorted vector for optimal memory layout.
15// This provides excellent cache locality and iteration performance, but slower
16// insertions and deletions (O(n)) compared to tree-based sets. Use flat_set when:
17// - You have frequent lookups and iteration (better cache locality)
18// - You don't do many insertions/deletions
19// - Memory layout matters for performance
20//
21// The container maintains sorted order and uses binary search for lookups.
22template <typename Key,
23 typename Less = fl::less<Key>>
24class flat_set {
25 public:
26 using key_type = Key;
27 using value_type = Key;
28 using size_type = fl::size;
30 using key_compare = Less;
31 using value_compare = Less;
35 using const_pointer = const value_type*;
36
40 using reverse_iterator = typename vector_type::reverse_iterator;
41 using const_reverse_iterator = typename vector_type::const_reverse_iterator;
42
43 private:
45 Less mLess;
46
47 public:
48 // Constructors
49 flat_set() FL_NOEXCEPT = default;
50
51 explicit flat_set(memory_resource* resource)
52 : mData(resource) {}
53
54 explicit flat_set(const Less& less)
55 : mLess(less) {}
56
57 flat_set(const Less& less, memory_resource* resource)
58 : mData(resource), mLess(less) {}
59
60 flat_set(const flat_set& other) FL_NOEXCEPT = default;
61 flat_set& operator=(const flat_set& other) = default;
62
64 : mData(fl::move(other.mData)), mLess(fl::move(other.mLess)) {}
65
67 if (this != &other) {
68 mData = fl::move(other.mData);
69 mLess = fl::move(other.mLess);
70 }
71 return *this;
72 }
73
74 // Iterators
75 iterator begin() { return mData.begin(); }
76 iterator end() { return mData.end(); }
77 const_iterator begin() const { return mData.begin(); }
78 const_iterator end() const { return mData.end(); }
79 const_iterator cbegin() const { return mData.begin(); }
80 const_iterator cend() const { return mData.end(); }
81
82 reverse_iterator rbegin() { return mData.rbegin(); }
83 reverse_iterator rend() { return mData.rend(); }
84 const_reverse_iterator rbegin() const { return mData.rbegin(); }
85 const_reverse_iterator rend() const { return mData.rend(); }
86
87 // Capacity
88 size_type size() const { return mData.size(); }
89 bool empty() const { return mData.empty(); }
90 size_type capacity() const { return mData.capacity(); }
91 size_type max_size() const { return mData.max_size(); }
92
93 // Lookup
94 iterator find(const Key& key) {
95 auto it = lower_bound(key);
96 if (it != end() && !mLess(key, *it) && !mLess(*it, key)) {
97 return it;
98 }
99 return end();
100 }
101
102 const_iterator find(const Key& key) const {
103 auto it = lower_bound(key);
104 if (it != end() && !mLess(key, *it) && !mLess(*it, key)) {
105 return it;
106 }
107 return end();
108 }
109
110 size_type count(const Key& key) const {
111 return find(key) != end() ? 1 : 0;
112 }
113
114 bool contains(const Key& key) const {
115 return find(key) != end();
116 }
117
118 // Bounds - binary search using pointer arithmetic
120 // Binary search: find first element where !(element < key)
121 iterator first = mData.begin();
122 size_type count = mData.size();
123
124 while (count > 0) {
125 size_type step = count / 2;
126 iterator it = first + step;
127 if (mLess(*it, key)) {
128 first = it + 1;
129 count -= step + 1;
130 } else {
131 count = step;
132 }
133 }
134 return first;
135 }
136
137 const_iterator lower_bound(const Key& key) const {
138 // Binary search: find first element where !(element < key)
139 const_iterator first = mData.begin();
140 size_type count = mData.size();
141
142 while (count > 0) {
143 size_type step = count / 2;
144 const_iterator it = first + step;
145 if (mLess(*it, key)) {
146 first = it + 1;
147 count -= step + 1;
148 } else {
149 count = step;
150 }
151 }
152 return first;
153 }
154
156 // Binary search: find first element where key < element
157 iterator first = mData.begin();
158 size_type count = mData.size();
159
160 while (count > 0) {
161 size_type step = count / 2;
162 iterator it = first + step;
163 if (!mLess(key, *it)) {
164 first = it + 1;
165 count -= step + 1;
166 } else {
167 count = step;
168 }
169 }
170 return first;
171 }
172
173 const_iterator upper_bound(const Key& key) const {
174 // Binary search: find first element where key < element
175 const_iterator first = mData.begin();
176 size_type count = mData.size();
177
178 while (count > 0) {
179 size_type step = count / 2;
180 const_iterator it = first + step;
181 if (!mLess(key, *it)) {
182 first = it + 1;
183 count -= step + 1;
184 } else {
185 count = step;
186 }
187 }
188 return first;
189 }
190
192 auto lower = lower_bound(key);
193 auto upper = upper_bound(key);
194 return fl::pair<iterator, iterator>(lower, upper);
195 }
196
198 auto lower = lower_bound(key);
199 auto upper = upper_bound(key);
200 return fl::pair<const_iterator, const_iterator>(lower, upper);
201 }
202
203 // Insertion
205 auto it = lower_bound(value);
206 if (it != end() && !mLess(value, *it) && !mLess(*it, value)) {
207 return fl::pair<iterator, bool>(it, false); // Already exists
208 }
209 bool success = mData.insert(it, value);
210 if (success) {
211 // After insert, find the newly inserted element
212 it = find(value);
213 return fl::pair<iterator, bool>(it, true);
214 }
215 return fl::pair<iterator, bool>(end(), false);
216 }
217
219 auto key = value;
220 auto it = lower_bound(key);
221 if (it != end() && !mLess(key, *it) && !mLess(*it, key)) {
222 return fl::pair<iterator, bool>(it, false); // Already exists
223 }
224 bool success = mData.insert(it, fl::move(value));
225 if (success) {
226 // After insert, find the newly inserted element
227 it = find(key);
228 return fl::pair<iterator, bool>(it, true);
229 }
230 return fl::pair<iterator, bool>(end(), false);
231 }
232
233 // Insert with hint (optimization hint, may be ignored)
235 // TODO: use hint for performance if it's valid
236 return insert(value).first;
237 }
238
240 return insert(fl::move(value)).first;
241 }
242
243 // Emplace
244 template <typename... Args>
249
250 template <typename... Args>
253 return insert(hint, fl::move(value));
254 }
255
256 // Deletion
258 // Vector erase() returns iterator in some versions, bool in others
259 // To be safe, erase and return the next element
260 iterator next = pos + 1;
261 mData.erase(pos);
262 return next;
263 }
264
266 // Convert const_iterator to iterator and erase
267 iterator it = const_cast<iterator>(pos);
268 iterator next = it + 1;
269 mData.erase(it);
270 return next;
271 }
272
274 // Erase range [first, last) by repeatedly erasing the element at first
275 fl::size count = last - first;
276 iterator pos = const_cast<iterator>(first);
277
278 for (fl::size i = 0; i < count && pos != end(); ++i) {
279 // Erase the element at pos. After erase, pos points to the next element
280 // (because all elements shift left)
281 mData.erase(pos);
282 // Don't increment pos - it already points to the next element after erase
283 }
284 return pos;
285 }
286
287 size_type erase(const Key& key) {
288 auto it = find(key);
289 if (it != end()) {
290 erase(it);
291 return 1;
292 }
293 return 0;
294 }
295
296 // Clear
297 void clear() {
298 mData.clear();
299 }
300
301 // Swap
302 void swap(flat_set& other) FL_NOEXCEPT {
303 mData.swap(other.mData);
304 fl::swap(mLess, other.mLess);
305 }
306
307 // Comparison
309 return mLess;
310 }
311
313 return mLess;
314 }
315
316 // Allows pre-allocating space (FastLED style)
318 mData.reserve(n);
319 }
320
321 memory_resource* get_memory_resource() const { return mData.get_resource(); }
322};
323
324// Comparison operators
325template <typename Key, typename Less>
327 const flat_set<Key, Less>& rhs) {
328 return lhs.size() == rhs.size() &&
329 fl::equal(lhs.begin(), lhs.end(), rhs.begin());
330}
331
332template <typename Key, typename Less>
334 const flat_set<Key, Less>& rhs) {
335 return !(lhs == rhs);
336}
337
338template <typename Key, typename Less>
340 const flat_set<Key, Less>& rhs) {
341 return fl::lexicographical_compare(lhs.begin(), lhs.end(),
342 rhs.begin(), rhs.end());
343}
344
345template <typename Key, typename Less>
347 const flat_set<Key, Less>& rhs) {
348 return !(rhs < lhs);
349}
350
351template <typename Key, typename Less>
353 const flat_set<Key, Less>& rhs) {
354 return rhs < lhs;
355}
356
357template <typename Key, typename Less>
359 const flat_set<Key, Less>& rhs) {
360 return !(lhs < rhs);
361}
362
363// Swap
364template <typename Key, typename Less>
367 lhs.swap(rhs);
368}
369
370} // namespace fl
uint8_t pos
Definition Blur.ino:11
flat_set & operator=(flat_set &&other) FL_NOEXCEPT
Definition flat_set.h:66
const_iterator find(const Key &key) const
Definition flat_set.h:102
fl::pair< iterator, bool > insert(value_type &&value)
Definition flat_set.h:218
flat_set() FL_NOEXCEPT=default
flat_set(const Less &less)
Definition flat_set.h:54
iterator emplace_hint(const_iterator hint, Args &&... args)
Definition flat_set.h:251
value_type * pointer
Definition flat_set.h:34
fl::size size_type
Definition flat_set.h:28
fl::vector< value_type > vector_type
Definition flat_set.h:37
bool contains(const Key &key) const
Definition flat_set.h:114
const value_type * const_pointer
Definition flat_set.h:35
iterator erase(const_iterator pos)
Definition flat_set.h:265
vector_type mData
Definition flat_set.h:44
reverse_iterator rend()
Definition flat_set.h:83
fl::pair< iterator, iterator > equal_range(const Key &key)
Definition flat_set.h:191
typename vector_type::reverse_iterator reverse_iterator
Definition flat_set.h:40
const_iterator cend() const
Definition flat_set.h:80
Key value_type
Definition flat_set.h:27
iterator upper_bound(const Key &key)
Definition flat_set.h:155
iterator insert(const_iterator hint, value_type &&value)
Definition flat_set.h:239
value_type & reference
Definition flat_set.h:32
const_iterator begin() const
Definition flat_set.h:77
typename vector_type::const_reverse_iterator const_reverse_iterator
Definition flat_set.h:41
fl::pair< const_iterator, const_iterator > equal_range(const Key &key) const
Definition flat_set.h:197
const_iterator cbegin() const
Definition flat_set.h:79
bool empty() const
Definition flat_set.h:89
iterator erase(iterator pos)
Definition flat_set.h:257
key_compare key_comp() const
Definition flat_set.h:308
Less value_compare
Definition flat_set.h:31
void swap(flat_set &other) FL_NOEXCEPT
Definition flat_set.h:302
flat_set(flat_set &&other) FL_NOEXCEPT
Definition flat_set.h:63
iterator begin()
Definition flat_set.h:75
void clear()
Definition flat_set.h:297
flat_set(const Less &less, memory_resource *resource)
Definition flat_set.h:57
const_iterator end() const
Definition flat_set.h:78
flat_set(const flat_set &other) FL_NOEXCEPT=default
iterator insert(const_iterator hint, const value_type &value)
Definition flat_set.h:234
value_compare value_comp() const
Definition flat_set.h:312
typename vector_type::const_iterator const_iterator
Definition flat_set.h:39
size_type max_size() const
Definition flat_set.h:91
iterator end()
Definition flat_set.h:76
size_type count(const Key &key) const
Definition flat_set.h:110
fl::pair< iterator, bool > emplace(Args &&... args)
Definition flat_set.h:245
const_iterator lower_bound(const Key &key) const
Definition flat_set.h:137
size_type erase(const Key &key)
Definition flat_set.h:287
ptrdiff_t difference_type
Definition flat_set.h:29
Less key_compare
Definition flat_set.h:30
const value_type & const_reference
Definition flat_set.h:33
iterator find(const Key &key)
Definition flat_set.h:94
const_reverse_iterator rend() const
Definition flat_set.h:85
const_iterator upper_bound(const Key &key) const
Definition flat_set.h:173
size_type size() const
Definition flat_set.h:88
fl::pair< iterator, bool > insert(const value_type &value)
Definition flat_set.h:204
memory_resource * get_memory_resource() const
Definition flat_set.h:321
iterator erase(const_iterator first, const_iterator last)
Definition flat_set.h:273
void reserve(size_type n)
Definition flat_set.h:317
iterator lower_bound(const Key &key)
Definition flat_set.h:119
typename vector_type::iterator iterator
Definition flat_set.h:38
reverse_iterator rbegin()
Definition flat_set.h:82
flat_set & operator=(const flat_set &other)=default
size_type capacity() const
Definition flat_set.h:90
const_reverse_iterator rbegin() const
Definition flat_set.h:84
Polymorphic memory resource base class (PMR-style).
const value_type * const_iterator
Definition vector.h:453
value_type * iterator
Definition vector.h:452
PMR-style polymorphic memory resource for type-erased allocation.
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 int type_rank< T >::value
bool lexicographical_compare(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) FL_NOEXCEPT
Definition algorithm.h:146
FASTLED_FORCE_INLINE bool operator!=(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if two CRGB objects do not have the same color data.
Definition crgb.h:739
bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2) FL_NOEXCEPT
Definition algorithm.h:96
void swap(array< T, N > &lhs, array< T, N > &rhs) FL_NOEXCEPT
Definition array.h:209
FASTLED_FORCE_INLINE bool operator<(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is less than another.
Definition crgb.h:745
FASTLED_FORCE_INLINE bool operator==(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if two CRGB objects have the same color data.
Definition crgb.h:733
FASTLED_FORCE_INLINE bool operator>(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is greater than another.
Definition crgb.h:754
FASTLED_FORCE_INLINE bool operator<=(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is less than or equal to another.
Definition crgb.h:772
constexpr enable_if< is_fixed_point< T >::value, T >::type step(T edge, T x) FL_NOEXCEPT
fl::ptrdiff ptrdiff_t
Definition s16x16x4.h:226
FASTLED_FORCE_INLINE bool operator>=(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if the sum of the color channels in one CRGB object is greater than or equal to another.
Definition crgb.h:763
Base definition for an LED controller.
Definition crgb.hpp:179
corkscrew_args args
Definition old.h:149
#define FL_NOEXCEPT
Definition Keyboard.h:22
Binary function object that returns whether the first argument is less than the second.
Definition utility.h:15