diff options
author | 2011-01-25 23:36:05 +0000 | |
---|---|---|
committer | 2011-01-25 23:36:05 +0000 | |
commit | 0e190d0e126991cfba4bc7415c1911761d7be87b (patch) | |
tree | 93cee043ffa6c09206bd63ff523d0bd17f8e31f4 | |
parent | 02cc5aa736086320649d8a932515691ae18a0dd5 (diff) |
add refdict class, for holding a dictionary of reference-counted objects
-- experimental
git-svn-id: http://skia.googlecode.com/svn/trunk@730 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkRefDict.h | 45 | ||||
-rw-r--r-- | src/core/SkRefDict.cpp | 80 | ||||
-rw-r--r-- | src/core/core_files.mk | 1 | ||||
-rw-r--r-- | tests/RefDictTest.cpp | 52 | ||||
-rw-r--r-- | tests/tests_files.mk | 1 |
5 files changed, 179 insertions, 0 deletions
diff --git a/include/core/SkRefDict.h b/include/core/SkRefDict.h new file mode 100644 index 0000000000..c66f808b5d --- /dev/null +++ b/include/core/SkRefDict.h @@ -0,0 +1,45 @@ +#ifndef SkRefDict_DEFINED +#define SkRefDict_DEFINED + +#include "SkRefCnt.h" + +/** + * A dictionary of string,refcnt pairs. The dictionary is also an owner of the + * refcnt objects while they are contained. + */ +class SkRefDict : SkNoncopyable { +public: + SkRefDict(); + ~SkRefDict(); + + /** + * Return the data associated with name[], or NULL if no matching entry + * is found. The reference-count of the entry is not affected. + */ + SkRefCnt* find(const char name[]) const; + + /** + * If data is NULL, remove (if present) the entry matching name and call + * prev_data->unref() on the data for the matching entry. + * If data is not-NULL, replace the existing entry matching name and + * call (prev_data->unref()), or add a new one. In either case, + * data->ref() is called. + */ + void set(const char name[], SkRefCnt* data); + + /** + * Remove the matching entry (if found) and unref its data. + */ + void remove(const char name[]) { this->set(name, NULL); } + + /** + * Remove all entries, and unref() their associated data. + */ + void removeAll(); + +private: + struct Impl; + Impl* fImpl; +}; + +#endif diff --git a/src/core/SkRefDict.cpp b/src/core/SkRefDict.cpp new file mode 100644 index 0000000000..572ed7e180 --- /dev/null +++ b/src/core/SkRefDict.cpp @@ -0,0 +1,80 @@ +#include "SkRefDict.h" +#include "SkString.h" + +struct SkRefDict::Impl { + Impl* fNext; + SkString fName; + SkRefCnt* fData; +}; + +SkRefDict::SkRefDict() : fImpl(NULL) {} + +SkRefDict::~SkRefDict() { + this->removeAll(); +} + +SkRefCnt* SkRefDict::find(const char name[]) const { + if (NULL == name) { + return NULL; + } + + Impl* rec = fImpl; + while (rec) { + if (rec->fName.equals(name)) { + return rec->fData; + } + rec = rec->fNext; + } + return NULL; +} + +void SkRefDict::set(const char name[], SkRefCnt* data) { + if (NULL == name) { + return; + } + + Impl* rec = fImpl; + Impl* prev = NULL; + while (rec) { + if (rec->fName.equals(name)) { + if (data) { + // replace + data->ref(); + rec->fData->unref(); + rec->fData = data; + } else { + // remove + rec->fData->unref(); + if (prev) { + prev->fNext = rec->fNext; + } else { + fImpl = rec->fNext; + } + } + return; + } + prev = rec; + rec = rec->fNext; + } + + // if get here, name was not found, so add it + data->ref(); + rec = new Impl; + rec->fName.set(name); + rec->fData = data; + // prepend to the head of our list + rec->fNext = fImpl; + fImpl = rec; +} + +void SkRefDict::removeAll() { + Impl* rec = fImpl; + while (rec) { + Impl* next = rec->fNext; + rec->fData->unref(); + delete rec; + rec = next; + } + fImpl = NULL; +} + diff --git a/src/core/core_files.mk b/src/core/core_files.mk index 235fa76ac2..3e3436e9cc 100644 --- a/src/core/core_files.mk +++ b/src/core/core_files.mk @@ -71,6 +71,7 @@ SOURCE := \ SkRasterizer.cpp \ SkRect.cpp \ SkRefCnt.cpp \ + SkRefDict.cpp \ SkRegion.cpp \ SkRegion_rects.cpp \ SkRegion_path.cpp \ diff --git a/tests/RefDictTest.cpp b/tests/RefDictTest.cpp new file mode 100644 index 0000000000..61f64e9a2c --- /dev/null +++ b/tests/RefDictTest.cpp @@ -0,0 +1,52 @@ +#include "Test.h" +#include "SkRefDict.h" + +class TestRC : public SkRefCnt { +}; + +static void TestRefDict(skiatest::Reporter* reporter) { + TestRC data0, data1; + SkRefDict dict; + + REPORTER_ASSERT(reporter, NULL == dict.find(NULL)); + REPORTER_ASSERT(reporter, NULL == dict.find("foo")); + REPORTER_ASSERT(reporter, NULL == dict.find("bar")); + + dict.set("foo", &data0); + REPORTER_ASSERT(reporter, &data0 == dict.find("foo")); + REPORTER_ASSERT(reporter, 2 == data0.getRefCnt()); + + dict.set("foo", &data0); + REPORTER_ASSERT(reporter, &data0 == dict.find("foo")); + REPORTER_ASSERT(reporter, 2 == data0.getRefCnt()); + + dict.set("foo", &data1); + REPORTER_ASSERT(reporter, &data1 == dict.find("foo")); + REPORTER_ASSERT(reporter, 1 == data0.getRefCnt()); + REPORTER_ASSERT(reporter, 2 == data1.getRefCnt()); + + dict.set("foo", NULL); + REPORTER_ASSERT(reporter, NULL == dict.find("foo")); + REPORTER_ASSERT(reporter, 1 == data0.getRefCnt()); + REPORTER_ASSERT(reporter, 1 == data1.getRefCnt()); + + dict.set("foo", &data0); + dict.set("bar", &data1); + REPORTER_ASSERT(reporter, &data0 == dict.find("foo")); + REPORTER_ASSERT(reporter, &data1 == dict.find("bar")); + REPORTER_ASSERT(reporter, 2 == data0.getRefCnt()); + REPORTER_ASSERT(reporter, 2 == data1.getRefCnt()); + + dict.set("foo", &data1); + REPORTER_ASSERT(reporter, &data1 == dict.find("foo")); + REPORTER_ASSERT(reporter, &data1 == dict.find("bar")); + REPORTER_ASSERT(reporter, 1 == data0.getRefCnt()); + REPORTER_ASSERT(reporter, 3 == data1.getRefCnt()); + + dict.removeAll(); + REPORTER_ASSERT(reporter, NULL == dict.find("foo")); + REPORTER_ASSERT(reporter, NULL == dict.find("bar")); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("RefDict", RefDictTestClass, TestRefDict) diff --git a/tests/tests_files.mk b/tests/tests_files.mk index 0911c3f009..cc21c7c6f7 100644 --- a/tests/tests_files.mk +++ b/tests/tests_files.mk @@ -13,6 +13,7 @@ SOURCE := \ ParsePathTest.cpp \ PathMeasureTest.cpp \ PathTest.cpp \ + RefDictTest.cpp \ RegionTest.cpp \ Sk64Test.cpp \ skia_test.cpp \ |