Blender  V2.93
BLI_set.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 
72 #include <unordered_set>
73 
74 #include "BLI_array.hh"
75 #include "BLI_hash.hh"
76 #include "BLI_hash_tables.hh"
78 #include "BLI_set_slots.hh"
79 
80 namespace blender {
81 
82 template<
86  typename Key,
92  int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key)),
96  typename ProbingStrategy = DefaultProbingStrategy,
101  typename Hash = DefaultHash<Key>,
106  typename IsEqual = DefaultEquality,
115  typename Slot = typename DefaultSetSlot<Key>::type,
120  typename Allocator = GuardedAllocator>
121 class Set {
122  public:
123  class Iterator;
124  using value_type = Key;
125  using pointer = Key *;
126  using const_pointer = const Key *;
127  using reference = Key &;
128  using const_reference = const Key &;
131 
132  private:
137  int64_t removed_slots_;
138  int64_t occupied_and_removed_slots_;
139 
144  int64_t usable_slots_;
145 
150  uint64_t slot_mask_;
151 
153  Hash hash_;
154 
156  IsEqual is_equal_;
157 
159 #define LOAD_FACTOR 1, 2
160  LoadFactor max_load_factor_ = LoadFactor(LOAD_FACTOR);
161  using SlotArray =
162  Array<Slot, LoadFactor::compute_total_slots(InlineBufferCapacity, LOAD_FACTOR), Allocator>;
163 #undef LOAD_FACTOR
164 
169  SlotArray slots_;
170 
172 #define SET_SLOT_PROBING_BEGIN(HASH, R_SLOT) \
173  SLOT_PROBING_BEGIN (ProbingStrategy, HASH, slot_mask_, SLOT_INDEX) \
174  auto &R_SLOT = slots_[SLOT_INDEX];
175 #define SET_SLOT_PROBING_END() SLOT_PROBING_END()
176 
177  public:
183  Set(Allocator allocator = {}) noexcept
184  : removed_slots_(0),
185  occupied_and_removed_slots_(0),
186  usable_slots_(0),
187  slot_mask_(0),
188  slots_(1, allocator)
189  {
190  }
191 
192  Set(NoExceptConstructor, Allocator allocator = {}) noexcept : Set(allocator)
193  {
194  }
195 
196  Set(Span<Key> values, Allocator allocator = {}) : Set(NoExceptConstructor(), allocator)
197  {
198  this->add_multiple(values);
199  }
200 
204  Set(const std::initializer_list<Key> &values) : Set(Span<Key>(values))
205  {
206  }
207 
208  ~Set() = default;
209 
210  Set(const Set &other) = default;
211 
212  Set(Set &&other) noexcept(std::is_nothrow_move_constructible_v<SlotArray>)
213  : Set(NoExceptConstructor(), other.slots_.allocator())
214 
215  {
216  if constexpr (std::is_nothrow_move_constructible_v<SlotArray>) {
217  slots_ = std::move(other.slots_);
218  }
219  else {
220  try {
221  slots_ = std::move(other.slots_);
222  }
223  catch (...) {
224  other.noexcept_reset();
225  throw;
226  }
227  }
228  removed_slots_ = other.removed_slots_;
229  occupied_and_removed_slots_ = other.occupied_and_removed_slots_;
230  usable_slots_ = other.usable_slots_;
231  slot_mask_ = other.slot_mask_;
232  hash_ = std::move(other.hash_);
233  is_equal_ = std::move(other.is_equal_);
234  other.noexcept_reset();
235  }
236 
237  Set &operator=(const Set &other)
238  {
239  return copy_assign_container(*this, other);
240  }
241 
242  Set &operator=(Set &&other)
243  {
244  return move_assign_container(*this, std::move(other));
245  }
246 
252  void add_new(const Key &key)
253  {
254  this->add_new__impl(key, hash_(key));
255  }
256  void add_new(Key &&key)
257  {
258  this->add_new__impl(std::move(key), hash_(key));
259  }
260 
267  bool add(const Key &key)
268  {
269  return this->add_as(key);
270  }
271  bool add(Key &&key)
272  {
273  return this->add_as(std::move(key));
274  }
275  template<typename ForwardKey> bool add_as(ForwardKey &&key)
276  {
277  return this->add__impl(std::forward<ForwardKey>(key), hash_(key));
278  }
279 
288  {
289  for (const Key &key : keys) {
290  this->add(key);
291  }
292  }
293 
299  {
300  for (const Key &key : keys) {
301  this->add_new(key);
302  }
303  }
304 
310  bool contains(const Key &key) const
311  {
312  return this->contains_as(key);
313  }
314  template<typename ForwardKey> bool contains_as(const ForwardKey &key) const
315  {
316  return this->contains__impl(key, hash_(key));
317  }
318 
323  const Key &lookup_key(const Key &key) const
324  {
325  return this->lookup_key_as(key);
326  }
327  template<typename ForwardKey> const Key &lookup_key_as(const ForwardKey &key) const
328  {
329  return this->lookup_key__impl(key, hash_(key));
330  }
331 
336  const Key &lookup_key_default(const Key &key, const Key &default_value) const
337  {
338  return this->lookup_key_default_as(key, default_value);
339  }
340  template<typename ForwardKey>
341  const Key &lookup_key_default_as(const ForwardKey &key, const Key &default_key) const
342  {
343  const Key *ptr = this->lookup_key_ptr__impl(key, hash_(key));
344  if (ptr == nullptr) {
345  return default_key;
346  }
347  return *ptr;
348  }
349 
354  const Key *lookup_key_ptr(const Key &key) const
355  {
356  return this->lookup_key_ptr_as(key);
357  }
358  template<typename ForwardKey> const Key *lookup_key_ptr_as(const ForwardKey &key) const
359  {
360  return this->lookup_key_ptr__impl(key, hash_(key));
361  }
362 
367  const Key &lookup_key_or_add(const Key &key)
368  {
369  return this->lookup_key_or_add_as(key);
370  }
371  const Key &lookup_key_or_add(Key &&key)
372  {
373  return this->lookup_key_or_add_as(std::move(key));
374  }
375  template<typename ForwardKey> const Key &lookup_key_or_add_as(ForwardKey &&key)
376  {
377  return this->lookup_key_or_add__impl(std::forward<ForwardKey>(key), hash_(key));
378  }
379 
385  bool remove(const Key &key)
386  {
387  return this->remove_as(key);
388  }
389  template<typename ForwardKey> bool remove_as(const ForwardKey &key)
390  {
391  return this->remove__impl(key, hash_(key));
392  }
393 
397  void remove_contained(const Key &key)
398  {
399  this->remove_contained_as(key);
400  }
401  template<typename ForwardKey> void remove_contained_as(const ForwardKey &key)
402  {
403  this->remove_contained__impl(key, hash_(key));
404  }
405 
413  class Iterator {
414  public:
415  using iterator_category = std::forward_iterator_tag;
416  using value_type = Key;
417  using pointer = const Key *;
418  using reference = const Key &;
419  using difference_type = std::ptrdiff_t;
420 
421  private:
422  const Slot *slots_;
423  int64_t total_slots_;
424  int64_t current_slot_;
425 
426  public:
427  Iterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
428  : slots_(slots), total_slots_(total_slots), current_slot_(current_slot)
429  {
430  }
431 
433  {
434  while (++current_slot_ < total_slots_) {
435  if (slots_[current_slot_].is_occupied()) {
436  break;
437  }
438  }
439  return *this;
440  }
441 
442  Iterator operator++(int) const
443  {
444  Iterator copied_iterator = *this;
445  ++copied_iterator;
446  return copied_iterator;
447  }
448 
449  const Key &operator*() const
450  {
451  return *slots_[current_slot_].key();
452  }
453 
454  const Key *operator->() const
455  {
456  return slots_[current_slot_].key();
457  }
458 
459  friend bool operator!=(const Iterator &a, const Iterator &b)
460  {
461  BLI_assert(a.slots_ == b.slots_);
462  BLI_assert(a.total_slots_ == b.total_slots_);
463  return a.current_slot_ != b.current_slot_;
464  }
465 
466  friend bool operator==(const Iterator &a, const Iterator &b)
467  {
468  return !(a != b);
469  }
470  };
471 
472  Iterator begin() const
473  {
474  for (int64_t i = 0; i < slots_.size(); i++) {
475  if (slots_[i].is_occupied()) {
476  return Iterator(slots_.data(), slots_.size(), i);
477  }
478  }
479  return this->end();
480  }
481 
482  Iterator end() const
483  {
484  return Iterator(slots_.data(), slots_.size(), slots_.size());
485  }
486 
490  void print_stats(StringRef name = "") const
491  {
492  HashTableStats stats(*this, *this);
493  stats.print(name);
494  }
495 
500  int64_t count_collisions(const Key &key) const
501  {
502  return this->count_collisions__impl(key, hash_(key));
503  }
504 
508  void clear()
509  {
510  this->~Set();
511  new (this) Set();
512  }
513 
518  void rehash()
519  {
520  this->realloc_and_reinsert(this->size());
521  }
522 
526  int64_t size() const
527  {
528  return occupied_and_removed_slots_ - removed_slots_;
529  }
530 
534  bool is_empty() const
535  {
536  return occupied_and_removed_slots_ == removed_slots_;
537  }
538 
543  {
544  return slots_.size();
545  }
546 
551  {
552  return removed_slots_;
553  }
554 
559  {
560  return sizeof(Slot);
561  }
562 
568  {
569  return sizeof(Slot) * slots_.size();
570  }
571 
576  void reserve(const int64_t n)
577  {
578  if (usable_slots_ < n) {
579  this->realloc_and_reinsert(n);
580  }
581  }
582 
586  static bool Intersects(const Set &a, const Set &b)
587  {
588  /* Make sure we iterate over the shorter set. */
589  if (a.size() > b.size()) {
590  return Intersects(b, a);
591  }
592 
593  for (const Key &key : a) {
594  if (b.contains(key)) {
595  return true;
596  }
597  }
598  return false;
599  }
600 
604  static bool Disjoint(const Set &a, const Set &b)
605  {
606  return !Intersects(a, b);
607  }
608 
609  private:
610  BLI_NOINLINE void realloc_and_reinsert(const int64_t min_usable_slots)
611  {
612  int64_t total_slots, usable_slots;
613  max_load_factor_.compute_total_and_usable_slots(
614  SlotArray::inline_buffer_capacity(), min_usable_slots, &total_slots, &usable_slots);
615  BLI_assert(total_slots >= 1);
616  const uint64_t new_slot_mask = static_cast<uint64_t>(total_slots) - 1;
617 
621  if (this->size() == 0) {
622  try {
623  slots_.reinitialize(total_slots);
624  }
625  catch (...) {
626  this->noexcept_reset();
627  throw;
628  }
629  removed_slots_ = 0;
630  occupied_and_removed_slots_ = 0;
631  usable_slots_ = usable_slots;
632  slot_mask_ = new_slot_mask;
633  return;
634  }
635 
636  /* The grown array that we insert the keys into. */
637  SlotArray new_slots(total_slots);
638 
639  try {
640  for (Slot &slot : slots_) {
641  if (slot.is_occupied()) {
642  this->add_after_grow(slot, new_slots, new_slot_mask);
643  slot.remove();
644  }
645  }
646  slots_ = std::move(new_slots);
647  }
648  catch (...) {
649  this->noexcept_reset();
650  throw;
651  }
652 
653  occupied_and_removed_slots_ -= removed_slots_;
654  usable_slots_ = usable_slots;
655  removed_slots_ = 0;
656  slot_mask_ = new_slot_mask;
657  }
658 
659  void add_after_grow(Slot &old_slot, SlotArray &new_slots, const uint64_t new_slot_mask)
660  {
661  const uint64_t hash = old_slot.get_hash(Hash());
662 
663  SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
664  Slot &slot = new_slots[slot_index];
665  if (slot.is_empty()) {
666  slot.occupy(std::move(*old_slot.key()), hash);
667  return;
668  }
669  }
671  }
672 
677  void noexcept_reset() noexcept
678  {
679  Allocator allocator = slots_.allocator();
680  this->~Set();
681  new (this) Set(NoExceptConstructor(), allocator);
682  }
683 
684  template<typename ForwardKey>
685  bool contains__impl(const ForwardKey &key, const uint64_t hash) const
686  {
687  SET_SLOT_PROBING_BEGIN (hash, slot) {
688  if (slot.is_empty()) {
689  return false;
690  }
691  if (slot.contains(key, is_equal_, hash)) {
692  return true;
693  }
694  }
696  }
697 
698  template<typename ForwardKey>
699  const Key &lookup_key__impl(const ForwardKey &key, const uint64_t hash) const
700  {
701  BLI_assert(this->contains_as(key));
702 
703  SET_SLOT_PROBING_BEGIN (hash, slot) {
704  if (slot.contains(key, is_equal_, hash)) {
705  return *slot.key();
706  }
707  }
709  }
710 
711  template<typename ForwardKey>
712  const Key *lookup_key_ptr__impl(const ForwardKey &key, const uint64_t hash) const
713  {
714  SET_SLOT_PROBING_BEGIN (hash, slot) {
715  if (slot.contains(key, is_equal_, hash)) {
716  return slot.key();
717  }
718  if (slot.is_empty()) {
719  return nullptr;
720  }
721  }
723  }
724 
725  template<typename ForwardKey> void add_new__impl(ForwardKey &&key, const uint64_t hash)
726  {
727  BLI_assert(!this->contains_as(key));
728 
729  this->ensure_can_add();
730 
731  SET_SLOT_PROBING_BEGIN (hash, slot) {
732  if (slot.is_empty()) {
733  slot.occupy(std::forward<ForwardKey>(key), hash);
734  occupied_and_removed_slots_++;
735  return;
736  }
737  }
739  }
740 
741  template<typename ForwardKey> bool add__impl(ForwardKey &&key, const uint64_t hash)
742  {
743  this->ensure_can_add();
744 
745  SET_SLOT_PROBING_BEGIN (hash, slot) {
746  if (slot.is_empty()) {
747  slot.occupy(std::forward<ForwardKey>(key), hash);
748  occupied_and_removed_slots_++;
749  return true;
750  }
751  if (slot.contains(key, is_equal_, hash)) {
752  return false;
753  }
754  }
756  }
757 
758  template<typename ForwardKey> bool remove__impl(const ForwardKey &key, const uint64_t hash)
759  {
760  SET_SLOT_PROBING_BEGIN (hash, slot) {
761  if (slot.contains(key, is_equal_, hash)) {
762  slot.remove();
763  removed_slots_++;
764  return true;
765  }
766  if (slot.is_empty()) {
767  return false;
768  }
769  }
771  }
772 
773  template<typename ForwardKey>
774  void remove_contained__impl(const ForwardKey &key, const uint64_t hash)
775  {
776  BLI_assert(this->contains_as(key));
777 
778  SET_SLOT_PROBING_BEGIN (hash, slot) {
779  if (slot.contains(key, is_equal_, hash)) {
780  slot.remove();
781  removed_slots_++;
782  return;
783  }
784  }
786  }
787 
788  template<typename ForwardKey>
789  const Key &lookup_key_or_add__impl(ForwardKey &&key, const uint64_t hash)
790  {
791  this->ensure_can_add();
792 
793  SET_SLOT_PROBING_BEGIN (hash, slot) {
794  if (slot.contains(key, is_equal_, hash)) {
795  return *slot.key();
796  }
797  if (slot.is_empty()) {
798  slot.occupy(std::forward<ForwardKey>(key), hash);
799  occupied_and_removed_slots_++;
800  return *slot.key();
801  }
802  }
804  }
805 
806  template<typename ForwardKey>
807  int64_t count_collisions__impl(const ForwardKey &key, const uint64_t hash) const
808  {
809  int64_t collisions = 0;
810 
811  SET_SLOT_PROBING_BEGIN (hash, slot) {
812  if (slot.contains(key, is_equal_, hash)) {
813  return collisions;
814  }
815  if (slot.is_empty()) {
816  return collisions;
817  }
818  collisions++;
819  }
821  }
822 
823  void ensure_can_add()
824  {
825  if (occupied_and_removed_slots_ >= usable_slots_) {
826  this->realloc_and_reinsert(this->size() + 1);
827  BLI_assert(occupied_and_removed_slots_ < usable_slots_);
828  }
829  }
830 };
831 
836 template<typename Key> class StdUnorderedSetWrapper {
837  private:
838  using SetType = std::unordered_set<Key, blender::DefaultHash<Key>>;
839  SetType set_;
840 
841  public:
842  int64_t size() const
843  {
844  return static_cast<int64_t>(set_.size());
845  }
846 
847  bool is_empty() const
848  {
849  return set_.empty();
850  }
851 
852  void reserve(int64_t n)
853  {
854  set_.reserve(n);
855  }
856 
857  void add_new(const Key &key)
858  {
859  set_.insert(key);
860  }
861  void add_new(Key &&key)
862  {
863  set_.insert(std::move(key));
864  }
865 
866  bool add(const Key &key)
867  {
868  return set_.insert(key).second;
869  }
870  bool add(Key &&key)
871  {
872  return set_.insert(std::move(key)).second;
873  }
874 
876  {
877  for (const Key &key : keys) {
878  set_.insert(key);
879  }
880  }
881 
882  bool contains(const Key &key) const
883  {
884  return set_.find(key) != set_.end();
885  }
886 
887  bool remove(const Key &key)
888  {
889  return (bool)set_.erase(key);
890  }
891 
892  void remove_contained(const Key &key)
893  {
894  return set_.erase(key);
895  }
896 
897  void clear()
898  {
899  set_.clear();
900  }
901 
902  typename SetType::iterator begin() const
903  {
904  return set_.begin();
905  }
906 
907  typename SetType::iterator end() const
908  {
909  return set_.end();
910  }
911 };
912 
917 template<typename Key,
918  int64_t InlineBufferCapacity = default_inline_buffer_capacity(sizeof(Key)),
919  typename ProbingStrategy = DefaultProbingStrategy,
920  typename Hash = DefaultHash<Key>,
921  typename IsEqual = DefaultEquality,
922  typename Slot = typename DefaultSetSlot<Key>::type>
924 
925 } // namespace blender
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_NOINLINE
#define SLOT_PROBING_BEGIN(PROBING_STRATEGY, HASH, MASK, R_SLOT_INDEX)
#define SLOT_PROBING_END()
#define SET_SLOT_PROBING_END()
Definition: BLI_set.hh:175
#define SET_SLOT_PROBING_BEGIN(HASH, R_SLOT)
Definition: BLI_set.hh:172
#define LOAD_FACTOR
Definition: BLI_set.hh:159
struct Key Key
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)
std::ptrdiff_t difference_type
Definition: BLI_set.hh:419
friend bool operator!=(const Iterator &a, const Iterator &b)
Definition: BLI_set.hh:459
Iterator & operator++()
Definition: BLI_set.hh:432
const Key * operator->() const
Definition: BLI_set.hh:454
const Key & operator*() const
Definition: BLI_set.hh:449
std::forward_iterator_tag iterator_category
Definition: BLI_set.hh:415
friend bool operator==(const Iterator &a, const Iterator &b)
Definition: BLI_set.hh:466
Iterator(const Slot *slots, int64_t total_slots, int64_t current_slot)
Definition: BLI_set.hh:427
Iterator operator++(int) const
Definition: BLI_set.hh:442
Set(NoExceptConstructor, Allocator allocator={}) noexcept
Definition: BLI_set.hh:192
const Key & lookup_key_or_add(Key &&key)
Definition: BLI_set.hh:371
int64_t size_per_element() const
Definition: BLI_set.hh:558
const Key & lookup_key_default_as(const ForwardKey &key, const Key &default_key) const
Definition: BLI_set.hh:341
bool remove_as(const ForwardKey &key)
Definition: BLI_set.hh:389
Set(const std::initializer_list< Key > &values)
Definition: BLI_set.hh:204
Set & operator=(const Set &other)
Definition: BLI_set.hh:237
int64_t size_in_bytes() const
Definition: BLI_set.hh:567
Set & operator=(Set &&other)
Definition: BLI_set.hh:242
~Set()=default
Set(const Set &other)=default
Iterator begin() const
Definition: BLI_set.hh:472
void add_multiple_new(Span< Key > keys)
Definition: BLI_set.hh:298
const Key * lookup_key_ptr(const Key &key) const
Definition: BLI_set.hh:354
int64_t size_type
Definition: BLI_set.hh:130
static bool Disjoint(const Set &a, const Set &b)
Definition: BLI_set.hh:604
bool add(Key &&key)
Definition: BLI_set.hh:271
const Key & lookup_key(const Key &key) const
Definition: BLI_set.hh:323
int64_t size() const
Definition: BLI_set.hh:526
bool add_as(ForwardKey &&key)
Definition: BLI_set.hh:275
int64_t removed_amount() const
Definition: BLI_set.hh:550
bool contains_as(const ForwardKey &key) const
Definition: BLI_set.hh:314
void reserve(const int64_t n)
Definition: BLI_set.hh:576
const Key * lookup_key_ptr_as(const ForwardKey &key) const
Definition: BLI_set.hh:358
Iterator end() const
Definition: BLI_set.hh:482
Set(Span< Key > values, Allocator allocator={})
Definition: BLI_set.hh:196
void remove_contained(const Key &key)
Definition: BLI_set.hh:397
bool contains(const Key &key) const
Definition: BLI_set.hh:310
static bool Intersects(const Set &a, const Set &b)
Definition: BLI_set.hh:586
int64_t capacity() const
Definition: BLI_set.hh:542
const Key & lookup_key_or_add_as(ForwardKey &&key)
Definition: BLI_set.hh:375
const Key & lookup_key_or_add(const Key &key)
Definition: BLI_set.hh:367
int64_t count_collisions(const Key &key) const
Definition: BLI_set.hh:500
bool add(const Key &key)
Definition: BLI_set.hh:267
bool is_empty() const
Definition: BLI_set.hh:534
void add_multiple(Span< Key > keys)
Definition: BLI_set.hh:287
Set(Set &&other) noexcept(std::is_nothrow_move_constructible_v< SlotArray >)
Definition: BLI_set.hh:212
void add_new(const Key &key)
Definition: BLI_set.hh:252
Set(Allocator allocator={}) noexcept
Definition: BLI_set.hh:183
void clear()
Definition: BLI_set.hh:508
void remove_contained_as(const ForwardKey &key)
Definition: BLI_set.hh:401
void print_stats(StringRef name="") const
Definition: BLI_set.hh:490
const Key & lookup_key_default(const Key &key, const Key &default_value) const
Definition: BLI_set.hh:336
bool remove(const Key &key)
Definition: BLI_set.hh:385
const Key & lookup_key_as(const ForwardKey &key) const
Definition: BLI_set.hh:327
void rehash()
Definition: BLI_set.hh:518
void add_new(Key &&key)
Definition: BLI_set.hh:256
bool add(const Key &key)
Definition: BLI_set.hh:866
bool remove(const Key &key)
Definition: BLI_set.hh:887
bool contains(const Key &key) const
Definition: BLI_set.hh:882
void remove_contained(const Key &key)
Definition: BLI_set.hh:892
SetType::iterator begin() const
Definition: BLI_set.hh:902
void add_multiple(Span< Key > keys)
Definition: BLI_set.hh:875
void add_new(const Key &key)
Definition: BLI_set.hh:857
SetType::iterator end() const
Definition: BLI_set.hh:907
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
SimpleSetSlot< Key > type
PointerRNA * ptr
Definition: wm_files.c:3157