45 bool operator()(
const T &a,
const T &b)
const {
return a == b; }
53#ifndef FASTLED_HASHMAP_INLINED_COUNT
54#define FASTLED_HASHMAP_INLINED_COUNT 8
57template <
typename Key,
typename T,
typename Hash = Hash<Key>,
58 typename KeyEqual = EqualTo<Key>,
59 int INLINED_COUNT = FASTLED_HASHMAP_INLINED_COUNT>
65 HashMap(fl::size initial_capacity,
float max_load)
74 mLoadFactor = fl::map_range<float, u8>(f, 0.f, 1.f, 0, 255);
93 return {e.key, e.value};
100 auto& mutable_cached = *
reinterpret_cast<mutable_value_type*
>(&
_cached_value);
101 mutable_cached.~mutable_value_type();
102 new (&mutable_cached) mutable_value_type(
operator*());
111 mutable_cached.~mutable_value_type();
112 new (&mutable_cached) mutable_value_type(
operator*());
136 fl::size cap =
_map->_buckets.size();
164 return {e.key, e.value};
171 auto& mutable_cached = *
reinterpret_cast<mutable_value_type*
>(&
_cached_value);
172 mutable_cached.~mutable_value_type();
173 new (&mutable_cached) mutable_value_type(
operator*());
197 fl::size cap =
_map->_buckets.size();
210 iterator
begin() {
return iterator(
this, 0); }
212 const_iterator
begin()
const {
return const_iterator(
this, 0); }
213 const_iterator
end()
const {
return const_iterator(
this,
_buckets.size()); }
214 const_iterator
cbegin()
const {
return const_iterator(
this, 0); }
216 return const_iterator(
this,
_buckets.size());
223 u32 lhs = (
size + tombstones) << 8;
224 u32 rhs = (bucket_size * load_factor);
256 FASTLED_ASSERT(idx !=
npos(),
"HashMap::insert: invalid index at "
257 << idx <<
" which is " <<
npos());
285 FASTLED_ASSERT(idx !=
npos(),
"HashMap::insert: invalid index at "
286 << idx <<
" which is " <<
npos());
306 if (it ==
end() || it._map !=
this) {
317 it.advance_to_occupied();
341 return idx ==
npos() ?
end() : iterator(
this, idx);
346 return idx ==
npos() ?
end() : const_iterator(
this, idx);
351 return idx !=
npos();
387 static T default_value{};
388 return default_value;
409 return static_cast<fl::size
>(-1);
436 struct alignas(fl::max_align<Key, T>::value)
Entry {
453 const fl::size cap =
_buckets.size();
454 const fl::size mask = cap - 1;
455 const fl::size h =
_hash(key) & mask;
456 fl::size first_tomb =
npos();
460 for (fl::size i = 0; i < cap; ++i) {
461 const fl::size idx = (h + i) & mask;
464 return {first_tomb !=
npos() ? first_tomb : idx,
true};
466 if (first_tomb ==
npos())
476 const fl::size idx = (h + i + i * i) & mask;
479 return {first_tomb !=
npos() ? first_tomb : idx,
true};
481 if (first_tomb ==
npos())
488 for (; i < cap; ++i) {
489 const fl::size idx = (h + i) & mask;
492 return {first_tomb !=
npos() ? first_tomb : idx,
true};
494 if (first_tomb ==
npos())
502 return {
npos(),
false};
511 const fl::size cap =
_buckets.size();
512 const fl::size mask = cap - 1;
513 const fl::size h =
_hash(key) & mask;
517 for (fl::size i = 0; i < cap; ++i) {
518 const fl::size idx = (h + i) & mask;
528 const fl::size idx = (h + i + i * i) & mask;
535 for (; i < cap; ++i) {
536 const fl::size idx = (h + i) & mask;
548 const Key &key,
const fl::bitset<1024> &occupied_set)
const {
549 const fl::size cap =
_buckets.size();
550 const fl::size mask = cap - 1;
551 const fl::size h =
_hash(key) & mask;
555 for (fl::size i = 0; i < cap; ++i) {
556 const fl::size idx = (h + i) & mask;
557 bool occupied = occupied_set.test(idx);
567 const fl::size idx = (h + i + i * i) & mask;
568 bool occupied = occupied_set.test(idx);
575 for (; i < cap; ++i) {
576 const fl::size idx = (h + i) & mask;
577 bool occupied = occupied_set.test(idx);
590 fl::bitset<1024> old_occupied =
_occupied;
603 for (fl::size i = 0; i < old.
size(); i++) {
604 if (old_occupied.test(i))
617 for (fl::size i = 0; i < cap; ++i) {
630 fl::bitset<1024> occupied;
635 for (fl::size i = 0; i <
_size; ++i) {
636 const bool already_finished = occupied.test(i);
637 if (already_finished) {
649 false,
"HashMap::rehash_inline_no_resize: invalid index at "
650 << idx <<
" which is " <<
npos());
655 "HashMap::rehash_inline_no_resize: invalid tmp");
664 while (!tmp.
empty()) {
667 auto key = tmp.
ptr()->key;
670 if (new_idx ==
npos()) {
674 "HashMap::rehash_inline_no_resize: invalid index at "
675 << new_idx <<
" which is " <<
npos());
678 occupied.set(new_idx);
679 if (new_idx <
_size) {
692 "HashMap::rehash_inline_no_resize: invalid occupied at " << i);
694 tmp.
empty(),
"HashMap::rehash_inline_no_resize: invalid tmp at " << i);
714template <
typename Key,
typename T,
typename Hash = Hash<Key>,
715 typename KeyEqual = equal_to<Key>>
718template <
typename Key,
typename T,
typename Hash = Hash<Key>,
719 typename KeyEqual = equal_to<Key>>
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_NULL_DEREFERENCE void rehash_inline_no_resize()
T & operator[](const Key &key)
static fl::size next_power_of_two(fl::size n)
bool erase(const Key &key)
const T * find_value(const Key &key) const
pair< fl::size, bool > find_slot(const Key &key) const
const_iterator cend() const
void mark_empty(fl::size idx)
iterator erase(iterator it)
T * find_value(const Key &key)
fl::size find_unoccupied_index_using_bitset(const Key &key, const fl::bitset< 1024 > &occupied_set) const
bool is_deleted(fl::size idx) const
bool is_occupied(fl::size idx) const
fl::bitset< 1024 > _deleted
bool remove(const Key &key)
HashMap(fl::size initial_capacity, float max_load)
const_iterator end() const
fl::size find_index(const Key &key) const
void rehash(fl::size new_cap)
const_iterator find(const Key &key) const
fl::bitset< 1024 > _occupied
void mark_deleted(fl::size idx)
void insert(Key &&key, T &&value)
void setLoadFactor(float f)
HashMap(fl::size initial_capacity)
fl::size capacity() const
static bool NeedsRehash(fl::size size, fl::size bucket_size, fl::size tombstones, u8 load_factor)
FL_DISABLE_WARNING_POP fl::vector_inlined< Entry, FASTLED_HASHMAP_INLINED_COUNT > _buckets
bool is_empty(fl::size idx) const
bool contains(const Key &key) const
const_iterator begin() const
const_iterator cbegin() const
void mark_occupied(fl::size idx)
void insert(const Key &key, const T &value)
bool needs_rehash() const
iterator find(const Key &key)
#define FL_DISABLE_WARNING_PUSH
#define FL_DISABLE_WARNING_SHORTEN_64_TO_32
#define FL_DISABLE_WARNING_NULL_DEREFERENCE
#define FL_DISABLE_WARNING_POP
#define FASTLED_HASHMAP_INLINED_COUNT
constexpr remove_reference< T >::type && move(T &&t) noexcept
void swap(array< T, N > &lhs, array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
To bit_cast(const From &from) noexcept
InlinedVector< T, INLINED_SIZE > vector_inlined
FASTLED_FORCE_INLINE T clamp(T value, T min, T max)
HashMap< Key, T, Hash, KeyEqual > hash_map
HashMap< Key, T, Hash, KeyEqual > unordered_map
bool operator()(const T &a, const T &b) const
void advance_to_occupied()
const_iterator operator++(int)
const value_type * pointer
const_iterator(const HashMap *m, fl::size idx)
const_iterator & operator++()
bool operator==(const const_iterator &o) const
value_type operator*() const
const_iterator(const iterator &it)
pair< const Key, T > value_type
bool operator!=(const const_iterator &o) const
const value_type & reference
pointer operator->() const
pointer operator->() const
void advance_to_occupied()
pair< const Key, T > value_type
value_type operator*() const
bool operator!=(const iterator &o) const
bool operator==(const iterator &o) const
iterator(HashMap *m, fl::size idx)