hash_map.h - Engine C API Reference

hash_map.h
  1. #pragma once
  2. #include "hash_function.h"
  3. #include "pair.h"
  4. #include "bucket_iterator.h"
  5. #include "vector.h"
  6. #include "functional.h"
  7. namespace stingray_plugin_foundation {
  8. // Implements an unordered map using a hash table.
  9. //
  10. // The hash table allocates its memory in a single block to be as cache
  11. // friendly as possible. Hash collisions are resolved by chaining into
  12. // a separate region of that memory block. This avoids clustering while
  13. // also avoiding the cache inefficiency of linked lists.
  14. //
  15. // A lookup in the spillover area will likely lead to a cache miss, so
  16. // from a cache perspective linear probing might be more efficient.
  17. // OTOH linear probing has a tendency to cause clustering which can
  18. // heavily degrade performance. It also complicates hash table deletes.
  19. //
  20. // For a randomly distributed hash function, a lookup in this hash table
  21. // on average has too look at 1.3 nodes. The expected memory use is
  22. //
  23. // $ 1.37 n (K_s D_s + 4) $,
  24. //
  25. // where `n` is the number of elements and `K_s` is the size of
  26. // the key elements and `D_s` is the size of the data elements. The
  27. // spillover region is set to 37 % of the hash region size. Experimentally
  28. // this has been found to be a good trade off value.
  29. //
  30. // HashMap is a good choice when you need to insert and lookup continuously
  31. // (so you can't use SortMap) and you don't need to do an ordered traversal
  32. // of the items.
  33. // \tparam K the key type
  34. // \tparam D the data type
  35. // \tparam HASH hash functor, defaults to default_hash>
  36. // \tparam EQUAL equality functor, defaults to std::equal_to<K>
  37. template <class K, class D, class HASH = default_hash<K>, class EQUAL = equal_to >
  38. class HashMap
  39. {
  40. public:
  41. ALLOCATOR_AWARE;
  42. typedef K key_type;
  43. typedef D data_type;
  44. typedef HASH key_hash;
  45. typedef EQUAL key_equal;
  46. typedef HashMap<K, D, HASH, EQUAL> this_type;
  47. typedef Pair<key_type, data_type, IS_ALLOCATOR_AWARE(key_type), IS_ALLOCATOR_AWARE(data_type)> value_type;
  48. // Special values for marker
  49. enum {END_OF_LIST = 0x7fffffff, UNUSED = 0xfffffffe, END_OF_FREELIST = 0xffffffff};
  50. typedef BucketIterator<this_type, value_type> iterator;
  51. typedef ConstBucketIterator<this_type, value_type> const_iterator;
  52. HashMap(Allocator &a);
  53. // Creates an unordered map presized to the specified number of buckets and
  54. // spill-over buckets. It is recommended that spill = 0.37 * buckets.
  55. HashMap(unsigned buckets, unsigned spill, Allocator &a);
  56. HashMap(const HashMap<K,D,HASH,EQUAL> &o);
  57. ~HashMap();
  58. void operator=(const HashMap<K,D,HASH,EQUAL> &o);
  59. void swap(HashMap<K,D,HASH,EQUAL> &o);
  60. iterator begin();
  61. iterator end();
  62. const_iterator begin() const;
  63. const_iterator end() const;
  64. template <class KEY_EQ> const_iterator find(const KEY_EQ &k) const;
  65. template <class KEY_EQ> iterator find(const KEY_EQ &k);
  66. Allocator & allocator() const;
  67. void reserve(unsigned size);
  68. unsigned size() const;
  69. bool empty() const;
  70. // Returns true if the key is in the hash
  71. template <class KEY_EQ> bool has(const KEY_EQ &k) const;
  72. template <class KEY_EQ> data_type &operator[](const KEY_EQ &k);
  73. template <class KEY_EQ> value_type &get_pair(const KEY_EQ &k);
  74. template <class KEY_EQ> const data_type &operator[](const KEY_EQ &k) const;
  75. // Returns the value for `k` if it exists and `def` otherwise.
  76. template <class KEY_EQ> data_type &get(const KEY_EQ &k, data_type &def);
  77. template <class KEY_EQ> const data_type &get(const KEY_EQ &k, const data_type &def) const;
  78. void clear();
  79. // Inserts the data point (`k`, `v`) in the map.
  80. template <class KEY_EQ, class DATA_EQ> void insert(const KEY_EQ &k, const DATA_EQ &v);
  81. template <class KEY_EQ> void erase(const KEY_EQ &k);
  82. // Rehashes the data to the specified number of buckets (and a spill
  83. // region of 0.37 * buckets).
  84. // You can use this to reserve memory in the hash before inserting a lot
  85. // of elements to avoid rehashing during insertion. You can also use it
  86. // to shrink a hash, but you cannot shrink a hash beyond its current size.
  87. void rehash(unsigned new_buckets);
  88. // Used by iterator
  89. unsigned num_buckets() const;
  90. bool bucket_valid(unsigned i) const;
  91. value_type &bucket_value(unsigned i);
  92. const value_type &bucket_value(unsigned i) const;
  93. // Serializes the hash map to the stream.
  94. template <class STREAM> void serialize(STREAM &stream);
  95. private:
  96. template <class KEY_EQ> unsigned find_or_fail(const KEY_EQ &k) const;
  97. template <class KEY_EQ> unsigned find_or_make(const KEY_EQ &k);
  98. template <class KEY_EQ> void find_and_erase(const KEY_EQ &k);
  99. bool full() const;
  100. void grow();
  101. template <class KEY_EQ> unsigned hash(const KEY_EQ &k) const;
  102. unsigned allocate_spill();
  103. void free_spill(unsigned i);
  104. void clear_freelist();
  105. void allocate_data(unsigned count);
  106. void construct(value_type &p) { new (&p) value_type(_allocator); }
  107. void destruct(value_type &p) { p.~value_type(); }
  108. struct Data {
  109. Data() : size(), marker(), value() {}
  110. unsigned size;
  111. unsigned *marker;
  112. value_type *value;
  113. };
  114. key_hash _hash;
  115. key_equal _equal;
  116. Data _data;
  117. unsigned _used;
  118. unsigned _buckets;
  119. unsigned _spill_unused;
  120. unsigned _spill_freelist;
  121. Allocator &_allocator;
  122. };
  123. } // namespace stingray_plugin_foundation
  124. #include "hash_map.inl"