aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-01-25 23:36:05 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-01-25 23:36:05 +0000
commit0e190d0e126991cfba4bc7415c1911761d7be87b (patch)
tree93cee043ffa6c09206bd63ff523d0bd17f8e31f4
parent02cc5aa736086320649d8a932515691ae18a0dd5 (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.h45
-rw-r--r--src/core/SkRefDict.cpp80
-rw-r--r--src/core/core_files.mk1
-rw-r--r--tests/RefDictTest.cpp52
-rw-r--r--tests/tests_files.mk1
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 \