Blender V5.0
BLI_map.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
54
55#include <optional>
56
57#include "BLI_array.hh"
58#include "BLI_hash.hh"
59#include "BLI_hash_tables.hh"
60#include "BLI_map_slots.hh"
62
63namespace blender {
64
68template<typename Key, typename Value> struct MapItem {
69 const Key &key;
70 const Value &value;
71};
72
77template<typename Key, typename Value> struct MutableMapItem {
78 const Key &key;
79 Value &value;
80
81 operator MapItem<Key, Value>() const
82 {
83 return {this->key, this->value};
84 }
85};
86
87template<
92 typename Key,
96 typename Value,
102 int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key) + sizeof(Value)),
106 typename ProbingStrategy = DefaultProbingStrategy,
111 typename Hash = DefaultHash<Key>,
116 typename IsEqual = DefaultEquality<Key>,
123 typename Slot = typename DefaultMapSlot<Key, Value>::type,
128 typename Allocator = GuardedAllocator>
129class Map {
130 public:
134
135 private:
140 int64_t removed_slots_;
141 int64_t occupied_and_removed_slots_;
142
147 int64_t usable_slots_;
148
153 uint64_t slot_mask_;
154
156 BLI_NO_UNIQUE_ADDRESS Hash hash_;
157
159 BLI_NO_UNIQUE_ADDRESS IsEqual is_equal_;
160
162#define LOAD_FACTOR 1, 2
163 static constexpr LoadFactor max_load_factor_ = LoadFactor(LOAD_FACTOR);
164 using SlotArray =
165 Array<Slot, LoadFactor::compute_total_slots(InlineBufferCapacity, LOAD_FACTOR), Allocator>;
166#undef LOAD_FACTOR
167
172 SlotArray slots_;
173
175#define MAP_SLOT_PROBING_BEGIN(HASH, R_SLOT) \
176 SLOT_PROBING_BEGIN (ProbingStrategy, HASH, slot_mask_, SLOT_INDEX) \
177 auto &R_SLOT = slots_[SLOT_INDEX];
178#define MAP_SLOT_PROBING_END() SLOT_PROBING_END()
179
180 public:
186 Map(Allocator allocator = {}) noexcept
187 : removed_slots_(0),
188 occupied_and_removed_slots_(0),
189 usable_slots_(0),
190 slot_mask_(0),
191 hash_(),
192 is_equal_(),
193 slots_(1, allocator)
194 {
195 }
196
197 Map(NoExceptConstructor, Allocator allocator = {}) noexcept : Map(allocator) {}
198
199 ~Map() = default;
200
201 Map(const Map &other) = default;
202
203 Map(Map &&other) noexcept(std::is_nothrow_move_constructible_v<SlotArray>)
204 : Map(NoExceptConstructor(), other.slots_.allocator())
205 {
206 if constexpr (std::is_nothrow_move_constructible_v<SlotArray>) {
207 slots_ = std::move(other.slots_);
208 }
209 else {
210 try {
211 slots_ = std::move(other.slots_);
212 }
213 catch (...) {
214 other.noexcept_reset();
215 throw;
216 }
217 }
218 removed_slots_ = other.removed_slots_;
219 occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
220 usable_slots_ = other.usable_slots_;
221 slot_mask_ = other.slot_mask_;
222 hash_ = std::move(other.hash_);
223 is_equal_ = std::move(other.is_equal_);
224 other.noexcept_reset();
225 }
226
235 Map(const Span<std::pair<Key, Value>> items, Allocator allocator = {}) : Map(allocator)
236 {
237 for (const std::pair<Key, Value> &item : items) {
238 this->add(item.first, item.second);
239 }
240 }
241
246 Map(const std::initializer_list<std::pair<Key, Value>> items, Allocator allocator = {})
247 : Map(Span(items), allocator)
248 {
249 }
250
251 Map &operator=(const Map &other)
252 {
253 return copy_assign_container(*this, other);
254 }
255
256 Map &operator=(Map &&other)
257 {
258 return move_assign_container(*this, std::move(other));
259 }
260
265 void add_new(const Key &key, const Value &value)
266 {
267 this->add_new_as(key, value);
268 }
269 void add_new(const Key &key, Value &&value)
270 {
271 this->add_new_as(key, std::move(value));
272 }
273 void add_new(Key &&key, const Value &value)
274 {
275 this->add_new_as(std::move(key), value);
276 }
277 void add_new(Key &&key, Value &&value)
278 {
279 this->add_new_as(std::move(key), std::move(value));
280 }
281 template<typename ForwardKey, typename... ForwardValue>
282 void add_new_as(ForwardKey &&key, ForwardValue &&...value)
283 {
284 this->add_new__impl(
285 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
286 }
287
295 bool add(const Key &key, const Value &value)
296 {
297 return this->add_as(key, value);
298 }
299 bool add(const Key &key, Value &&value)
300 {
301 return this->add_as(key, std::move(value));
302 }
303 bool add(Key &&key, const Value &value)
304 {
305 return this->add_as(std::move(key), value);
306 }
307 bool add(Key &&key, Value &&value)
308 {
309 return this->add_as(std::move(key), std::move(value));
310 }
311 template<typename ForwardKey, typename... ForwardValue>
312 bool add_as(ForwardKey &&key, ForwardValue &&...value)
313 {
314 return this->add__impl(
315 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
316 }
317
325 bool add_overwrite(const Key &key, const Value &value)
326 {
327 return this->add_overwrite_as(key, value);
328 }
329 bool add_overwrite(const Key &key, Value &&value)
330 {
331 return this->add_overwrite_as(key, std::move(value));
332 }
333 bool add_overwrite(Key &&key, const Value &value)
334 {
335 return this->add_overwrite_as(std::move(key), value);
336 }
337 bool add_overwrite(Key &&key, Value &&value)
338 {
339 return this->add_overwrite_as(std::move(key), std::move(value));
340 }
341 template<typename ForwardKey, typename... ForwardValue>
342 bool add_overwrite_as(ForwardKey &&key, ForwardValue &&...value)
343 {
344 return this->add_overwrite__impl(
345 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
346 }
347
353 bool contains(const Key &key) const
354 {
355 return this->contains_as(key);
356 }
357 template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
358 {
359 return this->lookup_slot_ptr(key, hash_(key)) != nullptr;
360 }
361
368 bool remove(const Key &key)
369 {
370 return this->remove_as(key);
371 }
372 template<typename ForwardKey> bool remove_as(const ForwardKey &key)
373 {
374 Slot *slot = this->lookup_slot_ptr(key, hash_(key));
375 if (slot == nullptr) {
376 return false;
377 }
378 slot->remove();
379 removed_slots_++;
380 return true;
381 }
382
387 void remove_contained(const Key &key)
388 {
389 this->remove_contained_as(key);
390 }
391 template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
392 {
393 Slot &slot = this->lookup_slot(key, hash_(key));
394 slot.remove();
395 removed_slots_++;
396 }
397
402 Value pop(const Key &key)
403 {
404 return this->pop_as(key);
405 }
406 template<typename ForwardKey> Value pop_as(const ForwardKey &key)
407 {
408 Slot &slot = this->lookup_slot(key, hash_(key));
409 Value value = std::move(*slot.value());
410 slot.remove();
411 removed_slots_++;
412 return value;
413 }
414
419 std::optional<Value> pop_try(const Key &key)
420 {
421 return this->pop_try_as(key);
422 }
423 template<typename ForwardKey> std::optional<Value> pop_try_as(const ForwardKey &key)
424 {
425 Slot *slot = this->lookup_slot_ptr(key, hash_(key));
426 if (slot == nullptr) {
427 return {};
428 }
429 std::optional<Value> value = std::move(*slot->value());
430 slot->remove();
431 removed_slots_++;
432 return value;
433 }
434
439 Value pop_default(const Key &key, const Value &default_value)
440 {
441 return this->pop_default_as(key, default_value);
442 }
443 Value pop_default(const Key &key, Value &&default_value)
444 {
445 return this->pop_default_as(key, std::move(default_value));
446 }
447 template<typename ForwardKey, typename... ForwardValue>
448 Value pop_default_as(const ForwardKey &key, ForwardValue &&...default_value)
449 {
450 Slot *slot = this->lookup_slot_ptr(key, hash_(key));
451 if (slot == nullptr) {
452 return Value(std::forward<ForwardValue>(default_value)...);
453 }
454 Value value = std::move(*slot->value());
455 slot->remove();
456 removed_slots_++;
457 return value;
458 }
459
480 template<typename CreateValueF, typename ModifyValueF>
481 auto add_or_modify(const Key &key,
482 const CreateValueF &create_value,
483 const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
484 {
485 return this->add_or_modify_as(key, create_value, modify_value);
486 }
487 template<typename CreateValueF, typename ModifyValueF>
488 auto add_or_modify(Key &&key, const CreateValueF &create_value, const ModifyValueF &modify_value)
489 -> decltype(create_value(nullptr))
490 {
491 return this->add_or_modify_as(std::move(key), create_value, modify_value);
492 }
493 template<typename ForwardKey, typename CreateValueF, typename ModifyValueF>
494 auto add_or_modify_as(ForwardKey &&key,
495 const CreateValueF &create_value,
496 const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
497 {
498 return this->add_or_modify__impl(
499 std::forward<ForwardKey>(key), create_value, modify_value, hash_(key));
500 }
501
508 const Value *lookup_ptr(const Key &key) const
509 {
510 return this->lookup_ptr_as(key);
511 }
512 Value *lookup_ptr(const Key &key)
513 {
514 return this->lookup_ptr_as(key);
515 }
516 template<typename ForwardKey> const Value *lookup_ptr_as(const ForwardKey &key) const
517 {
518 const Slot *slot = this->lookup_slot_ptr(key, hash_(key));
519 return (slot != nullptr) ? slot->value() : nullptr;
520 }
521 template<typename ForwardKey> Value *lookup_ptr_as(const ForwardKey &key)
522 {
523 return const_cast<Value *>(const_cast<const Map *>(this)->lookup_ptr_as(key));
524 }
525
531 std::optional<Value> lookup_try(const Key &key) const
532 {
533 return this->lookup_try_as(key);
534 }
535 template<typename ForwardKey> std::optional<Value> lookup_try_as(const ForwardKey &key) const
536 {
537 const Slot *slot = this->lookup_slot_ptr(key, hash_(key));
538 return (slot != nullptr) ? std::optional<Value>(*slot->value()) : std::nullopt;
539 }
540
545 const Value &lookup(const Key &key) const
546 {
547 return this->lookup_as(key);
548 }
549 Value &lookup(const Key &key)
550 {
551 return this->lookup_as(key);
552 }
553 template<typename ForwardKey> const Value &lookup_as(const ForwardKey &key) const
554 {
555 const Value *ptr = this->lookup_ptr_as(key);
556 BLI_assert(ptr != nullptr);
557 return *ptr;
558 }
559 template<typename ForwardKey> Value &lookup_as(const ForwardKey &key)
560 {
561 Value *ptr = this->lookup_ptr_as(key);
562 BLI_assert(ptr != nullptr);
563 return *ptr;
564 }
565
570 Value lookup_default(const Key &key, const Value &default_value) const
571 {
572 return this->lookup_default_as(key, default_value);
573 }
574 template<typename ForwardKey, typename... ForwardValue>
575 Value lookup_default_as(const ForwardKey &key, ForwardValue &&...default_value) const
576 {
577 const Value *ptr = this->lookup_ptr_as(key);
578 if (ptr != nullptr) {
579 return *ptr;
580 }
581 return Value(std::forward<ForwardValue>(default_value)...);
582 }
583
588 Value &lookup_or_add(const Key &key, const Value &value)
589 {
590 return this->lookup_or_add_as(key, value);
591 }
592 Value &lookup_or_add(const Key &key, Value &&value)
593 {
594 return this->lookup_or_add_as(key, std::move(value));
595 }
596 Value &lookup_or_add(Key &&key, const Value &value)
597 {
598 return this->lookup_or_add_as(std::move(key), value);
599 }
600 Value &lookup_or_add(Key &&key, Value &&value)
601 {
602 return this->lookup_or_add_as(std::move(key), std::move(value));
603 }
604 template<typename ForwardKey, typename... ForwardValue>
605 Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&...value)
606 {
607 return this->lookup_or_add__impl(
608 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
609 }
610
619 template<typename CreateValueF>
620 Value &lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
621 {
622 return this->lookup_or_add_cb_as(key, create_value);
623 }
624 template<typename CreateValueF>
625 Value &lookup_or_add_cb(Key &&key, const CreateValueF &create_value)
626 {
627 return this->lookup_or_add_cb_as(std::move(key), create_value);
628 }
629 template<typename ForwardKey, typename CreateValueF>
630 Value &lookup_or_add_cb_as(ForwardKey &&key, const CreateValueF &create_value)
631 {
632 return this->lookup_or_add_cb__impl(std::forward<ForwardKey>(key), create_value, hash_(key));
633 }
634
639 Value &lookup_or_add_default(const Key &key)
640 {
641 return this->lookup_or_add_default_as(key);
642 }
644 {
645 return this->lookup_or_add_default_as(std::move(key));
646 }
647 template<typename ForwardKey> Value &lookup_or_add_default_as(ForwardKey &&key)
648 {
649 return this->lookup_or_add_cb_as(std::forward<ForwardKey>(key), []() { return Value(); });
650 }
651
656 const Key &lookup_key(const Key &key) const
657 {
658 return this->lookup_key_as(key);
659 }
660 template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
661 {
662 const Slot &slot = this->lookup_slot(key, hash_(key));
663 return *slot.key();
664 }
665
670 const Key *lookup_key_ptr(const Key &key) const
671 {
672 return this->lookup_key_ptr_as(key);
673 }
674 template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
675 {
676 const Slot *slot = this->lookup_slot_ptr(key, hash_(key));
677 if (slot == nullptr) {
678 return nullptr;
679 }
680 return slot->key();
681 }
682
687 template<typename FuncT> void foreach_item(const FuncT &func) const
688 {
689 int64_t size = slots_.size();
690 for (int64_t i = 0; i < size; i++) {
691 const Slot &slot = slots_[i];
692 if (slot.is_occupied()) {
693 const Key &key = *slot.key();
694 const Value &value = *slot.value();
695 func(key, value);
696 }
697 }
698 }
699
700 /* Common base class for all iterators below. */
702 public:
703 using iterator_category = std::forward_iterator_tag;
704 using difference_type = std::ptrdiff_t;
705
706 protected:
707 /* We could have separate base iterators for const and non-const iterators, but that would add
708 * more complexity than benefits right now. */
709 Slot *slots_;
712
713 friend Map;
714
715 public:
716 BaseIterator(const Slot *slots, const int64_t total_slots, const int64_t current_slot)
717 : slots_(const_cast<Slot *>(slots)), total_slots_(total_slots), current_slot_(current_slot)
718 {
719 }
720
722 {
723 while (++current_slot_ < total_slots_) {
724 if (slots_[current_slot_].is_occupied()) {
725 break;
726 }
727 }
728 return *this;
729 }
730
732 {
733 BaseIterator copied_iterator = *this;
734 ++(*this);
735 return copied_iterator;
736 }
737
738 friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
739 {
740 BLI_assert(a.slots_ == b.slots_);
741 BLI_assert(a.total_slots_ == b.total_slots_);
742 return a.current_slot_ != b.current_slot_;
743 }
744
745 friend bool operator==(const BaseIterator &a, const BaseIterator &b)
746 {
747 return !(a != b);
748 }
749
750 protected:
751 Slot &current_slot() const
752 {
753 return slots_[current_slot_];
754 }
755 };
756
761 template<typename SubIterator> class BaseIteratorRange : public BaseIterator {
762 public:
763 BaseIteratorRange(const Slot *slots, int64_t total_slots, int64_t current_slot)
764 : BaseIterator(slots, total_slots, current_slot)
765 {
766 }
767
768 SubIterator begin() const
769 {
770 for (int64_t i = 0; i < this->total_slots_; i++) {
771 if (this->slots_[i].is_occupied()) {
772 return SubIterator(this->slots_, this->total_slots_, i);
773 }
774 }
775 return this->end();
776 }
777
778 SubIterator end() const
779 {
780 return SubIterator(this->slots_, this->total_slots_, this->total_slots_);
781 }
782 };
783
784 class KeyIterator final : public BaseIteratorRange<KeyIterator> {
785 public:
787 using pointer = const Key *;
788 using reference = const Key &;
789
790 KeyIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
791 : BaseIteratorRange<KeyIterator>(slots, total_slots, current_slot)
792 {
793 }
794
795 const Key &operator*() const
796 {
797 return *this->current_slot().key();
798 }
799 };
800
801 class ValueIterator final : public BaseIteratorRange<ValueIterator> {
802 public:
803 using value_type = Value;
804 using pointer = const Value *;
805 using reference = const Value &;
806
807 ValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
808 : BaseIteratorRange<ValueIterator>(slots, total_slots, current_slot)
809 {
810 }
811
812 const Value &operator*() const
813 {
814 return *this->current_slot().value();
815 }
816 };
817
818 class MutableValueIterator final : public BaseIteratorRange<MutableValueIterator> {
819 public:
820 using value_type = Value;
821 using pointer = Value *;
822 using reference = Value &;
823
826 {
827 }
828
829 Value &operator*()
830 {
831 return *this->current_slot().value();
832 }
833 };
834
835 class ItemIterator final : public BaseIteratorRange<ItemIterator> {
836 public:
838 using pointer = Item *;
839 using reference = Item &;
840
841 ItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
842 : BaseIteratorRange<ItemIterator>(slots, total_slots, current_slot)
843 {
844 }
845
847 {
848 const Slot &slot = this->current_slot();
849 return {*slot.key(), *slot.value()};
850 }
851 };
852
853 class MutableItemIterator final : public BaseIteratorRange<MutableItemIterator> {
854 public:
858
861 {
862 }
863
865 {
866 Slot &slot = this->current_slot();
867 return {*slot.key(), *slot.value()};
868 }
869 };
870
875 KeyIterator keys() const &
876 {
877 return KeyIterator(slots_.data(), slots_.size(), 0);
878 }
879
884 ValueIterator values() const &
885 {
886 return ValueIterator(slots_.data(), slots_.size(), 0);
887 }
888
893 MutableValueIterator values() &
894 {
895 return MutableValueIterator(slots_.data(), slots_.size(), 0);
896 }
897
902 ItemIterator items() const &
903 {
904 return ItemIterator(slots_.data(), slots_.size(), 0);
905 }
906
913 MutableItemIterator items() &
914 {
915 return MutableItemIterator(slots_.data(), slots_.size(), 0);
916 }
917
923 KeyIterator keys() const && = delete;
924 MutableValueIterator values() && = delete;
925 ValueIterator values() const && = delete;
926 ItemIterator items() const && = delete;
927 MutableItemIterator items() && = delete;
928
934 void remove(const BaseIterator &iterator)
935 {
936 Slot &slot = iterator.current_slot();
937 BLI_assert(slot.is_occupied());
938 slot.remove();
939 removed_slots_++;
940 }
941
948 template<typename Predicate> int64_t remove_if(Predicate &&predicate)
949 {
950 const int64_t prev_size = this->size();
951 for (Slot &slot : slots_) {
952 if (slot.is_occupied()) {
953 const Key &key = *slot.key();
954 Value &value = *slot.value();
955 if (predicate(MutableItem{key, value})) {
956 slot.remove();
957 removed_slots_++;
958 }
959 }
960 }
961 return prev_size - this->size();
962 }
963
967 void print_stats(const char *name) const
968 {
969 HashTableStats stats(*this, this->keys());
970 stats.print(name);
971 }
972
976 int64_t size() const
977 {
978 return occupied_and_removed_slots_ - removed_slots_;
979 }
980
986 bool is_empty() const
987 {
988 return occupied_and_removed_slots_ == removed_slots_;
989 }
990
995 {
996 return slots_.size();
997 }
998
1003 {
1004 return removed_slots_;
1005 }
1006
1011 {
1012 return sizeof(Slot);
1013 }
1014
1020 {
1021 return int64_t(sizeof(Slot) * slots_.size());
1022 }
1023
1029 {
1030 if (usable_slots_ < n) {
1031 this->realloc_and_reinsert(n);
1032 }
1033 }
1034
1038 void clear()
1039 {
1040 std::destroy_at(this);
1041 new (this) Map(NoExceptConstructor{});
1042 }
1043
1052 {
1053 for (Slot &slot : slots_) {
1054 slot.~Slot();
1055 new (&slot) Slot();
1056 }
1057
1058 removed_slots_ = 0;
1059 occupied_and_removed_slots_ = 0;
1060 }
1061
1066 int64_t count_collisions(const Key &key) const
1067 {
1068 return this->count_collisions__impl(key, hash_(key));
1069 }
1070
1074 friend bool operator==(const Map &a, const Map &b)
1075 {
1076 if (a.size() != b.size()) {
1077 return false;
1078 }
1079 for (const Item item : a.items()) {
1080 const Key &key = item.key;
1081 const Value &value_a = item.value;
1082 const Value *value_b = b.lookup_ptr(key);
1083 if (value_b == nullptr) {
1084 return false;
1085 }
1086 if (value_a != *value_b) {
1087 return false;
1088 }
1089 }
1090 return true;
1091 }
1092
1093 friend bool operator!=(const Map &a, const Map &b)
1094 {
1095 return !(a == b);
1096 }
1097
1098 private:
1099 BLI_NOINLINE void realloc_and_reinsert(int64_t min_usable_slots)
1100 {
1101 int64_t total_slots, usable_slots;
1102 max_load_factor_.compute_total_and_usable_slots(
1103 SlotArray::inline_buffer_capacity(), min_usable_slots, &total_slots, &usable_slots);
1104 BLI_assert(total_slots >= 1);
1105 const uint64_t new_slot_mask = uint64_t(total_slots) - 1;
1106
1110 if (this->size() == 0) {
1111 try {
1112 slots_.reinitialize(total_slots);
1113 }
1114 catch (...) {
1115 this->noexcept_reset();
1116 throw;
1117 }
1118 removed_slots_ = 0;
1119 occupied_and_removed_slots_ = 0;
1120 usable_slots_ = usable_slots;
1121 slot_mask_ = new_slot_mask;
1122 return;
1123 }
1124
1125 SlotArray new_slots(total_slots);
1126
1127 try {
1128 for (Slot &slot : slots_) {
1129 if (slot.is_occupied()) {
1130 this->add_after_grow(slot, new_slots, new_slot_mask);
1131 slot.remove();
1132 }
1133 }
1134 slots_ = std::move(new_slots);
1135 }
1136 catch (...) {
1137 this->noexcept_reset();
1138 throw;
1139 }
1140
1141 occupied_and_removed_slots_ -= removed_slots_;
1142 usable_slots_ = usable_slots;
1143 removed_slots_ = 0;
1144 slot_mask_ = new_slot_mask;
1145 }
1146
1147 void add_after_grow(Slot &old_slot, SlotArray &new_slots, uint64_t new_slot_mask)
1148 {
1149 uint64_t hash = old_slot.get_hash(Hash());
1150 SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
1151 Slot &slot = new_slots[slot_index];
1152 if (slot.is_empty()) {
1153 slot.occupy(std::move(*old_slot.key()), hash, std::move(*old_slot.value()));
1154 return;
1155 }
1156 }
1158 }
1159
1160 void noexcept_reset() noexcept
1161 {
1162 Allocator allocator = slots_.allocator();
1163 this->~Map();
1164 new (this) Map(NoExceptConstructor(), allocator);
1165 }
1166
1167 template<typename ForwardKey, typename... ForwardValue>
1168 void add_new__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1169 {
1170 BLI_assert(!this->contains_as(key));
1171
1172 this->ensure_can_add();
1173
1175 if (slot.is_empty()) {
1176 slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
1177 BLI_assert(hash_(*slot.key()) == hash);
1178 occupied_and_removed_slots_++;
1179 return;
1180 }
1181 }
1183 }
1184
1185 template<typename ForwardKey, typename... ForwardValue>
1186 bool add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1187 {
1188 this->ensure_can_add();
1189
1191 if (slot.is_empty()) {
1192 slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
1193 BLI_assert(hash_(*slot.key()) == hash);
1194 occupied_and_removed_slots_++;
1195 return true;
1196 }
1197 if (slot.contains(key, is_equal_, hash)) {
1198 return false;
1199 }
1200 }
1202 }
1203
1204 template<typename ForwardKey, typename CreateValueF, typename ModifyValueF>
1205 auto add_or_modify__impl(ForwardKey &&key,
1206 const CreateValueF &create_value,
1207 const ModifyValueF &modify_value,
1208 uint64_t hash) -> decltype(create_value(nullptr))
1209 {
1210 using CreateReturnT = decltype(create_value(nullptr));
1211 using ModifyReturnT = decltype(modify_value(nullptr));
1212 BLI_STATIC_ASSERT((std::is_same_v<CreateReturnT, ModifyReturnT>),
1213 "Both callbacks should return the same type.");
1214
1215 this->ensure_can_add();
1216
1218 if (slot.is_empty()) {
1219 Value *value_ptr = slot.value();
1220 if constexpr (std::is_void_v<CreateReturnT>) {
1221 create_value(value_ptr);
1222 slot.occupy_no_value(std::forward<ForwardKey>(key), hash);
1223 occupied_and_removed_slots_++;
1224 return;
1225 }
1226 else {
1227 auto &&return_value = create_value(value_ptr);
1228 slot.occupy_no_value(std::forward<ForwardKey>(key), hash);
1229 occupied_and_removed_slots_++;
1230 return return_value;
1231 }
1232 }
1233 if (slot.contains(key, is_equal_, hash)) {
1234 Value *value_ptr = slot.value();
1235 return modify_value(value_ptr);
1236 }
1237 }
1239 }
1240
1241 template<typename ForwardKey, typename CreateValueF>
1242 Value &lookup_or_add_cb__impl(ForwardKey &&key, const CreateValueF &create_value, uint64_t hash)
1243 {
1244 this->ensure_can_add();
1245
1247 if (slot.is_empty()) {
1248 slot.occupy(std::forward<ForwardKey>(key), hash, create_value());
1249 BLI_assert(hash_(*slot.key()) == hash);
1250 occupied_and_removed_slots_++;
1251 return *slot.value();
1252 }
1253 if (slot.contains(key, is_equal_, hash)) {
1254 return *slot.value();
1255 }
1256 }
1258 }
1259
1260 template<typename ForwardKey, typename... ForwardValue>
1261 Value &lookup_or_add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1262 {
1263 this->ensure_can_add();
1264
1266 if (slot.is_empty()) {
1267 slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
1268 BLI_assert(hash_(*slot.key()) == hash);
1269 occupied_and_removed_slots_++;
1270 return *slot.value();
1271 }
1272 if (slot.contains(key, is_equal_, hash)) {
1273 return *slot.value();
1274 }
1275 }
1277 }
1278
1279 template<typename ForwardKey, typename... ForwardValue>
1280 bool add_overwrite__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1281 {
1282 auto create_func = [&](Value *ptr) {
1283 new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value)...);
1284 return true;
1285 };
1286 auto modify_func = [&](Value *ptr) {
1287 *ptr = Value(std::forward<ForwardValue>(value)...);
1288 return false;
1289 };
1290 return this->add_or_modify__impl(
1291 std::forward<ForwardKey>(key), create_func, modify_func, hash);
1292 }
1293
1294 template<typename ForwardKey>
1295 const Slot &lookup_slot(const ForwardKey &key, const uint64_t hash) const
1296 {
1297 BLI_assert(this->contains_as(key));
1299 if (slot.contains(key, is_equal_, hash)) {
1300 return slot;
1301 }
1302 }
1304 }
1305
1306 template<typename ForwardKey> Slot &lookup_slot(const ForwardKey &key, const uint64_t hash)
1307 {
1308 return const_cast<Slot &>(const_cast<const Map *>(this)->lookup_slot(key, hash));
1309 }
1310
1311 template<typename ForwardKey>
1312 const Slot *lookup_slot_ptr(const ForwardKey &key, const uint64_t hash) const
1313 {
1315 if (slot.contains(key, is_equal_, hash)) {
1316 return &slot;
1317 }
1318 if (slot.is_empty()) {
1319 return nullptr;
1320 }
1321 }
1323 }
1324
1325 template<typename ForwardKey> Slot *lookup_slot_ptr(const ForwardKey &key, const uint64_t hash)
1326 {
1327 return const_cast<Slot *>(const_cast<const Map *>(this)->lookup_slot_ptr(key, hash));
1328 }
1329
1330 template<typename ForwardKey>
1331 int64_t count_collisions__impl(const ForwardKey &key, uint64_t hash) const
1332 {
1333 int64_t collisions = 0;
1334
1336 if (slot.contains(key, is_equal_, hash)) {
1337 return collisions;
1338 }
1339 if (slot.is_empty()) {
1340 return collisions;
1341 }
1342 collisions++;
1343 }
1345 }
1346
1347 void ensure_can_add()
1348 {
1349 if (occupied_and_removed_slots_ >= usable_slots_) {
1350 this->realloc_and_reinsert(this->size() + 1);
1351 BLI_assert(occupied_and_removed_slots_ < usable_slots_);
1352 }
1353 }
1354};
1355
1360template<typename Key,
1361 typename Value,
1362 int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key) +
1363 sizeof(Value)),
1364 typename ProbingStrategy = DefaultProbingStrategy,
1365 typename Hash = DefaultHash<Key>,
1366 typename IsEqual = DefaultEquality<Key>,
1367 typename Slot = typename DefaultMapSlot<Key, Value>::type>
1368using RawMap =
1370
1371} // namespace blender
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_NOINLINE
#define final(a, b, c)
Definition BLI_hash.h:19
#define LOAD_FACTOR
Definition BLI_map.hh:162
#define MAP_SLOT_PROBING_END()
Definition BLI_map.hh:178
#define MAP_SLOT_PROBING_BEGIN(HASH, R_SLOT)
Definition BLI_map.hh:175
#define SLOT_PROBING_BEGIN(PROBING_STRATEGY, HASH, MASK, R_SLOT_INDEX)
#define SLOT_PROBING_END()
#define BLI_NO_UNIQUE_ADDRESS
struct Key Key
long long int int64_t
unsigned long long int uint64_t
BaseIteratorRange(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:763
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
void print(const char *name) const
constexpr void compute_total_and_usable_slots(int64_t min_total_slots, int64_t min_usable_slots, int64_t *r_total_slots, int64_t *r_usable_slots) const
static constexpr int64_t compute_total_slots(int64_t min_usable_slots, uint8_t numerator, uint8_t denominator)
SubIterator begin() const
Definition BLI_map.hh:768
BaseIteratorRange(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:763
SubIterator end() const
Definition BLI_map.hh:778
ItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:841
KeyIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:790
const Key & operator*() const
Definition BLI_map.hh:795
MutableItemIterator(Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:859
MutableItem operator*() const
Definition BLI_map.hh:864
MutableValueIterator(Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:824
const Value & operator*() const
Definition BLI_map.hh:812
ValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:807
MutableValueIterator values() &
Definition BLI_map.hh:893
Value pop_as(const ForwardKey &key)
Definition BLI_map.hh:406
bool add_overwrite(Key &&key, Value &&value)
Definition BLI_map.hh:337
Value pop_default_as(const ForwardKey &key, ForwardValue &&...default_value)
Definition BLI_map.hh:448
KeyIterator keys() const &&=delete
void clear()
Definition BLI_map.hh:1038
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
void print_stats(const char *name) const
Definition BLI_map.hh:967
int64_t size_in_bytes() const
Definition BLI_map.hh:1019
Value pop(const Key &key)
Definition BLI_map.hh:402
Value & lookup(const Key &key)
Definition BLI_map.hh:549
std::optional< Value > lookup_try(const Key &key) const
Definition BLI_map.hh:531
friend bool operator!=(const Map &a, const Map &b)
Definition BLI_map.hh:1093
Value & lookup_as(const ForwardKey &key)
Definition BLI_map.hh:559
std::optional< Value > pop_try(const Key &key)
Definition BLI_map.hh:419
void add_new(const Key &key, Value &&value)
Definition BLI_map.hh:269
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:639
MutableMapItem< PropIdentifier, AnimatedProperty > MutableItem
Definition BLI_map.hh:133
void add_new(Key &&key, const Value &value)
Definition BLI_map.hh:273
Value & lookup_or_add(Key &&key, const Value &value)
Definition BLI_map.hh:596
const Key & lookup_key_as(const ForwardKey &key) const
Definition BLI_map.hh:660
Map(const Span< std::pair< Key, Value > > items, Allocator allocator={})
Definition BLI_map.hh:235
Value & lookup_or_add_default(Key &&key)
Definition BLI_map.hh:643
int64_t removed_amount() const
Definition BLI_map.hh:1002
Map(NoExceptConstructor, Allocator allocator={}) noexcept
Definition BLI_map.hh:197
Map(const std::initializer_list< std::pair< Key, Value > > items, Allocator allocator={})
Definition BLI_map.hh:246
bool remove_as(const ForwardKey &key)
Definition BLI_map.hh:372
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:325
~Map()=default
ValueIterator values() const &
Definition BLI_map.hh:884
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
int64_t size_per_element() const
Definition BLI_map.hh:1010
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value & lookup_or_add(const Key &key, Value &&value)
Definition BLI_map.hh:592
void remove_contained_as(const ForwardKey &key)
Definition BLI_map.hh:391
std::optional< Value > lookup_try_as(const ForwardKey &key) const
Definition BLI_map.hh:535
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:570
const Key * lookup_key_ptr_as(const ForwardKey &key) const
Definition BLI_map.hh:674
bool add_overwrite(Key &&key, const Value &value)
Definition BLI_map.hh:333
int64_t count_collisions(const Key &key) const
Definition BLI_map.hh:1066
Value & lookup_or_add_cb(Key &&key, const CreateValueF &create_value)
Definition BLI_map.hh:625
int64_t capacity() const
Definition BLI_map.hh:994
void add_new_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:282
Value & lookup_or_add_default_as(ForwardKey &&key)
Definition BLI_map.hh:647
Value & lookup_or_add_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:605
void clear_and_keep_capacity()
Definition BLI_map.hh:1051
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
const Value * lookup_ptr_as(const ForwardKey &key) const
Definition BLI_map.hh:516
friend bool operator==(const Map &a, const Map &b)
Definition BLI_map.hh:1074
Value * lookup_ptr(const Key &key)
Definition BLI_map.hh:512
void foreach_item(const FuncT &func) const
Definition BLI_map.hh:687
void remove_contained(const Key &key)
Definition BLI_map.hh:387
MutableItemIterator items() &
Definition BLI_map.hh:913
Map(const Map &other)=default
Map(Allocator allocator={}) noexcept
Definition BLI_map.hh:186
const Key & lookup_key(const Key &key) const
Definition BLI_map.hh:656
bool add_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:312
auto add_or_modify_as(ForwardKey &&key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:494
Value & lookup_or_add_cb_as(ForwardKey &&key, const CreateValueF &create_value)
Definition BLI_map.hh:630
void add_new(Key &&key, Value &&value)
Definition BLI_map.hh:277
const Key * lookup_key_ptr(const Key &key) const
Definition BLI_map.hh:670
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:265
bool add(Key &&key, Value &&value)
Definition BLI_map.hh:307
Map & operator=(Map &&other)
Definition BLI_map.hh:256
Map(Map &&other) noexcept(std::is_nothrow_move_constructible_v< SlotArray >)
Definition BLI_map.hh:203
const Value & lookup_as(const ForwardKey &key) const
Definition BLI_map.hh:553
bool remove(const Key &key)
Definition BLI_map.hh:368
bool contains_as(const ForwardKey &key) const
Definition BLI_map.hh:357
MapItem< PropIdentifier, AnimatedProperty > Item
Definition BLI_map.hh:132
bool add(const Key &key, Value &&value)
Definition BLI_map.hh:299
KeyIterator keys() const &
Definition BLI_map.hh:875
auto add_or_modify(Key &&key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:488
bool is_empty() const
Definition BLI_map.hh:986
void reserve(int64_t n)
Definition BLI_map.hh:1028
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:342
bool contains(const Key &key) const
Definition BLI_map.hh:353
Map & operator=(const Map &other)
Definition BLI_map.hh:251
Value pop_default(const Key &key, Value &&default_value)
Definition BLI_map.hh:443
bool add(Key &&key, const Value &value)
Definition BLI_map.hh:303
Value * lookup_ptr_as(const ForwardKey &key)
Definition BLI_map.hh:521
bool add_overwrite(const Key &key, Value &&value)
Definition BLI_map.hh:329
Value lookup_default_as(const ForwardKey &key, ForwardValue &&...default_value) const
Definition BLI_map.hh:575
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:481
int64_t remove_if(Predicate &&predicate)
Definition BLI_map.hh:948
Value pop_default(const Key &key, const Value &default_value)
Definition BLI_map.hh:439
Value & lookup_or_add(Key &&key, Value &&value)
Definition BLI_map.hh:600
std::optional< Value > pop_try_as(const ForwardKey &key)
Definition BLI_map.hh:423
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:588
blender::Vector< blender::nodes::ItemDeclarationPtr >::const_iterator ItemIterator
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)
Map< Key, Value, InlineBufferCapacity, ProbingStrategy, Hash, IsEqual, Slot, RawAllocator > RawMap
Definition BLI_map.hh:1368
PythonProbingStrategy<> DefaultProbingStrategy
#define hash
Definition noise_c.cc:154
static PyObject * create_func(PyObject *, PyObject *args)
Definition python.cpp:157
const char * name
SimpleMapSlot< Key, Value > type
const Value & value
Definition BLI_map.hh:70
const Key & key
Definition BLI_map.hh:69
friend bool operator==(const BaseIterator &a, const BaseIterator &b)
Definition BLI_map.hh:745
Slot & current_slot() const
Definition BLI_map.hh:751
BaseIterator operator++(int)
Definition BLI_map.hh:731
friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
Definition BLI_map.hh:738
BaseIterator & operator++()
Definition BLI_map.hh:721
std::ptrdiff_t difference_type
Definition BLI_map.hh:704
std::forward_iterator_tag iterator_category
Definition BLI_map.hh:703
BaseIterator(const Slot *slots, const int64_t total_slots, const int64_t current_slot)
Definition BLI_map.hh:716
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238