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 8 #ifndef SkTHash_DEFINED 9 #define SkTHash_DEFINED 10 11 #include "include/core/SkTypes.h" 12 #include "include/private/SkChecksum.h" 13 #include "include/private/base/SkTemplates.h" 14 15 #include <initializer_list> 16 #include <new> 17 #include <utility> 18 19 // Before trying to use SkTHashTable, look below to see if SkTHashMap or SkTHashSet works for you. 20 // They're easier to use, usually perform the same, and have fewer sharp edges. 21 22 // T and K are treated as ordinary copyable C++ types. 23 // Traits must have: 24 // - static K GetKey(T) 25 // - static uint32_t Hash(K) 26 // If the key is large and stored inside T, you may want to make K a const&. 27 // Similarly, if T is large you might want it to be a pointer. 28 template <typename T, typename K, typename Traits = T> 29 class SkTHashTable { 30 public: 31 SkTHashTable() = default; 32 ~SkTHashTable() = default; 33 SkTHashTable(const SkTHashTable & that)34 SkTHashTable(const SkTHashTable& that) { *this = that; } SkTHashTable(SkTHashTable && that)35 SkTHashTable( SkTHashTable&& that) { *this = std::move(that); } 36 37 SkTHashTable& operator=(const SkTHashTable& that) { 38 if (this != &that) { 39 fCount = that.fCount; 40 fCapacity = that.fCapacity; 41 fSlots.reset(that.fCapacity); 42 for (int i = 0; i < fCapacity; i++) { 43 fSlots[i] = that.fSlots[i]; 44 } 45 } 46 return *this; 47 } 48 49 SkTHashTable& operator=(SkTHashTable&& that) { 50 if (this != &that) { 51 fCount = that.fCount; 52 fCapacity = that.fCapacity; 53 fSlots = std::move(that.fSlots); 54 55 that.fCount = that.fCapacity = 0; 56 } 57 return *this; 58 } 59 60 // Clear the table. reset()61 void reset() { *this = SkTHashTable(); } 62 63 // How many entries are in the table? count()64 int count() const { return fCount; } 65 66 // How many slots does the table contain? (Note that unlike an array, hash tables can grow 67 // before reaching 100% capacity.) capacity()68 int capacity() const { return fCapacity; } 69 70 // Approximately how many bytes of memory do we use beyond sizeof(*this)? approxBytesUsed()71 size_t approxBytesUsed() const { return fCapacity * sizeof(Slot); } 72 73 // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!!!!! 74 // set(), find() and foreach() all allow mutable access to table entries. 75 // If you change an entry so that it no longer has the same key, all hell 76 // will break loose. Do not do that! 77 // 78 // Please prefer to use SkTHashMap or SkTHashSet, which do not have this danger. 79 80 // The pointers returned by set() and find() are valid only until the next call to set(). 81 // The pointers you receive in foreach() are only valid for its duration. 82 83 // Copy val into the hash table, returning a pointer to the copy now in the table. 84 // If there already is an entry in the table with the same key, we overwrite it. set(T val)85 T* set(T val) { 86 if (4 * fCount >= 3 * fCapacity) { 87 this->resize(fCapacity > 0 ? fCapacity * 2 : 4); 88 } 89 return this->uncheckedSet(std::move(val)); 90 } 91 92 // If there is an entry in the table with this key, return a pointer to it. If not, null. find(const K & key)93 T* find(const K& key) const { 94 uint32_t hash = Hash(key); 95 int index = hash & (fCapacity-1); 96 for (int n = 0; n < fCapacity; n++) { 97 Slot& s = fSlots[index]; 98 if (s.empty()) { 99 return nullptr; 100 } 101 if (hash == s.fHash && key == Traits::GetKey(*s)) { 102 return &*s; 103 } 104 index = this->next(index); 105 } 106 SkASSERT(fCapacity == fCount); 107 return nullptr; 108 } 109 110 // If there is an entry in the table with this key, return it. If not, null. 111 // This only works for pointer type T, and cannot be used to find an nullptr entry. findOrNull(const K & key)112 T findOrNull(const K& key) const { 113 if (T* p = this->find(key)) { 114 return *p; 115 } 116 return nullptr; 117 } 118 119 // Remove the value with this key from the hash table. remove(const K & key)120 void remove(const K& key) { 121 SkASSERT(this->find(key)); 122 123 uint32_t hash = Hash(key); 124 int index = hash & (fCapacity-1); 125 for (int n = 0; n < fCapacity; n++) { 126 Slot& s = fSlots[index]; 127 SkASSERT(s.has_value()); 128 if (hash == s.fHash && key == Traits::GetKey(*s)) { 129 this->removeSlot(index); 130 if (4 * fCount <= fCapacity && fCapacity > 4) { 131 this->resize(fCapacity / 2); 132 } 133 return; 134 } 135 index = this->next(index); 136 } 137 } 138 139 // Hash tables will automatically resize themselves when set() and remove() are called, but 140 // resize() can be called to manually grow capacity before a bulk insertion. resize(int capacity)141 void resize(int capacity) { 142 SkASSERT(capacity >= fCount); 143 int oldCapacity = fCapacity; 144 SkDEBUGCODE(int oldCount = fCount); 145 146 fCount = 0; 147 fCapacity = capacity; 148 skia_private::AutoTArray<Slot> oldSlots = std::move(fSlots); 149 fSlots = skia_private::AutoTArray<Slot>(capacity); 150 151 for (int i = 0; i < oldCapacity; i++) { 152 Slot& s = oldSlots[i]; 153 if (s.has_value()) { 154 this->uncheckedSet(*std::move(s)); 155 } 156 } 157 SkASSERT(fCount == oldCount); 158 } 159 160 // Call fn on every entry in the table. You may mutate the entries, but be very careful. 161 template <typename Fn> // f(T*) foreach(Fn && fn)162 void foreach(Fn&& fn) { 163 for (int i = 0; i < fCapacity; i++) { 164 if (fSlots[i].has_value()) { 165 fn(&*fSlots[i]); 166 } 167 } 168 } 169 170 // Call fn on every entry in the table. You may not mutate anything. 171 template <typename Fn> // f(T) or f(const T&) foreach(Fn && fn)172 void foreach(Fn&& fn) const { 173 for (int i = 0; i < fCapacity; i++) { 174 if (fSlots[i].has_value()) { 175 fn(*fSlots[i]); 176 } 177 } 178 } 179 180 // A basic iterator-like class which disallows mutation; sufficient for range-based for loops. 181 // Intended for use by SkTHashMap and SkTHashSet via begin() and end(). 182 // Adding or removing elements may invalidate all iterators. 183 template <typename SlotVal> 184 class Iter { 185 public: 186 using TTable = SkTHashTable<T, K, Traits>; 187 Iter(const TTable * table,int slot)188 Iter(const TTable* table, int slot) : fTable(table), fSlot(slot) {} 189 MakeBegin(const TTable * table)190 static Iter MakeBegin(const TTable* table) { 191 return Iter{table, table->firstPopulatedSlot()}; 192 } 193 MakeEnd(const TTable * table)194 static Iter MakeEnd(const TTable* table) { 195 return Iter{table, table->capacity()}; 196 } 197 198 const SlotVal& operator*() const { 199 return *fTable->slot(fSlot); 200 } 201 202 const SlotVal* operator->() const { 203 return fTable->slot(fSlot); 204 } 205 206 bool operator==(const Iter& that) const { 207 // Iterators from different tables shouldn't be compared against each other. 208 SkASSERT(fTable == that.fTable); 209 return fSlot == that.fSlot; 210 } 211 212 bool operator!=(const Iter& that) const { 213 return !(*this == that); 214 } 215 216 Iter& operator++() { 217 fSlot = fTable->nextPopulatedSlot(fSlot); 218 return *this; 219 } 220 221 Iter operator++(int) { 222 Iter old = *this; 223 this->operator++(); 224 return old; 225 } 226 227 protected: 228 const TTable* fTable; 229 int fSlot; 230 }; 231 232 private: 233 // Finds the first non-empty slot for an iterator. firstPopulatedSlot()234 int firstPopulatedSlot() const { 235 for (int i = 0; i < fCapacity; i++) { 236 if (fSlots[i].has_value()) { 237 return i; 238 } 239 } 240 return fCapacity; 241 } 242 243 // Increments an iterator's slot. nextPopulatedSlot(int currentSlot)244 int nextPopulatedSlot(int currentSlot) const { 245 for (int i = currentSlot + 1; i < fCapacity; i++) { 246 if (fSlots[i].has_value()) { 247 return i; 248 } 249 } 250 return fCapacity; 251 } 252 253 // Reads from an iterator's slot. slot(int i)254 const T* slot(int i) const { 255 SkASSERT(fSlots[i].has_value()); 256 return &*fSlots[i]; 257 } 258 uncheckedSet(T && val)259 T* uncheckedSet(T&& val) { 260 const K& key = Traits::GetKey(val); 261 SkASSERT(key == key); 262 uint32_t hash = Hash(key); 263 int index = hash & (fCapacity-1); 264 for (int n = 0; n < fCapacity; n++) { 265 Slot& s = fSlots[index]; 266 if (s.empty()) { 267 // New entry. 268 s.emplace(std::move(val), hash); 269 fCount++; 270 return &*s; 271 } 272 if (hash == s.fHash && key == Traits::GetKey(*s)) { 273 // Overwrite previous entry. 274 // Note: this triggers extra copies when adding the same value repeatedly. 275 s.emplace(std::move(val), hash); 276 return &*s; 277 } 278 279 index = this->next(index); 280 } 281 SkASSERT(false); 282 return nullptr; 283 } 284 removeSlot(int index)285 void removeSlot(int index) { 286 fCount--; 287 288 // Rearrange elements to restore the invariants for linear probing. 289 for (;;) { 290 Slot& emptySlot = fSlots[index]; 291 int emptyIndex = index; 292 int originalIndex; 293 // Look for an element that can be moved into the empty slot. 294 // If the empty slot is in between where an element landed, and its native slot, then 295 // move it to the empty slot. Don't move it if its native slot is in between where 296 // the element landed and the empty slot. 297 // [native] <= [empty] < [candidate] == GOOD, can move candidate to empty slot 298 // [empty] < [native] < [candidate] == BAD, need to leave candidate where it is 299 do { 300 index = this->next(index); 301 Slot& s = fSlots[index]; 302 if (s.empty()) { 303 // We're done shuffling elements around. Clear the last empty slot. 304 emptySlot.reset(); 305 return; 306 } 307 originalIndex = s.fHash & (fCapacity - 1); 308 } while ((index <= originalIndex && originalIndex < emptyIndex) 309 || (originalIndex < emptyIndex && emptyIndex < index) 310 || (emptyIndex < index && index <= originalIndex)); 311 // Move the element to the empty slot. 312 Slot& moveFrom = fSlots[index]; 313 emptySlot = std::move(moveFrom); 314 } 315 } 316 next(int index)317 int next(int index) const { 318 index--; 319 if (index < 0) { index += fCapacity; } 320 return index; 321 } 322 Hash(const K & key)323 static uint32_t Hash(const K& key) { 324 uint32_t hash = Traits::Hash(key) & 0xffffffff; 325 return hash ? hash : 1; // We reserve hash 0 to mark empty. 326 } 327 328 class Slot { 329 public: 330 Slot() = default; ~Slot()331 ~Slot() { this->reset(); } 332 Slot(const Slot & that)333 Slot(const Slot& that) { *this = that; } 334 Slot& operator=(const Slot& that) { 335 if (this == &that) { 336 return *this; 337 } 338 if (fHash) { 339 if (that.fHash) { 340 fVal.fStorage = that.fVal.fStorage; 341 fHash = that.fHash; 342 } else { 343 this->reset(); 344 } 345 } else { 346 if (that.fHash) { 347 new (&fVal.fStorage) T(that.fVal.fStorage); 348 fHash = that.fHash; 349 } else { 350 // do nothing, no value on either side 351 } 352 } 353 return *this; 354 } 355 Slot(Slot && that)356 Slot(Slot&& that) { *this = std::move(that); } 357 Slot& operator=(Slot&& that) { 358 if (this == &that) { 359 return *this; 360 } 361 if (fHash) { 362 if (that.fHash) { 363 fVal.fStorage = std::move(that.fVal.fStorage); 364 fHash = that.fHash; 365 } else { 366 this->reset(); 367 } 368 } else { 369 if (that.fHash) { 370 new (&fVal.fStorage) T(std::move(that.fVal.fStorage)); 371 fHash = that.fHash; 372 } else { 373 // do nothing, no value on either side 374 } 375 } 376 return *this; 377 } 378 379 T& operator*() & { return fVal.fStorage; } 380 const T& operator*() const& { return fVal.fStorage; } 381 T&& operator*() && { return std::move(fVal.fStorage); } 382 const T&& operator*() const&& { return std::move(fVal.fStorage); } 383 emplace(T && v,uint32_t h)384 Slot& emplace(T&& v, uint32_t h) { 385 this->reset(); 386 new (&fVal.fStorage) T(std::move(v)); 387 fHash = h; 388 return *this; 389 } 390 has_value()391 bool has_value() const { return fHash != 0; } 392 explicit operator bool() const { return this->has_value(); } empty()393 bool empty() const { return !this->has_value(); } 394 reset()395 void reset() { 396 if (fHash) { 397 fVal.fStorage.~T(); 398 fHash = 0; 399 } 400 } 401 402 uint32_t fHash = 0; 403 404 private: 405 union Storage { 406 T fStorage; Storage()407 Storage() {} ~Storage()408 ~Storage() {} 409 } fVal; 410 }; 411 412 int fCount = 0, 413 fCapacity = 0; 414 skia_private::AutoTArray<Slot> fSlots; 415 }; 416 417 // Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for most use cases. 418 // K and V are treated as ordinary copyable C++ types, with no assumed relationship between the two. 419 template <typename K, typename V, typename HashK = SkGoodHash> 420 class SkTHashMap { 421 public: 422 // Allow default construction and assignment. 423 SkTHashMap() = default; 424 425 SkTHashMap(SkTHashMap<K, V, HashK>&& that) = default; 426 SkTHashMap(const SkTHashMap<K, V, HashK>& that) = default; 427 428 SkTHashMap<K, V, HashK>& operator=(SkTHashMap<K, V, HashK>&& that) = default; 429 SkTHashMap<K, V, HashK>& operator=(const SkTHashMap<K, V, HashK>& that) = default; 430 431 // Construct with an initializer list of key-value pairs. 432 struct Pair : public std::pair<K, V> { 433 using std::pair<K, V>::pair; GetKeyPair434 static const K& GetKey(const Pair& p) { return p.first; } HashPair435 static auto Hash(const K& key) { return HashK()(key); } 436 }; 437 SkTHashMap(std::initializer_list<Pair> pairs)438 SkTHashMap(std::initializer_list<Pair> pairs) { 439 fTable.resize(pairs.size() * 5 / 3); 440 for (const Pair& p : pairs) { 441 fTable.set(p); 442 } 443 } 444 445 // Clear the map. reset()446 void reset() { fTable.reset(); } 447 448 // How many key/value pairs are in the table? count()449 int count() const { return fTable.count(); } 450 451 // Is empty? empty()452 bool empty() const { return fTable.count() == 0; } 453 454 // Approximately how many bytes of memory do we use beyond sizeof(*this)? approxBytesUsed()455 size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } 456 457 // N.B. The pointers returned by set() and find() are valid only until the next call to set(). 458 459 // Set key to val in the table, replacing any previous value with the same key. 460 // We copy both key and val, and return a pointer to the value copy now in the table. set(K key,V val)461 V* set(K key, V val) { 462 Pair* out = fTable.set({std::move(key), std::move(val)}); 463 return &out->second; 464 } 465 466 // If there is key/value entry in the table with this key, return a pointer to the value. 467 // If not, return null. find(const K & key)468 V* find(const K& key) const { 469 if (Pair* p = fTable.find(key)) { 470 return &p->second; 471 } 472 return nullptr; 473 } 474 475 V& operator[](const K& key) { 476 if (V* val = this->find(key)) { 477 return *val; 478 } 479 return *this->set(key, V{}); 480 } 481 482 // Remove the key/value entry in the table with this key. remove(const K & key)483 void remove(const K& key) { 484 SkASSERT(this->find(key)); 485 fTable.remove(key); 486 } 487 488 // Call fn on every key/value pair in the table. You may mutate the value but not the key. 489 template <typename Fn> // f(K, V*) or f(const K&, V*) foreach(Fn && fn)490 void foreach(Fn&& fn) { 491 fTable.foreach([&fn](Pair* p){ fn(p->first, &p->second); }); 492 } 493 494 // Call fn on every key/value pair in the table. You may not mutate anything. 495 template <typename Fn> // f(K, V), f(const K&, V), f(K, const V&) or f(const K&, const V&). foreach(Fn && fn)496 void foreach(Fn&& fn) const { 497 fTable.foreach([&fn](const Pair& p){ fn(p.first, p.second); }); 498 } 499 500 // Dereferencing an iterator gives back a key-value pair, suitable for structured binding. 501 using Iter = typename SkTHashTable<Pair, K>::template Iter<std::pair<K, V>>; 502 begin()503 Iter begin() const { 504 return Iter::MakeBegin(&fTable); 505 } 506 end()507 Iter end() const { 508 return Iter::MakeEnd(&fTable); 509 } 510 511 private: 512 SkTHashTable<Pair, K> fTable; 513 }; 514 515 // A set of T. T is treated as an ordinary copyable C++ type. 516 template <typename T, typename HashT = SkGoodHash> 517 class SkTHashSet { 518 public: 519 // Allow default construction and assignment. 520 SkTHashSet() = default; 521 522 SkTHashSet(SkTHashSet<T, HashT>&& that) = default; 523 SkTHashSet(const SkTHashSet<T, HashT>& that) = default; 524 525 SkTHashSet<T, HashT>& operator=(SkTHashSet<T, HashT>&& that) = default; 526 SkTHashSet<T, HashT>& operator=(const SkTHashSet<T, HashT>& that) = default; 527 528 // Construct with an initializer list of Ts. SkTHashSet(std::initializer_list<T> vals)529 SkTHashSet(std::initializer_list<T> vals) { 530 fTable.resize(vals.size() * 5 / 3); 531 for (const T& val : vals) { 532 fTable.set(val); 533 } 534 } 535 536 // Clear the set. reset()537 void reset() { fTable.reset(); } 538 539 // How many items are in the set? count()540 int count() const { return fTable.count(); } 541 542 // Is empty? empty()543 bool empty() const { return fTable.count() == 0; } 544 545 // Approximately how many bytes of memory do we use beyond sizeof(*this)? approxBytesUsed()546 size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } 547 548 // Copy an item into the set. add(T item)549 void add(T item) { fTable.set(std::move(item)); } 550 551 // Is this item in the set? contains(const T & item)552 bool contains(const T& item) const { return SkToBool(this->find(item)); } 553 554 // If an item equal to this is in the set, return a pointer to it, otherwise null. 555 // This pointer remains valid until the next call to add(). find(const T & item)556 const T* find(const T& item) const { return fTable.find(item); } 557 558 // Remove the item in the set equal to this. remove(const T & item)559 void remove(const T& item) { 560 SkASSERT(this->contains(item)); 561 fTable.remove(item); 562 } 563 564 // Call fn on every item in the set. You may not mutate anything. 565 template <typename Fn> // f(T), f(const T&) foreach(Fn && fn)566 void foreach (Fn&& fn) const { 567 fTable.foreach(fn); 568 } 569 570 private: 571 struct Traits { GetKeyTraits572 static const T& GetKey(const T& item) { return item; } HashTraits573 static auto Hash(const T& item) { return HashT()(item); } 574 }; 575 576 public: 577 using Iter = typename SkTHashTable<T, T, Traits>::template Iter<T>; 578 begin()579 Iter begin() const { 580 return Iter::MakeBegin(&fTable); 581 } 582 end()583 Iter end() const { 584 return Iter::MakeEnd(&fTable); 585 } 586 587 private: 588 SkTHashTable<T, T, Traits> fTable; 589 }; 590 591 #endif//SkTHash_DEFINED 592