Blender  V2.93
BLI_map.hh
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #pragma once
18 
69 #include <optional>
70 #include <unordered_map>
71 
72 #include "BLI_array.hh"
73 #include "BLI_hash.hh"
74 #include "BLI_hash_tables.hh"
75 #include "BLI_map_slots.hh"
77 
78 namespace blender {
79 
80 template<
85  typename Key,
89  typename Value,
95  int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key) + sizeof(Value)),
99  typename ProbingStrategy = DefaultProbingStrategy,
104  typename Hash = DefaultHash<Key>,
109  typename IsEqual = DefaultEquality,
116  typename Slot = typename DefaultMapSlot<Key, Value>::type,
121  typename Allocator = GuardedAllocator>
122 class Map {
123  public:
125 
126  private:
131  int64_t removed_slots_;
132  int64_t occupied_and_removed_slots_;
133 
138  int64_t usable_slots_;
139 
144  uint64_t slot_mask_;
145 
147  Hash hash_;
148 
150  IsEqual is_equal_;
151 
153 #define LOAD_FACTOR 1, 2
154  LoadFactor max_load_factor_ = LoadFactor(LOAD_FACTOR);
155  using SlotArray =
156  Array<Slot, LoadFactor::compute_total_slots(InlineBufferCapacity, LOAD_FACTOR), Allocator>;
157 #undef LOAD_FACTOR
158 
163  SlotArray slots_;
164 
166 #define MAP_SLOT_PROBING_BEGIN(HASH, R_SLOT) \
167  SLOT_PROBING_BEGIN (ProbingStrategy, HASH, slot_mask_, SLOT_INDEX) \
168  auto &R_SLOT = slots_[SLOT_INDEX];
169 #define MAP_SLOT_PROBING_END() SLOT_PROBING_END()
170 
171  public:
177  Map(Allocator allocator = {}) noexcept
178  : removed_slots_(0),
179  occupied_and_removed_slots_(0),
180  usable_slots_(0),
181  slot_mask_(0),
182  hash_(),
183  is_equal_(),
184  slots_(1, allocator)
185  {
186  }
187 
188  Map(NoExceptConstructor, Allocator allocator = {}) noexcept : Map(allocator)
189  {
190  }
191 
192  ~Map() = default;
193 
194  Map(const Map &other) = default;
195 
196  Map(Map &&other) noexcept(std::is_nothrow_move_constructible_v<SlotArray>)
197  : Map(NoExceptConstructor(), other.slots_.allocator())
198  {
199  if constexpr (std::is_nothrow_move_constructible_v<SlotArray>) {
200  slots_ = std::move(other.slots_);
201  }
202  else {
203  try {
204  slots_ = std::move(other.slots_);
205  }
206  catch (...) {
207  other.noexcept_reset();
208  throw;
209  }
210  }
211  removed_slots_ = other.removed_slots_;
212  occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
213  usable_slots_ = other.usable_slots_;
214  slot_mask_ = other.slot_mask_;
215  hash_ = std::move(other.hash_);
216  is_equal_ = std::move(other.is_equal_);
217  other.noexcept_reset();
218  }
219 
220  Map &operator=(const Map &other)
221  {
222  return copy_assign_container(*this, other);
223  }
224 
225  Map &operator=(Map &&other)
226  {
227  return move_assign_container(*this, std::move(other));
228  }
229 
234  void add_new(const Key &key, const Value &value)
235  {
236  this->add_new_as(key, value);
237  }
238  void add_new(const Key &key, Value &&value)
239  {
240  this->add_new_as(key, std::move(value));
241  }
242  void add_new(Key &&key, const Value &value)
243  {
244  this->add_new_as(std::move(key), value);
245  }
246  void add_new(Key &&key, Value &&value)
247  {
248  this->add_new_as(std::move(key), std::move(value));
249  }
250  template<typename ForwardKey, typename ForwardValue>
251  void add_new_as(ForwardKey &&key, ForwardValue &&value)
252  {
253  this->add_new__impl(
254  std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
255  }
256 
264  bool add(const Key &key, const Value &value)
265  {
266  return this->add_as(key, value);
267  }
268  bool add(const Key &key, Value &&value)
269  {
270  return this->add_as(key, std::move(value));
271  }
272  bool add(Key &&key, const Value &value)
273  {
274  return this->add_as(std::move(key), value);
275  }
276  bool add(Key &&key, Value &&value)
277  {
278  return this->add_as(std::move(key), std::move(value));
279  }
280  template<typename ForwardKey, typename ForwardValue>
281  bool add_as(ForwardKey &&key, ForwardValue &&value)
282  {
283  return this->add__impl(
284  std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
285  }
286 
294  bool add_overwrite(const Key &key, const Value &value)
295  {
296  return this->add_overwrite_as(key, value);
297  }
298  bool add_overwrite(const Key &key, Value &&value)
299  {
300  return this->add_overwrite_as(key, std::move(value));
301  }
302  bool add_overwrite(Key &&key, const Value &value)
303  {
304  return this->add_overwrite_as(std::move(key), value);
305  }
306  bool add_overwrite(Key &&key, Value &&value)
307  {
308  return this->add_overwrite_as(std::move(key), std::move(value));
309  }
310  template<typename ForwardKey, typename ForwardValue>
311  bool add_overwrite_as(ForwardKey &&key, ForwardValue &&value)
312  {
313  return this->add_overwrite__impl(
314  std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
315  }
316 
322  bool contains(const Key &key) const
323  {
324  return this->contains_as(key);
325  }
326  template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
327  {
328  return this->lookup_slot_ptr(key, hash_(key)) != nullptr;
329  }
330 
337  bool remove(const Key &key)
338  {
339  return this->remove_as(key);
340  }
341  template<typename ForwardKey> bool remove_as(const ForwardKey &key)
342  {
343  Slot *slot = this->lookup_slot_ptr(key, hash_(key));
344  if (slot == nullptr) {
345  return false;
346  }
347  slot->remove();
348  removed_slots_++;
349  return true;
350  }
351 
356  void remove_contained(const Key &key)
357  {
358  this->remove_contained_as(key);
359  }
360  template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
361  {
362  Slot &slot = this->lookup_slot(key, hash_(key));
363  slot.remove();
364  removed_slots_++;
365  }
366 
371  Value pop(const Key &key)
372  {
373  return this->pop_as(key);
374  }
375  template<typename ForwardKey> Value pop_as(const ForwardKey &key)
376  {
377  Slot &slot = this->lookup_slot(key, hash_(key));
378  Value value = std::move(*slot.value());
379  slot.remove();
380  removed_slots_++;
381  return value;
382  }
383 
388  std::optional<Value> pop_try(const Key &key)
389  {
390  return this->pop_try_as(key);
391  }
392  template<typename ForwardKey> std::optional<Value> pop_try_as(const ForwardKey &key)
393  {
394  Slot *slot = this->lookup_slot_ptr(key, hash_(key));
395  if (slot == nullptr) {
396  return {};
397  }
398  std::optional<Value> value = std::move(*slot->value());
399  slot->remove();
400  removed_slots_++;
401  return value;
402  }
403 
408  Value pop_default(const Key &key, const Value &default_value)
409  {
410  return this->pop_default_as(key, default_value);
411  }
412  Value pop_default(const Key &key, Value &&default_value)
413  {
414  return this->pop_default_as(key, std::move(default_value));
415  }
416  template<typename ForwardKey, typename ForwardValue>
417  Value pop_default_as(const ForwardKey &key, ForwardValue &&default_value)
418  {
419  Slot *slot = this->lookup_slot_ptr(key, hash_(key));
420  if (slot == nullptr) {
421  return std::forward<ForwardValue>(default_value);
422  }
423  Value value = std::move(*slot->value());
424  slot->remove();
425  removed_slots_++;
426  return value;
427  }
428 
449  template<typename CreateValueF, typename ModifyValueF>
450  auto add_or_modify(const Key &key,
451  const CreateValueF &create_value,
452  const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
453  {
454  return this->add_or_modify_as(key, create_value, modify_value);
455  }
456  template<typename CreateValueF, typename ModifyValueF>
457  auto add_or_modify(Key &&key, const CreateValueF &create_value, const ModifyValueF &modify_value)
458  -> decltype(create_value(nullptr))
459  {
460  return this->add_or_modify_as(std::move(key), create_value, modify_value);
461  }
462  template<typename ForwardKey, typename CreateValueF, typename ModifyValueF>
463  auto add_or_modify_as(ForwardKey &&key,
464  const CreateValueF &create_value,
465  const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
466  {
467  return this->add_or_modify__impl(
468  std::forward<ForwardKey>(key), create_value, modify_value, hash_(key));
469  }
470 
477  const Value *lookup_ptr(const Key &key) const
478  {
479  return this->lookup_ptr_as(key);
480  }
481  Value *lookup_ptr(const Key &key)
482  {
483  return this->lookup_ptr_as(key);
484  }
485  template<typename ForwardKey> const Value *lookup_ptr_as(const ForwardKey &key) const
486  {
487  const Slot *slot = this->lookup_slot_ptr(key, hash_(key));
488  return (slot != nullptr) ? slot->value() : nullptr;
489  }
490  template<typename ForwardKey> Value *lookup_ptr_as(const ForwardKey &key)
491  {
492  return const_cast<Value *>(const_cast<const Map *>(this)->lookup_ptr_as(key));
493  }
494 
499  const Value &lookup(const Key &key) const
500  {
501  return this->lookup_as(key);
502  }
503  Value &lookup(const Key &key)
504  {
505  return this->lookup_as(key);
506  }
507  template<typename ForwardKey> const Value &lookup_as(const ForwardKey &key) const
508  {
509  const Value *ptr = this->lookup_ptr_as(key);
510  BLI_assert(ptr != nullptr);
511  return *ptr;
512  }
513  template<typename ForwardKey> Value &lookup_as(const ForwardKey &key)
514  {
515  Value *ptr = this->lookup_ptr_as(key);
516  BLI_assert(ptr != nullptr);
517  return *ptr;
518  }
519 
524  Value lookup_default(const Key &key, const Value &default_value) const
525  {
526  return this->lookup_default_as(key, default_value);
527  }
528  template<typename ForwardKey, typename ForwardValue>
529  Value lookup_default_as(const ForwardKey &key, ForwardValue &&default_value) const
530  {
531  const Value *ptr = this->lookup_ptr_as(key);
532  if (ptr != nullptr) {
533  return *ptr;
534  }
535  else {
536  return std::forward<ForwardValue>(default_value);
537  }
538  }
539 
544  Value &lookup_or_add(const Key &key, const Value &value)
545  {
546  return this->lookup_or_add_as(key, value);
547  }
548  Value &lookup_or_add(const Key &key, Value &&value)
549  {
550  return this->lookup_or_add_as(key, std::move(value));
551  }
552  Value &lookup_or_add(Key &&key, const Value &value)
553  {
554  return this->lookup_or_add_as(std::move(key), value);
555  }
556  Value &lookup_or_add(Key &&key, Value &&value)
557  {
558  return this->lookup_or_add_as(std::move(key), std::move(value));
559  }
560  template<typename ForwardKey, typename ForwardValue>
561  Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&value)
562  {
563  return this->lookup_or_add__impl(
564  std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
565  }
566 
574  template<typename CreateValueF>
575  Value &lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
576  {
577  return this->lookup_or_add_cb_as(key, create_value);
578  }
579  template<typename CreateValueF>
580  Value &lookup_or_add_cb(Key &&key, const CreateValueF &create_value)
581  {
582  return this->lookup_or_add_cb_as(std::move(key), create_value);
583  }
584  template<typename ForwardKey, typename CreateValueF>
585  Value &lookup_or_add_cb_as(ForwardKey &&key, const CreateValueF &create_value)
586  {
587  return this->lookup_or_add_cb__impl(std::forward<ForwardKey>(key), create_value, hash_(key));
588  }
589 
595  {
596  return this->lookup_or_add_default_as(key);
597  }
599  {
600  return this->lookup_or_add_default_as(std::move(key));
601  }
602  template<typename ForwardKey> Value &lookup_or_add_default_as(ForwardKey &&key)
603  {
604  return this->lookup_or_add_cb_as(std::forward<ForwardKey>(key), []() { return Value(); });
605  }
606 
611  template<typename FuncT> void foreach_item(const FuncT &func) const
612  {
613  int64_t size = slots_.size();
614  for (int64_t i = 0; i < size; i++) {
615  const Slot &slot = slots_[i];
616  if (slot.is_occupied()) {
617  const Key &key = *slot.key();
618  const Value &value = *slot.value();
619  func(key, value);
620  }
621  }
622  }
623 
628  template<typename SubIterator> struct BaseIterator {
629  using iterator_category = std::forward_iterator_tag;
630  using difference_type = std::ptrdiff_t;
631 
632  Slot *slots_;
635 
636  BaseIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
637  : slots_(const_cast<Slot *>(slots)), total_slots_(total_slots), current_slot_(current_slot)
638  {
639  }
640 
642  {
643  while (++current_slot_ < total_slots_) {
644  if (slots_[current_slot_].is_occupied()) {
645  break;
646  }
647  }
648  return *this;
649  }
650 
652  {
653  BaseIterator copied_iterator = *this;
654  ++copied_iterator;
655  return copied_iterator;
656  }
657 
658  friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
659  {
660  BLI_assert(a.slots_ == b.slots_);
661  BLI_assert(a.total_slots_ == b.total_slots_);
662  return a.current_slot_ != b.current_slot_;
663  }
664 
665  friend bool operator==(const BaseIterator &a, const BaseIterator &b)
666  {
667  return !(a != b);
668  }
669 
670  SubIterator begin() const
671  {
672  for (int64_t i = 0; i < total_slots_; i++) {
673  if (slots_[i].is_occupied()) {
674  return SubIterator(slots_, total_slots_, i);
675  }
676  }
677  return this->end();
678  }
679 
680  SubIterator end() const
681  {
682  return SubIterator(slots_, total_slots_, total_slots_);
683  }
684 
685  Slot &current_slot() const
686  {
687  return slots_[current_slot_];
688  }
689  };
690 
691  class KeyIterator final : public BaseIterator<KeyIterator> {
692  public:
693  using value_type = Key;
694  using pointer = const Key *;
695  using reference = const Key &;
696 
697  KeyIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
698  : BaseIterator<KeyIterator>(slots, total_slots, current_slot)
699  {
700  }
701 
702  const Key &operator*() const
703  {
704  return *this->current_slot().key();
705  }
706  };
707 
708  class ValueIterator final : public BaseIterator<ValueIterator> {
709  public:
710  using value_type = Value;
711  using pointer = const Value *;
712  using reference = const Value &;
713 
714  ValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
715  : BaseIterator<ValueIterator>(slots, total_slots, current_slot)
716  {
717  }
718 
719  const Value &operator*() const
720  {
721  return *this->current_slot().value();
722  }
723  };
724 
725  class MutableValueIterator final : public BaseIterator<MutableValueIterator> {
726  public:
727  using value_type = Value;
728  using pointer = Value *;
729  using reference = Value &;
730 
731  MutableValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
732  : BaseIterator<MutableValueIterator>(slots, total_slots, current_slot)
733  {
734  }
735 
737  {
738  return *this->current_slot().value();
739  }
740  };
741 
742  struct Item {
743  const Key &key;
744  const Value &value;
745  };
746 
747  struct MutableItem {
748  const Key &key;
750 
751  operator Item() const
752  {
753  return Item{key, value};
754  }
755  };
756 
757  class ItemIterator final : public BaseIterator<ItemIterator> {
758  public:
759  using value_type = Item;
760  using pointer = Item *;
761  using reference = Item &;
762 
763  ItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
764  : BaseIterator<ItemIterator>(slots, total_slots, current_slot)
765  {
766  }
767 
768  Item operator*() const
769  {
770  const Slot &slot = this->current_slot();
771  return {*slot.key(), *slot.value()};
772  }
773  };
774 
775  class MutableItemIterator final : public BaseIterator<MutableItemIterator> {
776  public:
778  using pointer = MutableItem *;
780 
781  MutableItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
782  : BaseIterator<MutableItemIterator>(slots, total_slots, current_slot)
783  {
784  }
785 
787  {
788  Slot &slot = this->current_slot();
789  return {*slot.key(), *slot.value()};
790  }
791  };
792 
798  {
799  return KeyIterator(slots_.data(), slots_.size(), 0);
800  }
801 
807  {
808  return ValueIterator(slots_.data(), slots_.size(), 0);
809  }
810 
816  {
817  return MutableValueIterator(slots_.data(), slots_.size(), 0);
818  }
819 
826  {
827  return ItemIterator(slots_.data(), slots_.size(), 0);
828  }
829 
838  {
839  return MutableItemIterator(slots_.data(), slots_.size(), 0);
840  }
841 
845  void print_stats(StringRef name = "") const
846  {
847  HashTableStats stats(*this, this->keys());
848  stats.print(name);
849  }
850 
854  int64_t size() const
855  {
856  return occupied_and_removed_slots_ - removed_slots_;
857  }
858 
864  bool is_empty() const
865  {
866  return occupied_and_removed_slots_ == removed_slots_;
867  }
868 
873  {
874  return slots_.size();
875  }
876 
881  {
882  return removed_slots_;
883  }
884 
889  {
890  return sizeof(Slot);
891  }
892 
898  {
899  return static_cast<int64_t>(sizeof(Slot) * slots_.size());
900  }
901 
906  void reserve(int64_t n)
907  {
908  if (usable_slots_ < n) {
909  this->realloc_and_reinsert(n);
910  }
911  }
912 
916  void clear()
917  {
918  this->noexcept_reset();
919  }
920 
925  int64_t count_collisions(const Key &key) const
926  {
927  return this->count_collisions__impl(key, hash_(key));
928  }
929 
930  private:
931  BLI_NOINLINE void realloc_and_reinsert(int64_t min_usable_slots)
932  {
933  int64_t total_slots, usable_slots;
934  max_load_factor_.compute_total_and_usable_slots(
935  SlotArray::inline_buffer_capacity(), min_usable_slots, &total_slots, &usable_slots);
936  BLI_assert(total_slots >= 1);
937  const uint64_t new_slot_mask = static_cast<uint64_t>(total_slots) - 1;
938 
942  if (this->size() == 0) {
943  try {
944  slots_.reinitialize(total_slots);
945  }
946  catch (...) {
947  this->noexcept_reset();
948  throw;
949  }
950  removed_slots_ = 0;
951  occupied_and_removed_slots_ = 0;
952  usable_slots_ = usable_slots;
953  slot_mask_ = new_slot_mask;
954  return;
955  }
956 
957  SlotArray new_slots(total_slots);
958 
959  try {
960  for (Slot &slot : slots_) {
961  if (slot.is_occupied()) {
962  this->add_after_grow(slot, new_slots, new_slot_mask);
963  slot.remove();
964  }
965  }
966  slots_ = std::move(new_slots);
967  }
968  catch (...) {
969  this->noexcept_reset();
970  throw;
971  }
972 
973  occupied_and_removed_slots_ -= removed_slots_;
974  usable_slots_ = usable_slots;
975  removed_slots_ = 0;
976  slot_mask_ = new_slot_mask;
977  }
978 
979  void add_after_grow(Slot &old_slot, SlotArray &new_slots, uint64_t new_slot_mask)
980  {
981  uint64_t hash = old_slot.get_hash(Hash());
982  SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
983  Slot &slot = new_slots[slot_index];
984  if (slot.is_empty()) {
985  slot.occupy(std::move(*old_slot.key()), std::move(*old_slot.value()), hash);
986  return;
987  }
988  }
990  }
991 
992  void noexcept_reset() noexcept
993  {
994  Allocator allocator = slots_.allocator();
995  this->~Map();
996  new (this) Map(NoExceptConstructor(), allocator);
997  }
998 
999  template<typename ForwardKey, typename ForwardValue>
1000  void add_new__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
1001  {
1002  BLI_assert(!this->contains_as(key));
1003 
1004  this->ensure_can_add();
1005 
1006  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1007  if (slot.is_empty()) {
1008  slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
1009  occupied_and_removed_slots_++;
1010  return;
1011  }
1012  }
1014  }
1015 
1016  template<typename ForwardKey, typename ForwardValue>
1017  bool add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
1018  {
1019  this->ensure_can_add();
1020 
1021  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1022  if (slot.is_empty()) {
1023  slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
1024  occupied_and_removed_slots_++;
1025  return true;
1026  }
1027  if (slot.contains(key, is_equal_, hash)) {
1028  return false;
1029  }
1030  }
1032  }
1033 
1034  template<typename ForwardKey, typename CreateValueF, typename ModifyValueF>
1035  auto add_or_modify__impl(ForwardKey &&key,
1036  const CreateValueF &create_value,
1037  const ModifyValueF &modify_value,
1038  uint64_t hash) -> decltype(create_value(nullptr))
1039  {
1040  using CreateReturnT = decltype(create_value(nullptr));
1041  using ModifyReturnT = decltype(modify_value(nullptr));
1042  BLI_STATIC_ASSERT((std::is_same_v<CreateReturnT, ModifyReturnT>),
1043  "Both callbacks should return the same type.");
1044 
1045  this->ensure_can_add();
1046 
1047  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1048  if (slot.is_empty()) {
1049  Value *value_ptr = slot.value();
1050  if constexpr (std::is_void_v<CreateReturnT>) {
1051  create_value(value_ptr);
1052  slot.occupy_no_value(std::forward<ForwardKey>(key), hash);
1053  occupied_and_removed_slots_++;
1054  return;
1055  }
1056  else {
1057  auto &&return_value = create_value(value_ptr);
1058  slot.occupy_no_value(std::forward<ForwardKey>(key), hash);
1059  occupied_and_removed_slots_++;
1060  return return_value;
1061  }
1062  }
1063  if (slot.contains(key, is_equal_, hash)) {
1064  Value *value_ptr = slot.value();
1065  return modify_value(value_ptr);
1066  }
1067  }
1069  }
1070 
1071  template<typename ForwardKey, typename CreateValueF>
1072  Value &lookup_or_add_cb__impl(ForwardKey &&key, const CreateValueF &create_value, uint64_t hash)
1073  {
1074  this->ensure_can_add();
1075 
1076  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1077  if (slot.is_empty()) {
1078  slot.occupy(std::forward<ForwardKey>(key), create_value(), hash);
1079  occupied_and_removed_slots_++;
1080  return *slot.value();
1081  }
1082  if (slot.contains(key, is_equal_, hash)) {
1083  return *slot.value();
1084  }
1085  }
1087  }
1088 
1089  template<typename ForwardKey, typename ForwardValue>
1090  Value &lookup_or_add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
1091  {
1092  this->ensure_can_add();
1093 
1094  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1095  if (slot.is_empty()) {
1096  slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
1097  occupied_and_removed_slots_++;
1098  return *slot.value();
1099  }
1100  if (slot.contains(key, is_equal_, hash)) {
1101  return *slot.value();
1102  }
1103  }
1105  }
1106 
1107  template<typename ForwardKey, typename ForwardValue>
1108  bool add_overwrite__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
1109  {
1110  auto create_func = [&](Value *ptr) {
1111  new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value));
1112  return true;
1113  };
1114  auto modify_func = [&](Value *ptr) {
1115  *ptr = std::forward<ForwardValue>(value);
1116  return false;
1117  };
1118  return this->add_or_modify__impl(
1119  std::forward<ForwardKey>(key), create_func, modify_func, hash);
1120  }
1121 
1122  template<typename ForwardKey>
1123  const Slot &lookup_slot(const ForwardKey &key, const uint64_t hash) const
1124  {
1125  BLI_assert(this->contains_as(key));
1126  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1127  if (slot.contains(key, is_equal_, hash)) {
1128  return slot;
1129  }
1130  }
1132  }
1133 
1134  template<typename ForwardKey> Slot &lookup_slot(const ForwardKey &key, const uint64_t hash)
1135  {
1136  return const_cast<Slot &>(const_cast<const Map *>(this)->lookup_slot(key, hash));
1137  }
1138 
1139  template<typename ForwardKey>
1140  const Slot *lookup_slot_ptr(const ForwardKey &key, const uint64_t hash) const
1141  {
1142  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1143  if (slot.contains(key, is_equal_, hash)) {
1144  return &slot;
1145  }
1146  if (slot.is_empty()) {
1147  return nullptr;
1148  }
1149  }
1151  }
1152 
1153  template<typename ForwardKey> Slot *lookup_slot_ptr(const ForwardKey &key, const uint64_t hash)
1154  {
1155  return const_cast<Slot *>(const_cast<const Map *>(this)->lookup_slot_ptr(key, hash));
1156  }
1157 
1158  template<typename ForwardKey>
1159  int64_t count_collisions__impl(const ForwardKey &key, uint64_t hash) const
1160  {
1161  int64_t collisions = 0;
1162 
1163  MAP_SLOT_PROBING_BEGIN (hash, slot) {
1164  if (slot.contains(key, is_equal_, hash)) {
1165  return collisions;
1166  }
1167  if (slot.is_empty()) {
1168  return collisions;
1169  }
1170  collisions++;
1171  }
1173  }
1174 
1175  void ensure_can_add()
1176  {
1177  if (occupied_and_removed_slots_ >= usable_slots_) {
1178  this->realloc_and_reinsert(this->size() + 1);
1179  BLI_assert(occupied_and_removed_slots_ < usable_slots_);
1180  }
1181  }
1182 };
1183 
1188 template<typename Key,
1189  typename Value,
1190  int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key) +
1191  sizeof(Value)),
1192  typename ProbingStrategy = DefaultProbingStrategy,
1193  typename Hash = DefaultHash<Key>,
1194  typename IsEqual = DefaultEquality,
1195  typename Slot = typename DefaultMapSlot<Key, Value>::type>
1196 using RawMap =
1198 
1203 template<typename Key, typename Value> class StdUnorderedMapWrapper {
1204  private:
1205  using MapType = std::unordered_map<Key, Value, blender::DefaultHash<Key>>;
1206  MapType map_;
1207 
1208  public:
1209  int64_t size() const
1210  {
1211  return static_cast<int64_t>(map_.size());
1212  }
1213 
1214  bool is_empty() const
1215  {
1216  return map_.empty();
1217  }
1218 
1220  {
1221  map_.reserve(n);
1222  }
1223 
1224  template<typename ForwardKey, typename ForwardValue>
1225  void add_new(ForwardKey &&key, ForwardValue &&value)
1226  {
1227  map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)});
1228  }
1229 
1230  template<typename ForwardKey, typename ForwardValue>
1231  bool add(ForwardKey &&key, ForwardValue &&value)
1232  {
1233  return map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)}).second;
1234  }
1235 
1236  bool contains(const Key &key) const
1237  {
1238  return map_.find(key) != map_.end();
1239  }
1240 
1241  bool remove(const Key &key)
1242  {
1243  return (bool)map_.erase(key);
1244  }
1245 
1246  Value &lookup(const Key &key)
1247  {
1248  return map_.find(key)->second;
1249  }
1250 
1251  const Value &lookup(const Key &key) const
1252  {
1253  return map_.find(key)->second;
1254  }
1255 
1256  void clear()
1257  {
1258  map_.clear();
1259  }
1260 
1261  void print_stats(StringRef UNUSED(name) = "") const
1262  {
1263  }
1264 };
1265 
1266 } // namespace blender
#define BLI_STATIC_ASSERT(a, msg)
Definition: BLI_assert.h:86
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_NOINLINE
#define final(a, b, c)
Definition: BLI_hash.h:35
#define LOAD_FACTOR
Definition: BLI_map.hh:153
#define MAP_SLOT_PROBING_END()
Definition: BLI_map.hh:169
#define MAP_SLOT_PROBING_BEGIN(HASH, R_SLOT)
Definition: BLI_map.hh:166
#define SLOT_PROBING_BEGIN(PROBING_STRATEGY, HASH, MASK, R_SLOT_INDEX)
#define SLOT_PROBING_END()
#define UNUSED(x)
struct Key Key
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume Image Sky Noise Wave Voronoi Brick Texture Vector Combine Vertex Separate Vector White Value
static PyObject * create_func(PyObject *, PyObject *args)
static int64_t inline_buffer_capacity()
Definition: BLI_array.hh:375
void print(StringRef name="")
static constexpr int64_t compute_total_slots(int64_t min_usable_slots, uint8_t numerator, uint8_t denominator)
Item operator*() const
Definition: BLI_map.hh:768
ItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition: BLI_map.hh:763
KeyIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition: BLI_map.hh:697
const Key & operator*() const
Definition: BLI_map.hh:702
MutableItem operator*() const
Definition: BLI_map.hh:786
MutableItemIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition: BLI_map.hh:781
MutableValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition: BLI_map.hh:731
const Value & reference
Definition: BLI_map.hh:712
const Value & operator*() const
Definition: BLI_map.hh:719
ValueIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition: BLI_map.hh:714
MutableItemIterator items()
Definition: BLI_map.hh:837
Value pop_default_as(const ForwardKey &key, ForwardValue &&default_value)
Definition: BLI_map.hh:417
Map & operator=(Map &&other)
Definition: BLI_map.hh:225
Value pop_as(const ForwardKey &key)
Definition: BLI_map.hh:375
bool add_overwrite(Key &&key, Value &&value)
Definition: BLI_map.hh:306
Value & lookup_or_add_default_as(ForwardKey &&key)
Definition: BLI_map.hh:602
void clear()
Definition: BLI_map.hh:916
int64_t size_type
Definition: BLI_map.hh:124
int64_t size_in_bytes() const
Definition: BLI_map.hh:897
Value pop(const Key &key)
Definition: BLI_map.hh:371
void add_new(const Key &key, Value &&value)
Definition: BLI_map.hh:238
void add_new(Key &&key, const Value &value)
Definition: BLI_map.hh:242
KeyIterator keys() const
Definition: BLI_map.hh:797
int64_t removed_amount() const
Definition: BLI_map.hh:880
Map(NoExceptConstructor, Allocator allocator={}) noexcept
Definition: BLI_map.hh:188
Value & lookup_as(const ForwardKey &key)
Definition: BLI_map.hh:513
Map & operator=(const Map &other)
Definition: BLI_map.hh:220
bool remove_as(const ForwardKey &key)
Definition: BLI_map.hh:341
bool add_overwrite(const Key &key, const Value &value)
Definition: BLI_map.hh:294
std::optional< Value > pop_try_as(const ForwardKey &key)
Definition: BLI_map.hh:392
~Map()=default
void add_new_as(ForwardKey &&key, ForwardValue &&value)
Definition: BLI_map.hh:251
Value & lookup_or_add_cb(Key &&key, const CreateValueF &create_value)
Definition: BLI_map.hh:580
bool add(const Key &key, const Value &value)
Definition: BLI_map.hh:264
int64_t size_per_element() const
Definition: BLI_map.hh:888
Value & lookup_or_add(Key &&key, const Value &value)
Definition: BLI_map.hh:552
void remove_contained_as(const ForwardKey &key)
Definition: BLI_map.hh:360
void print_stats(StringRef name="") const
Definition: BLI_map.hh:845
Value lookup_default(const Key &key, const Value &default_value) const
Definition: BLI_map.hh:524
Value & lookup_or_add(Key &&key, Value &&value)
Definition: BLI_map.hh:556
bool add_overwrite(Key &&key, const Value &value)
Definition: BLI_map.hh:302
int64_t count_collisions(const Key &key) const
Definition: BLI_map.hh:925
ValueIterator values() const
Definition: BLI_map.hh:806
MutableValueIterator values()
Definition: BLI_map.hh:815
Value & lookup_or_add_default(Key &&key)
Definition: BLI_map.hh:598
int64_t capacity() const
Definition: BLI_map.hh:872
const Value * lookup_ptr_as(const ForwardKey &key) const
Definition: BLI_map.hh:485
const Value & lookup(const Key &key) const
Definition: BLI_map.hh:499
Value * lookup_ptr_as(const ForwardKey &key)
Definition: BLI_map.hh:490
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition: BLI_map.hh:575
Value & lookup_or_add_cb_as(ForwardKey &&key, const CreateValueF &create_value)
Definition: BLI_map.hh:585
void foreach_item(const FuncT &func) const
Definition: BLI_map.hh:611
void remove_contained(const Key &key)
Definition: BLI_map.hh:356
Map(const Map &other)=default
Map(Allocator allocator={}) noexcept
Definition: BLI_map.hh:177
Value & lookup_or_add_default(const Key &key)
Definition: BLI_map.hh:594
auto add_or_modify_as(ForwardKey &&key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition: BLI_map.hh:463
void add_new(Key &&key, Value &&value)
Definition: BLI_map.hh:246
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:234
bool add(Key &&key, Value &&value)
Definition: BLI_map.hh:276
Map(Map &&other) noexcept(std::is_nothrow_move_constructible_v< SlotArray >)
Definition: BLI_map.hh:196
Value & lookup_or_add(const Key &key, const Value &value)
Definition: BLI_map.hh:544
bool add_as(ForwardKey &&key, ForwardValue &&value)
Definition: BLI_map.hh:281
bool remove(const Key &key)
Definition: BLI_map.hh:337
int64_t size() const
Definition: BLI_map.hh:854
bool contains_as(const ForwardKey &key) const
Definition: BLI_map.hh:326
ItemIterator items() const
Definition: BLI_map.hh:825
const Value & lookup_as(const ForwardKey &key) const
Definition: BLI_map.hh:507
bool add(const Key &key, Value &&value)
Definition: BLI_map.hh:268
Value & lookup_or_add(const Key &key, Value &&value)
Definition: BLI_map.hh:548
auto add_or_modify(Key &&key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition: BLI_map.hh:457
bool is_empty() const
Definition: BLI_map.hh:864
void reserve(int64_t n)
Definition: BLI_map.hh:906
Value & lookup(const Key &key)
Definition: BLI_map.hh:503
Value lookup_default_as(const ForwardKey &key, ForwardValue &&default_value) const
Definition: BLI_map.hh:529
bool contains(const Key &key) const
Definition: BLI_map.hh:322
Value pop_default(const Key &key, Value &&default_value)
Definition: BLI_map.hh:412
bool add(Key &&key, const Value &value)
Definition: BLI_map.hh:272
bool add_overwrite(const Key &key, Value &&value)
Definition: BLI_map.hh:298
Value * lookup_ptr(const Key &key)
Definition: BLI_map.hh:481
const Value * lookup_ptr(const Key &key) const
Definition: BLI_map.hh:477
auto add_or_modify(const Key &key, const CreateValueF &create_value, const ModifyValueF &modify_value) -> decltype(create_value(nullptr))
Definition: BLI_map.hh:450
bool add_overwrite_as(ForwardKey &&key, ForwardValue &&value)
Definition: BLI_map.hh:311
Value & lookup_or_add_as(ForwardKey &&key, ForwardValue &&value)
Definition: BLI_map.hh:561
Value pop_default(const Key &key, const Value &default_value)
Definition: BLI_map.hh:408
std::optional< Value > pop_try(const Key &key)
Definition: BLI_map.hh:388
const Value & lookup(const Key &key) const
Definition: BLI_map.hh:1251
void add_new(ForwardKey &&key, ForwardValue &&value)
Definition: BLI_map.hh:1225
bool add(ForwardKey &&key, ForwardValue &&value)
Definition: BLI_map.hh:1231
bool contains(const Key &key) const
Definition: BLI_map.hh:1236
void print_stats(StringRef UNUSED(name)="") const
Definition: BLI_map.hh:1261
bool remove(const Key &key)
Definition: BLI_map.hh:1241
Value & lookup(const Key &key)
Definition: BLI_map.hh:1246
static unsigned a[3]
Definition: RandGen.cpp:92
Container & move_assign_container(Container &dst, Container &&src) noexcept(std::is_nothrow_move_constructible_v< Container >)
Container & copy_assign_container(Container &dst, const Container &src)
PythonProbingStrategy<> DefaultProbingStrategy
constexpr int64_t default_inline_buffer_capacity(size_t element_size)
#define hash
Definition: noise.c:169
__int64 int64_t
Definition: stdint.h:92
unsigned __int64 uint64_t
Definition: stdint.h:93
SimpleMapSlot< Key, Value > type
friend bool operator==(const BaseIterator &a, const BaseIterator &b)
Definition: BLI_map.hh:665
BaseIterator & operator++()
Definition: BLI_map.hh:641
BaseIterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition: BLI_map.hh:636
std::forward_iterator_tag iterator_category
Definition: BLI_map.hh:629
std::ptrdiff_t difference_type
Definition: BLI_map.hh:630
friend bool operator!=(const BaseIterator &a, const BaseIterator &b)
Definition: BLI_map.hh:658
BaseIterator operator++(int) const
Definition: BLI_map.hh:651
SubIterator end() const
Definition: BLI_map.hh:680
SubIterator begin() const
Definition: BLI_map.hh:670
Slot & current_slot() const
Definition: BLI_map.hh:685
const Key & key
Definition: BLI_map.hh:743
const Value & value
Definition: BLI_map.hh:744
PointerRNA * ptr
Definition: wm_files.c:3157