SkTDynamicHash.h revision 5d1e5589fe446a59372debd8c7221170e21ec2b8
15d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com/* 25d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com * Copyright 2013 Google Inc. 35d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com * 45d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com * Use of this source code is governed by a BSD-style license that can be 55d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com * found in the LICENSE file. 65d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com */ 75d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 85d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#ifndef SkTDynamicHash_DEFINED 95d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#define SkTDynamicHash_DEFINED 105d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 115d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#include "SkTypes.h" 125d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 135d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comtemplate <typename T, typename KEY, const KEY& (KEY_FROM_T)(const T&), 145d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comuint32_t (HASH_FROM_KEY)(const Key&), bool (EQ_T_KEY)(const T&, const Key&)> 155d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comclass SkTDynamicHash { 165d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comprivate: 175d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com T* fStorage[1]; 185d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com T** fArray; 195d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int fCapacity; 205d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int fCountUsed; 215d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int fCountDeleted; 225d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 235d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com unsigned hashMask() const { return fCapacity - 1; } 245d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const T* deletedValue() const { return reinterpret_cast<const T*>(-1); } 255d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 265d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.compublic: 275d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkTDynamicHash() { 285d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fArray = fStorage; 295d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCapacity = 1; 305d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCountUsed = fCountDeleted = 0; 315d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 325d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com ~SkTDynamicHash() { 335d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (fArray != fStorage) { 345d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com sk_free(fArray); 355d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 365d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 375d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 385d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com T* find(const KEY& key) { 395d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const T* const deleted = this->deletedValue(); 405d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const unsigned mask = this->hashMask(); 415d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int index = HASH_FROM_KEY(key) & mask; 425d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const int origIndex = index; 435d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int delta = 1; 445d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 455d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com do { 465d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com T* candidate = fArray[index]; 475d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (NULL == candidate) { 485d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com return NULL; 495d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 505d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (deleted != candidate && EQ_T_KEY(*candidate, key)) { 515d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com return candidate; 525d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 535d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com index = (index + delta) & mask; 545d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com delta <<= 1; 555d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } while (index != origIndex); 565d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com return NULL; 575d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 585d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 595d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com bool add(const KEY& key, T* newElement, bool autoGrow = true) { 605d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const T* const deleted = this->deletedValue(); 615d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com for (;;) { 625d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const unsigned mask = this->hashMask(); 635d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int index = HASH_FROM_KEY(key) & mask; 645d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const int origIndex = index; 655d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int delta = 1; 665d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 675d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com do { 685d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const T* candidate = fArray[index]; 695d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (NULL == candidate || deleted == candidate) { 705d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fArray[index] = newElement; 715d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCountUsed += 1; 725d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (deleted == candidate) { 735d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkASSERT(fCountDeleted > 0); 745d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCountDeleted -= 1; 755d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 765d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com return true; 775d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 785d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com index = (index + delta) & mask; 795d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com delta <<= 1; 805d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } while (index != origIndex); 815d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (autoGrow) { 825d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com this->grow(); 835d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } else { 845d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com return false; 855d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 865d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 875d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkASSERT(!"never get here"); 885d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com return false; 895d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 905d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 915d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com void remove(const KEY& key) { 925d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const T* const deleted = this->deletedValue(); 935d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const unsigned mask = this->hashMask(); 945d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const uint32_t hash = HASH_FROM_KEY(key); 955d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int index = hash & mask; 965d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkDEBUGCODE(const int origIndex = index;) 975d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int delta = 1; 985d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 995d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com for (;;) { 1005d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const T* candidate = fArray[index]; 1015d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkASSERT(candidate); 1025d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (deleted != candidate && EQ_T_KEY(*candidate, key)) { 1035d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fArray[index] = const_cast<T*>(deleted); 1045d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCountDeleted += 1; 1055d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com break; 1065d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 1075d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com index = (index + delta) & mask; 1085d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com delta <<= 1; 1095d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkASSERT(index != origIndex); 1105d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 1115d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com this->checkStrink(); 1125d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 1135d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 1145d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.comprivate: 1155d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com void grow() { 1165d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com const T* const deleted = this->deletedValue(); 1175d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 1185d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int oldCapacity = fCapacity; 1195d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com T** oldArray = fArray; 1205d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 1215d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com int newCapacity = oldCapacity << 1; 1225d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com T** newArray = (T**)sk_malloc_throw(sizeof(T*) * newCapacity); 1235d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com sk_bzero(newArray, sizeof(T*) * newCapacity); 1245d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 1255d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkDEBUGCODE(int oldCountUsed = fCountUsed;) 1265d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fArray = newArray; 1275d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCapacity = newCapacity; 1285d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCountUsed = 0; 1295d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com fCountDeleted = 0; 1305d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 1315d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com for (int i = 0; i < oldCapacity; ++i) { 1325d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com T* elem = oldArray[i]; 1335d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com if (NULL == elem || deleted == elem) { 1345d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com continue; 1355d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 1365d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkDEBUGCODE(bool success =) this->add(KEY_FROM_T(*elem), elem, false); 1375d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkASSERT(success); 1385d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 1395d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com SkASSERT(oldCountUsed == fCountUsed); 1405d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com sk_free(oldArray); 1415d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com } 1425d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 1435d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com void checkStrink() {} 1445d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com}; 1455d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com 1465d1e5589fe446a59372debd8c7221170e21ec2b8reed@google.com#endif 147