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_;
188 hash_ = std::move(
hash);
189 is_equal_ = std::move(is_equal);
202 VectorSet(
const std::initializer_list<Key> &keys, Allocator allocator = {})
210 if (keys_ != inline_buffer_) {
211 this->deallocate_keys_array(keys_);
217 if (other.
size() <= InlineBufferCapacity) {
218 usable_slots_ = other.size();
219 keys_ = inline_buffer_;
222 keys_ = this->allocate_keys_array(other.usable_slots_);
223 usable_slots_ = other.usable_slots_;
226 uninitialized_copy_n(other.keys_, other.size(), keys_);
229 if (keys_ != inline_buffer_) {
230 this->deallocate_keys_array(keys_);
235 removed_slots_ = other.removed_slots_;
236 occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
237 slot_mask_ = other.slot_mask_;
239 is_equal_ = other.is_equal_;
242 template<
int64_t OtherInlineBufferCapacity>
246 : removed_slots_(other.removed_slots_),
247 occupied_and_removed_slots_(other.occupied_and_removed_slots_),
248 slot_mask_(other.slot_mask_),
249 slots_(std::move(other.slots_))
251 if (other.is_inline()) {
253 usable_slots_ =
size;
255 constexpr bool other_is_same_type = std::is_same_v<
VectorSet, std::decay_t<
decltype(other)>>;
256 constexpr size_t max_full_copy_size = 32;
257 if constexpr (other_is_same_type && std::is_trivial_v<Key> &&
258 sizeof(inline_buffer_) <= max_full_copy_size)
261 keys_ = inline_buffer_;
263 memcpy(inline_buffer_, other.inline_buffer_,
sizeof(inline_buffer_));
267 if (OtherInlineBufferCapacity <= InlineBufferCapacity ||
size <= InlineBufferCapacity) {
268 keys_ = inline_buffer_;
271 keys_ = this->allocate_keys_array(
size);
278 usable_slots_ = other.usable_slots_;
280 other.removed_slots_ = 0;
281 other.occupied_and_removed_slots_ = 0;
282 other.usable_slots_ = 0;
283 other.slot_mask_ = 0;
284 other.slots_ = SlotArray(1);
285 other.keys_ = other.inline_buffer_;
331 this->add_new__impl(key, hash_(key));
335 this->add_new__impl(std::move(key), hash_(key));
350 return this->
add_as(std::move(key));
352 template<
typename ForwardKey>
bool add_as(ForwardKey &&key)
354 return this->add__impl(std::forward<ForwardKey>(key), hash_(key));
377 return this->add_overwrite__impl(std::forward<ForwardKey>(key), hash_(key));
389 for (
const Key &key : keys) {
403 template<
typename ForwardKey>
bool contains_as(
const ForwardKey &key)
const
405 return this->contains__impl(key, hash_(key));
418 template<
typename ForwardKey>
bool remove_as(
const ForwardKey &key)
420 return this->remove__impl(key, hash_(key));
433 this->remove_contained__impl(key, hash_(key));
445 for (Slot &slot : slots_) {
446 if (slot.is_occupied()) {
447 const int64_t index = slot.index();
448 const Key &key = keys_[index];
449 if (predicate(key)) {
450 this->remove_key_internal(slot);
454 return prev_size - this->
size();
463 return this->pop__impl();
476 return this->index_of__impl(key, hash_(key));
489 return this->index_of_try__impl(key, hash_(key));
506 return this->index_of_or_add__impl(std::forward<ForwardKey>(key), hash_(key));
532 template<
typename ForwardKey,
typename... ForwardDefault>
536 if (
ptr ==
nullptr) {
537 return Key(std::forward<ForwardDefault>(default_key)...);
552 const int64_t index = this->index_of_try__impl(key, hash_(key));
554 return keys_ + index;
574 return keys_ + this->
size();
596 return keys_ == inline_buffer_;
604 return occupied_and_removed_slots_ - removed_slots_;
612 return occupied_and_removed_slots_ == removed_slots_;
620 return slots_.size();
628 return removed_slots_;
636 return sizeof(Slot) +
sizeof(
Key);
645 return int64_t(
sizeof(Slot) * slots_.size() +
sizeof(
Key) * usable_slots_);
653 if (usable_slots_ < n) {
654 this->realloc_and_reinsert(n);
663 std::destroy_at(
this);
677 for (Slot &slot : slots_) {
683 occupied_and_removed_slots_ = 0;
692 return this->count_collisions__impl(key, hash_(key));
711 data.
data = this->allocate_keys_array(
size);
718 this->deallocate_keys_array(
data.data);
725 data.capacity = usable_slots_;
730 keys_ = inline_buffer_;
731 occupied_and_removed_slots_ = 0;
733 std::destroy_at(
this);
742 int64_t total_slots, usable_slots;
743 max_load_factor_.compute_total_and_usable_slots(
749 if (this->
size() == 0) {
751 slots_.reinitialize(total_slots);
754 if (usable_slots <= InlineBufferCapacity) {
755 new_keys = inline_buffer_;
758 new_keys = this->allocate_keys_array(usable_slots);
761 if (keys_ != inline_buffer_) {
762 this->deallocate_keys_array(keys_);
768 this->noexcept_reset();
772 occupied_and_removed_slots_ = 0;
773 usable_slots_ = usable_slots;
774 slot_mask_ = new_slot_mask;
778 SlotArray new_slots(total_slots);
781 for (Slot &slot : slots_) {
782 if (slot.is_occupied()) {
783 this->add_after_grow(slot, new_slots, new_slot_mask);
787 slots_ = std::move(new_slots);
790 this->noexcept_reset();
796 if (usable_slots <= InlineBufferCapacity) {
797 new_keys = inline_buffer_;
800 new_keys = this->allocate_keys_array(usable_slots);
805 if (new_keys != keys_) {
810 if (new_keys != inline_buffer_) {
811 this->deallocate_keys_array(new_keys);
813 this->noexcept_reset();
819 if (keys_ != inline_buffer_) {
820 this->deallocate_keys_array(keys_);
824 occupied_and_removed_slots_ -= removed_slots_;
825 usable_slots_ = usable_slots;
827 slot_mask_ = new_slot_mask;
830 void add_after_grow(Slot &old_slot, SlotArray &new_slots,
const uint64_t new_slot_mask)
832 const Key &key = keys_[old_slot.index()];
836 Slot &slot = new_slots[slot_index];
837 if (slot.is_empty()) {
838 slot.occupy(old_slot.index(),
hash);
845 void noexcept_reset() noexcept
847 Allocator allocator = slots_.allocator();
849 new (
this)
VectorSet(NoExceptConstructor(), allocator);
852 template<
typename ForwardKey>
853 bool contains__impl(
const ForwardKey &key,
const uint64_t hash)
const
856 if (slot.is_empty()) {
859 if (slot.contains(key, is_equal_,
hash, keys_)) {
866 template<
typename ForwardKey>
void add_new__impl(ForwardKey &&key,
const uint64_t hash)
870 this->ensure_can_add();
873 if (slot.is_empty()) {
875 Key *dst = keys_ + index;
876 new (dst)
Key(std::forward<ForwardKey>(key));
878 slot.occupy(index,
hash);
879 occupied_and_removed_slots_++;
886 template<
typename ForwardKey>
bool add__impl(ForwardKey &&key,
const uint64_t hash)
888 this->ensure_can_add();
891 if (slot.is_empty()) {
893 Key *dst = keys_ + index;
894 new (dst)
Key(std::forward<ForwardKey>(key));
896 slot.occupy(index,
hash);
897 occupied_and_removed_slots_++;
900 if (slot.contains(key, is_equal_,
hash, keys_)) {
907 template<
typename ForwardKey>
bool add_overwrite__impl(ForwardKey &&key,
const uint64_t hash)
909 this->ensure_can_add();
912 if (slot.is_empty()) {
914 Key *dst = keys_ + index;
915 new (dst)
Key(std::forward<ForwardKey>(key));
917 slot.occupy(index,
hash);
918 occupied_and_removed_slots_++;
921 if (slot.contains(key, is_equal_,
hash, keys_)) {
922 const int64_t index = slot.index();
923 Key &stored_key = keys_[index];
924 stored_key = std::forward<ForwardKey>(key);
932 template<
typename ForwardKey>
938 if (slot.contains(key, is_equal_,
hash, keys_)) {
945 template<
typename ForwardKey>
949 if (slot.contains(key, is_equal_,
hash, keys_)) {
952 if (slot.is_empty()) {
959 template<
typename ForwardKey>
962 this->ensure_can_add();
965 if (slot.contains(key, is_equal_,
hash, keys_)) {
968 if (slot.is_empty()) {
970 Key *dst = keys_ + index;
971 new (dst)
Key(std::forward<ForwardKey>(key));
973 slot.occupy(index,
hash);
974 occupied_and_removed_slots_++;
986 Key key = std::move(keys_[index_to_pop]);
987 keys_[index_to_pop].~Key();
993 if (slot.has_index(index_to_pop)) {
1001 template<
typename ForwardKey>
bool remove__impl(
const ForwardKey &key,
const uint64_t hash)
1004 if (slot.contains(key, is_equal_,
hash, keys_)) {
1005 this->remove_key_internal(slot);
1008 if (slot.is_empty()) {
1015 template<
typename ForwardKey>
1016 void remove_contained__impl(
const ForwardKey &key,
const uint64_t hash)
1021 if (slot.contains(key, is_equal_,
hash, keys_)) {
1022 this->remove_key_internal(slot);
1029 void remove_key_internal(Slot &slot)
1031 int64_t index_to_remove = slot.index();
1035 if (index_to_remove < last_element_index) {
1036 keys_[index_to_remove] = std::move(keys_[last_element_index]);
1037 this->update_slot_index(keys_[index_to_remove], last_element_index, index_to_remove);
1040 keys_[last_element_index].~Key();
1045 void update_slot_index(
const Key &key,
const int64_t old_index,
const int64_t new_index)
1049 if (slot.has_index(old_index)) {
1050 slot.update_index(new_index);
1057 template<
typename ForwardKey>
1063 if (slot.contains(key, is_equal_,
hash, keys_)) {
1066 if (slot.is_empty()) {
1074 void ensure_can_add()
1076 if (occupied_and_removed_slots_ >= usable_slots_) {
1077 this->realloc_and_reinsert(this->
size() + 1);
1078 BLI_assert(occupied_and_removed_slots_ < usable_slots_);
1084 return static_cast<Key *
>(
1085 slots_.allocator().allocate(
sizeof(
Key) *
size_t(
size),
alignof(
Key),
AT));
1088 void deallocate_keys_array(
Key *keys)
1090 slots_.allocator().deallocate(keys);