Blender V4.5
BLI_vector_set.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
46
47#include "BLI_array.hh"
48#include "BLI_hash.hh"
49#include "BLI_hash_tables.hh"
51#include "BLI_vector.hh"
53
54namespace blender {
55
56template<
61 typename Key,
65 int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key)),
69 typename ProbingStrategy = DefaultProbingStrategy,
74 typename Hash = DefaultHash<Key>,
79 typename IsEqual = DefaultEquality<Key>,
86 typename Slot = typename DefaultVectorSetSlot<Key>::type,
91 typename Allocator = GuardedAllocator>
92class VectorSet {
93 public:
94 using value_type = Key;
95 using pointer = Key *;
96 using const_pointer = const Key *;
97 using reference = Key &;
98 using const_reference = const Key &;
99 using iterator = Key *;
100 using const_iterator = const Key *;
102
103 private:
108 int64_t removed_slots_;
109 int64_t occupied_and_removed_slots_;
110
115 int64_t usable_slots_;
116
121 uint64_t slot_mask_;
122
124 BLI_NO_UNIQUE_ADDRESS Hash hash_;
125
127 BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
128
130#define LOAD_FACTOR 1, 2
131 static constexpr LoadFactor max_load_factor_ = LoadFactor(LOAD_FACTOR);
132 using SlotArray = Array<Slot, LoadFactor::compute_total_slots(4, LOAD_FACTOR), Allocator>;
133#undef LOAD_FACTOR
134
139 SlotArray slots_;
140
142 BLI_NO_UNIQUE_ADDRESS TypedBuffer<Key, InlineBufferCapacity> inline_buffer_;
143
149 Key *keys_;
150
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()
156
161 template<typename Other,
162 int64_t OtherInlineBufferCapacity,
163 typename OtherProbingStrategy,
164 typename OtherHash,
165 typename OtherIsEqual,
166 typename OtherSlot,
167 typename OtherAllocator>
168 friend class VectorSet;
169
170 public:
176 VectorSet(Allocator allocator = {}) noexcept
177 : removed_slots_(0),
178 occupied_and_removed_slots_(0),
179 usable_slots_(0),
180 slot_mask_(0),
181 slots_(1, allocator)
182 {
183 keys_ = inline_buffer_;
184 }
185
186 VectorSet(NoExceptConstructor, Allocator allocator = {}) : VectorSet(allocator) {}
187
188 VectorSet(Span<Key> keys, Allocator allocator = {}) : VectorSet(NoExceptConstructor(), allocator)
189 {
190 this->add_multiple(keys);
191 }
192
196 VectorSet(const std::initializer_list<Key> &keys, Allocator allocator = {})
197 : VectorSet(Span(keys), allocator)
198 {
199 }
200
202 {
203 destruct_n(keys_, this->size());
204 if (keys_ != inline_buffer_) {
205 this->deallocate_keys_array(keys_);
206 }
207 }
208
209 VectorSet(const VectorSet &other) : slots_(other.slots_)
210 {
211 if (other.size() <= InlineBufferCapacity) {
212 usable_slots_ = other.size();
213 keys_ = inline_buffer_;
214 }
215 else {
216 keys_ = this->allocate_keys_array(other.usable_slots_);
217 usable_slots_ = other.usable_slots_;
218 }
219 try {
220 uninitialized_copy_n(other.keys_, other.size(), keys_);
221 }
222 catch (...) {
223 if (keys_ != inline_buffer_) {
224 this->deallocate_keys_array(keys_);
225 }
226 throw;
227 }
228
229 removed_slots_ = other.removed_slots_;
230 occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
231 slot_mask_ = other.slot_mask_;
232 hash_ = other.hash_;
233 is_equal_ = other.is_equal_;
234 }
235
236 template<int64_t OtherInlineBufferCapacity>
239 &&other) noexcept
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_))
244 {
245 if (other.is_inline()) {
246 const int64_t size = other.size();
247 usable_slots_ = size;
248
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)
253 {
254 /* Optimize by copying the full inline buffer. Similar to #Vector move constructor. */
255 keys_ = inline_buffer_;
256 if (size > 0) {
257 memcpy(inline_buffer_, other.inline_buffer_, sizeof(inline_buffer_));
258 }
259 }
260 else {
261 if (OtherInlineBufferCapacity <= InlineBufferCapacity || size <= InlineBufferCapacity) {
262 keys_ = inline_buffer_;
263 }
264 else {
265 keys_ = this->allocate_keys_array(size);
266 }
267 uninitialized_relocate_n(other.keys_, size, keys_);
268 }
269 }
270 else {
271 keys_ = other.keys_;
272 usable_slots_ = other.usable_slots_;
273 }
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_;
280 }
281
283 {
284 return copy_assign_container(*this, other);
285 }
286
288 {
289 return move_assign_container(*this, std::move(other));
290 }
291
295 const Key &operator[](const int64_t index) const
296 {
297 BLI_assert(index >= 0);
298 BLI_assert(index <= this->size());
299 return keys_[index];
300 }
301
302 operator Span<Key>() const
303 {
304 return Span<Key>(keys_, this->size());
305 }
306
314 {
315 return *this;
316 }
317
323 void add_new(const Key &key)
324 {
325 this->add_new__impl(key, hash_(key));
326 }
327 void add_new(Key &&key)
328 {
329 this->add_new__impl(std::move(key), hash_(key));
330 }
331
338 bool add(const Key &key)
339 {
340 return this->add_as(key);
341 }
342 bool add(Key &&key)
343 {
344 return this->add_as(std::move(key));
345 }
346 template<typename ForwardKey> bool add_as(ForwardKey &&key)
347 {
348 return this->add__impl(std::forward<ForwardKey>(key), hash_(key));
349 }
350
361 bool add_overwrite(const Key &key)
362 {
363 return this->add_overwrite_as(key);
364 }
365 bool add_overwrite(Key &&key)
366 {
367 return this->add_overwrite_as(std::move(key));
368 }
369 template<typename ForwardKey> bool add_overwrite_as(ForwardKey &&key)
370 {
371 return this->add_overwrite__impl(std::forward<ForwardKey>(key), hash_(key));
372 }
373
382 {
383 for (const Key &key : keys) {
384 this->add(key);
385 }
386 }
387
393 bool contains(const Key &key) const
394 {
395 return this->contains_as(key);
396 }
397 template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
398 {
399 return this->contains__impl(key, hash_(key));
400 }
401
408 bool remove(const Key &key)
409 {
410 return this->remove_as(key);
411 }
412 template<typename ForwardKey> bool remove_as(const ForwardKey &key)
413 {
414 return this->remove__impl(key, hash_(key));
415 }
416
421 void remove_contained(const Key &key)
422 {
423 this->remove_contained_as(key);
424 }
425 template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
426 {
427 this->remove_contained__impl(key, hash_(key));
428 }
429
436 template<typename Predicate> int64_t remove_if(Predicate &&predicate)
437 {
438 const int64_t prev_size = this->size();
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);
445 }
446 }
447 }
448 return prev_size - this->size();
449 }
450
456 {
457 return this->pop__impl();
458 }
459
464 int64_t index_of(const Key &key) const
465 {
466 return this->index_of_as(key);
467 }
468 template<typename ForwardKey> int64_t index_of_as(const ForwardKey &key) const
469 {
470 return this->index_of__impl(key, hash_(key));
471 }
472
477 int64_t index_of_try(const Key &key) const
478 {
479 return this->index_of_try_as(key);
480 }
481 template<typename ForwardKey> int64_t index_of_try_as(const ForwardKey &key) const
482 {
483 return this->index_of_try__impl(key, hash_(key));
484 }
485
491 {
492 return this->index_of_or_add_as(key);
493 }
495 {
496 return this->index_of_or_add_as(std::move(key));
497 }
498 template<typename ForwardKey> int64_t index_of_or_add_as(ForwardKey &&key)
499 {
500 return this->index_of_or_add__impl(std::forward<ForwardKey>(key), hash_(key));
501 }
502
507 const Key &lookup_key(const Key &key) const
508 {
509 return this->lookup_key_as(key);
510 }
511 template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
512 {
513 const Key *key_ptr = this->lookup_key_ptr_as(key);
514 BLI_assert(key_ptr != nullptr);
515 return *key_ptr;
516 }
517
522 Key lookup_key_default(const Key &key, const Key &default_value) const
523 {
524 return this->lookup_key_default_as(key, default_value);
525 }
526 template<typename ForwardKey, typename... ForwardDefault>
527 Key lookup_key_default_as(const ForwardKey &key, ForwardDefault &&...default_key) const
528 {
529 const Key *ptr = this->lookup_key_ptr_as(key);
530 if (ptr == nullptr) {
531 return Key(std::forward<ForwardDefault>(default_key)...);
532 }
533 return *ptr;
534 }
535
540 const Key *lookup_key_ptr(const Key &key) const
541 {
542 return this->lookup_key_ptr_as(key);
543 }
544 template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
545 {
546 const int64_t index = this->index_of_try__impl(key, hash_(key));
547 if (index >= 0) {
548 return keys_ + index;
549 }
550 return nullptr;
551 }
552
556 const Key *data() const
557 {
558 return keys_;
559 }
560
561 const Key *begin() const
562 {
563 return keys_;
564 }
565
566 const Key *end() const
567 {
568 return keys_ + this->size();
569 }
570
575 {
576 return IndexRange(this->size());
577 }
578
582 void print_stats(const char *name) const
583 {
584 HashTableStats stats(*this, this->as_span());
585 stats.print(name);
586 }
587
588 bool is_inline() const
589 {
590 return keys_ == inline_buffer_;
591 }
592
596 int64_t size() const
597 {
598 return occupied_and_removed_slots_ - removed_slots_;
599 }
600
604 bool is_empty() const
605 {
606 return occupied_and_removed_slots_ == removed_slots_;
607 }
608
613 {
614 return slots_.size();
615 }
616
621 {
622 return removed_slots_;
623 }
624
629 {
630 return sizeof(Slot) + sizeof(Key);
631 }
632
638 {
639 return int64_t(sizeof(Slot) * slots_.size() + sizeof(Key) * usable_slots_);
640 }
641
645 void reserve(const int64_t n)
646 {
647 if (usable_slots_ < n) {
648 this->realloc_and_reinsert(n);
649 }
650 }
651
655 void clear()
656 {
657 std::destroy_at(this);
658 new (this) VectorSet(NoExceptConstructor{});
659 }
660
669 {
670 destruct_n(keys_, this->size());
671 for (Slot &slot : slots_) {
672 slot.~Slot();
673 new (&slot) Slot();
674 }
675
676 removed_slots_ = 0;
677 occupied_and_removed_slots_ = 0;
678 }
679
684 int64_t count_collisions(const Key &key) const
685 {
686 return this->count_collisions__impl(key, hash_(key));
687 }
688
689 using VectorT = Vector<Key, default_inline_buffer_capacity(sizeof(Key)), Allocator>;
690
701 {
702 const int64_t size = this->size();
704 if (this->is_inline()) {
705 data.data = this->allocate_keys_array(size);
706 data.size = size;
707 data.capacity = size;
708 try {
709 uninitialized_relocate_n(keys_, size, data.data);
710 }
711 catch (...) {
712 this->deallocate_keys_array(data.data);
713 throw;
714 }
715 }
716 else {
717 data.data = keys_;
718 data.size = size;
719 data.capacity = usable_slots_;
720 }
721
722 /* Reset some values so that the destructor does not free the data that is moved to the
723 * #Vector. */
724 keys_ = inline_buffer_;
725 occupied_and_removed_slots_ = 0;
726 removed_slots_ = 0;
727 std::destroy_at(this);
728 new (this) VectorSet();
729
730 return VectorT(data);
731 }
732
733 private:
734 BLI_NOINLINE void realloc_and_reinsert(const int64_t min_usable_slots)
735 {
736 int64_t total_slots, usable_slots;
737 max_load_factor_.compute_total_and_usable_slots(
738 SlotArray::inline_buffer_capacity(), min_usable_slots, &total_slots, &usable_slots);
739 BLI_assert(total_slots >= 1);
740 const uint64_t new_slot_mask = uint64_t(total_slots) - 1;
741
742 /* Optimize the case when the set was empty beforehand. We can avoid some copies here. */
743 if (this->size() == 0) {
744 try {
745 slots_.reinitialize(total_slots);
746
747 Key *new_keys;
748 if (usable_slots <= InlineBufferCapacity) {
749 new_keys = inline_buffer_;
750 }
751 else {
752 new_keys = this->allocate_keys_array(usable_slots);
753 }
754
755 if (keys_ != inline_buffer_) {
756 this->deallocate_keys_array(keys_);
757 }
758
759 keys_ = new_keys;
760 }
761 catch (...) {
762 this->noexcept_reset();
763 throw;
764 }
765 removed_slots_ = 0;
766 occupied_and_removed_slots_ = 0;
767 usable_slots_ = usable_slots;
768 slot_mask_ = new_slot_mask;
769 return;
770 }
771
772 SlotArray new_slots(total_slots);
773
774 try {
775 for (Slot &slot : slots_) {
776 if (slot.is_occupied()) {
777 this->add_after_grow(slot, new_slots, new_slot_mask);
778 slot.remove();
779 }
780 }
781 slots_ = std::move(new_slots);
782 }
783 catch (...) {
784 this->noexcept_reset();
785 throw;
786 }
787
788 /* Allocate the new keys array, or use the inline buffer if possible. */
789 Key *new_keys;
790 if (usable_slots <= InlineBufferCapacity) {
791 new_keys = inline_buffer_;
792 }
793 else {
794 new_keys = this->allocate_keys_array(usable_slots);
795 }
796
797 /* Copy the keys to the new array. When the inline buffer isn't used before and after the
798 * reallocation (`new_keys` also references the inline buffer), no copying is necessary. */
799 if (new_keys != keys_) {
800 try {
801 uninitialized_relocate_n(keys_, this->size(), new_keys);
802 }
803 catch (...) {
804 if (new_keys != inline_buffer_) {
805 this->deallocate_keys_array(new_keys);
806 }
807 this->noexcept_reset();
808 throw;
809 }
810 }
811
812 /* Free the old keys array. */
813 if (keys_ != inline_buffer_) {
814 this->deallocate_keys_array(keys_);
815 }
816
817 keys_ = new_keys;
818 occupied_and_removed_slots_ -= removed_slots_;
819 usable_slots_ = usable_slots;
820 removed_slots_ = 0;
821 slot_mask_ = new_slot_mask;
822 }
823
824 void add_after_grow(Slot &old_slot, SlotArray &new_slots, const uint64_t new_slot_mask)
825 {
826 const Key &key = keys_[old_slot.index()];
827 const uint64_t hash = old_slot.get_hash(key, Hash());
828
829 SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
830 Slot &slot = new_slots[slot_index];
831 if (slot.is_empty()) {
832 slot.occupy(old_slot.index(), hash);
833 return;
834 }
835 }
837 }
838
839 void noexcept_reset() noexcept
840 {
841 Allocator allocator = slots_.allocator();
842 this->~VectorSet();
843 new (this) VectorSet(NoExceptConstructor(), allocator);
844 }
845
846 template<typename ForwardKey>
847 bool contains__impl(const ForwardKey &key, const uint64_t hash) const
848 {
850 if (slot.is_empty()) {
851 return false;
852 }
853 if (slot.contains(key, is_equal_, hash, keys_)) {
854 return true;
855 }
856 }
858 }
859
860 template<typename ForwardKey> void add_new__impl(ForwardKey &&key, const uint64_t hash)
861 {
862 BLI_assert(!this->contains_as(key));
863
864 this->ensure_can_add();
865
867 if (slot.is_empty()) {
868 int64_t index = this->size();
869 Key *dst = keys_ + index;
870 new (dst) Key(std::forward<ForwardKey>(key));
871 BLI_assert(hash_(*dst) == hash);
872 slot.occupy(index, hash);
873 occupied_and_removed_slots_++;
874 return;
875 }
876 }
878 }
879
880 template<typename ForwardKey> bool add__impl(ForwardKey &&key, const uint64_t hash)
881 {
882 this->ensure_can_add();
883
885 if (slot.is_empty()) {
886 const int64_t index = this->size();
887 Key *dst = keys_ + index;
888 new (dst) Key(std::forward<ForwardKey>(key));
889 BLI_assert(hash_(*dst) == hash);
890 slot.occupy(index, hash);
891 occupied_and_removed_slots_++;
892 return true;
893 }
894 if (slot.contains(key, is_equal_, hash, keys_)) {
895 return false;
896 }
897 }
899 }
900
901 template<typename ForwardKey> bool add_overwrite__impl(ForwardKey &&key, const uint64_t hash)
902 {
903 this->ensure_can_add();
904
906 if (slot.is_empty()) {
907 const int64_t index = this->size();
908 Key *dst = keys_ + index;
909 new (dst) Key(std::forward<ForwardKey>(key));
910 BLI_assert(hash_(*dst) == hash);
911 slot.occupy(index, hash);
912 occupied_and_removed_slots_++;
913 return true;
914 }
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);
919 BLI_assert(hash_(stored_key) == hash);
920 return false;
921 }
922 }
924 }
925
926 template<typename ForwardKey>
927 int64_t index_of__impl(const ForwardKey &key, const uint64_t hash) const
928 {
929 BLI_assert(this->contains_as(key));
930
932 if (slot.contains(key, is_equal_, hash, keys_)) {
933 return slot.index();
934 }
935 }
937 }
938
939 template<typename ForwardKey>
940 int64_t index_of_try__impl(const ForwardKey &key, const uint64_t hash) const
941 {
943 if (slot.contains(key, is_equal_, hash, keys_)) {
944 return slot.index();
945 }
946 if (slot.is_empty()) {
947 return -1;
948 }
949 }
951 }
952
953 template<typename ForwardKey>
954 int64_t index_of_or_add__impl(ForwardKey &&key, const uint64_t hash)
955 {
956 this->ensure_can_add();
957
959 if (slot.contains(key, is_equal_, hash, keys_)) {
960 return slot.index();
961 }
962 if (slot.is_empty()) {
963 const int64_t index = this->size();
964 Key *dst = keys_ + index;
965 new (dst) Key(std::forward<ForwardKey>(key));
966 BLI_assert(hash_(*dst) == hash);
967 slot.occupy(index, hash);
968 occupied_and_removed_slots_++;
969 return index;
970 }
971 }
973 }
974
975 Key pop__impl()
976 {
977 BLI_assert(this->size() > 0);
978
979 const int64_t index_to_pop = this->size() - 1;
980 Key key = std::move(keys_[index_to_pop]);
981 keys_[index_to_pop].~Key();
982 const uint64_t hash = hash_(key);
983
984 removed_slots_++;
985
987 if (slot.has_index(index_to_pop)) {
988 slot.remove();
989 return key;
990 }
991 }
993 }
994
995 template<typename ForwardKey> bool remove__impl(const ForwardKey &key, const uint64_t hash)
996 {
998 if (slot.contains(key, is_equal_, hash, keys_)) {
999 this->remove_key_internal(slot);
1000 return true;
1001 }
1002 if (slot.is_empty()) {
1003 return false;
1004 }
1005 }
1007 }
1008
1009 template<typename ForwardKey>
1010 void remove_contained__impl(const ForwardKey &key, const uint64_t hash)
1011 {
1012 BLI_assert(this->contains_as(key));
1013
1015 if (slot.contains(key, is_equal_, hash, keys_)) {
1016 this->remove_key_internal(slot);
1017 return;
1018 }
1019 }
1021 }
1022
1023 void remove_key_internal(Slot &slot)
1024 {
1025 int64_t index_to_remove = slot.index();
1026 int64_t size = this->size();
1027 int64_t last_element_index = size - 1;
1028
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);
1032 }
1033
1034 keys_[last_element_index].~Key();
1035 slot.remove();
1036 removed_slots_++;
1037 }
1038
1039 void update_slot_index(const Key &key, const int64_t old_index, const int64_t new_index)
1040 {
1041 uint64_t hash = hash_(key);
1043 if (slot.has_index(old_index)) {
1044 slot.update_index(new_index);
1045 return;
1046 }
1047 }
1049 }
1050
1051 template<typename ForwardKey>
1052 int64_t count_collisions__impl(const ForwardKey &key, const uint64_t hash) const
1053 {
1054 int64_t collisions = 0;
1055
1057 if (slot.contains(key, is_equal_, hash, keys_)) {
1058 return collisions;
1059 }
1060 if (slot.is_empty()) {
1061 return collisions;
1062 }
1063 collisions++;
1064 }
1066 }
1067
1068 void ensure_can_add()
1069 {
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_);
1073 }
1074 }
1075
1076 Key *allocate_keys_array(const int64_t size)
1077 {
1078 return static_cast<Key *>(
1079 slots_.allocator().allocate(sizeof(Key) * size_t(size), alignof(Key), AT));
1080 }
1081
1082 void deallocate_keys_array(Key *keys)
1083 {
1084 slots_.allocator().deallocate(keys);
1085 }
1086};
1087
1092template<typename Key,
1093 int64_t InlineBufferCapacity = 4,
1094 typename ProbingStrategy = DefaultProbingStrategy,
1095 typename Hash = DefaultHash<Key>,
1096 typename IsEqual = DefaultEquality<Key>,
1097 typename Slot = typename DefaultVectorSetSlot<Key>::type>
1100
1101template<typename T, typename GetIDFn> struct CustomIDHash {
1102 using CustomIDType = decltype(GetIDFn{}(std::declval<T>()));
1103
1104 uint64_t operator()(const T &value) const
1105 {
1106 return get_default_hash(GetIDFn{}(value));
1107 }
1109 {
1110 return get_default_hash(value);
1111 }
1112};
1113
1114template<typename T, typename GetIDFn> struct CustomIDEqual {
1115 using CustomIDType = decltype(GetIDFn{}(std::declval<T>()));
1116
1117 bool operator()(const T &a, const T &b) const
1118 {
1119 return GetIDFn{}(a) == GetIDFn{}(b);
1120 }
1121 bool operator()(const CustomIDType &a, const T &b) const
1122 {
1123 return a == GetIDFn{}(b);
1124 }
1125 bool operator()(const T &a, const CustomIDType &b) const
1126 {
1127 return GetIDFn{}(a) == b;
1128 }
1129};
1130
1138template<typename T, typename GetIDFn, int64_t InlineBufferCapacity = 4>
1140 InlineBufferCapacity,
1144
1145} // namespace blender
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
#define LOAD_FACTOR
Definition BLI_map.hh:162
#define SLOT_PROBING_BEGIN(PROBING_STRATEGY, HASH, MASK, R_SLOT_INDEX)
#define SLOT_PROBING_END()
#define AT
#define BLI_NO_UNIQUE_ADDRESS
#define VECTOR_SET_SLOT_PROBING_BEGIN(HASH, R_SLOT)
#define VECTOR_SET_SLOT_PROBING_END()
struct Key Key
long long int int64_t
unsigned long long int uint64_t
void print(const char *name) const
static constexpr int64_t compute_total_slots(int64_t min_usable_slots, uint8_t numerator, uint8_t denominator)
VectorSet(Span< Key > keys, Allocator allocator={})
VectorSet & operator=(const VectorSet &other)
int64_t index_of_try(const Key &key) const
int64_t index_of_try_as(const ForwardKey &key) const
const Key & lookup_key_as(const ForwardKey &key) const
int64_t removed_amount() const
bool contains_as(const ForwardKey &key) const
const Key * data() const
VectorSet & operator=(VectorSet &&other)
int64_t index_of_or_add_as(ForwardKey &&key)
bool add_overwrite_as(ForwardKey &&key)
bool remove(const Key &key)
bool add_overwrite(Key &&key)
bool add(const Key &key)
int64_t index_of_as(const ForwardKey &key) const
void add_new(Key &&key)
void remove_contained_as(const ForwardKey &key)
const Key * lookup_key_ptr(const Key &key) const
VectorSet(Allocator allocator={}) noexcept
VectorSet(VectorSet< Key, OtherInlineBufferCapacity, ProbingStrategy, Hash, IsEqual, Slot, Allocator > &&other) noexcept
bool remove_as(const ForwardKey &key)
int64_t index_of_or_add(const Key &key)
const Key & lookup_key(const Key &key) const
int64_t capacity() const
const Key * lookup_key_ptr_as(const ForwardKey &key) const
void print_stats(const char *name) const
int64_t count_collisions(const Key &key) const
VectorSet(const std::initializer_list< Key > &keys, Allocator allocator={})
Key lookup_key_default(const Key &key, const Key &default_value) const
bool add_as(ForwardKey &&key)
void reserve(const int64_t n)
int64_t index_of_or_add(Key &&key)
int64_t size_in_bytes() const
const Key * begin() const
void add_multiple(Span< Key > keys)
int64_t size() const
bool add_overwrite(const Key &key)
const Key & operator[](const int64_t index) const
int64_t index_of(const Key &key) const
Key lookup_key_default_as(const ForwardKey &key, ForwardDefault &&...default_key) const
const Key * end() const
VectorSet(NoExceptConstructor, Allocator allocator={})
int64_t size_per_element() const
IndexRange index_range() const
VectorSet(const VectorSet &other)
bool contains(const Key &key) const
int64_t remove_if(Predicate &&predicate)
bool add(Key &&key)
Span< Key > as_span() const
void add_new(const Key &key)
void remove_contained(const Key &key)
#define T
VectorSet< T, InlineBufferCapacity, DefaultProbingStrategy, CustomIDHash< T, GetIDFn >, CustomIDEqual< T, GetIDFn > > CustomIDVectorSet
VectorSet< Key, InlineBufferCapacity, ProbingStrategy, Hash, IsEqual, Slot, RawAllocator > RawVectorSet
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
Container & copy_assign_container(Container &dst, const Container &src)
Container & move_assign_container(Container &dst, Container &&src) noexcept(std::is_nothrow_move_constructible_v< Container >)
constexpr int64_t default_inline_buffer_capacity(size_t element_size)
PythonProbingStrategy<> DefaultProbingStrategy
void uninitialized_relocate_n(T *src, int64_t n, T *dst)
void destruct_n(T *ptr, int64_t n)
#define hash
Definition noise_c.cc:154
decltype(GetIDFn{}(std::declval< T >())) CustomIDType
bool operator()(const T &a, const CustomIDType &b) const
bool operator()(const T &a, const T &b) const
bool operator()(const CustomIDType &a, const T &b) const
uint64_t operator()(const T &value) const
decltype(GetIDFn{}(std::declval< T >())) CustomIDType
uint64_t operator()(const CustomIDType &value) const
SimpleVectorSetSlot< Key > type
PointerRNA * ptr
Definition wm_files.cc:4226