FastLED 3.10.8
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
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_NO_EXCEPT = 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 return mData.erase(pos);
259 }
260
262 return mData.erase(const_cast<iterator>(pos));
263 }
264
266 // Erase range [first, last) by repeatedly erasing the element at first
267 fl::size count = last - first;
268 iterator pos = const_cast<iterator>(first);
269
270 for (fl::size i = 0; i < count && pos != end(); ++i) {
271 // Erase the element at pos. After erase, pos points to the next element
272 // (because all elements shift left)
273 mData.erase(pos);
274 // Don't increment pos - it already points to the next element after erase
275 }
276 return pos;
277 }
278
279 size_type erase(const Key& key) {
280 auto it = find(key);
281 if (it != end()) {
282 erase(it);
283 return 1;
284 }
285 return 0;
286 }
287
288 // Clear
289 void clear() {
290 mData.clear();
291 }
292
293 // Swap
295 mData.swap(other.mData);
296 fl::swap(mLess, other.mLess);
297 }
298
299 // Comparison
301 return mLess;
302 }
303
305 return mLess;
306 }
307
308 // Allows pre-allocating space (FastLED style)
310 mData.reserve(n);
311 }
312
313 memory_resource* get_memory_resource() const { return mData.get_resource(); }
314};
315
316// Comparison operators
317template <typename Key, typename Less>
319 const flat_set<Key, Less>& rhs) {
320 return lhs.size() == rhs.size() &&
321 fl::equal(lhs.begin(), lhs.end(), rhs.begin());
322}
323
324template <typename Key, typename Less>
326 const flat_set<Key, Less>& rhs) {
327 return !(lhs == rhs);
328}
329
330template <typename Key, typename Less>
332 const flat_set<Key, Less>& rhs) {
333 return fl::lexicographical_compare(lhs.begin(), lhs.end(),
334 rhs.begin(), rhs.end());
335}
336
337template <typename Key, typename Less>
339 const flat_set<Key, Less>& rhs) {
340 return !(rhs < lhs);
341}
342
343template <typename Key, typename Less>
345 const flat_set<Key, Less>& rhs) {
346 return rhs < lhs;
347}
348
349template <typename Key, typename Less>
351 const flat_set<Key, Less>& rhs) {
352 return !(lhs < rhs);
353}
354
355// Swap
356template <typename Key, typename Less>
359 lhs.swap(rhs);
360}
361
362} // namespace fl
uint8_t pos
Definition Blur.ino:11
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(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
void swap(flat_set &other) FL_NO_EXCEPT
Definition flat_set.h:294
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:261
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
flat_set() FL_NO_EXCEPT=default
Key value_type
Definition flat_set.h:27
iterator upper_bound(const Key &key)
Definition flat_set.h:155
flat_set(const flat_set &other) FL_NO_EXCEPT=default
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:300
Less value_compare
Definition flat_set.h:31
iterator begin()
Definition flat_set.h:75
void clear()
Definition flat_set.h:289
flat_set(const Less &less, memory_resource *resource)
Definition flat_set.h:57
const_iterator end() const
Definition flat_set.h:78
iterator insert(const_iterator hint, const value_type &value)
Definition flat_set.h:234
value_compare value_comp() const
Definition flat_set.h:304
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
flat_set(flat_set &&other) FL_NO_EXCEPT
Definition flat_set.h:63
const_iterator lower_bound(const Key &key) const
Definition flat_set.h:137
size_type erase(const Key &key)
Definition flat_set.h:279
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:313
iterator erase(const_iterator first, const_iterator last)
Definition flat_set.h:265
void reserve(size_type n)
Definition flat_set.h:309
flat_set & operator=(flat_set &&other) FL_NO_EXCEPT
Definition flat_set.h:66
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 remove_reference< T >::type && move(T &&t) FL_NO_EXCEPT
Definition move.h:30
bool lexicographical_compare(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) FL_NO_EXCEPT
Definition algorithm.h:149
constexpr T && forward(typename remove_reference< T >::type &t) FL_NO_EXCEPT
bool equal(Iterator1 first1, Iterator1 last1, Iterator2 first2) FL_NO_EXCEPT
Definition algorithm.h:99
void swap(array< T, N > &lhs, array< T, N > &rhs) FL_NO_EXCEPT
Definition array.h:209
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr int type_rank< T >::value
FASTLED_FORCE_INLINE bool operator==(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if two CRGB objects have the same color data.
Definition crgb.h:740
FASTLED_FORCE_INLINE bool operator>(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if the sum of the color channels in one CRGB object is greater than another.
Definition crgb.h:761
FASTLED_FORCE_INLINE bool operator<=(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if the sum of the color channels in one CRGB object is less than or equal to another.
Definition crgb.h:779
constexpr enable_if< is_fixed_point< T >::value, T >::type step(T edge, T x) FL_NO_EXCEPT
fl::ptrdiff_t ptrdiff_t
Definition s16x16x4.h:63
FASTLED_FORCE_INLINE bool operator!=(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if two CRGB objects do not have the same color data.
Definition crgb.h:746
FASTLED_FORCE_INLINE bool operator>=(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if the sum of the color channels in one CRGB object is greater than or equal to another.
Definition crgb.h:770
FASTLED_FORCE_INLINE bool operator<(const CRGB &lhs, const CRGB &rhs) FL_NO_EXCEPT
Check if the sum of the color channels in one CRGB object is less than another.
Definition crgb.h:752
Base definition for an LED controller.
Definition crgb.hpp:179
corkscrew_args args
Definition old.h:149
Definition Keyboard.h:22
Binary function object that returns whether the first argument is less than the second.
Definition utility.h:15