7a4b9fab28
This eliminates any dynamic allocation for hash tables that are never used. This helps SkPicture, where some tables (SkPaint) are almost always used, but some rarely (SkMatrix) or never (SkRegion). This also removes the (as yet unimportant) ability for the hash table to shrink. This makes resizing harder to reason about, so I'd like to leave it out until we see a need. BUG=skia:1850 R=tomhudson@chromium.org, reed@google.com Author: mtklein@google.com Review URL: https://codereview.chromium.org/136403004 git-svn-id: http://skia.googlecode.com/svn/trunk@13051 2bbb7eff-a529-9590-31e7-b0007b416f81
146 lines
3.4 KiB
C++
146 lines
3.4 KiB
C++
/*
|
|
* Copyright 2013 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "Test.h"
|
|
#include "TestClassDef.h"
|
|
#include "SkTDynamicHash.h"
|
|
|
|
namespace {
|
|
|
|
struct Entry {
|
|
int key;
|
|
double value;
|
|
};
|
|
|
|
const int& GetKey(const Entry& entry) { return entry.key; }
|
|
uint32_t GetHash(const int& key) { return key; }
|
|
bool AreEqual(const Entry& entry, const int& key) { return entry.key == key; }
|
|
|
|
class Hash : public SkTDynamicHash<Entry, int, GetKey, GetHash, AreEqual> {
|
|
public:
|
|
Hash() : INHERITED() {}
|
|
|
|
// Promote protected methods to public for this test.
|
|
int capacity() const { return this->INHERITED::capacity(); }
|
|
int countCollisions(const int& key) const { return this->INHERITED::countCollisions(key); }
|
|
|
|
private:
|
|
typedef SkTDynamicHash<Entry, int, GetKey, GetHash, AreEqual> INHERITED;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
#define ASSERT(x) REPORTER_ASSERT(reporter, x)
|
|
|
|
static void test_growth(skiatest::Reporter* reporter) {
|
|
Entry a = { 1, 2.0 };
|
|
Entry b = { 2, 3.0 };
|
|
Entry c = { 3, 4.0 };
|
|
Entry d = { 4, 5.0 };
|
|
Entry e = { 5, 6.0 };
|
|
|
|
Hash hash;
|
|
ASSERT(hash.capacity() == 0);
|
|
|
|
hash.add(&a);
|
|
ASSERT(hash.capacity() == 4);
|
|
|
|
hash.add(&b);
|
|
ASSERT(hash.capacity() == 4);
|
|
|
|
hash.add(&c);
|
|
ASSERT(hash.capacity() == 4);
|
|
|
|
hash.add(&d);
|
|
ASSERT(hash.capacity() == 8);
|
|
|
|
hash.add(&e);
|
|
ASSERT(hash.capacity() == 8);
|
|
|
|
ASSERT(hash.count() == 5);
|
|
}
|
|
|
|
static void test_add(skiatest::Reporter* reporter) {
|
|
Hash hash;
|
|
Entry a = { 1, 2.0 };
|
|
Entry b = { 2, 3.0 };
|
|
|
|
ASSERT(hash.count() == 0);
|
|
hash.add(&a);
|
|
ASSERT(hash.count() == 1);
|
|
hash.add(&b);
|
|
ASSERT(hash.count() == 2);
|
|
}
|
|
|
|
static void test_lookup(skiatest::Reporter* reporter) {
|
|
Hash hash;
|
|
|
|
// These collide.
|
|
Entry a = { 1, 2.0 };
|
|
Entry b = { 5, 3.0 };
|
|
|
|
// Before we insert anything, nothing can collide.
|
|
ASSERT(hash.countCollisions(1) == 0);
|
|
ASSERT(hash.countCollisions(5) == 0);
|
|
ASSERT(hash.countCollisions(9) == 0);
|
|
|
|
// First is easy.
|
|
hash.add(&a);
|
|
ASSERT(hash.countCollisions(1) == 0);
|
|
ASSERT(hash.countCollisions(5) == 1);
|
|
ASSERT(hash.countCollisions(9) == 1);
|
|
|
|
// Second is one step away.
|
|
hash.add(&b);
|
|
ASSERT(hash.countCollisions(1) == 0);
|
|
ASSERT(hash.countCollisions(5) == 1);
|
|
ASSERT(hash.countCollisions(9) == 2);
|
|
|
|
// We can find our data right?
|
|
ASSERT(hash.find(1) != NULL);
|
|
ASSERT(hash.find(1)->value == 2.0);
|
|
ASSERT(hash.find(5) != NULL);
|
|
ASSERT(hash.find(5)->value == 3.0);
|
|
|
|
// These aren't in the hash.
|
|
ASSERT(hash.find(2) == NULL);
|
|
ASSERT(hash.find(9) == NULL);
|
|
}
|
|
|
|
static void test_remove(skiatest::Reporter* reporter) {
|
|
Hash hash;
|
|
|
|
// These collide.
|
|
Entry a = { 1, 2.0 };
|
|
Entry b = { 5, 3.0 };
|
|
Entry c = { 9, 4.0 };
|
|
|
|
hash.add(&a);
|
|
hash.add(&b);
|
|
hash.remove(1);
|
|
// a should be marked deleted, and b should still be findable.
|
|
|
|
ASSERT(hash.find(1) == NULL);
|
|
ASSERT(hash.find(5) != NULL);
|
|
ASSERT(hash.find(5)->value == 3.0);
|
|
|
|
// This will go in the same slot as 'a' did before.
|
|
ASSERT(hash.countCollisions(9) == 0);
|
|
hash.add(&c);
|
|
ASSERT(hash.find(9) != NULL);
|
|
ASSERT(hash.find(9)->value == 4.0);
|
|
ASSERT(hash.find(5) != NULL);
|
|
ASSERT(hash.find(5)->value == 3.0);
|
|
}
|
|
|
|
DEF_TEST(DynamicHash, reporter) {
|
|
test_growth(reporter);
|
|
test_add(reporter);
|
|
test_lookup(reporter);
|
|
test_remove(reporter);
|
|
}
|