SkTHash.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. * Copyright 2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #ifndef SkTHash_DEFINED
  8. #define SkTHash_DEFINED
  9. #include "SkChecksum.h"
  10. #include "SkTypes.h"
  11. #include "SkTemplates.h"
  12. #include <new>
  13. // Before trying to use SkTHashTable, look below to see if SkTHashMap or SkTHashSet works for you.
  14. // They're easier to use, usually perform the same, and have fewer sharp edges.
  15. // T and K are treated as ordinary copyable C++ types.
  16. // Traits must have:
  17. // - static K GetKey(T)
  18. // - static uint32_t Hash(K)
  19. // If the key is large and stored inside T, you may want to make K a const&.
  20. // Similarly, if T is large you might want it to be a pointer.
  21. template <typename T, typename K, typename Traits = T>
  22. class SkTHashTable {
  23. public:
  24. SkTHashTable() : fCount(0), fCapacity(0) {}
  25. SkTHashTable(SkTHashTable&& other)
  26. : fCount(other.fCount)
  27. , fCapacity(other.fCapacity)
  28. , fSlots(std::move(other.fSlots)) { other.fCount = other.fCapacity = 0; }
  29. SkTHashTable& operator=(SkTHashTable&& other) {
  30. if (this != &other) {
  31. this->~SkTHashTable();
  32. new (this) SkTHashTable(std::move(other));
  33. }
  34. return *this;
  35. }
  36. // Clear the table.
  37. void reset() { *this = SkTHashTable(); }
  38. // How many entries are in the table?
  39. int count() const { return fCount; }
  40. // Approximately how many bytes of memory do we use beyond sizeof(*this)?
  41. size_t approxBytesUsed() const { return fCapacity * sizeof(Slot); }
  42. // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!!!!!
  43. // set(), find() and foreach() all allow mutable access to table entries.
  44. // If you change an entry so that it no longer has the same key, all hell
  45. // will break loose. Do not do that!
  46. //
  47. // Please prefer to use SkTHashMap or SkTHashSet, which do not have this danger.
  48. // The pointers returned by set() and find() are valid only until the next call to set().
  49. // The pointers you receive in foreach() are only valid for its duration.
  50. // Copy val into the hash table, returning a pointer to the copy now in the table.
  51. // If there already is an entry in the table with the same key, we overwrite it.
  52. T* set(T val) {
  53. if (4 * fCount >= 3 * fCapacity) {
  54. this->resize(fCapacity > 0 ? fCapacity * 2 : 4);
  55. }
  56. return this->uncheckedSet(std::move(val));
  57. }
  58. // If there is an entry in the table with this key, return a pointer to it. If not, null.
  59. T* find(const K& key) const {
  60. uint32_t hash = Hash(key);
  61. int index = hash & (fCapacity-1);
  62. for (int n = 0; n < fCapacity; n++) {
  63. Slot& s = fSlots[index];
  64. if (s.empty()) {
  65. return nullptr;
  66. }
  67. if (hash == s.hash && key == Traits::GetKey(s.val)) {
  68. return &s.val;
  69. }
  70. index = this->next(index);
  71. }
  72. SkASSERT(fCapacity == 0);
  73. return nullptr;
  74. }
  75. // Remove the value with this key from the hash table.
  76. void remove(const K& key) {
  77. SkASSERT(this->find(key));
  78. uint32_t hash = Hash(key);
  79. int index = hash & (fCapacity-1);
  80. for (int n = 0; n < fCapacity; n++) {
  81. Slot& s = fSlots[index];
  82. SkASSERT(!s.empty());
  83. if (hash == s.hash && key == Traits::GetKey(s.val)) {
  84. fCount--;
  85. break;
  86. }
  87. index = this->next(index);
  88. }
  89. // Rearrange elements to restore the invariants for linear probing.
  90. for (;;) {
  91. Slot& emptySlot = fSlots[index];
  92. int emptyIndex = index;
  93. int originalIndex;
  94. // Look for an element that can be moved into the empty slot.
  95. // If the empty slot is in between where an element landed, and its native slot, then
  96. // move it to the empty slot. Don't move it if its native slot is in between where
  97. // the element landed and the empty slot.
  98. // [native] <= [empty] < [candidate] == GOOD, can move candidate to empty slot
  99. // [empty] < [native] < [candidate] == BAD, need to leave candidate where it is
  100. do {
  101. index = this->next(index);
  102. Slot& s = fSlots[index];
  103. if (s.empty()) {
  104. // We're done shuffling elements around. Clear the last empty slot.
  105. emptySlot = Slot();
  106. return;
  107. }
  108. originalIndex = s.hash & (fCapacity - 1);
  109. } while ((index <= originalIndex && originalIndex < emptyIndex)
  110. || (originalIndex < emptyIndex && emptyIndex < index)
  111. || (emptyIndex < index && index <= originalIndex));
  112. // Move the element to the empty slot.
  113. Slot& moveFrom = fSlots[index];
  114. emptySlot = std::move(moveFrom);
  115. }
  116. }
  117. // Call fn on every entry in the table. You may mutate the entries, but be very careful.
  118. template <typename Fn> // f(T*)
  119. void foreach(Fn&& fn) {
  120. for (int i = 0; i < fCapacity; i++) {
  121. if (!fSlots[i].empty()) {
  122. fn(&fSlots[i].val);
  123. }
  124. }
  125. }
  126. // Call fn on every entry in the table. You may not mutate anything.
  127. template <typename Fn> // f(T) or f(const T&)
  128. void foreach(Fn&& fn) const {
  129. for (int i = 0; i < fCapacity; i++) {
  130. if (!fSlots[i].empty()) {
  131. fn(fSlots[i].val);
  132. }
  133. }
  134. }
  135. private:
  136. T* uncheckedSet(T&& val) {
  137. const K& key = Traits::GetKey(val);
  138. uint32_t hash = Hash(key);
  139. int index = hash & (fCapacity-1);
  140. for (int n = 0; n < fCapacity; n++) {
  141. Slot& s = fSlots[index];
  142. if (s.empty()) {
  143. // New entry.
  144. s.val = std::move(val);
  145. s.hash = hash;
  146. fCount++;
  147. return &s.val;
  148. }
  149. if (hash == s.hash && key == Traits::GetKey(s.val)) {
  150. // Overwrite previous entry.
  151. // Note: this triggers extra copies when adding the same value repeatedly.
  152. s.val = std::move(val);
  153. return &s.val;
  154. }
  155. index = this->next(index);
  156. }
  157. SkASSERT(false);
  158. return nullptr;
  159. }
  160. void resize(int capacity) {
  161. int oldCapacity = fCapacity;
  162. SkDEBUGCODE(int oldCount = fCount);
  163. fCount = 0;
  164. fCapacity = capacity;
  165. SkAutoTArray<Slot> oldSlots = std::move(fSlots);
  166. fSlots = SkAutoTArray<Slot>(capacity);
  167. for (int i = 0; i < oldCapacity; i++) {
  168. Slot& s = oldSlots[i];
  169. if (!s.empty()) {
  170. this->uncheckedSet(std::move(s.val));
  171. }
  172. }
  173. SkASSERT(fCount == oldCount);
  174. }
  175. int next(int index) const {
  176. index--;
  177. if (index < 0) { index += fCapacity; }
  178. return index;
  179. }
  180. static uint32_t Hash(const K& key) {
  181. uint32_t hash = Traits::Hash(key);
  182. return hash ? hash : 1; // We reserve hash 0 to mark empty.
  183. }
  184. struct Slot {
  185. Slot() : hash(0) {}
  186. Slot(T&& v, uint32_t h) : val(std::move(v)), hash(h) {}
  187. Slot(Slot&& o) { *this = std::move(o); }
  188. Slot& operator=(Slot&& o) {
  189. val = std::move(o.val);
  190. hash = o.hash;
  191. return *this;
  192. }
  193. bool empty() const { return this->hash == 0; }
  194. T val;
  195. uint32_t hash;
  196. };
  197. int fCount, fCapacity;
  198. SkAutoTArray<Slot> fSlots;
  199. SkTHashTable(const SkTHashTable&) = delete;
  200. SkTHashTable& operator=(const SkTHashTable&) = delete;
  201. };
  202. // Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for most use cases.
  203. // K and V are treated as ordinary copyable C++ types, with no assumed relationship between the two.
  204. template <typename K, typename V, typename HashK = SkGoodHash>
  205. class SkTHashMap {
  206. public:
  207. SkTHashMap() {}
  208. SkTHashMap(SkTHashMap&&) = default;
  209. SkTHashMap& operator=(SkTHashMap&&) = default;
  210. // Clear the map.
  211. void reset() { fTable.reset(); }
  212. // How many key/value pairs are in the table?
  213. int count() const { return fTable.count(); }
  214. // Approximately how many bytes of memory do we use beyond sizeof(*this)?
  215. size_t approxBytesUsed() const { return fTable.approxBytesUsed(); }
  216. // N.B. The pointers returned by set() and find() are valid only until the next call to set().
  217. // Set key to val in the table, replacing any previous value with the same key.
  218. // We copy both key and val, and return a pointer to the value copy now in the table.
  219. V* set(K key, V val) {
  220. Pair* out = fTable.set({std::move(key), std::move(val)});
  221. return &out->val;
  222. }
  223. // If there is key/value entry in the table with this key, return a pointer to the value.
  224. // If not, return null.
  225. V* find(const K& key) const {
  226. if (Pair* p = fTable.find(key)) {
  227. return &p->val;
  228. }
  229. return nullptr;
  230. }
  231. // Remove the key/value entry in the table with this key.
  232. void remove(const K& key) {
  233. SkASSERT(this->find(key));
  234. fTable.remove(key);
  235. }
  236. // Call fn on every key/value pair in the table. You may mutate the value but not the key.
  237. template <typename Fn> // f(K, V*) or f(const K&, V*)
  238. void foreach(Fn&& fn) {
  239. fTable.foreach([&fn](Pair* p){ fn(p->key, &p->val); });
  240. }
  241. // Call fn on every key/value pair in the table. You may not mutate anything.
  242. template <typename Fn> // f(K, V), f(const K&, V), f(K, const V&) or f(const K&, const V&).
  243. void foreach(Fn&& fn) const {
  244. fTable.foreach([&fn](const Pair& p){ fn(p.key, p.val); });
  245. }
  246. private:
  247. struct Pair {
  248. K key;
  249. V val;
  250. static const K& GetKey(const Pair& p) { return p.key; }
  251. static uint32_t Hash(const K& key) { return HashK()(key); }
  252. };
  253. SkTHashTable<Pair, K> fTable;
  254. SkTHashMap(const SkTHashMap&) = delete;
  255. SkTHashMap& operator=(const SkTHashMap&) = delete;
  256. };
  257. // A set of T. T is treated as an ordinary copyable C++ type.
  258. template <typename T, typename HashT = SkGoodHash>
  259. class SkTHashSet {
  260. public:
  261. SkTHashSet() {}
  262. SkTHashSet(SkTHashSet&&) = default;
  263. SkTHashSet& operator=(SkTHashSet&&) = default;
  264. // Clear the set.
  265. void reset() { fTable.reset(); }
  266. // How many items are in the set?
  267. int count() const { return fTable.count(); }
  268. // Approximately how many bytes of memory do we use beyond sizeof(*this)?
  269. size_t approxBytesUsed() const { return fTable.approxBytesUsed(); }
  270. // Copy an item into the set.
  271. void add(T item) { fTable.set(std::move(item)); }
  272. // Is this item in the set?
  273. bool contains(const T& item) const { return SkToBool(this->find(item)); }
  274. // If an item equal to this is in the set, return a pointer to it, otherwise null.
  275. // This pointer remains valid until the next call to add().
  276. const T* find(const T& item) const { return fTable.find(item); }
  277. // Remove the item in the set equal to this.
  278. void remove(const T& item) {
  279. SkASSERT(this->contains(item));
  280. fTable.remove(item);
  281. }
  282. // Call fn on every item in the set. You may not mutate anything.
  283. template <typename Fn> // f(T), f(const T&)
  284. void foreach (Fn&& fn) const {
  285. fTable.foreach(fn);
  286. }
  287. private:
  288. struct Traits {
  289. static const T& GetKey(const T& item) { return item; }
  290. static uint32_t Hash(const T& item) { return HashT()(item); }
  291. };
  292. SkTHashTable<T, T, Traits> fTable;
  293. SkTHashSet(const SkTHashSet&) = delete;
  294. SkTHashSet& operator=(const SkTHashSet&) = delete;
  295. };
  296. #endif//SkTHash_DEFINED