Index: src/core/SkTDynamicHash.h |
diff --git a/src/core/SkTDynamicHash.h b/src/core/SkTDynamicHash.h |
index 665028abaa398cd25700237316122d47ca6b91e7..b4787fb89e361ec793ab13cf25181795e5978789 100644 |
--- a/src/core/SkTDynamicHash.h |
+++ b/src/core/SkTDynamicHash.h |
@@ -14,19 +14,22 @@ template <typename T, typename KEY, const KEY& (KEY_FROM_T)(const T&), |
uint32_t (HASH_FROM_KEY)(const Key&), bool (EQ_T_KEY)(const T&, const Key&)> |
class SkTDynamicHash { |
private: |
- T* fStorage[1]; |
+ T* fStorage[4]; |
T** fArray; |
int fCapacity; |
int fCountUsed; |
int fCountDeleted; |
- unsigned hashMask() const { return fCapacity - 1; } |
const T* deletedValue() const { return reinterpret_cast<const T*>(-1); } |
- |
+ uint32_t hashMask() const { return fCapacity - 1; } |
+ int hashToIndex(uint32_t hash) const { |
+ return ((hash >> 16) ^ hash) & (fCapacity - 1); |
+ } |
public: |
SkTDynamicHash() { |
+ sk_bzero(fStorage, sizeof(fStorage)); |
fArray = fStorage; |
- fCapacity = 1; |
+ fCapacity = SK_ARRAY_COUNT(fStorage); |
fCountUsed = fCountDeleted = 0; |
} |
~SkTDynamicHash() { |
@@ -38,8 +41,7 @@ public: |
T* find(const KEY& key) { |
const T* const deleted = this->deletedValue(); |
const unsigned mask = this->hashMask(); |
- int index = HASH_FROM_KEY(key) & mask; |
- const int origIndex = index; |
+ int index = this->hashToIndex(HASH_FROM_KEY(key)); |
int delta = 1; |
do { |
@@ -52,7 +54,7 @@ public: |
} |
index = (index + delta) & mask; |
delta <<= 1; |
- } while (index != origIndex); |
+ } while (delta <= fCapacity); |
return NULL; |
} |
@@ -60,8 +62,7 @@ public: |
const T* const deleted = this->deletedValue(); |
for (;;) { |
const unsigned mask = this->hashMask(); |
- int index = HASH_FROM_KEY(key) & mask; |
- const int origIndex = index; |
+ int index = this->hashToIndex(HASH_FROM_KEY(key)); |
int delta = 1; |
do { |
@@ -77,7 +78,7 @@ public: |
} |
index = (index + delta) & mask; |
delta <<= 1; |
- } while (index != origIndex); |
+ } while (delta <= fCapacity); |
if (autoGrow) { |
this->grow(); |
} else { |
@@ -91,9 +92,7 @@ public: |
void remove(const KEY& key) { |
const T* const deleted = this->deletedValue(); |
const unsigned mask = this->hashMask(); |
- const uint32_t hash = HASH_FROM_KEY(key); |
- int index = hash & mask; |
- SkDEBUGCODE(const int origIndex = index;) |
+ int index = this->hashToIndex(HASH_FROM_KEY(key)); |
int delta = 1; |
for (;;) { |
@@ -101,20 +100,51 @@ public: |
SkASSERT(candidate); |
if (deleted != candidate && EQ_T_KEY(*candidate, key)) { |
fArray[index] = const_cast<T*>(deleted); |
+ fCountUsed -= 1; |
fCountDeleted += 1; |
break; |
} |
index = (index + delta) & mask; |
delta <<= 1; |
- SkASSERT(index != origIndex); |
+ SkASSERT(delta <= fCapacity); |
} |
this->checkStrink(); |
} |
private: |
+ int countCollisions(const Key& key) const { |
+ const T* const deleted = this->deletedValue(); |
+ const unsigned mask = this->hashMask(); |
+ int index = this->hashToIndex(HASH_FROM_KEY(key)); |
+ int delta = 1; |
+ int collisionCount = 0; |
+ |
+ for (;;) { |
+ const T* candidate = fArray[index]; |
+ SkASSERT(candidate); |
+ if (deleted != candidate && EQ_T_KEY(*candidate, key)) { |
+ break; |
+ } |
+ index = (index + delta) & mask; |
+ delta <<= 1; |
+ collisionCount += 1; |
+ SkASSERT(delta <= fCapacity); |
+ } |
+ return collisionCount; |
+ } |
+ |
void grow() { |
const T* const deleted = this->deletedValue(); |
- |
+#if 0 |
+ SkDebugf("growing from %d: used=%d\n", fCapacity, fCountUsed); |
+ for (int i = 0; i < fCapacity; ++i) { |
+ T* elem = fArray[i]; |
+ if (NULL == elem || deleted == elem) { |
+ continue; |
+ } |
+ SkDebugf(" entry[%d] had %d collisions\n", i, countCollisions(KEY_FROM_T(*elem))); |
+ } |
+#endif |
int oldCapacity = fCapacity; |
T** oldArray = fArray; |
@@ -137,10 +167,16 @@ private: |
SkASSERT(success); |
} |
SkASSERT(oldCountUsed == fCountUsed); |
- sk_free(oldArray); |
+ |
+ if (oldArray != fStorage) { |
+ sk_free(oldArray); |
+ } |
} |
- void checkStrink() {} |
+ void checkStrink() { |
+ // todo: based on density and deadspace (fCountDeleted), consider |
+ // shrinking fArray and repopulating it. |
+ } |
}; |
#endif |