109 int64_t occupied_and_removed_slots_;
130#define LOAD_FACTOR 1, 2
131 static constexpr LoadFactor max_load_factor_ = LoadFactor(
LOAD_FACTOR);
152#define VECTOR_SET_SLOT_PROBING_BEGIN(HASH, R_SLOT) \
153 SLOT_PROBING_BEGIN (ProbingStrategy, HASH, slot_mask_, SLOT_INDEX) \
154 auto &R_SLOT = slots_[SLOT_INDEX];
155#define VECTOR_SET_SLOT_PROBING_END() SLOT_PROBING_END()
161 template<
typename Other,
162 int64_t OtherInlineBufferCapacity,
163 typename OtherProbingStrategy,
165 typename OtherIsEqual,
167 typename OtherAllocator>
178 occupied_and_removed_slots_(0),
183 keys_ = inline_buffer_;
196 VectorSet(
const std::initializer_list<Key> &keys, Allocator allocator = {})
204 if (keys_ != inline_buffer_) {
205 this->deallocate_keys_array(keys_);
211 if (other.
size() <= InlineBufferCapacity) {
212 usable_slots_ = other.size();
213 keys_ = inline_buffer_;
216 keys_ = this->allocate_keys_array(other.usable_slots_);
217 usable_slots_ = other.usable_slots_;
220 uninitialized_copy_n(other.keys_, other.size(), keys_);
223 if (keys_ != inline_buffer_) {
224 this->deallocate_keys_array(keys_);
229 removed_slots_ = other.removed_slots_;
230 occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
231 slot_mask_ = other.slot_mask_;
233 is_equal_ = other.is_equal_;
236 template<
int64_t OtherInlineBufferCapacity>
240 : removed_slots_(other.removed_slots_),
241 occupied_and_removed_slots_(other.occupied_and_removed_slots_),
242 slot_mask_(other.slot_mask_),
243 slots_(std::move(other.slots_))
245 if (other.is_inline()) {
247 usable_slots_ =
size;
249 constexpr bool other_is_same_type = std::is_same_v<
VectorSet, std::decay_t<
decltype(other)>>;
250 constexpr size_t max_full_copy_size = 32;
251 if constexpr (other_is_same_type && std::is_trivial_v<Key> &&
252 sizeof(inline_buffer_) <= max_full_copy_size)
255 keys_ = inline_buffer_;
257 memcpy(inline_buffer_, other.inline_buffer_,
sizeof(inline_buffer_));
261 if (OtherInlineBufferCapacity <= InlineBufferCapacity ||
size <= InlineBufferCapacity) {
262 keys_ = inline_buffer_;
265 keys_ = this->allocate_keys_array(
size);
272 usable_slots_ = other.usable_slots_;
274 other.removed_slots_ = 0;
275 other.occupied_and_removed_slots_ = 0;
276 other.usable_slots_ = 0;
277 other.slot_mask_ = 0;
278 other.slots_ = SlotArray(1);
279 other.keys_ = other.inline_buffer_;
325 this->add_new__impl(key, hash_(key));
329 this->add_new__impl(std::move(key), hash_(key));
344 return this->
add_as(std::move(key));
346 template<
typename ForwardKey>
bool add_as(ForwardKey &&key)
348 return this->add__impl(std::forward<ForwardKey>(key), hash_(key));
371 return this->add_overwrite__impl(std::forward<ForwardKey>(key), hash_(key));
383 for (
const Key &key : keys) {
397 template<
typename ForwardKey>
bool contains_as(
const ForwardKey &key)
const
399 return this->contains__impl(key, hash_(key));
412 template<
typename ForwardKey>
bool remove_as(
const ForwardKey &key)
414 return this->remove__impl(key, hash_(key));
427 this->remove_contained__impl(key, hash_(key));
439 for (Slot &slot : slots_) {
440 if (slot.is_occupied()) {
441 const int64_t index = slot.index();
442 const Key &key = keys_[index];
443 if (predicate(key)) {
444 this->remove_key_internal(slot);
448 return prev_size - this->
size();
457 return this->pop__impl();
470 return this->index_of__impl(key, hash_(key));
483 return this->index_of_try__impl(key, hash_(key));
500 return this->index_of_or_add__impl(std::forward<ForwardKey>(key), hash_(key));
526 template<
typename ForwardKey,
typename... ForwardDefault>
530 if (
ptr ==
nullptr) {
531 return Key(std::forward<ForwardDefault>(default_key)...);
546 const int64_t index = this->index_of_try__impl(key, hash_(key));
548 return keys_ + index;
568 return keys_ + this->
size();
590 return keys_ == inline_buffer_;
598 return occupied_and_removed_slots_ - removed_slots_;
606 return occupied_and_removed_slots_ == removed_slots_;
614 return slots_.size();
622 return removed_slots_;
630 return sizeof(Slot) +
sizeof(
Key);
639 return int64_t(
sizeof(Slot) * slots_.size() +
sizeof(
Key) * usable_slots_);
647 if (usable_slots_ < n) {
648 this->realloc_and_reinsert(n);
657 std::destroy_at(
this);
671 for (Slot &slot : slots_) {
677 occupied_and_removed_slots_ = 0;
686 return this->count_collisions__impl(key, hash_(key));
705 data.
data = this->allocate_keys_array(
size);
712 this->deallocate_keys_array(
data.data);
719 data.capacity = usable_slots_;
724 keys_ = inline_buffer_;
725 occupied_and_removed_slots_ = 0;
727 std::destroy_at(
this);
736 int64_t total_slots, usable_slots;
737 max_load_factor_.compute_total_and_usable_slots(
743 if (this->
size() == 0) {
745 slots_.reinitialize(total_slots);
748 if (usable_slots <= InlineBufferCapacity) {
749 new_keys = inline_buffer_;
752 new_keys = this->allocate_keys_array(usable_slots);
755 if (keys_ != inline_buffer_) {
756 this->deallocate_keys_array(keys_);
762 this->noexcept_reset();
766 occupied_and_removed_slots_ = 0;
767 usable_slots_ = usable_slots;
768 slot_mask_ = new_slot_mask;
772 SlotArray new_slots(total_slots);
775 for (Slot &slot : slots_) {
776 if (slot.is_occupied()) {
777 this->add_after_grow(slot, new_slots, new_slot_mask);
781 slots_ = std::move(new_slots);
784 this->noexcept_reset();
790 if (usable_slots <= InlineBufferCapacity) {
791 new_keys = inline_buffer_;
794 new_keys = this->allocate_keys_array(usable_slots);
799 if (new_keys != keys_) {
804 if (new_keys != inline_buffer_) {
805 this->deallocate_keys_array(new_keys);
807 this->noexcept_reset();
813 if (keys_ != inline_buffer_) {
814 this->deallocate_keys_array(keys_);
818 occupied_and_removed_slots_ -= removed_slots_;
819 usable_slots_ = usable_slots;
821 slot_mask_ = new_slot_mask;
824 void add_after_grow(Slot &old_slot, SlotArray &new_slots,
const uint64_t new_slot_mask)
826 const Key &key = keys_[old_slot.index()];
830 Slot &slot = new_slots[slot_index];
831 if (slot.is_empty()) {
832 slot.occupy(old_slot.index(),
hash);
839 void noexcept_reset() noexcept
841 Allocator allocator = slots_.allocator();
843 new (
this)
VectorSet(NoExceptConstructor(), allocator);
846 template<
typename ForwardKey>
847 bool contains__impl(
const ForwardKey &key,
const uint64_t hash)
const
850 if (slot.is_empty()) {
853 if (slot.contains(key, is_equal_,
hash, keys_)) {
860 template<
typename ForwardKey>
void add_new__impl(ForwardKey &&key,
const uint64_t hash)
864 this->ensure_can_add();
867 if (slot.is_empty()) {
869 Key *dst = keys_ + index;
870 new (dst)
Key(std::forward<ForwardKey>(key));
872 slot.occupy(index,
hash);
873 occupied_and_removed_slots_++;
880 template<
typename ForwardKey>
bool add__impl(ForwardKey &&key,
const uint64_t hash)
882 this->ensure_can_add();
885 if (slot.is_empty()) {
887 Key *dst = keys_ + index;
888 new (dst)
Key(std::forward<ForwardKey>(key));
890 slot.occupy(index,
hash);
891 occupied_and_removed_slots_++;
894 if (slot.contains(key, is_equal_,
hash, keys_)) {
901 template<
typename ForwardKey>
bool add_overwrite__impl(ForwardKey &&key,
const uint64_t hash)
903 this->ensure_can_add();
906 if (slot.is_empty()) {
908 Key *dst = keys_ + index;
909 new (dst)
Key(std::forward<ForwardKey>(key));
911 slot.occupy(index,
hash);
912 occupied_and_removed_slots_++;
915 if (slot.contains(key, is_equal_,
hash, keys_)) {
916 const int64_t index = slot.index();
917 Key &stored_key = keys_[index];
918 stored_key = std::forward<ForwardKey>(key);
926 template<
typename ForwardKey>
932 if (slot.contains(key, is_equal_,
hash, keys_)) {
939 template<
typename ForwardKey>
943 if (slot.contains(key, is_equal_,
hash, keys_)) {
946 if (slot.is_empty()) {
953 template<
typename ForwardKey>
956 this->ensure_can_add();
959 if (slot.contains(key, is_equal_,
hash, keys_)) {
962 if (slot.is_empty()) {
964 Key *dst = keys_ + index;
965 new (dst)
Key(std::forward<ForwardKey>(key));
967 slot.occupy(index,
hash);
968 occupied_and_removed_slots_++;
980 Key key = std::move(keys_[index_to_pop]);
981 keys_[index_to_pop].~Key();
987 if (slot.has_index(index_to_pop)) {
995 template<
typename ForwardKey>
bool remove__impl(
const ForwardKey &key,
const uint64_t hash)
998 if (slot.contains(key, is_equal_,
hash, keys_)) {
999 this->remove_key_internal(slot);
1002 if (slot.is_empty()) {
1009 template<
typename ForwardKey>
1010 void remove_contained__impl(
const ForwardKey &key,
const uint64_t hash)
1015 if (slot.contains(key, is_equal_,
hash, keys_)) {
1016 this->remove_key_internal(slot);
1023 void remove_key_internal(Slot &slot)
1025 int64_t index_to_remove = slot.index();
1029 if (index_to_remove < last_element_index) {
1030 keys_[index_to_remove] = std::move(keys_[last_element_index]);
1031 this->update_slot_index(keys_[index_to_remove], last_element_index, index_to_remove);
1034 keys_[last_element_index].~Key();
1039 void update_slot_index(
const Key &key,
const int64_t old_index,
const int64_t new_index)
1043 if (slot.has_index(old_index)) {
1044 slot.update_index(new_index);
1051 template<
typename ForwardKey>
1057 if (slot.contains(key, is_equal_,
hash, keys_)) {
1060 if (slot.is_empty()) {
1068 void ensure_can_add()
1070 if (occupied_and_removed_slots_ >= usable_slots_) {
1071 this->realloc_and_reinsert(this->
size() + 1);
1072 BLI_assert(occupied_and_removed_slots_ < usable_slots_);
1078 return static_cast<Key *
>(
1079 slots_.allocator().allocate(
sizeof(
Key) *
size_t(
size),
alignof(
Key),
AT));
1082 void deallocate_keys_array(
Key *keys)
1084 slots_.allocator().deallocate(keys);