Blender V5.0
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(Hash hash, IsEqual is_equal) : VectorSet()
187 {
188 hash_ = std::move(hash);
189 is_equal_ = std::move(is_equal);
190 }
191
192 VectorSet(NoExceptConstructor, Allocator allocator = {}) : VectorSet(allocator) {}
193
194 VectorSet(Span<Key> keys, Allocator allocator = {}) : VectorSet(NoExceptConstructor(), allocator)
195 {
196 this->add_multiple(keys);
197 }
198
202 VectorSet(const std::initializer_list<Key> &keys, Allocator allocator = {})
203 : VectorSet(Span(keys), allocator)
204 {
205 }
206
208 {
209 destruct_n(keys_, this->size());
210 if (keys_ != inline_buffer_) {
211 this->deallocate_keys_array(keys_);
212 }
213 }
214
215 VectorSet(const VectorSet &other) : slots_(other.slots_)
216 {
217 if (other.size() <= InlineBufferCapacity) {
218 usable_slots_ = other.size();
219 keys_ = inline_buffer_;
220 }
221 else {
222 keys_ = this->allocate_keys_array(other.usable_slots_);
223 usable_slots_ = other.usable_slots_;
224 }
225 try {
226 uninitialized_copy_n(other.keys_, other.size(), keys_);
227 }
228 catch (...) {
229 if (keys_ != inline_buffer_) {
230 this->deallocate_keys_array(keys_);
231 }
232 throw;
233 }
234
235 removed_slots_ = other.removed_slots_;
236 occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
237 slot_mask_ = other.slot_mask_;
238 hash_ = other.hash_;
239 is_equal_ = other.is_equal_;
240 }
241
242 template<int64_t OtherInlineBufferCapacity>
245 &&other) noexcept
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_))
250 {
251 if (other.is_inline()) {
252 const int64_t size = other.size();
253 usable_slots_ = size;
254
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)
259 {
260 /* Optimize by copying the full inline buffer. Similar to #Vector move constructor. */
261 keys_ = inline_buffer_;
262 if (size > 0) {
263 memcpy(inline_buffer_, other.inline_buffer_, sizeof(inline_buffer_));
264 }
265 }
266 else {
267 if (OtherInlineBufferCapacity <= InlineBufferCapacity || size <= InlineBufferCapacity) {
268 keys_ = inline_buffer_;
269 }
270 else {
271 keys_ = this->allocate_keys_array(size);
272 }
273 uninitialized_relocate_n(other.keys_, size, keys_);
274 }
275 }
276 else {
277 keys_ = other.keys_;
278 usable_slots_ = other.usable_slots_;
279 }
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_;
286 }
287
289 {
290 return copy_assign_container(*this, other);
291 }
292
294 {
295 return move_assign_container(*this, std::move(other));
296 }
297
301 const Key &operator[](const int64_t index) const
302 {
303 BLI_assert(index >= 0);
304 BLI_assert(index <= this->size());
305 return keys_[index];
306 }
307
308 operator Span<Key>() const
309 {
310 return Span<Key>(keys_, this->size());
311 }
312
320 {
321 return *this;
322 }
323
329 void add_new(const Key &key)
330 {
331 this->add_new__impl(key, hash_(key));
332 }
333 void add_new(Key &&key)
334 {
335 this->add_new__impl(std::move(key), hash_(key));
336 }
337
344 bool add(const Key &key)
345 {
346 return this->add_as(key);
347 }
348 bool add(Key &&key)
349 {
350 return this->add_as(std::move(key));
351 }
352 template<typename ForwardKey> bool add_as(ForwardKey &&key)
353 {
354 return this->add__impl(std::forward<ForwardKey>(key), hash_(key));
355 }
356
367 bool add_overwrite(const Key &key)
368 {
369 return this->add_overwrite_as(key);
370 }
371 bool add_overwrite(Key &&key)
372 {
373 return this->add_overwrite_as(std::move(key));
374 }
375 template<typename ForwardKey> bool add_overwrite_as(ForwardKey &&key)
376 {
377 return this->add_overwrite__impl(std::forward<ForwardKey>(key), hash_(key));
378 }
379
388 {
389 for (const Key &key : keys) {
390 this->add(key);
391 }
392 }
393
399 bool contains(const Key &key) const
400 {
401 return this->contains_as(key);
402 }
403 template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
404 {
405 return this->contains__impl(key, hash_(key));
406 }
407
414 bool remove(const Key &key)
415 {
416 return this->remove_as(key);
417 }
418 template<typename ForwardKey> bool remove_as(const ForwardKey &key)
419 {
420 return this->remove__impl(key, hash_(key));
421 }
422
427 void remove_contained(const Key &key)
428 {
429 this->remove_contained_as(key);
430 }
431 template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
432 {
433 this->remove_contained__impl(key, hash_(key));
434 }
435
442 template<typename Predicate> int64_t remove_if(Predicate &&predicate)
443 {
444 const int64_t prev_size = this->size();
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);
451 }
452 }
453 }
454 return prev_size - this->size();
455 }
456
462 {
463 return this->pop__impl();
464 }
465
470 int64_t index_of(const Key &key) const
471 {
472 return this->index_of_as(key);
473 }
474 template<typename ForwardKey> int64_t index_of_as(const ForwardKey &key) const
475 {
476 return this->index_of__impl(key, hash_(key));
477 }
478
483 int64_t index_of_try(const Key &key) const
484 {
485 return this->index_of_try_as(key);
486 }
487 template<typename ForwardKey> int64_t index_of_try_as(const ForwardKey &key) const
488 {
489 return this->index_of_try__impl(key, hash_(key));
490 }
491
497 {
498 return this->index_of_or_add_as(key);
499 }
501 {
502 return this->index_of_or_add_as(std::move(key));
503 }
504 template<typename ForwardKey> int64_t index_of_or_add_as(ForwardKey &&key)
505 {
506 return this->index_of_or_add__impl(std::forward<ForwardKey>(key), hash_(key));
507 }
508
513 const Key &lookup_key(const Key &key) const
514 {
515 return this->lookup_key_as(key);
516 }
517 template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
518 {
519 const Key *key_ptr = this->lookup_key_ptr_as(key);
520 BLI_assert(key_ptr != nullptr);
521 return *key_ptr;
522 }
523
528 Key lookup_key_default(const Key &key, const Key &default_value) const
529 {
530 return this->lookup_key_default_as(key, default_value);
531 }
532 template<typename ForwardKey, typename... ForwardDefault>
533 Key lookup_key_default_as(const ForwardKey &key, ForwardDefault &&...default_key) const
534 {
535 const Key *ptr = this->lookup_key_ptr_as(key);
536 if (ptr == nullptr) {
537 return Key(std::forward<ForwardDefault>(default_key)...);
538 }
539 return *ptr;
540 }
541
546 const Key *lookup_key_ptr(const Key &key) const
547 {
548 return this->lookup_key_ptr_as(key);
549 }
550 template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
551 {
552 const int64_t index = this->index_of_try__impl(key, hash_(key));
553 if (index >= 0) {
554 return keys_ + index;
555 }
556 return nullptr;
557 }
558
562 const Key *data() const
563 {
564 return keys_;
565 }
566
567 const Key *begin() const
568 {
569 return keys_;
570 }
571
572 const Key *end() const
573 {
574 return keys_ + this->size();
575 }
576
581 {
582 return IndexRange(this->size());
583 }
584
588 void print_stats(const char *name) const
589 {
590 HashTableStats stats(*this, this->as_span());
591 stats.print(name);
592 }
593
594 bool is_inline() const
595 {
596 return keys_ == inline_buffer_;
597 }
598
602 int64_t size() const
603 {
604 return occupied_and_removed_slots_ - removed_slots_;
605 }
606
610 bool is_empty() const
611 {
612 return occupied_and_removed_slots_ == removed_slots_;
613 }
614
619 {
620 return slots_.size();
621 }
622
627 {
628 return removed_slots_;
629 }
630
635 {
636 return sizeof(Slot) + sizeof(Key);
637 }
638
644 {
645 return int64_t(sizeof(Slot) * slots_.size() + sizeof(Key) * usable_slots_);
646 }
647
651 void reserve(const int64_t n)
652 {
653 if (usable_slots_ < n) {
654 this->realloc_and_reinsert(n);
655 }
656 }
657
661 void clear()
662 {
663 std::destroy_at(this);
664 new (this) VectorSet(NoExceptConstructor{});
665 }
666
675 {
676 destruct_n(keys_, this->size());
677 for (Slot &slot : slots_) {
678 slot.~Slot();
679 new (&slot) Slot();
680 }
681
682 removed_slots_ = 0;
683 occupied_and_removed_slots_ = 0;
684 }
685
690 int64_t count_collisions(const Key &key) const
691 {
692 return this->count_collisions__impl(key, hash_(key));
693 }
694
695 using VectorT = Vector<Key, default_inline_buffer_capacity(sizeof(Key)), Allocator>;
696
707 {
708 const int64_t size = this->size();
710 if (this->is_inline()) {
711 data.data = this->allocate_keys_array(size);
712 data.size = size;
713 data.capacity = size;
714 try {
715 uninitialized_relocate_n(keys_, size, data.data);
716 }
717 catch (...) {
718 this->deallocate_keys_array(data.data);
719 throw;
720 }
721 }
722 else {
723 data.data = keys_;
724 data.size = size;
725 data.capacity = usable_slots_;
726 }
727
728 /* Reset some values so that the destructor does not free the data that is moved to the
729 * #Vector. */
730 keys_ = inline_buffer_;
731 occupied_and_removed_slots_ = 0;
732 removed_slots_ = 0;
733 std::destroy_at(this);
734 new (this) VectorSet();
735
736 return VectorT(data);
737 }
738
739 private:
740 BLI_NOINLINE void realloc_and_reinsert(const int64_t min_usable_slots)
741 {
742 int64_t total_slots, usable_slots;
743 max_load_factor_.compute_total_and_usable_slots(
744 SlotArray::inline_buffer_capacity(), min_usable_slots, &total_slots, &usable_slots);
745 BLI_assert(total_slots >= 1);
746 const uint64_t new_slot_mask = uint64_t(total_slots) - 1;
747
748 /* Optimize the case when the set was empty beforehand. We can avoid some copies here. */
749 if (this->size() == 0) {
750 try {
751 slots_.reinitialize(total_slots);
752
753 Key *new_keys;
754 if (usable_slots <= InlineBufferCapacity) {
755 new_keys = inline_buffer_;
756 }
757 else {
758 new_keys = this->allocate_keys_array(usable_slots);
759 }
760
761 if (keys_ != inline_buffer_) {
762 this->deallocate_keys_array(keys_);
763 }
764
765 keys_ = new_keys;
766 }
767 catch (...) {
768 this->noexcept_reset();
769 throw;
770 }
771 removed_slots_ = 0;
772 occupied_and_removed_slots_ = 0;
773 usable_slots_ = usable_slots;
774 slot_mask_ = new_slot_mask;
775 return;
776 }
777
778 SlotArray new_slots(total_slots);
779
780 try {
781 for (Slot &slot : slots_) {
782 if (slot.is_occupied()) {
783 this->add_after_grow(slot, new_slots, new_slot_mask);
784 slot.remove();
785 }
786 }
787 slots_ = std::move(new_slots);
788 }
789 catch (...) {
790 this->noexcept_reset();
791 throw;
792 }
793
794 /* Allocate the new keys array, or use the inline buffer if possible. */
795 Key *new_keys;
796 if (usable_slots <= InlineBufferCapacity) {
797 new_keys = inline_buffer_;
798 }
799 else {
800 new_keys = this->allocate_keys_array(usable_slots);
801 }
802
803 /* Copy the keys to the new array. When the inline buffer isn't used before and after the
804 * reallocation (`new_keys` also references the inline buffer), no copying is necessary. */
805 if (new_keys != keys_) {
806 try {
807 uninitialized_relocate_n(keys_, this->size(), new_keys);
808 }
809 catch (...) {
810 if (new_keys != inline_buffer_) {
811 this->deallocate_keys_array(new_keys);
812 }
813 this->noexcept_reset();
814 throw;
815 }
816 }
817
818 /* Free the old keys array. */
819 if (keys_ != inline_buffer_) {
820 this->deallocate_keys_array(keys_);
821 }
822
823 keys_ = new_keys;
824 occupied_and_removed_slots_ -= removed_slots_;
825 usable_slots_ = usable_slots;
826 removed_slots_ = 0;
827 slot_mask_ = new_slot_mask;
828 }
829
830 void add_after_grow(Slot &old_slot, SlotArray &new_slots, const uint64_t new_slot_mask)
831 {
832 const Key &key = keys_[old_slot.index()];
833 const uint64_t hash = old_slot.get_hash(key, Hash());
834
835 SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
836 Slot &slot = new_slots[slot_index];
837 if (slot.is_empty()) {
838 slot.occupy(old_slot.index(), hash);
839 return;
840 }
841 }
843 }
844
845 void noexcept_reset() noexcept
846 {
847 Allocator allocator = slots_.allocator();
848 this->~VectorSet();
849 new (this) VectorSet(NoExceptConstructor(), allocator);
850 }
851
852 template<typename ForwardKey>
853 bool contains__impl(const ForwardKey &key, const uint64_t hash) const
854 {
856 if (slot.is_empty()) {
857 return false;
858 }
859 if (slot.contains(key, is_equal_, hash, keys_)) {
860 return true;
861 }
862 }
864 }
865
866 template<typename ForwardKey> void add_new__impl(ForwardKey &&key, const uint64_t hash)
867 {
868 BLI_assert(!this->contains_as(key));
869
870 this->ensure_can_add();
871
873 if (slot.is_empty()) {
874 int64_t index = this->size();
875 Key *dst = keys_ + index;
876 new (dst) Key(std::forward<ForwardKey>(key));
877 BLI_assert(hash_(*dst) == hash);
878 slot.occupy(index, hash);
879 occupied_and_removed_slots_++;
880 return;
881 }
882 }
884 }
885
886 template<typename ForwardKey> bool add__impl(ForwardKey &&key, const uint64_t hash)
887 {
888 this->ensure_can_add();
889
891 if (slot.is_empty()) {
892 const int64_t index = this->size();
893 Key *dst = keys_ + index;
894 new (dst) Key(std::forward<ForwardKey>(key));
895 BLI_assert(hash_(*dst) == hash);
896 slot.occupy(index, hash);
897 occupied_and_removed_slots_++;
898 return true;
899 }
900 if (slot.contains(key, is_equal_, hash, keys_)) {
901 return false;
902 }
903 }
905 }
906
907 template<typename ForwardKey> bool add_overwrite__impl(ForwardKey &&key, const uint64_t hash)
908 {
909 this->ensure_can_add();
910
912 if (slot.is_empty()) {
913 const int64_t index = this->size();
914 Key *dst = keys_ + index;
915 new (dst) Key(std::forward<ForwardKey>(key));
916 BLI_assert(hash_(*dst) == hash);
917 slot.occupy(index, hash);
918 occupied_and_removed_slots_++;
919 return true;
920 }
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);
925 BLI_assert(hash_(stored_key) == hash);
926 return false;
927 }
928 }
930 }
931
932 template<typename ForwardKey>
933 int64_t index_of__impl(const ForwardKey &key, const uint64_t hash) const
934 {
935 BLI_assert(this->contains_as(key));
936
938 if (slot.contains(key, is_equal_, hash, keys_)) {
939 return slot.index();
940 }
941 }
943 }
944
945 template<typename ForwardKey>
946 int64_t index_of_try__impl(const ForwardKey &key, const uint64_t hash) const
947 {
949 if (slot.contains(key, is_equal_, hash, keys_)) {
950 return slot.index();
951 }
952 if (slot.is_empty()) {
953 return -1;
954 }
955 }
957 }
958
959 template<typename ForwardKey>
960 int64_t index_of_or_add__impl(ForwardKey &&key, const uint64_t hash)
961 {
962 this->ensure_can_add();
963
965 if (slot.contains(key, is_equal_, hash, keys_)) {
966 return slot.index();
967 }
968 if (slot.is_empty()) {
969 const int64_t index = this->size();
970 Key *dst = keys_ + index;
971 new (dst) Key(std::forward<ForwardKey>(key));
972 BLI_assert(hash_(*dst) == hash);
973 slot.occupy(index, hash);
974 occupied_and_removed_slots_++;
975 return index;
976 }
977 }
979 }
980
981 Key pop__impl()
982 {
983 BLI_assert(this->size() > 0);
984
985 const int64_t index_to_pop = this->size() - 1;
986 Key key = std::move(keys_[index_to_pop]);
987 keys_[index_to_pop].~Key();
988 const uint64_t hash = hash_(key);
989
990 removed_slots_++;
991
993 if (slot.has_index(index_to_pop)) {
994 slot.remove();
995 return key;
996 }
997 }
999 }
1000
1001 template<typename ForwardKey> bool remove__impl(const ForwardKey &key, const uint64_t hash)
1002 {
1004 if (slot.contains(key, is_equal_, hash, keys_)) {
1005 this->remove_key_internal(slot);
1006 return true;
1007 }
1008 if (slot.is_empty()) {
1009 return false;
1010 }
1011 }
1013 }
1014
1015 template<typename ForwardKey>
1016 void remove_contained__impl(const ForwardKey &key, const uint64_t hash)
1017 {
1018 BLI_assert(this->contains_as(key));
1019
1021 if (slot.contains(key, is_equal_, hash, keys_)) {
1022 this->remove_key_internal(slot);
1023 return;
1024 }
1025 }
1027 }
1028
1029 void remove_key_internal(Slot &slot)
1030 {
1031 int64_t index_to_remove = slot.index();
1032 int64_t size = this->size();
1033 int64_t last_element_index = size - 1;
1034
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);
1038 }
1039
1040 keys_[last_element_index].~Key();
1041 slot.remove();
1042 removed_slots_++;
1043 }
1044
1045 void update_slot_index(const Key &key, const int64_t old_index, const int64_t new_index)
1046 {
1047 uint64_t hash = hash_(key);
1049 if (slot.has_index(old_index)) {
1050 slot.update_index(new_index);
1051 return;
1052 }
1053 }
1055 }
1056
1057 template<typename ForwardKey>
1058 int64_t count_collisions__impl(const ForwardKey &key, const uint64_t hash) const
1059 {
1060 int64_t collisions = 0;
1061
1063 if (slot.contains(key, is_equal_, hash, keys_)) {
1064 return collisions;
1065 }
1066 if (slot.is_empty()) {
1067 return collisions;
1068 }
1069 collisions++;
1070 }
1072 }
1073
1074 void ensure_can_add()
1075 {
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_);
1079 }
1080 }
1081
1082 Key *allocate_keys_array(const int64_t size)
1083 {
1084 return static_cast<Key *>(
1085 slots_.allocator().allocate(sizeof(Key) * size_t(size), alignof(Key), AT));
1086 }
1087
1088 void deallocate_keys_array(Key *keys)
1089 {
1090 slots_.allocator().deallocate(keys);
1091 }
1092};
1093
1098template<typename Key,
1099 int64_t InlineBufferCapacity = 4,
1100 typename ProbingStrategy = DefaultProbingStrategy,
1101 typename Hash = DefaultHash<Key>,
1102 typename IsEqual = DefaultEquality<Key>,
1103 typename Slot = typename DefaultVectorSetSlot<Key>::type>
1106
1107template<typename T, typename GetIDFn> struct CustomIDHash {
1108 using CustomIDType = decltype(GetIDFn{}(std::declval<T>()));
1109
1110 uint64_t operator()(const T &value) const
1111 {
1112 return get_default_hash(GetIDFn{}(value));
1113 }
1115 {
1116 return get_default_hash(value);
1117 }
1118};
1119
1120template<typename T, typename GetIDFn> struct CustomIDEqual {
1121 using CustomIDType = decltype(GetIDFn{}(std::declval<T>()));
1122
1123 bool operator()(const T &a, const T &b) const
1124 {
1125 return GetIDFn{}(a) == GetIDFn{}(b);
1126 }
1127 bool operator()(const CustomIDType &a, const T &b) const
1128 {
1129 return a == GetIDFn{}(b);
1130 }
1131 bool operator()(const T &a, const CustomIDType &b) const
1132 {
1133 return GetIDFn{}(a) == b;
1134 }
1135};
1136
1144template<typename T, typename GetIDFn, int64_t InlineBufferCapacity = 4>
1146 InlineBufferCapacity,
1150
1151} // 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
VectorSet(Hash hash, IsEqual is_equal)
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
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
VectorSet< T, InlineBufferCapacity, DefaultProbingStrategy, CustomIDHash< T, GetIDFn >, CustomIDEqual< T, GetIDFn > > CustomIDVectorSet
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)
VectorSet< Key, InlineBufferCapacity, ProbingStrategy, Hash, IsEqual, Slot, RawAllocator > RawVectorSet
#define hash
Definition noise_c.cc:154
const char * name
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:4238