const Key& (GetKey)(const T&),
uint32_t (Hash)(const Key&),
bool (Equal)(const T&, const Key&),
- int kGrowPercent = 75, // Larger -> more memory efficient, but slower.
- int kShrinkPercent = 25>
+ int kGrowPercent = 75> // Larger -> more memory efficient, but slower.
class SkTDynamicHash {
- static const int kMinCapacity = 4; // Smallest capacity we allow.
public:
- SkTDynamicHash(int initialCapacity=64/sizeof(T*)) {
- this->reset(SkNextPow2(initialCapacity > kMinCapacity ? initialCapacity : kMinCapacity));
+ SkTDynamicHash() : fCount(0), fDeleted(0), fCapacity(0), fArray(NULL) {
SkASSERT(this->validate());
}
}
index = this->nextIndex(index, round);
}
- SkASSERT(0); // find: should be unreachable
+ SkASSERT(fCapacity == 0);
return NULL;
}
SkASSERT(NULL != this->find(key));
this->innerRemove(key);
SkASSERT(this->validate());
- this->maybeShrink();
- SkASSERT(this->validate());
}
protected:
}
index = this->nextIndex(index, round);
}
- SkASSERT(0); // countCollisions: should be unreachable
- return -1;
+ SkASSERT(fCapacity == 0);
+ return 0;
}
private:
static T* Empty() { return reinterpret_cast<T*>(0); } // i.e. NULL
static T* Deleted() { return reinterpret_cast<T*>(1); } // Also an invalid pointer.
- static T** AllocArray(int capacity) {
- return (T**)sk_calloc_throw(sizeof(T*) * capacity); // All cells == Empty().
- }
-
- void reset(int capacity) {
- fCount = 0;
- fDeleted = 0;
- fCapacity = capacity;
- fArray = AllocArray(fCapacity);
- }
-
bool validate() const {
#define SKTDYNAMICHASH_CHECK(x) SkASSERT((x)); if (!(x)) return false
// Is capacity sane?
SKTDYNAMICHASH_CHECK(SkIsPow2(fCapacity));
- SKTDYNAMICHASH_CHECK(fCapacity >= kMinCapacity);
// Is fCount correct?
int count = 0;
}
index = this->nextIndex(index, round);
}
- SkASSERT(0); // add: should be unreachable
+ SkASSERT(fCapacity == 0);
}
void innerRemove(const Key& key) {
}
index = this->nextIndex(index, round);
}
- SkASSERT(0); // innerRemove: should be unreachable
+ SkASSERT(fCapacity == 0);
}
void maybeGrow() {
- if (fCount + fDeleted + 1 > (fCapacity * kGrowPercent) / 100) {
- resize(fCapacity * 2);
- }
- }
-
- void maybeShrink() {
- if (fCount < (fCapacity * kShrinkPercent) / 100 && fCapacity / 2 > kMinCapacity) {
- resize(fCapacity / 2);
+ if (100 * (fCount + fDeleted + 1) > fCapacity * kGrowPercent) {
+ this->resize(fCapacity > 0 ? fCapacity * 2 : 4);
}
}
void resize(int newCapacity) {
SkDEBUGCODE(int oldCount = fCount;)
int oldCapacity = fCapacity;
- T** oldArray = fArray;
+ SkAutoTMalloc<T*> oldArray(fArray);
- reset(newCapacity);
+ fCount = fDeleted = 0;
+ fCapacity = newCapacity;
+ fArray = (T**)sk_calloc_throw(sizeof(T*) * fCapacity);
for (int i = 0; i < oldCapacity; i++) {
T* entry = oldArray[i];
if (Empty() != entry && Deleted() != entry) {
- this->add(entry);
+ this->innerAdd(entry);
}
}
SkASSERT(oldCount == fCount);
-
- sk_free(oldArray);
}
// fCapacity is always a power of 2, so this masks the correct low bits to index into our hash.
class Hash : public SkTDynamicHash<Entry, int, GetKey, GetHash, AreEqual> {
public:
Hash() : INHERITED() {}
- Hash(int capacity) : INHERITED(capacity) {}
// Promote protected methods to public for this test.
int capacity() const { return this->INHERITED::capacity(); }
Entry d = { 4, 5.0 };
Entry e = { 5, 6.0 };
- Hash hash(4);
- ASSERT(hash.capacity() == 4);
+ Hash hash;
+ ASSERT(hash.capacity() == 0);
hash.add(&a);
ASSERT(hash.capacity() == 4);
}
static void test_lookup(skiatest::Reporter* reporter) {
- Hash hash(4);
- ASSERT(hash.capacity() == 4);
+ Hash hash;
// These collide.
Entry a = { 1, 2.0 };
}
static void test_remove(skiatest::Reporter* reporter) {
- Hash hash(4);
- ASSERT(hash.capacity() == 4);
+ Hash hash;
// These collide.
Entry a = { 1, 2.0 };