Blender V4.3
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
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 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
227 Map &operator=(const Map &other)
228 {
229 return copy_assign_container(*this, other);
230 }
231
232 Map &operator=(Map &&other)
233 {
234 return move_assign_container(*this, std::move(other));
235 }
236
241 void add_new(const Key &key, const Value &value)
242 {
243 this->add_new_as(key, value);
244 }
245 void add_new(const Key &key, Value &&value)
246 {
247 this->add_new_as(key, std::move(value));
248 }
249 void add_new(Key &&key, const Value &value)
250 {
251 this->add_new_as(std::move(key), value);
252 }
253 void add_new(Key &&key, Value &&value)
254 {
255 this->add_new_as(std::move(key), std::move(value));
256 }
257 template<typename ForwardKey, typename... ForwardValue>
258 void add_new_as(ForwardKey &&key, ForwardValue &&...value)
259 {
260 this->add_new__impl(
261 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
262 }
263
271 bool add(const Key &key, const Value &value)
272 {
273 return this->add_as(key, value);
274 }
275 bool add(const Key &key, Value &&value)
276 {
277 return this->add_as(key, std::move(value));
278 }
279 bool add(Key &&key, const Value &value)
280 {
281 return this->add_as(std::move(key), value);
282 }
283 bool add(Key &&key, Value &&value)
284 {
285 return this->add_as(std::move(key), std::move(value));
286 }
287 template<typename ForwardKey, typename... ForwardValue>
288 bool add_as(ForwardKey &&key, ForwardValue &&...value)
289 {
290 return this->add__impl(
291 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
292 }
293
301 bool add_overwrite(const Key &key, const Value &value)
302 {
303 return this->add_overwrite_as(key, value);
304 }
305 bool add_overwrite(const Key &key, Value &&value)
306 {
307 return this->add_overwrite_as(key, std::move(value));
308 }
309 bool add_overwrite(Key &&key, const Value &value)
310 {
311 return this->add_overwrite_as(std::move(key), value);
312 }
313 bool add_overwrite(Key &&key, Value &&value)
314 {
315 return this->add_overwrite_as(std::move(key), std::move(value));
316 }
317 template<typename ForwardKey, typename... ForwardValue>
318 bool add_overwrite_as(ForwardKey &&key, ForwardValue &&...value)
319 {
320 return this->add_overwrite__impl(
321 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
322 }
323
329 bool contains(const Key &key) const
330 {
331 return this->contains_as(key);
332 }
333 template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
334 {
335 return this->lookup_slot_ptr(key, hash_(key)) != nullptr;
336 }
337
344 bool remove(const Key &key)
345 {
346 return this->remove_as(key);
347 }
348 template<typename ForwardKey> bool remove_as(const ForwardKey &key)
349 {
350 Slot *slot = this->lookup_slot_ptr(key, hash_(key));
351 if (slot == nullptr) {
352 return false;
353 }
354 slot->remove();
355 removed_slots_++;
356 return true;
357 }
358
363 void remove_contained(const Key &key)
364 {
365 this->remove_contained_as(key);
366 }
367 template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
368 {
369 Slot &slot = this->lookup_slot(key, hash_(key));
370 slot.remove();
371 removed_slots_++;
372 }
373
378 Value pop(const Key &key)
379 {
380 return this->pop_as(key);
381 }
382 template<typename ForwardKey> Value pop_as(const ForwardKey &key)
383 {
384 Slot &slot = this->lookup_slot(key, hash_(key));
385 Value value = std::move(*slot.value());
386 slot.remove();
387 removed_slots_++;
388 return value;
389 }
390
395 std::optional<Value> pop_try(const Key &key)
396 {
397 return this->pop_try_as(key);
398 }
399 template<typename ForwardKey> std::optional<Value> pop_try_as(const ForwardKey &key)
400 {
401 Slot *slot = this->lookup_slot_ptr(key, hash_(key));
402 if (slot == nullptr) {
403 return {};
404 }
405 std::optional<Value> value = std::move(*slot->value());
406 slot->remove();
407 removed_slots_++;
408 return value;
409 }
410
415 Value pop_default(const Key &key, const Value &default_value)
416 {
417 return this->pop_default_as(key, default_value);
418 }
419 Value pop_default(const Key &key, Value &&default_value)
420 {
421 return this->pop_default_as(key, std::move(default_value));
422 }
423 template<typename ForwardKey, typename... ForwardValue>
424 Value pop_default_as(const ForwardKey &key, ForwardValue &&...default_value)
425 {
426 Slot *slot = this->lookup_slot_ptr(key, hash_(key));
427 if (slot == nullptr) {
428 return Value(std::forward<ForwardValue>(default_value)...);
429 }
430 Value value = std::move(*slot->value());
431 slot->remove();
432 removed_slots_++;
433 return value;
434 }
435
456 template<typename CreateValueF, typename ModifyValueF>
457 auto add_or_modify(const Key &key,
458 const CreateValueF &create_value,
459 const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
460 {
461 return this->add_or_modify_as(key, create_value, modify_value);
462 }
463 template<typename CreateValueF, typename ModifyValueF>
464 auto add_or_modify(Key &&key, const CreateValueF &create_value, const ModifyValueF &modify_value)
465 -> decltype(create_value(nullptr))
466 {
467 return this->add_or_modify_as(std::move(key), create_value, modify_value);
468 }
469 template<typename ForwardKey, typename CreateValueF, typename ModifyValueF>
470 auto add_or_modify_as(ForwardKey &&key,
471 const CreateValueF &create_value,
472 const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
473 {
474 return this->add_or_modify__impl(
475 std::forward<ForwardKey>(key), create_value, modify_value, hash_(key));
476 }
477
484 const Value *lookup_ptr(const Key &key) const
485 {
486 return this->lookup_ptr_as(key);
487 }
488 Value *lookup_ptr(const Key &key)
489 {
490 return this->lookup_ptr_as(key);
491 }
492 template<typename ForwardKey> const Value *lookup_ptr_as(const ForwardKey &key) const
493 {
494 const Slot *slot = this->lookup_slot_ptr(key, hash_(key));
495 return (slot != nullptr) ? slot->value() : nullptr;
496 }
497 template<typename ForwardKey> Value *lookup_ptr_as(const ForwardKey &key)
498 {
499 return const_cast<Value *>(const_cast<const Map *>(this)->lookup_ptr_as(key));
500 }
501
506 const Value &lookup(const Key &key) const
507 {
508 return this->lookup_as(key);
509 }
510 Value &lookup(const Key &key)
511 {
512 return this->lookup_as(key);
513 }
514 template<typename ForwardKey> const Value &lookup_as(const ForwardKey &key) const
515 {
516 const Value *ptr = this->lookup_ptr_as(key);
517 BLI_assert(ptr != nullptr);
518 return *ptr;
519 }
520 template<typename ForwardKey> Value &lookup_as(const ForwardKey &key)
521 {
522 Value *ptr = this->lookup_ptr_as(key);
523 BLI_assert(ptr != nullptr);
524 return *ptr;
525 }
526
531 Value lookup_default(const Key &key, const Value &default_value) const
532 {
533 return this->lookup_default_as(key, default_value);
534 }
535 template<typename ForwardKey, typename... ForwardValue>
536 Value lookup_default_as(const ForwardKey &key, ForwardValue &&...default_value) const
537 {
538 const Value *ptr = this->lookup_ptr_as(key);
539 if (ptr != nullptr) {
540 return *ptr;
541 }
542 else {
543 return Value(std::forward<ForwardValue>(default_value)...);
544 }
545 }
546
551 Value &lookup_or_add(const Key &key, const Value &value)
552 {
553 return this->lookup_or_add_as(key, value);
554 }
555 Value &lookup_or_add(const Key &key, Value &&value)
556 {
557 return this->lookup_or_add_as(key, std::move(value));
558 }
559 Value &lookup_or_add(Key &&key, const Value &value)
560 {
561 return this->lookup_or_add_as(std::move(key), value);
562 }
563 Value &lookup_or_add(Key &&key, Value &&value)
564 {
565 return this->lookup_or_add_as(std::move(key), std::move(value));
566 }
567 template<typename ForwardKey, typename... ForwardValue>
568 Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&...value)
569 {
570 return this->lookup_or_add__impl(
571 std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
572 }
573
581 template<typename CreateValueF>
582 Value &lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
583 {
584 return this->lookup_or_add_cb_as(key, create_value);
585 }
586 template<typename CreateValueF>
587 Value &lookup_or_add_cb(Key &&key, const CreateValueF &create_value)
588 {
589 return this->lookup_or_add_cb_as(std::move(key), create_value);
590 }
591 template<typename ForwardKey, typename CreateValueF>
592 Value &lookup_or_add_cb_as(ForwardKey &&key, const CreateValueF &create_value)
593 {
594 return this->lookup_or_add_cb__impl(std::forward<ForwardKey>(key), create_value, hash_(key));
595 }
596
601 Value &lookup_or_add_default(const Key &key)
602 {
603 return this->lookup_or_add_default_as(key);
604 }
606 {
607 return this->lookup_or_add_default_as(std::move(key));
608 }
609 template<typename ForwardKey> Value &lookup_or_add_default_as(ForwardKey &&key)
610 {
611 return this->lookup_or_add_cb_as(std::forward<ForwardKey>(key), []() { return Value(); });
612 }
613
618 const Key &lookup_key(const Key &key) const
619 {
620 return this->lookup_key_as(key);
621 }
622 template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
623 {
624 const Slot &slot = this->lookup_slot(key, hash_(key));
625 return *slot.key();
626 }
627
632 const Key *lookup_key_ptr(const Key &key) const
633 {
634 return this->lookup_key_ptr_as(key);
635 }
636 template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
637 {
638 const Slot *slot = this->lookup_slot_ptr(key, hash_(key));
639 if (slot == nullptr) {
640 return nullptr;
641 }
642 return slot->key();
643 }
644
649 template<typename FuncT> void foreach_item(const FuncT &func) const
650 {
651 int64_t size = slots_.size();
652 for (int64_t i = 0; i < size; i++) {
653 const Slot &slot = slots_[i];
654 if (slot.is_occupied()) {
655 const Key &key = *slot.key();
656 const Value &value = *slot.value();
657 func(key, value);
658 }
659 }
660 }
661
662 /* Common base class for all iterators below. */
664 public:
665 using iterator_category = std::forward_iterator_tag;
666 using difference_type = std::ptrdiff_t;
667
668 protected:
669 /* We could have separate base iterators for const and non-const iterators, but that would add
670 * more complexity than benefits right now. */
671 Slot *slots_;
674
675 friend Map;
676
677 public:
678 BaseIterator(const Slot *slots, const int64_t total_slots, const int64_t current_slot)
679 : slots_(const_cast<Slot *>(slots)), total_slots_(total_slots), current_slot_(current_slot)
680 {
681 }
682
684 {
685 while (++current_slot_ < total_slots_) {
686 if (slots_[current_slot_].is_occupied()) {
687 break;
688 }
689 }
690 return *this;
691 }
692
694 {
695 BaseIterator copied_iterator = *this;
696 ++(*this);
697 return copied_iterator;
698 }
699
700 friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
701 {
702 BLI_assert(a.slots_ == b.slots_);
703 BLI_assert(a.total_slots_ == b.total_slots_);
704 return a.current_slot_ != b.current_slot_;
705 }
706
707 friend bool operator==(const BaseIterator &a, const BaseIterator &b)
708 {
709 return !(a != b);
710 }
711
712 protected:
713 Slot &current_slot() const
714 {
715 return slots_[current_slot_];
716 }
717 };
718
723 template<typename SubIterator> class BaseIteratorRange : public BaseIterator {
724 public:
725 BaseIteratorRange(const Slot *slots, int64_t total_slots, int64_t current_slot)
726 : BaseIterator(slots, total_slots, current_slot)
727 {
728 }
729
730 SubIterator begin() const
731 {
732 for (int64_t i = 0; i < this->total_slots_; i++) {
733 if (this->slots_[i].is_occupied()) {
734 return SubIterator(this->slots_, this->total_slots_, i);
735 }
736 }
737 return this->end();
738 }
739
740 SubIterator end() const
741 {
742 return SubIterator(this->slots_, this->total_slots_, this->total_slots_);
743 }
744 };
745
746 class KeyIterator final : public BaseIteratorRange<KeyIterator> {
747 public:
749 using pointer = const Key *;
750 using reference = const Key &;
751
752 KeyIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
753 : BaseIteratorRange<KeyIterator>(slots, total_slots, current_slot)
754 {
755 }
756
757 const Key &operator*() const
758 {
759 return *this->current_slot().key();
760 }
761 };
762
763 class ValueIterator final : public BaseIteratorRange<ValueIterator> {
764 public:
766 using pointer = const Value *;
767 using reference = const Value &;
768
769 ValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
770 : BaseIteratorRange<ValueIterator>(slots, total_slots, current_slot)
771 {
772 }
773
774 const Value &operator*() const
775 {
776 return *this->current_slot().value();
777 }
778 };
779
780 class MutableValueIterator final : public BaseIteratorRange<MutableValueIterator> {
781 public:
783 using pointer = Value *;
784 using reference = Value &;
785
788 {
789 }
790
791 Value &operator*()
792 {
793 return *this->current_slot().value();
794 }
795 };
796
797 class ItemIterator final : public BaseIteratorRange<ItemIterator> {
798 public:
800 using pointer = Item *;
801 using reference = Item &;
802
803 ItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
804 : BaseIteratorRange<ItemIterator>(slots, total_slots, current_slot)
805 {
806 }
807
809 {
810 const Slot &slot = this->current_slot();
811 return {*slot.key(), *slot.value()};
812 }
813 };
814
815 class MutableItemIterator final : public BaseIteratorRange<MutableItemIterator> {
816 public:
820
823 {
824 }
825
827 {
828 Slot &slot = this->current_slot();
829 return {*slot.key(), *slot.value()};
830 }
831 };
832
838 {
839 return KeyIterator(slots_.data(), slots_.size(), 0);
840 }
841
847 {
848 return ValueIterator(slots_.data(), slots_.size(), 0);
849 }
850
856 {
857 return MutableValueIterator(slots_.data(), slots_.size(), 0);
858 }
859
865 {
866 return ItemIterator(slots_.data(), slots_.size(), 0);
867 }
868
876 {
877 return MutableItemIterator(slots_.data(), slots_.size(), 0);
878 }
879
885 void remove(const BaseIterator &iterator)
886 {
887 Slot &slot = iterator.current_slot();
888 BLI_assert(slot.is_occupied());
889 slot.remove();
890 removed_slots_++;
891 }
892
899 template<typename Predicate> int64_t remove_if(Predicate &&predicate)
900 {
901 const int64_t prev_size = this->size();
902 for (Slot &slot : slots_) {
903 if (slot.is_occupied()) {
904 const Key &key = *slot.key();
905 Value &value = *slot.value();
906 if (predicate(MutableItem{key, value})) {
907 slot.remove();
908 removed_slots_++;
909 }
910 }
911 }
912 return prev_size - this->size();
913 }
914
918 void print_stats(const char *name) const
919 {
920 HashTableStats stats(*this, this->keys());
921 stats.print(name);
922 }
923
927 int64_t size() const
928 {
929 return occupied_and_removed_slots_ - removed_slots_;
930 }
931
937 bool is_empty() const
938 {
939 return occupied_and_removed_slots_ == removed_slots_;
940 }
941
946 {
947 return slots_.size();
948 }
949
954 {
955 return removed_slots_;
956 }
957
962 {
963 return sizeof(Slot);
964 }
965
971 {
972 return int64_t(sizeof(Slot) * slots_.size());
973 }
974
980 {
981 if (usable_slots_ < n) {
982 this->realloc_and_reinsert(n);
983 }
984 }
985
989 void clear()
990 {
991 for (Slot &slot : slots_) {
992 slot.~Slot();
993 new (&slot) Slot();
994 }
995
996 removed_slots_ = 0;
997 occupied_and_removed_slots_ = 0;
998 }
999
1004 {
1005 std::destroy_at(this);
1006 new (this) Map(NoExceptConstructor{});
1007 }
1008
1013 int64_t count_collisions(const Key &key) const
1014 {
1015 return this->count_collisions__impl(key, hash_(key));
1016 }
1017
1021 friend bool operator==(const Map &a, const Map &b)
1022 {
1023 if (a.size() != b.size()) {
1024 return false;
1025 }
1026 for (const Item item : a.items()) {
1027 const Key &key = item.key;
1028 const Value &value_a = item.value;
1029 const Value *value_b = b.lookup_ptr(key);
1030 if (value_b == nullptr) {
1031 return false;
1032 }
1033 if (value_a != *value_b) {
1034 return false;
1035 }
1036 }
1037 return true;
1038 }
1039
1040 friend bool operator!=(const Map &a, const Map &b)
1041 {
1042 return !(a == b);
1043 }
1044
1045 private:
1046 BLI_NOINLINE void realloc_and_reinsert(int64_t min_usable_slots)
1047 {
1048 int64_t total_slots, usable_slots;
1049 max_load_factor_.compute_total_and_usable_slots(
1050 SlotArray::inline_buffer_capacity(), min_usable_slots, &total_slots, &usable_slots);
1051 BLI_assert(total_slots >= 1);
1052 const uint64_t new_slot_mask = uint64_t(total_slots) - 1;
1053
1057 if (this->size() == 0) {
1058 try {
1059 slots_.reinitialize(total_slots);
1060 }
1061 catch (...) {
1062 this->noexcept_reset();
1063 throw;
1064 }
1065 removed_slots_ = 0;
1066 occupied_and_removed_slots_ = 0;
1067 usable_slots_ = usable_slots;
1068 slot_mask_ = new_slot_mask;
1069 return;
1070 }
1071
1072 SlotArray new_slots(total_slots);
1073
1074 try {
1075 for (Slot &slot : slots_) {
1076 if (slot.is_occupied()) {
1077 this->add_after_grow(slot, new_slots, new_slot_mask);
1078 slot.remove();
1079 }
1080 }
1081 slots_ = std::move(new_slots);
1082 }
1083 catch (...) {
1084 this->noexcept_reset();
1085 throw;
1086 }
1087
1088 occupied_and_removed_slots_ -= removed_slots_;
1089 usable_slots_ = usable_slots;
1090 removed_slots_ = 0;
1091 slot_mask_ = new_slot_mask;
1092 }
1093
1094 void add_after_grow(Slot &old_slot, SlotArray &new_slots, uint64_t new_slot_mask)
1095 {
1096 uint64_t hash = old_slot.get_hash(Hash());
1097 SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
1098 Slot &slot = new_slots[slot_index];
1099 if (slot.is_empty()) {
1100 slot.occupy(std::move(*old_slot.key()), hash, std::move(*old_slot.value()));
1101 return;
1102 }
1103 }
1105 }
1106
1107 void noexcept_reset() noexcept
1108 {
1109 Allocator allocator = slots_.allocator();
1110 this->~Map();
1111 new (this) Map(NoExceptConstructor(), allocator);
1112 }
1113
1114 template<typename ForwardKey, typename... ForwardValue>
1115 void add_new__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1116 {
1117 BLI_assert(!this->contains_as(key));
1118
1119 this->ensure_can_add();
1120
1122 if (slot.is_empty()) {
1123 slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
1124 BLI_assert(hash_(*slot.key()) == hash);
1125 occupied_and_removed_slots_++;
1126 return;
1127 }
1128 }
1130 }
1131
1132 template<typename ForwardKey, typename... ForwardValue>
1133 bool add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1134 {
1135 this->ensure_can_add();
1136
1138 if (slot.is_empty()) {
1139 slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
1140 BLI_assert(hash_(*slot.key()) == hash);
1141 occupied_and_removed_slots_++;
1142 return true;
1143 }
1144 if (slot.contains(key, is_equal_, hash)) {
1145 return false;
1146 }
1147 }
1149 }
1150
1151 template<typename ForwardKey, typename CreateValueF, typename ModifyValueF>
1152 auto add_or_modify__impl(ForwardKey &&key,
1153 const CreateValueF &create_value,
1154 const ModifyValueF &modify_value,
1155 uint64_t hash) -> decltype(create_value(nullptr))
1156 {
1157 using CreateReturnT = decltype(create_value(nullptr));
1158 using ModifyReturnT = decltype(modify_value(nullptr));
1159 BLI_STATIC_ASSERT((std::is_same_v<CreateReturnT, ModifyReturnT>),
1160 "Both callbacks should return the same type.");
1161
1162 this->ensure_can_add();
1163
1165 if (slot.is_empty()) {
1166 Value *value_ptr = slot.value();
1167 if constexpr (std::is_void_v<CreateReturnT>) {
1168 create_value(value_ptr);
1169 slot.occupy_no_value(std::forward<ForwardKey>(key), hash);
1170 occupied_and_removed_slots_++;
1171 return;
1172 }
1173 else {
1174 auto &&return_value = create_value(value_ptr);
1175 slot.occupy_no_value(std::forward<ForwardKey>(key), hash);
1176 occupied_and_removed_slots_++;
1177 return return_value;
1178 }
1179 }
1180 if (slot.contains(key, is_equal_, hash)) {
1181 Value *value_ptr = slot.value();
1182 return modify_value(value_ptr);
1183 }
1184 }
1186 }
1187
1188 template<typename ForwardKey, typename CreateValueF>
1189 Value &lookup_or_add_cb__impl(ForwardKey &&key, const CreateValueF &create_value, uint64_t hash)
1190 {
1191 this->ensure_can_add();
1192
1194 if (slot.is_empty()) {
1195 slot.occupy(std::forward<ForwardKey>(key), hash, create_value());
1196 BLI_assert(hash_(*slot.key()) == hash);
1197 occupied_and_removed_slots_++;
1198 return *slot.value();
1199 }
1200 if (slot.contains(key, is_equal_, hash)) {
1201 return *slot.value();
1202 }
1203 }
1205 }
1206
1207 template<typename ForwardKey, typename... ForwardValue>
1208 Value &lookup_or_add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1209 {
1210 this->ensure_can_add();
1211
1213 if (slot.is_empty()) {
1214 slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
1215 BLI_assert(hash_(*slot.key()) == hash);
1216 occupied_and_removed_slots_++;
1217 return *slot.value();
1218 }
1219 if (slot.contains(key, is_equal_, hash)) {
1220 return *slot.value();
1221 }
1222 }
1224 }
1225
1226 template<typename ForwardKey, typename... ForwardValue>
1227 bool add_overwrite__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&...value)
1228 {
1229 auto create_func = [&](Value *ptr) {
1230 new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value)...);
1231 return true;
1232 };
1233 auto modify_func = [&](Value *ptr) {
1234 *ptr = Value(std::forward<ForwardValue>(value)...);
1235 return false;
1236 };
1237 return this->add_or_modify__impl(
1238 std::forward<ForwardKey>(key), create_func, modify_func, hash);
1239 }
1240
1241 template<typename ForwardKey>
1242 const Slot &lookup_slot(const ForwardKey &key, const uint64_t hash) const
1243 {
1244 BLI_assert(this->contains_as(key));
1246 if (slot.contains(key, is_equal_, hash)) {
1247 return slot;
1248 }
1249 }
1251 }
1252
1253 template<typename ForwardKey> Slot &lookup_slot(const ForwardKey &key, const uint64_t hash)
1254 {
1255 return const_cast<Slot &>(const_cast<const Map *>(this)->lookup_slot(key, hash));
1256 }
1257
1258 template<typename ForwardKey>
1259 const Slot *lookup_slot_ptr(const ForwardKey &key, const uint64_t hash) const
1260 {
1262 if (slot.contains(key, is_equal_, hash)) {
1263 return &slot;
1264 }
1265 if (slot.is_empty()) {
1266 return nullptr;
1267 }
1268 }
1270 }
1271
1272 template<typename ForwardKey> Slot *lookup_slot_ptr(const ForwardKey &key, const uint64_t hash)
1273 {
1274 return const_cast<Slot *>(const_cast<const Map *>(this)->lookup_slot_ptr(key, hash));
1275 }
1276
1277 template<typename ForwardKey>
1278 int64_t count_collisions__impl(const ForwardKey &key, uint64_t hash) const
1279 {
1280 int64_t collisions = 0;
1281
1283 if (slot.contains(key, is_equal_, hash)) {
1284 return collisions;
1285 }
1286 if (slot.is_empty()) {
1287 return collisions;
1288 }
1289 collisions++;
1290 }
1292 }
1293
1294 void ensure_can_add()
1295 {
1296 if (occupied_and_removed_slots_ >= usable_slots_) {
1297 this->realloc_and_reinsert(this->size() + 1);
1298 BLI_assert(occupied_and_removed_slots_ < usable_slots_);
1299 }
1300 }
1301};
1302
1307template<typename Key,
1308 typename Value,
1309 int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key) +
1310 sizeof(Value)),
1311 typename ProbingStrategy = DefaultProbingStrategy,
1312 typename Hash = DefaultHash<Key>,
1313 typename IsEqual = DefaultEquality<Key>,
1314 typename Slot = typename DefaultMapSlot<Key, Value>::type>
1315using RawMap =
1317
1318} // namespace blender
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:87
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_NOINLINE
#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
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue Hue Saturation Value
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Map
int64_t size() const
Definition BLI_array.hh:245
static int64_t inline_buffer_capacity()
Definition BLI_array.hh:379
const T * data() const
Definition BLI_array.hh:301
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
Allocator & allocator()
Definition BLI_array.hh:366
void print(const char *name) const
static constexpr int64_t compute_total_slots(int64_t min_usable_slots, uint8_t numerator, uint8_t denominator)
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
SubIterator begin() const
Definition BLI_map.hh:730
BaseIteratorRange(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:725
SubIterator end() const
Definition BLI_map.hh:740
ItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:803
KeyIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:752
const Key & operator*() const
Definition BLI_map.hh:757
MutableItemIterator(Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:821
MutableItem operator*() const
Definition BLI_map.hh:826
MutableValueIterator(Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:786
const Value & operator*() const
Definition BLI_map.hh:774
ValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition BLI_map.hh:769
MutableItemIterator items()
Definition BLI_map.hh:875
Value pop_as(const ForwardKey &key)
Definition BLI_map.hh:382
bool add_overwrite(Key &&key, Value &&value)
Definition BLI_map.hh:313
Value pop_default_as(const ForwardKey &key, ForwardValue &&...default_value)
Definition BLI_map.hh:424
void clear()
Definition BLI_map.hh:989
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
void print_stats(const char *name) const
Definition BLI_map.hh:918
int64_t size_type
Definition BLI_map.hh:131
int64_t size_in_bytes() const
Definition BLI_map.hh:970
Value pop(const Key &key)
Definition BLI_map.hh:378
Value & lookup(const Key &key)
Definition BLI_map.hh:510
friend bool operator!=(const Map &a, const Map &b)
Definition BLI_map.hh:1040
Value & lookup_as(const ForwardKey &key)
Definition BLI_map.hh:520
std::optional< Value > pop_try(const Key &key)
Definition BLI_map.hh:395
void add_new(const Key &key, Value &&value)
Definition BLI_map.hh:245
Value & lookup_or_add_default(const Key &key)
Definition BLI_map.hh:601
MutableMapItem< Key, Value > MutableItem
Definition BLI_map.hh:133
void add_new(Key &&key, const Value &value)
Definition BLI_map.hh:249
Value & lookup_or_add(Key &&key, const Value &value)
Definition BLI_map.hh:559
const Key & lookup_key_as(const ForwardKey &key) const
Definition BLI_map.hh:622
KeyIterator keys() const
Definition BLI_map.hh:837
Value & lookup_or_add_default(Key &&key)
Definition BLI_map.hh:605
int64_t removed_amount() const
Definition BLI_map.hh:953
Map(NoExceptConstructor, Allocator allocator={}) noexcept
Definition BLI_map.hh:197
bool remove_as(const ForwardKey &key)
Definition BLI_map.hh:348
bool add_overwrite(const Key &key, const Value &value)
Definition BLI_map.hh:301
~Map()=default
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:271
int64_t size_per_element() const
Definition BLI_map.hh:961
const Value & lookup(const Key &key) const
Definition BLI_map.hh:506
Value & lookup_or_add(const Key &key, Value &&value)
Definition BLI_map.hh:555
void remove_contained_as(const ForwardKey &key)
Definition BLI_map.hh:367
Value lookup_default(const Key &key, const Value &default_value) const
Definition BLI_map.hh:531
const Key * lookup_key_ptr_as(const ForwardKey &key) const
Definition BLI_map.hh:636
bool add_overwrite(Key &&key, const Value &value)
Definition BLI_map.hh:309
int64_t count_collisions(const Key &key) const
Definition BLI_map.hh:1013
ValueIterator values() const
Definition BLI_map.hh:846
MutableValueIterator values()
Definition BLI_map.hh:855
Value & lookup_or_add_cb(Key &&key, const CreateValueF &create_value)
Definition BLI_map.hh:587
int64_t capacity() const
Definition BLI_map.hh:945
void add_new_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:258
Value & lookup_or_add_default_as(ForwardKey &&key)
Definition BLI_map.hh:609
Value & lookup_or_add_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:568
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:582
const Value * lookup_ptr_as(const ForwardKey &key) const
Definition BLI_map.hh:492
friend bool operator==(const Map &a, const Map &b)
Definition BLI_map.hh:1021
Value * lookup_ptr(const Key &key)
Definition BLI_map.hh:488
void foreach_item(const FuncT &func) const
Definition BLI_map.hh:649
void remove_contained(const Key &key)
Definition BLI_map.hh:363
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:618
bool add_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:288
auto add_or_modify_as(ForwardKey &&key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:470
void clear_and_shrink()
Definition BLI_map.hh:1003
Value & lookup_or_add_cb_as(ForwardKey &&key, const CreateValueF &create_value)
Definition BLI_map.hh:592
void add_new(Key &&key, Value &&value)
Definition BLI_map.hh:253
const Key * lookup_key_ptr(const Key &key) const
Definition BLI_map.hh:632
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
bool add(Key &&key, Value &&value)
Definition BLI_map.hh:283
Map & operator=(Map &&other)
Definition BLI_map.hh:232
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:514
bool remove(const Key &key)
Definition BLI_map.hh:344
int64_t size() const
Definition BLI_map.hh:927
bool contains_as(const ForwardKey &key) const
Definition BLI_map.hh:333
MapItem< Key, Value > Item
Definition BLI_map.hh:132
ItemIterator items() const
Definition BLI_map.hh:864
bool add(const Key &key, Value &&value)
Definition BLI_map.hh:275
auto add_or_modify(Key &&key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:464
bool is_empty() const
Definition BLI_map.hh:937
void reserve(int64_t n)
Definition BLI_map.hh:979
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&...value)
Definition BLI_map.hh:318
bool contains(const Key &key) const
Definition BLI_map.hh:329
Map & operator=(const Map &other)
Definition BLI_map.hh:227
Value pop_default(const Key &key, Value &&default_value)
Definition BLI_map.hh:419
bool add(Key &&key, const Value &value)
Definition BLI_map.hh:279
Value * lookup_ptr_as(const ForwardKey &key)
Definition BLI_map.hh:497
bool add_overwrite(const Key &key, Value &&value)
Definition BLI_map.hh:305
Value lookup_default_as(const ForwardKey &key, ForwardValue &&...default_value) const
Definition BLI_map.hh:536
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition BLI_map.hh:457
int64_t remove_if(Predicate &&predicate)
Definition BLI_map.hh:899
Value pop_default(const Key &key, const Value &default_value)
Definition BLI_map.hh:415
Value & lookup_or_add(Key &&key, Value &&value)
Definition BLI_map.hh:563
std::optional< Value > pop_try_as(const ForwardKey &key)
Definition BLI_map.hh:399
void remove(const BaseIterator &iterator)
Definition BLI_map.hh:885
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:551
local_group_size(16, 16) .push_constant(Type b
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)
PythonProbingStrategy<> DefaultProbingStrategy
#define hash
Definition noise.c:154
static PyObject * create_func(PyObject *, PyObject *args)
Definition python.cpp:161
__int64 int64_t
Definition stdint.h:89
unsigned __int64 uint64_t
Definition stdint.h:90
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:707
Slot & current_slot() const
Definition BLI_map.hh:713
BaseIterator operator++(int)
Definition BLI_map.hh:693
friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
Definition BLI_map.hh:700
BaseIterator & operator++()
Definition BLI_map.hh:683
std::ptrdiff_t difference_type
Definition BLI_map.hh:666
std::forward_iterator_tag iterator_category
Definition BLI_map.hh:665
BaseIterator(const Slot *slots, const int64_t total_slots, const int64_t current_slot)
Definition BLI_map.hh:678
PointerRNA * ptr
Definition wm_files.cc:4126