11#include <initializer_list>
14#include "roo_backport.h"
15#include "roo_backport/string_view.h"
24inline bool operator==(const ::String& a, roo::string_view b) {
25 return roo::string_view(a.c_str(), a.length()) == b;
28inline bool operator==(roo::string_view a,
const String& b) {
return (b == a); }
44 0x1, 0x3, 0x7, 0xb, 0x1f, 0x3b, 0x7f, 0xfb,
45 0x1f7, 0x3fb, 0x7f7, 0xffb, 0x1fff, 0x3feb, 0x7fcf, 0xffef};
51 0x281474976700001, 0xD5C26DD2255556, 0x5B9C78357DB6DC, 0x1745d1745d18,
52 0x84210842109, 0x456c797dd4a, 0x20408102041, 0x105197f7d74,
53 0x824a4e60b4, 0x4050647d9e, 0x202428adc4, 0x100501907e,
54 0x800400201, 0x401506e65, 0x200c44b25, 0x100110122};
57inline uint16_t
fastmod(uint32_t n,
int idx) {
63 uint32_t ht_len = (uint32_t)(((
float)size_hint) /
kMaxFillRatio) + 1;
64 for (
int radkeIdx = 0; radkeIdx < 15; ++radkeIdx) {
70template <
typename Key>
76 return murmur3_32(val.data(), val.size(), 0x92F4E42BUL);
103struct DefaultHashFn<::String> {
104 size_t operator()(::String val)
const {
105 return DefaultHashFn<::roo::string_view>()(
106 ::roo::string_view(val.c_str(), val.length()));
133 inline size_t operator()(::String val)
const {
143 template <
typename X,
typename Y>
149template <
typename _Func,
typename _SfinaeType,
typename = std::
void_t<>>
152template <
typename _Func,
typename _SfinaeType>
154 std::
void_t<typename _Func::is_transparent>> {
158template <
typename _Func,
typename _SfinaeType>
163template <
typename Entry>
179template <
typename Entry,
typename Key,
typename HashFn = DefaultHashFn<Key>,
180 typename KeyFn = DefaultKeyFn<Entry>,
181 typename KeyCmpFn = std::equal_to<Key>>
213 return ht_ ==
other.ht_ && pos_ ==
other.pos_;
217 return ht_ !=
other.ht_ || pos_ !=
other.pos_;
226 : ht_(
ht), pos_(
pos) {}
263 return ht_ ==
other.ht_ && pos_ ==
other.pos_;
267 return ht_ !=
other.ht_ || pos_ !=
other.pos_;
275 : ht_(
ht), pos_(
pos) {}
289 template <
typename InputIt>
329 : &dummy_empty_state_) {
330 std::fill(&states_[0], &states_[
kRadkePrimes[capacity_idx_]], EMPTY);
337 key_cmp_fn_(std::
move(
other.key_cmp_fn_)),
338 capacity_idx_(
other.capacity_idx_),
340 erased_(
other.erased_),
341 resize_threshold_(
other.resize_threshold_),
342 buffer_(
other.buffer_),
343 states_(capacity_idx_ > 0 ?
other.states_ : &dummy_empty_state_) {
344 other.capacity_idx_ = 0;
347 other.buffer_ =
nullptr;
348 other.states_ = &dummy_empty_state_;
353 : hash_fn_(
other.hash_fn_),
354 key_fn_(
other.key_fn_),
355 key_cmp_fn_(
other.key_cmp_fn_),
356 capacity_idx_(
other.capacity_idx_),
358 erased_(
other.erased_),
359 resize_threshold_(
other.resize_threshold_),
363 : &dummy_empty_state_) {
364 if (
other.buffer_ !=
nullptr) {
374 if (capacity_idx_ > 0)
delete[] states_;
380 if (
this != &
other) {
381 if (capacity_idx_ > 0)
delete[] states_;
383 hash_fn_ = std::move(
other.hash_fn_);
384 key_fn_ = std::move(
other.key_fn_);
385 key_cmp_fn_ = std::move(
other.key_cmp_fn_);
386 capacity_idx_ =
other.capacity_idx_;
388 erased_ =
other.erased_;
389 resize_threshold_ =
other.resize_threshold_;
390 if (capacity_idx_ > 0) {
391 buffer_ =
other.buffer_;
392 states_ =
other.states_;
393 other.capacity_idx_ = 0;
396 other.buffer_ =
nullptr;
397 other.states_ = &dummy_empty_state_;
400 states_ = &dummy_empty_state_;
408 if (
this != &
other) {
409 if (capacity_idx_ > 0)
delete[] states_;
411 hash_fn_ =
other.hash_fn_;
412 key_fn_ =
other.key_fn_;
413 key_cmp_fn_ =
other.key_cmp_fn_;
414 capacity_idx_ =
other.capacity_idx_;
416 erased_ =
other.erased_;
417 resize_threshold_ =
other.resize_threshold_;
420 states_ = capacity_idx_ > 0 ?
new State[
kRadkePrimes[capacity_idx_]]
421 : &dummy_empty_state_;
422 if (
other.buffer_ !=
nullptr) {
423 std::copy(&
other.buffer_[0],
434 if (
other.size() !=
size())
return false;
438 for (
const auto&
e : *
this) {
440 if (
itr ==
other.end())
return false;
441 if (*
itr !=
e)
return false;
456 if (states_[
pos] < 0)
break;
466 if (states_[
pos] < 0)
break;
481 bool empty()
const {
return used_ == erased_; }
489 size_t hash = hash_fn_(
key);
491 if (states_[
pos] == EMPTY)
return end();
492 if (states_[
pos] < 0 && (states_[
pos] & 0x7F) == (hash & 0x7F) &&
493 key_cmp_fn_(key_fn_(buffer_[
pos]),
key)) {
502 if (states_[
p] == EMPTY)
return end();
503 if (states_[
p] < 0 && (states_[
p] & 0x7F) == (hash & 0x7F) &&
504 key_cmp_fn_(key_fn_(buffer_[
p]),
key)) {
509 p += (
j >= 0 ?
j : -
j);
515 template <
typename K,
typename = has_is_transparent_t<HashFn, K>,
516 typename = has_is_transparent_t<KeyCmpFn, K>>
518 size_t hash = hash_fn_(
key);
520 if (states_[
pos] == EMPTY)
return end();
521 if (states_[
pos] < 0 && (states_[
pos] & 0x7F) == (hash & 0x7F) &&
522 key_cmp_fn_(key_fn_(buffer_[
pos]),
key)) {
531 if (states_[
p] == EMPTY)
return end();
532 if (states_[
p] < 0 && (states_[
p] & 0x7F) == (hash & 0x7F) &&
533 key_cmp_fn_(key_fn_(buffer_[
p]),
key)) {
538 p += (
j >= 0 ?
j : -
j);
545 size_t hash = hash_fn_(
key);
547 if (states_[
pos] == EMPTY)
return false;
548 if (states_[
pos] < 0 && (states_[
pos] & 0x7F) == (hash & 0x7F) &&
549 key_cmp_fn_(key_fn_(buffer_[
pos]),
key)) {
551 if (used_ == 1 && erased_ == 0) {
555 states_[
pos] = EMPTY;
558 states_[
pos] = DELETED;
569 if (states_[
p] == EMPTY)
return false;
570 if (states_[
p] < 0 && (states_[
p] & 0x7F) == (hash & 0x7F) &&
571 key_cmp_fn_(key_fn_(buffer_[
p]),
key)) {
572 states_[
p] = DELETED;
579 p += (
j >= 0 ?
j : -
j);
585 template <
typename K,
typename = has_is_transparent_t<HashFn, K>,
586 typename = has_is_transparent_t<KeyCmpFn, K>>
588 size_t hash = hash_fn_(
key);
590 if (states_[
pos] == EMPTY)
return false;
591 if (states_[
pos] < 0 && (states_[
pos] & 0x7F) == (hash & 0x7F) &&
592 key_cmp_fn_(key_fn_(buffer_[
pos]),
key)) {
593 states_[
pos] = DELETED;
604 if (states_[
p] == EMPTY)
return false;
605 if (states_[
p] < 0 && (states_[
p] & 0x7F) == (hash & 0x7F) &&
606 key_cmp_fn_(key_fn_(buffer_[
p]),
key)) {
607 states_[
p] = DELETED;
614 p += (
j >= 0 ?
j : -
j);
629 if (used_ == 0 && erased_ == 0)
return;
630 std::fill(&states_[0], &states_[
kRadkePrimes[capacity_idx_]], EMPTY);
643 if (
capacity_idx == capacity_idx_ && erased_ == 0)
return;
646 size(), hash_fn_, key_fn_, key_cmp_fn_);
647 for (
auto&
e : *
this) {
648 newt.insert(std::move(
e));
650 *
this = std::move(
newt);
657 template <
typename K,
typename = has_is_transparent_t<HashFn, K>,
658 typename = has_is_transparent_t<KeyCmpFn, K>>
667 size_t hash = hash_fn_(
key);
670 if (states_[
pos] < 0 && (states_[
pos] & 0x7F) == (hash & 0x7F) &&
671 key_cmp_fn_(key_fn_(buffer_[
pos]),
key)) {
674 if (used_ >= resize_threshold_) {
675 if (
empty() && erased_ > 0) {
682 return std::make_pair(
itr,
false);
686 size() + 1, hash_fn_, key_fn_, key_cmp_fn_);
689 for (
auto&
e : *
this) {
690 newt.insert(std::move(
e));
701 buffer_[
i] = std::move(
newt.buffer_[
i]);
704 *
this = std::move(
newt);
710 if (states_[
pos] == EMPTY) {
711 states_[
pos] = (hash & 0x7F) | 0x80;
712 buffer_[
pos] = std::move(
val);
722 if (states_[
p] == EMPTY) {
724 states_[
p] = (hash & 0x7F) | 0x80;
725 buffer_[
p] = std::move(
val);
727 return std::make_pair(
Iterator(
this,
p),
true);
729 if (states_[
p] < 0 && (states_[
p] & 0x7F) == (hash & 0x7F) &&
730 key_cmp_fn_(key_fn_(buffer_[
p]),
key)) {
731 return std::make_pair(
Iterator(
this,
p),
false);
735 p += (
j >= 0 ?
j : -
j);
741 size_t hash = hash_fn_(
key);
743 if (states_[
pos] == EMPTY)
return end();
744 if (states_[
pos] < 0 && (states_[
pos] & 0x7F) == (hash & 0x7F) &&
745 key_cmp_fn_(key_fn_(buffer_[
pos]),
key)) {
754 if (states_[
p] == EMPTY)
return end();
755 if (states_[
p] < 0 && (states_[
p] & 0x7F) == (hash & 0x7F) &&
756 key_cmp_fn_(key_fn_(buffer_[
p]),
key)) {
761 p += (
j >= 0 ?
j : -
j);
765 template <
typename K,
typename = has_is_transparent_t<HashFn, K>,
766 typename = has_is_transparent_t<KeyCmpFn, K>>
768 size_t hash = hash_fn_(
key);
770 if (states_[
pos] == EMPTY)
return end();
771 if (states_[
pos] < 0 && (states_[
pos] & 0x7F) == (hash & 0x7F) &&
772 key_cmp_fn_(key_fn_(buffer_[
pos]),
key)) {
781 if (states_[
p] == EMPTY)
return end();
782 if (states_[
p] < 0 && (states_[
p] & 0x7F) == (hash & 0x7F) &&
783 key_cmp_fn_(key_fn_(buffer_[
p]),
key)) {
788 p += (
j >= 0 ?
j : -
j);
794 static constexpr State EMPTY = 0;
795 static constexpr State DELETED = 1;
810 State dummy_empty_state_;
Constant forward iterator.
const Entry & operator*() const
std::ptrdiff_t difference_type
std::forward_iterator_tag iterator_category
ConstIterator & operator++()
bool operator!=(const ConstIterator &other) const
bool operator==(const ConstIterator &other) const
ConstIterator operator++(int n)
const Entry * operator->() const
Mutable forward iterator.
std::forward_iterator_tag iterator_category
Iterator operator++(int n)
bool operator==(const Iterator &other) const
std::ptrdiff_t difference_type
bool operator!=(const Iterator &other) const
Flat, memory-conscious hash table optimized for small collections.
std::pair< Iterator, bool > insert(Entry val)
Inserts val if key is not present.
bool operator!=(const FlatSmallHashtable &other)
bool contains(const Key &key) const
Returns whether key exists in the table.
Iterator lookup(const Key &key)
Iterator erase(const ConstIterator &itr)
Removes the entry at itr and returns iterator to the next entry.
Iterator end()
Returns iterator past the end.
FlatSmallHashtable(InputIt first, InputIt last, HashFn hash_fn=HashFn(), KeyFn key_fn=KeyFn(), KeyCmpFn key_cmp_fn=KeyCmpFn())
Constructs a table from an iterator range.
bool empty() const
Returns whether the table is empty.
FlatSmallHashtable(FlatSmallHashtable &&other)
Move constructor.
FlatSmallHashtable & operator=(const FlatSmallHashtable &other)
Copy assignment.
FlatSmallHashtable(uint16_t size_hint, HashFn hash_fn=HashFn(), KeyFn key_fn=KeyFn(), KeyCmpFn key_cmp_fn=KeyCmpFn())
Constructs an empty table sized for size_hint elements.
~FlatSmallHashtable()
Destructor.
FlatSmallHashtable & operator=(FlatSmallHashtable &&other)
Move assignment.
uint16_t ht_len() const
Returns the internal bucket array length.
bool erase(const K &key)
Heterogeneous key overload of erase.
uint16_t capacity() const
Returns the number of elements insertable before rehashing.
Iterator lookup(const K &key)
void clear()
Removes all entries while preserving current allocated capacity.
FlatSmallHashtable(std::initializer_list< Entry > init, HashFn hash_fn=HashFn(), KeyFn key_fn=KeyFn(), KeyCmpFn key_cmp_fn=KeyCmpFn())
Constructs a table from an initializer list.
bool erase(const Key &key)
Removes an entry by key.
FlatSmallHashtable(HashFn hash_fn=HashFn(), KeyFn key_fn=KeyFn(), KeyCmpFn key_cmp_fn=KeyCmpFn())
Constructs an empty table with default initial capacity.
uint16_t size() const
Returns the number of stored elements.
bool operator==(const FlatSmallHashtable &other) const
Equality comparison by key/value content.
void compact()
Rebuilds the table to remove tombstones and shrink capacity.
FlatSmallHashtable(const FlatSmallHashtable &other)
Copy constructor.
ConstIterator end() const
Returns const iterator past the end.
bool contains(const K &key) const
Heterogeneous key overload of contains.
ConstIterator begin() const
Returns an iterator to the first element.
ConstIterator find(const Key &key) const
Finds key and returns a const iterator to the matching entry.
Iterator begin()
Returns a mutable iterator to the first element.
ConstIterator find(const K &key) const
Heterogeneous lookup overload of find.
Fixed-capacity string stored inline (no heap allocation).
Hashing utilities used by roo_collections containers.
static constexpr uint64_t kRadkePrimeInverts[]
int initialCapacityIdx(uint16_t size_hint)
static constexpr uint16_t kRadkePrimes[]
uint16_t fastmod(uint32_t n, int idx)
uint32_t murmur3_32(const void *key, size_t len, uint32_t seed)
Computes 32-bit MurmurHash3 of a binary buffer.
static constexpr float kMaxFillRatio
typename has_is_transparent< _Func, _SfinaeType >::type has_is_transparent_t
Fixed-capacity string utility type.
size_t operator()(const SmallString< N > &str) const
size_t operator()(const char *val) const
size_t operator()(const std::string &val) const
size_t operator()(::roo::string_view val) const
const Entry & operator()(const Entry &entry) const
bool operator()(const X &x, const Y &y) const
size_t operator()(const std::string &val) const
size_t operator()(const SmallString< N > &val) const
size_t operator()(const char *val) const
size_t operator()(::roo::string_view val) const