43 bool operator()(
const T &a,
const T &b)
const {
return a == b; }
51#ifndef FASTLED_HASHMAP_INLINED_COUNT
52#define FASTLED_HASHMAP_INLINED_COUNT 8
55template <
typename Key,
typename T,
typename Hash = Hash<Key>,
56 typename KeyEqual = EqualTo<Key>,
57 int INLINED_COUNT = FASTLED_HASHMAP_INLINED_COUNT>
84 for (fl::size i = 0; i < other._buckets.size(); ++i) {
85 if (other.is_occupied(i)) {
86 insert(other._buckets[i].key, other._buckets[i].value);
99 other._tombstones = 0;
103 template<
typename InputIt>
125 if (
this != &other) {
130 if (
_buckets.size() != other._buckets.size()) {
132 _buckets.assign(other._buckets.size(), Entry{});
136 _deleted.resize(other._buckets.size());
140 for (fl::size i = 0; i < other._buckets.size(); ++i) {
141 if (other.is_occupied(i)) {
157 if (
this != &other) {
169 other._tombstones = 0;
231 fl::size cap =
_map->_buckets.size();
287 fl::size cap =
_map->_buckets.size();
299 iterator
begin() {
return iterator(
this, 0); }
301 const_iterator
begin()
const {
return const_iterator(
this, 0); }
302 const_iterator
end()
const {
return const_iterator(
this,
_buckets.size()); }
303 const_iterator
cbegin()
const {
return const_iterator(
this, 0); }
305 return const_iterator(
this,
_buckets.size());
312 u32 lhs = (
size + tombstones) << 8;
346 FASTLED_ASSERT(idx !=
npos(),
"unordered_map::insert: invalid index at "
347 << idx <<
" which is " <<
npos());
350 return {iterator(
this, idx), is_new};
377 FASTLED_ASSERT(idx !=
npos(),
"unordered_map::insert: invalid index at "
378 << idx <<
" which is " <<
npos());
381 return {iterator(
this, idx), is_new};
398 template<
typename InputIt>
399 void insert(InputIt first, InputIt last) {
400 for (; first != last; ++first) {
408 for (
const auto& kv :
init) {
435 FASTLED_ASSERT(idx !=
npos(),
"unordered_map::insert_or_assign: invalid index");
438 return {iterator(
this, idx), is_new};
462 FASTLED_ASSERT(idx !=
npos(),
"unordered_map::insert_or_assign: invalid index");
465 return {iterator(
this, idx), is_new};
470 template<
typename... Args>
480 template<
typename... Args>
488 template<
typename... Args>
511 return {iterator(
this, idx), is_new};
515 template<
typename... Args>
538 return {iterator(
this, idx), is_new};
556 if (it ==
end() || it._map !=
this) {
567 it.advance_to_occupied();
572 iterator
erase(const_iterator first, const_iterator last) {
573 if (first._map !=
this || last._map !=
this) {
579 iterator current(
this, first._idx);
580 current.advance_to_occupied();
582 while (current !=
end() && current._idx < last._idx) {
583 fl::size idx_to_erase = current._idx;
585 current.advance_to_occupied();
629 return idx ==
npos() ?
end() : iterator(
this, idx);
634 return idx ==
npos() ?
end() : const_iterator(
this, idx);
639 return idx !=
npos();
645 FASTLED_ASSERT(
value !=
nullptr,
"unordered_map::at: key not found");
651 FASTLED_ASSERT(
value !=
nullptr,
"unordered_map::at: key not found");
662 iterator it =
find(key);
672 const_iterator it =
find(key);
676 const_iterator next = it;
714 static T default_value{};
715 FASTLED_ASSERT(
false,
"unordered_map::operator[]: Failed to allocate after rehash");
716 return default_value;
737 return static_cast<fl::size
>(-1) /
sizeof(Entry);
753 return static_cast<float>(
_size) /
static_cast<float>(
_buckets.size());
775 fl::size min_buckets =
_size;
776 if (n < min_buckets) {
791 if (max_lf <= 0.0f) {
795 fl::size required_buckets =
static_cast<fl::size
>(
796 static_cast<float>(n) / max_lf + 0.999999f
798 if (required_buckets >
_buckets.size()) {
805 return static_cast<fl::size
>(-1);
836 void swap(Entry &other) {
850 const fl::size cap =
_buckets.size();
851 const fl::size mask = cap - 1;
852 const fl::size h =
_hash(key) & mask;
853 fl::size first_tomb =
npos();
857 for (fl::size i = 0; i < cap; ++i) {
858 const fl::size idx = (h + i) & mask;
861 return {first_tomb !=
npos() ? first_tomb : idx,
true};
863 if (first_tomb ==
npos())
873 const fl::size idx = (h + i + i * i) & mask;
876 return {first_tomb !=
npos() ? first_tomb : idx,
true};
878 if (first_tomb ==
npos())
885 for (; i < cap; ++i) {
886 const fl::size idx = (h + i) & mask;
889 return {first_tomb !=
npos() ? first_tomb : idx,
true};
891 if (first_tomb ==
npos())
899 return {
npos(),
false};
908 const fl::size cap =
_buckets.size();
909 const fl::size mask = cap - 1;
910 const fl::size h =
_hash(key) & mask;
914 for (fl::size i = 0; i < cap; ++i) {
915 const fl::size idx = (h + i) & mask;
925 const fl::size idx = (h + i + i * i) & mask;
932 for (; i < cap; ++i) {
933 const fl::size idx = (h + i) & mask;
945 const Key &key,
const fl::bitset<1024> &occupied_set)
const {
946 const fl::size cap =
_buckets.size();
947 const fl::size mask = cap - 1;
948 const fl::size h =
_hash(key) & mask;
952 for (fl::size i = 0; i < cap; ++i) {
953 const fl::size idx = (h + i) & mask;
954 bool occupied = occupied_set.test(idx);
964 const fl::size idx = (h + i + i * i) & mask;
965 bool occupied = occupied_set.test(idx);
972 for (; i < cap; ++i) {
973 const fl::size idx = (h + i) & mask;
974 bool occupied = occupied_set.test(idx);
987 fl::bitset<1024> old_occupied =
_occupied;
1000 for (fl::size i = 0; i < old.
size(); i++) {
1001 if (old_occupied.test(i))
1014 for (fl::size i = 0; i < cap; ++i) {
1027 fl::bitset<1024> occupied;
1032 for (fl::size i = 0; i <
_size; ++i) {
1033 const bool already_finished = occupied.test(i);
1034 if (already_finished) {
1043 if (idx ==
npos()) {
1046 false,
"unordered_map::rehash_inline_no_resize: invalid index at "
1047 << idx <<
" which is " <<
npos());
1051 FASTLED_ASSERT(!tmp,
1052 "unordered_map::rehash_inline_no_resize: invalid tmp");
1061 while (!tmp.
empty()) {
1064 auto key = tmp.
ptr()->key;
1067 if (new_idx ==
npos()) {
1071 "unordered_map::rehash_inline_no_resize: invalid index at "
1072 << new_idx <<
" which is " <<
npos());
1075 occupied.set(new_idx);
1076 if (new_idx <
_size) {
1089 "unordered_map::rehash_inline_no_resize: invalid occupied at " << i);
1091 tmp.
empty(),
"unordered_map::rehash_inline_no_resize: invalid tmp at " << i);
1101 if (
size() != other.
size())
return false;
1102 for (
const auto& kv : *
this) {
1103 auto it = other.
find(kv.first);
1104 if (it == other.
end() || it->
second != kv.second)
return false;
1111 return !(*
this == other);
1131template <
typename Key,
typename T,
typename Hash = Hash<Key>,
1132 typename KeyEqual = equal_to<Key>>
Alignment macros and utilities for FastLED.
bool empty() const FL_NOEXCEPT
Polymorphic memory resource base class (PMR-style).
fl::size find_index(const vec2< u16 > &key) const
bool operator==(const unordered_map &other) const
Equality comparison (map equality: same key-value pairs, order-independent)
unordered_map & operator=(unordered_map &&other) FL_NOEXCEPT
Hash< vec2< u16 > > _hash
fl::bitset< 1024 > _occupied
pair< const_iterator, const_iterator > equal_range(const Key &key) const
unordered_map(fl::size n, const Hash &hf, const KeyEqual &eq)
void mark_occupied(fl::size idx)
iterator find(const Key &key)
bool operator!=(const unordered_map &other) const
Inequality comparison.
unordered_map(fl::size initial_capacity)
bool is_deleted(fl::size idx) const
unordered_map & operator=(fl::initializer_list< pair< Key, T > > init) FL_NOEXCEPT
iterator emplace_hint(const_iterator hint, Args &&... args)
iterator erase(iterator it)
fl::size count(const Key &key) const
void insert(InputIt first, InputIt last)
const T & at(const Key &key) const
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void rehash_inline_no_resize()
bool is_empty(fl::size idx) const
unordered_map(fl::initializer_list< pair< Key, T > > init)
void mark_deleted(fl::size idx)
float load_factor() const
bool remove(const Key &key)
const T * find_value(const Key &key) const
EqualTo< vec2< u16 > > _equal
unordered_map() FL_NOEXCEPT
void insert(fl::initializer_list< pair< Key, T > > init)
fl::vector_inlined< Entry, FASTLED_HASHMAP_INLINED_COUNT > _buckets
pair< fl::size, bool > find_slot(const vec2< u16 > &key) const
fl::size find_unoccupied_index_using_bitset(const Key &key, const fl::bitset< 1024 > &occupied_set) const
pair< iterator, bool > emplace(Args &&... args)
unordered_map(memory_resource *resource)
fl::size capacity() const
T * find_value(const Key &key)
unordered_map(const unordered_map &other) FL_NOEXCEPT
const_iterator cbegin() const
pair< iterator, bool > try_emplace(const Key &k, Args &&... args)
iterator erase(const_iterator first, const_iterator last)
static bool NeedsRehash(fl::size size, fl::size bucket_size, fl::size tombstones, u8 load_factor)
struct FL_ALIGN_AS_T(EntryAlign::value) Entry
fl::size bucket_count() const
float max_load_factor() const
pair< iterator, bool > try_emplace(Key &&k, Args &&... args)
unordered_map & operator=(const unordered_map &other) FL_NOEXCEPT
bool erase(const Key &key)
pair< iterator, bool > insert_or_assign(Key &&key, T &&value)
static fl::size next_power_of_two(fl::size n)
bool is_occupied(fl::size idx) const
pair< iterator, bool > insert(const vec2< u16 > &key, const u8 &value)
unordered_map(unordered_map &&other) FL_NOEXCEPT
bool needs_rehash() const
const_iterator begin() const
pair< iterator, bool > insert_or_assign(const Key &key, T &&value)
max_align< vec2< u16 >, u8 > EntryAlign
const_iterator cend() const
unordered_map(InputIt first, InputIt last)
void swap(unordered_map &other)
fl::size max_size() const
const_iterator end() const
void rehash_internal(fl::size new_cap)
pair< iterator, bool > insert(Key &&key, T &&value)
bool contains(const Key &key) const
memory_resource * get_memory_resource() const
void mark_empty(fl::size idx)
const_iterator find(const Key &key) const
void max_load_factor(float ml)
pair< iterator, iterator > equal_range(const Key &key)
fl::bitset< 1024 > _deleted
pair< iterator, bool > insert(pair< Key, T > &&kv)
pair< iterator, bool > insert(const pair< Key, T > &kv)
T & operator[](const Key &key)
Hash hash_function() const
void setLoadFactor(float f)
unordered_map(fl::size initial_capacity, float max_load)
fl::size size() const FL_NOEXCEPT
PMR-style polymorphic memory resource for type-erased allocation.
constexpr T && forward(typename remove_reference< T >::type &t) FL_NOEXCEPT
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
constexpr remove_reference< T >::type && move(T &&t) FL_NOEXCEPT
constexpr int type_rank< T >::value
unordered_map< Key, T, Hash, KeyEqual > hash_map
void init(Context &ctx, int w, int h)
FASTLED_FORCE_INLINE U map_range(T value, T in_min, T in_max, U out_min, U out_max) FL_NOEXCEPT
void swap(array< T, N > &lhs, array< T, N > &rhs) FL_NOEXCEPT
VectorN< T, INLINED_SIZE > vector_inlined
To bit_cast(const From &from) FL_NOEXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type clamp(T x, T lo, T hi) FL_NOEXCEPT
Base definition for an LED controller.
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_SHORTEN_64_TO_32
#define FL_DISABLE_WARNING_NULL_DEREFERENCE
#define FL_DISABLE_WARNING_POP
bool operator()(const T &a, const T &b) const
const_iterator(const unordered_map *m, fl::size idx)
pair< const Key, T > value_type
const value_type & reference
const_iterator operator++(int)
const_iterator() FL_NOEXCEPT
fl::forward_iterator_tag iterator_category
bool operator==(const const_iterator &o) const
pointer operator->() const
const value_type * pointer
friend class unordered_map
void advance_to_occupied()
const_iterator & operator++()
const unordered_map * _map
bool operator!=(const const_iterator &o) const
const_iterator(const iterator &it)
reference operator*() const
bool operator==(const iterator &o) const
fl::forward_iterator_tag iterator_category
reference operator*() const
pointer operator->() const
friend class unordered_map
iterator(unordered_map *m, fl::size idx)
bool operator!=(const iterator &o) const
void advance_to_occupied()
pair< const Key, T > value_type
#define FASTLED_HASHMAP_INLINED_COUNT