FastLED 3.10.8
Loading...
Searching...
No Matches
flat_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"
5#include "fl/stl/algorithm.h"
6#include "fl/stl/assert.h" // IWYU pragma: keep
8#include "fl/stl/flat_map_basic.h" // type-erased binary-search helpers (#3235 Tier 2D)
9#include "fl/stl/pair.h"
10#include "fl/stl/singleton.h" // fl::Singleton — OOM sink for operator[] (#3588)
11#include "fl/stl/vector.h"
12#include "fl/stl/allocator.h"
14#include "platforms/assert_defs.h"
15#include "fl/stl/noexcept.h"
16
17namespace fl {
18
19// A cache-friendly sorted map using contiguous storage.
20//
21// flat_map stores key-value pairs in a sorted vector for optimal memory layout.
22// This provides excellent cache locality and iteration performance, but slower
23// insertions and deletions (O(n)) compared to tree-based maps. Use flat_map when:
24// - You have frequent lookups and iteration (better cache locality)
25// - You don't do many insertions/deletions
26// - Memory layout matters for performance
27//
28// The container maintains sorted order by key and uses binary search for lookups.
29template <typename Key, typename Value,
30 typename Less = fl::less<Key>>
31class flat_map {
32 public:
33 enum insert_result { inserted = 0, exists = 1, at_capacity = 2 };
34
35 using key_type = Key;
36 using mapped_type = Value;
38 using size_type = fl::size;
40 using key_compare = Less;
44 using const_pointer = const value_type*;
45
49 using reverse_iterator = typename vector_type::reverse_iterator;
50 using const_reverse_iterator = typename vector_type::const_reverse_iterator;
51
52 private:
54 Less mLess;
55
56 public:
57 // Constructors
58 flat_map() = default;
59
61 : mData(resource) {}
62
63 explicit flat_map(const Less& less) FL_NO_EXCEPT
64 : mLess(less) {}
65
66 flat_map(const Less& less, memory_resource* resource) FL_NO_EXCEPT
67 : mData(resource), mLess(less) {}
68
70 : mData(other.mData), mLess(other.mLess) {}
71 flat_map& operator=(const flat_map& other) = default;
72
74 : mData(fl::move(other.mData)), mLess(fl::move(other.mLess)) {}
75
77 if (this != &other) {
78 mData = fl::move(other.mData);
79 mLess = fl::move(other.mLess);
80 }
81 return *this;
82 }
83
84 // Iterators
85 iterator begin() FL_NO_EXCEPT { return mData.begin(); }
86 iterator end() FL_NO_EXCEPT { return mData.end(); }
87 const_iterator begin() const FL_NO_EXCEPT { return mData.begin(); }
88 const_iterator end() const FL_NO_EXCEPT { return mData.end(); }
89 const_iterator cbegin() const FL_NO_EXCEPT { return mData.begin(); }
90 const_iterator cend() const FL_NO_EXCEPT { return mData.end(); }
91
94 const_reverse_iterator rbegin() const FL_NO_EXCEPT { return mData.rbegin(); }
95 const_reverse_iterator rend() const FL_NO_EXCEPT { return mData.rend(); }
96
97 // Capacity
98 size_type size() const FL_NO_EXCEPT { return mData.size(); }
99 bool empty() const FL_NO_EXCEPT { return mData.empty(); }
100 size_type capacity() const FL_NO_EXCEPT { return mData.capacity(); }
101 size_type max_size() const FL_NO_EXCEPT { return mData.max_size(); }
102 bool full() const FL_NO_EXCEPT { return size() >= capacity(); }
103
104 // Element access - check keys are equal (not less than in either direction)
105 Value& operator[](const Key& key) FL_NO_EXCEPT {
106 auto it = lower_bound(key);
107 if (it != end() && !mLess(key, it->first) && !mLess(it->first, key)) {
108 return it->second;
109 }
110 // Key not found, insert it with default value.
111 bool success = mData.insert(it, value_type(key, Value()));
112 if (!success) {
113 // FastLED#3588: under memory pressure the backing vector
114 // could not grow, so the key was NOT inserted. The old code
115 // then did `find(key)` (which returns end(), the key being
116 // absent) and returned `end()->second` — a reference ONE PAST
117 // the buffer. The caller's assignment through it wrote a value
118 // into the neighboring heap allocation, corrupting it (e.g. a
119 // shared_ptr control block, detonating later as a wild-pointer
120 // refcount decrement). Degrade gracefully instead: hand back a
121 // discardable sink so the caller's write is dropped rather than
122 // corrupting the heap. This matches the library's no-throw OOM
123 // policy (a failed insert simply does not take effect). The
124 // sink is a process-lifetime Singleton (shared, never
125 // destroyed) so the reference stays valid across DLL
126 // boundaries and does not add per-map storage.
128 sink = Value();
129 return sink;
130 }
131 // Find the newly inserted element
132 it = find(key);
133 return it->second;
134 }
135
136 Value& at(const Key& key) FL_NO_EXCEPT {
137 auto it = lower_bound(key);
138 if (it != end() && !mLess(key, it->first) && !mLess(it->first, key)) {
139 return it->second;
140 }
141 // Key not found - could throw, but FastLED style is to assert
142 FASTLED_ASSERT(false, "Key not found in flat_map");
143 return mData.front().second; // unreachable
144 }
145
146 const Value& at(const Key& key) const FL_NO_EXCEPT {
147 auto it = lower_bound(key);
148 if (it != end() && !mLess(key, it->first) && !mLess(it->first, key)) {
149 return it->second;
150 }
151 FASTLED_ASSERT(false, "Key not found in flat_map");
152 return mData.front().second; // unreachable
153 }
154
155 // Lookup
157 auto it = lower_bound(key);
158 if (it != end() && !mLess(key, it->first) && !mLess(it->first, key)) {
159 return it;
160 }
161 return end();
162 }
163
165 auto it = lower_bound(key);
166 if (it != end() && !mLess(key, it->first) && !mLess(it->first, key)) {
167 return it;
168 }
169 return end();
170 }
171
172 size_type count(const Key& key) const FL_NO_EXCEPT {
173 return find(key) != end() ? 1 : 0;
174 }
175
176 bool contains(const Key& key) const FL_NO_EXCEPT {
177 return find(key) != end();
178 }
179
180 // Alias for contains (FastLED compatibility)
181 bool has(const Key& key) const FL_NO_EXCEPT {
182 return contains(key);
183 }
184
185 // Bounds - delegate to the type-erased binary-search core. The per-Sig
186 // tax (~80-150 B of duplicated binary-search code per instantiation)
187 // shifts to a one-time ~80 B body in `fl/stl/flat_map_basic.cpp.hpp`
188 // shared across every `flat_map<K, V, Less>` instantiation in the
189 // binary. See FastLED #3235 Tier 2D.
190private:
191 template <typename L = Less>
192 static bool less_thunk(const void* ctx, const void* a, const void* b) FL_NO_EXCEPT {
193 const L* less = static_cast<const L*>(ctx);
194 const Key* ka = static_cast<const Key*>(a);
195 const Key* kb = static_cast<const Key*>(b);
196 return (*less)(*ka, *kb);
197 }
198
202 ops.less_ctx = static_cast<const void*>(&mLess);
203 ops.element_size = sizeof(value_type);
204 return ops;
205 }
206
207public:
210 mData.data(), mData.size(), &key, make_ops());
211 return mData.begin() + idx;
212 }
213
216 mData.data(), mData.size(), &key, make_ops());
217 return mData.begin() + idx;
218 }
219
222 mData.data(), mData.size(), &key, make_ops());
223 return mData.begin() + idx;
224 }
225
228 mData.data(), mData.size(), &key, make_ops());
229 return mData.begin() + idx;
230 }
231
233 auto lower = lower_bound(key);
234 auto upper = upper_bound(key);
235 return fl::pair<iterator, iterator>(lower, upper);
236 }
237
239 auto lower = lower_bound(key);
240 auto upper = upper_bound(key);
241 return fl::pair<const_iterator, const_iterator>(lower, upper);
242 }
243
244 // Insertion
246 auto it = lower_bound(value.first);
247 if (it != end() && !mLess(value.first, it->first) && !mLess(it->first, value.first)) {
248 return fl::pair<iterator, bool>(it, false); // Already exists
249 }
250 bool success = mData.insert(it, value);
251 if (success) {
252 // After insert, find the newly inserted element
253 it = find(value.first);
254 return fl::pair<iterator, bool>(it, true);
255 }
256 return fl::pair<iterator, bool>(end(), false);
257 }
258
260 auto key = value.first;
261 auto it = lower_bound(key);
262 if (it != end() && !mLess(key, it->first) && !mLess(it->first, key)) {
263 return fl::pair<iterator, bool>(it, false); // Already exists
264 }
265 bool success = mData.insert(it, fl::move(value));
266 if (success) {
267 // After insert, find the newly inserted element
268 it = find(key);
269 return fl::pair<iterator, bool>(it, true);
270 }
271 return fl::pair<iterator, bool>(end(), false);
272 }
273
274 // Insert with hint (optimization hint, may be ignored)
278
282
283 bool insert(const Key& key, const Value& value, insert_result* result = nullptr) FL_NO_EXCEPT {
284 auto it = lower_bound(key);
285 if (it != end() && !mLess(key, it->first) && !mLess(it->first, key)) {
286 if (result) *result = exists;
287 return false;
288 }
289 bool success = mData.insert(it, value_type(key, value));
290 if (success) {
291 if (result) *result = inserted;
292 return true;
293 }
294 if (result) *result = at_capacity;
295 return false;
296 }
297
298 bool insert(Key&& key, Value&& value, insert_result* result = nullptr) FL_NO_EXCEPT {
299 auto key_copy = key;
300 auto it = lower_bound(key_copy);
301 if (it != end() && !mLess(key_copy, it->first) && !mLess(it->first, key_copy)) {
302 if (result) *result = exists;
303 return false;
304 }
305 bool success = mData.insert(it, value_type(fl::move(key), fl::move(value)));
306 if (success) {
307 if (result) *result = inserted;
308 return true;
309 }
310 if (result) *result = at_capacity;
311 return false;
312 }
313
314 // Emplace
315 template <typename... Args>
320
321 template <typename... Args>
326
327 // Deletion
329 return mData.erase(pos);
330 }
331
333 return mData.erase(const_cast<iterator>(pos));
334 }
335
337 // Erase range [first, last) by repeatedly erasing the element at first
338 fl::size count = last - first;
339 iterator pos = const_cast<iterator>(first);
340
341 for (fl::size i = 0; i < count && pos != end(); ++i) {
342 // Erase the element at pos. After erase, pos points to the next element
343 // (because all elements shift left)
344 mData.erase(pos);
345 // Don't increment pos - it already points to the next element after erase
346 }
347 return pos;
348 }
349
351 auto it = find(key);
352 if (it != end()) {
353 erase(it);
354 return 1;
355 }
356 return 0;
357 }
358
359 // Clear
361 mData.clear();
362 }
363
364 // Swap
366 mData.swap(other.mData);
367 fl::swap(mLess, other.mLess);
368 }
369
370 // Comparison
372 return mLess;
373 }
374
375 // Element access
377 FASTLED_ASSERT(!empty(), "flat_map::front() on empty map");
378 return mData.front();
379 }
380
382 FASTLED_ASSERT(!empty(), "flat_map::front() on empty map");
383 return mData.front();
384 }
385
387 FASTLED_ASSERT(!empty(), "flat_map::back() on empty map");
388 return mData.back();
389 }
390
391 const value_type& back() const FL_NO_EXCEPT {
392 FASTLED_ASSERT(!empty(), "flat_map::back() on empty map");
393 return mData.back();
394 }
395
396 // FastLED-specific methods
397
398 // Get value with default return if not found
399 Value get(const Key& key, const Value& defaultValue) const FL_NO_EXCEPT {
400 auto it = find(key);
401 if (it != end()) {
402 return it->second;
403 }
404 return defaultValue;
405 }
406
407 // Get value with out parameter
408 bool get(const Key& key, Value* out_value) const FL_NO_EXCEPT {
409 auto it = find(key);
410 if (it != end()) {
411 *out_value = it->second;
412 return true;
413 }
414 return false;
415 }
416
417 // Insert or update (returns whether it was inserted)
419 iterator it = find(key);
420 if (it != end()) {
421 it->second = value;
422 return fl::pair<iterator, bool>(it, false); // Updated, not inserted
423 }
424 return insert(value_type(key, value));
425 }
426
427 // FastLED-style update: insert if missing, update if exists
428 bool update(const Key& key, const Value& value) FL_NO_EXCEPT {
429 iterator it = find(key);
430 if (it != end()) {
431 it->second = value;
432 return true; // Updated
433 }
434 // Key doesn't exist, insert it
435 auto result = insert(value_type(key, value));
436 return result.second; // Return whether insertion succeeded
437 }
438
439 // Move version of update
440 bool update(const Key& key, Value&& value) FL_NO_EXCEPT {
441 iterator it = find(key);
442 if (it != end()) {
443 it->second = fl::move(value);
444 return true; // Updated
445 }
446 // Key doesn't exist, insert it
447 auto result = insert(value_type(key, fl::move(value)));
448 return result.second; // Return whether insertion succeeded
449 }
450
451 // Navigate to next element by key (FastLED compatibility)
452 bool next(const Key& key, Key* next_key, bool allow_rollover = false) const FL_NO_EXCEPT {
453 auto it = find(key);
454 if (it != end()) {
455 ++it;
456 if (it != end()) {
457 *next_key = it->first;
458 return true;
459 } else if (allow_rollover && !empty()) {
460 *next_key = begin()->first;
461 return true;
462 }
463 }
464 return false;
465 }
466
467 // Navigate to previous element by key (FastLED compatibility)
468 bool prev(const Key& key, Key* prev_key, bool allow_rollover = false) const FL_NO_EXCEPT {
469 auto it = find(key);
470 if (it != end()) {
471 if (it != begin()) {
472 --it;
473 *prev_key = it->first;
474 return true;
475 } else if (allow_rollover && !empty()) {
476 *prev_key = mData.back().first;
477 return true;
478 }
479 }
480 return false;
481 }
482
483 // Allows pre-allocating space
485 mData.reserve(n);
486 }
487
488 // Shrink capacity to fit size
490 mData.shrink_to_fit();
491 }
492
493 memory_resource* get_memory_resource() const FL_NO_EXCEPT { return mData.get_resource(); }
494};
495
496// Comparison operators
497template <typename Key, typename Value, typename Less>
500 return lhs.size() == rhs.size() &&
501 fl::equal(lhs.begin(), lhs.end(), rhs.begin());
502}
503
504template <typename Key, typename Value, typename Less>
507 return !(lhs == rhs);
508}
509
510template <typename Key, typename Value, typename Less>
513 return fl::lexicographical_compare(lhs.begin(), lhs.end(),
514 rhs.begin(), rhs.end());
515}
516
517template <typename Key, typename Value, typename Less>
520 return !(rhs < lhs);
521}
522
523template <typename Key, typename Value, typename Less>
526 return rhs < lhs;
527}
528
529template <typename Key, typename Value, typename Less>
532 return !(lhs < rhs);
533}
534
535// Swap
536template <typename Key, typename Value, typename Less>
539 lhs.swap(rhs);
540}
541
542} // namespace fl
uint8_t pos
Definition Blur.ino:11
static T & instance() FL_NO_EXCEPT
Definition singleton.h:81
bool update(const Key &key, Value &&value) FL_NO_EXCEPT
Definition flat_map.h:440
iterator erase(const_iterator pos) FL_NO_EXCEPT
Definition flat_map.h:332
flat_map(flat_map &&other) FL_NO_EXCEPT
Definition flat_map.h:73
bool next(const Key &key, Key *next_key, bool allow_rollover=false) const FL_NO_EXCEPT
Definition flat_map.h:452
flat_map(const Less &less) FL_NO_EXCEPT
Definition flat_map.h:63
Value & operator[](const Key &key) FL_NO_EXCEPT
Definition flat_map.h:105
const Value & at(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:146
bool has(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:181
iterator erase(const_iterator first, const_iterator last) FL_NO_EXCEPT
Definition flat_map.h:336
bool full() const FL_NO_EXCEPT
Definition flat_map.h:102
iterator insert(const_iterator, value_type &&value) FL_NO_EXCEPT
Definition flat_map.h:279
typename vector_type::reverse_iterator reverse_iterator
Definition flat_map.h:49
iterator erase(iterator pos) FL_NO_EXCEPT
Definition flat_map.h:328
typename vector_type::iterator iterator
Definition flat_map.h:47
fl::pair< iterator, bool > insert(value_type &&value) FL_NO_EXCEPT
Definition flat_map.h:259
bool contains(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:176
reverse_iterator rend() FL_NO_EXCEPT
Definition flat_map.h:93
size_type capacity() const FL_NO_EXCEPT
Definition flat_map.h:100
typename vector_type::const_reverse_iterator const_reverse_iterator
Definition flat_map.h:50
const_iterator end() const FL_NO_EXCEPT
Definition flat_map.h:88
fl::pair< const_iterator, const_iterator > equal_range(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:238
const_iterator lower_bound(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:214
iterator upper_bound(const Key &key) FL_NO_EXCEPT
Definition flat_map.h:220
size_type max_size() const FL_NO_EXCEPT
Definition flat_map.h:101
const value_type & back() const FL_NO_EXCEPT
Definition flat_map.h:391
flat_map & operator=(const flat_map &other)=default
flat_map(const flat_map &other) FL_NO_EXCEPT
Definition flat_map.h:69
fl::less< int > mLess
Definition flat_map.h:54
bool get(const Key &key, Value *out_value) const FL_NO_EXCEPT
Definition flat_map.h:408
key_compare key_comp() const FL_NO_EXCEPT
Definition flat_map.h:371
const_iterator cbegin() const FL_NO_EXCEPT
Definition flat_map.h:89
bool update(const Key &key, const Value &value) FL_NO_EXCEPT
Definition flat_map.h:428
const value_type & front() const FL_NO_EXCEPT
Definition flat_map.h:381
const_iterator begin() const FL_NO_EXCEPT
Definition flat_map.h:87
iterator emplace_hint(const_iterator hint, Args &&... args) FL_NO_EXCEPT
Definition flat_map.h:322
void shrink_to_fit() FL_NO_EXCEPT
Definition flat_map.h:489
static bool less_thunk(const void *ctx, const void *a, const void *b) FL_NO_EXCEPT
Definition flat_map.h:192
void reserve(size_type n) FL_NO_EXCEPT
Definition flat_map.h:484
value_type & front() FL_NO_EXCEPT
Definition flat_map.h:376
Value & at(const Key &key) FL_NO_EXCEPT
Definition flat_map.h:136
const value_type & const_reference
Definition flat_map.h:42
bool insert(const Key &key, const Value &value, insert_result *result=nullptr) FL_NO_EXCEPT
Definition flat_map.h:283
flat_map & operator=(flat_map &&other) FL_NO_EXCEPT
Definition flat_map.h:76
fl::pair< iterator, bool > insert_or_update(const Key &key, const Value &value) FL_NO_EXCEPT
Definition flat_map.h:418
iterator find(const Key &key) FL_NO_EXCEPT
Definition flat_map.h:156
fl::pair< int, FxPtr > value_type
Definition flat_map.h:37
iterator insert(const_iterator, const value_type &value) FL_NO_EXCEPT
Definition flat_map.h:275
iterator lower_bound(const Key &key) FL_NO_EXCEPT
Definition flat_map.h:208
iterator begin() FL_NO_EXCEPT
Definition flat_map.h:85
flat_map(memory_resource *resource) FL_NO_EXCEPT
Definition flat_map.h:60
size_type size() const FL_NO_EXCEPT
Definition flat_map.h:98
fl::pair< iterator, bool > emplace(Args &&... args) FL_NO_EXCEPT
Definition flat_map.h:316
const_iterator upper_bound(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:226
flat_map()=default
bool insert(Key &&key, Value &&value, insert_result *result=nullptr) FL_NO_EXCEPT
Definition flat_map.h:298
Value get(const Key &key, const Value &defaultValue) const FL_NO_EXCEPT
Definition flat_map.h:399
void clear() FL_NO_EXCEPT
Definition flat_map.h:360
bool prev(const Key &key, Key *prev_key, bool allow_rollover=false) const FL_NO_EXCEPT
Definition flat_map.h:468
size_type erase(const Key &key) FL_NO_EXCEPT
Definition flat_map.h:350
value_type & back() FL_NO_EXCEPT
Definition flat_map.h:386
bool empty() const FL_NO_EXCEPT
Definition flat_map.h:99
fl::pair< iterator, bool > insert(const value_type &value) FL_NO_EXCEPT
Definition flat_map.h:245
typename vector_type::const_iterator const_iterator
Definition flat_map.h:48
fl::pair< iterator, iterator > equal_range(const Key &key) FL_NO_EXCEPT
Definition flat_map.h:232
const value_type * const_pointer
Definition flat_map.h:44
const_iterator find(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:164
size_type count(const Key &key) const FL_NO_EXCEPT
Definition flat_map.h:172
const_reverse_iterator rend() const FL_NO_EXCEPT
Definition flat_map.h:95
detail::flat_map_ops make_ops() const FL_NO_EXCEPT
Definition flat_map.h:199
void swap(flat_map &other) FL_NO_EXCEPT
Definition flat_map.h:365
flat_map(const Less &less, memory_resource *resource) FL_NO_EXCEPT
Definition flat_map.h:66
fl::vector< value_type > vector_type
Definition flat_map.h:46
fl::less< int > key_compare
Definition flat_map.h:40
iterator end() FL_NO_EXCEPT
Definition flat_map.h:86
const_iterator cend() const FL_NO_EXCEPT
Definition flat_map.h:90
reverse_iterator rbegin() FL_NO_EXCEPT
Definition flat_map.h:92
memory_resource * get_memory_resource() const FL_NO_EXCEPT
Definition flat_map.h:493
const_reverse_iterator rbegin() const FL_NO_EXCEPT
Definition flat_map.h:94
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
FL_NO_INLINE fl::size flat_map_lower_bound_idx(const void *data, fl::size n, const void *key, const flat_map_ops &ops) FL_NO_EXCEPT
FL_NO_INLINE fl::size flat_map_upper_bound_idx(const void *data, fl::size n, const void *key, const flat_map_ops &ops) FL_NO_EXCEPT
flat_map_less_thunk_t less_fn
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
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
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