From e733071abeb9cce9f524f5a85851bc7fbb8d867b Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Wed, 30 Mar 2011 18:23:21 +0000 Subject: [PATCH] add refcnt helper to metadata add unittests for metadata git-svn-id: http://skia.googlecode.com/svn/trunk@1019 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkMetaData.h | 117 ++++++++++++++----------- src/core/SkMetaData.cpp | 217 ++++++++++++++-------------------------------- tests/MetaDataTest.cpp | 112 ++++++++++++++++++++++++ tests/tests_files.mk | 1 + 4 files changed, 248 insertions(+), 199 deletions(-) create mode 100644 tests/MetaDataTest.cpp diff --git a/include/core/SkMetaData.h b/include/core/SkMetaData.h index 9509710..5e6f376 100644 --- a/include/core/SkMetaData.h +++ b/include/core/SkMetaData.h @@ -19,47 +19,69 @@ #include "SkScalar.h" +class SkRefCnt; + class SkMetaData { public: + /** + * Used to manage the life-cycle of a ptr in the metadata. This is option + * in setPtr, and is only invoked when either copying one metadata to + * another, or when the metadata is destroyed. + * + * setPtr(name, ptr, proc) { + * fPtr = proc(ptr, true); + * } + * + * copy: A = B { + * A.fPtr = B.fProc(B.fPtr, true); + * } + * + * ~SkMetaData { + * fProc(fPtr, false); + * } + */ + typedef void* (*PtrProc)(void* ptr, bool doRef); + + /** + * Implements PtrProc for SkRefCnt pointers + */ + static void* RefCntProc(void* ptr, bool doRef); + SkMetaData(); SkMetaData(const SkMetaData& src); ~SkMetaData(); SkMetaData& operator=(const SkMetaData& src); - void reset(); + void reset(); - bool findS32(const char name[], int32_t* value = NULL) const; - bool findScalar(const char name[], SkScalar* value = NULL) const; - const SkScalar* findScalars(const char name[], int* count, SkScalar values[] = NULL) const; + bool findS32(const char name[], int32_t* value = NULL) const; + bool findScalar(const char name[], SkScalar* value = NULL) const; + const SkScalar* findScalars(const char name[], int* count, + SkScalar values[] = NULL) const; const char* findString(const char name[]) const; - bool findPtr(const char name[], void** value = NULL) const; - bool findBool(const char name[], bool* value = NULL) const; + bool findPtr(const char name[], void** value = NULL, PtrProc* = NULL) const; + bool findBool(const char name[], bool* value = NULL) const; const void* findData(const char name[], size_t* byteCount = NULL) const; - bool hasS32(const char name[], int32_t value) const - { + bool hasS32(const char name[], int32_t value) const { int32_t v; return this->findS32(name, &v) && v == value; } - bool hasScalar(const char name[], SkScalar value) const - { - SkScalar v; + bool hasScalar(const char name[], SkScalar value) const { + SkScalar v; return this->findScalar(name, &v) && v == value; } - bool hasString(const char name[], const char value[]) const - { + bool hasString(const char name[], const char value[]) const { const char* v = this->findString(name); return v == NULL && value == NULL || v != NULL && value != NULL && !strcmp(v, value); } - bool hasPtr(const char name[], void* value) const - { - void* v; + bool hasPtr(const char name[], void* value) const { + void* v; return this->findPtr(name, &v) && v == value; } - bool hasBool(const char name[], bool value) const - { + bool hasBool(const char name[], bool value) const { bool v; return this->findBool(name, &v) && v == value; } @@ -69,23 +91,35 @@ public: return NULL != ptr && len == byteCount && !memcmp(ptr, data, len); } - void setS32(const char name[], int32_t value); - void setScalar(const char name[], SkScalar value); + void setS32(const char name[], int32_t value); + void setScalar(const char name[], SkScalar value); SkScalar* setScalars(const char name[], int count, const SkScalar values[] = NULL); - void setString(const char name[], const char value[]); - void setPtr(const char name[], void* value); - void setBool(const char name[], bool value); + void setString(const char name[], const char value[]); + void setPtr(const char name[], void* value, PtrProc proc = NULL); + void setBool(const char name[], bool value); // the data is copied from the input pointer. - void setData(const char name[], const void* data, size_t byteCount); - - bool removeS32(const char name[]); - bool removeScalar(const char name[]); - bool removeString(const char name[]); - bool removePtr(const char name[]); - bool removeBool(const char name[]); - bool removeData(const char name[]); - - SkDEBUGCODE(static void UnitTest();) + void setData(const char name[], const void* data, size_t byteCount); + + bool removeS32(const char name[]); + bool removeScalar(const char name[]); + bool removeString(const char name[]); + bool removePtr(const char name[]); + bool removeBool(const char name[]); + bool removeData(const char name[]); + + // helpers for SkRefCnt + bool findRefCnt(const char name[], SkRefCnt** ptr = NULL) { + return this->findPtr(name, reinterpret_cast(ptr)); + } + bool hasRefCnt(const char name[], SkRefCnt* ptr) { + return this->hasPtr(name, ptr); + } + void setRefCnt(const char name[], SkRefCnt* ptr) { + this->setPtr(name, ptr, RefCntProc); + } + bool removeRefCnt(const char name[]) { + return this->removePtr(name); + } enum Type { kS32_Type, @@ -110,7 +144,7 @@ public: /** Reset the iterator, so that calling next() will return the first data element. This is done implicitly in the constructor. */ - void reset(const SkMetaData&); + void reset(const SkMetaData&); /** Each time next is called, it returns the name of the next data element, or null when there are no more elements. If non-null is returned, then the @@ -128,22 +162,7 @@ public: Rec* fNext; uint16_t fDataCount; // number of elements uint8_t fDataLen; // sizeof a single element -#ifdef SK_DEBUG - Type fType; -#else uint8_t fType; -#endif - -#ifdef SK_DEBUG - const char* fName; - union { - int32_t fS32; - SkScalar fScalar; - const char* fString; - void* fPtr; - bool fBool; - } fData; -#endif const void* data() const { return (this + 1); } void* data() { return (this + 1); } diff --git a/src/core/SkMetaData.cpp b/src/core/SkMetaData.cpp index c871efb..b1901dc 100644 --- a/src/core/SkMetaData.cpp +++ b/src/core/SkMetaData.cpp @@ -16,6 +16,24 @@ */ #include "SkMetaData.h" +#include "SkRefCnt.h" + +struct PtrPair { + void* fPtr; + SkMetaData::PtrProc fProc; +}; + +void* SkMetaData::RefCntProc(void* ptr, bool doRef) { + SkASSERT(ptr); + SkRefCnt* refcnt = reinterpret_cast(ptr); + + if (doRef) { + refcnt->ref(); + } else { + refcnt->unref(); + } + return ptr; +} SkMetaData::SkMetaData() : fRec(NULL) { @@ -34,8 +52,13 @@ SkMetaData::~SkMetaData() void SkMetaData::reset() { Rec* rec = fRec; - while (rec) - { + while (rec) { + if (kPtr_Type == rec->fType) { + PtrPair* pair = (PtrPair*)rec->data(); + if (pair->fProc && pair->fPtr) { + pair->fPtr = pair->fProc(pair->fPtr, false); + } + } Rec* next = rec->fNext; Rec::Free(rec); rec = next; @@ -79,9 +102,9 @@ void SkMetaData::setString(const char name[], const char value[]) (void)this->set(name, value, sizeof(char), kString_Type, strlen(value) + 1); } -void SkMetaData::setPtr(const char name[], void* ptr) -{ - (void)this->set(name, &ptr, sizeof(void*), kPtr_Type, 1); +void SkMetaData::setPtr(const char name[], void* ptr, PtrProc proc) { + PtrPair pair = { ptr, proc }; + (void)this->set(name, &pair, sizeof(PtrPair), kPtr_Type, 1); } void SkMetaData::setBool(const char name[], bool value) @@ -115,32 +138,12 @@ void* SkMetaData::set(const char name[], const void* data, size_t dataSize, Type memcpy(rec->data(), data, dataSize * count); memcpy(rec->name(), name, len + 1); -#ifdef SK_DEBUG - rec->fName = rec->name(); - switch (type) { - case kS32_Type: - rec->fData.fS32 = *(const int32_t*)rec->data(); - break; - case kScalar_Type: - rec->fData.fScalar = *(const SkScalar*)rec->data(); - break; - case kString_Type: - rec->fData.fString = (const char*)rec->data(); - break; - case kPtr_Type: - rec->fData.fPtr = *(void**)rec->data(); - break; - case kBool_Type: - rec->fData.fBool = *(const bool*)rec->data(); - break; - case kData_Type: - rec->fData.fPtr = rec->data(); - break; - default: - SkASSERT(!"bad type"); - break; + if (kPtr_Type == type) { + PtrPair* pair = (PtrPair*)rec->data(); + if (pair->fProc && pair->fPtr) { + pair->fPtr = pair->fProc(pair->fPtr, true); + } } -#endif rec->fNext = fRec; fRec = rec; @@ -187,14 +190,17 @@ const SkScalar* SkMetaData::findScalars(const char name[], int* count, SkScalar return NULL; } -bool SkMetaData::findPtr(const char name[], void** value) const -{ +bool SkMetaData::findPtr(const char name[], void** ptr, PtrProc* proc) const { const Rec* rec = this->find(name, kPtr_Type); - if (rec) - { + if (rec) { SkASSERT(rec->fDataCount == 1); - if (value) - *value = *(void**)rec->data(); + const PtrPair* pair = (const PtrPair*)rec->data(); + if (ptr) { + *ptr = pair->fPtr; + } + if (proc) { + *proc = pair->fProc; + } return true; } return false; @@ -244,19 +250,24 @@ const SkMetaData::Rec* SkMetaData::find(const char name[], Type type) const return NULL; } -bool SkMetaData::remove(const char name[], Type type) -{ +bool SkMetaData::remove(const char name[], Type type) { Rec* rec = fRec; Rec* prev = NULL; - while (rec) - { + while (rec) { Rec* next = rec->fNext; - if (rec->fType == type && !strcmp(rec->name(), name)) - { - if (prev) + if (rec->fType == type && !strcmp(rec->name(), name)) { + if (prev) { prev->fNext = next; - else + } else { fRec = next; + } + + if (kPtr_Type == type) { + PtrPair* pair = (PtrPair*)rec->data(); + if (pair->fProc && pair->fPtr) { + (void)pair->fProc(pair->fPtr, false); + } + } Rec::Free(rec); return true; } @@ -295,28 +306,26 @@ bool SkMetaData::removeData(const char name[]) { return this->remove(name, kData_Type); } -/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -SkMetaData::Iter::Iter(const SkMetaData& metadata) -{ +SkMetaData::Iter::Iter(const SkMetaData& metadata) { fRec = metadata.fRec; } -void SkMetaData::Iter::reset(const SkMetaData& metadata) -{ +void SkMetaData::Iter::reset(const SkMetaData& metadata) { fRec = metadata.fRec; } -const char* SkMetaData::Iter::next(SkMetaData::Type* t, int* count) -{ +const char* SkMetaData::Iter::next(SkMetaData::Type* t, int* count) { const char* name = NULL; - if (fRec) - { - if (t) + if (fRec) { + if (t) { *t = (SkMetaData::Type)fRec->fType; - if (count) + } + if (count) { *count = fRec->fDataCount; + } name = fRec->name(); fRec = fRec->fNext; @@ -324,105 +333,13 @@ const char* SkMetaData::Iter::next(SkMetaData::Type* t, int* count) return name; } -/////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -SkMetaData::Rec* SkMetaData::Rec::Alloc(size_t size) -{ +SkMetaData::Rec* SkMetaData::Rec::Alloc(size_t size) { return (Rec*)sk_malloc_throw(size); } -void SkMetaData::Rec::Free(Rec* rec) -{ +void SkMetaData::Rec::Free(Rec* rec) { sk_free(rec); } -/////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////// - -#ifdef SK_DEBUG - -void SkMetaData::UnitTest() -{ -#ifdef SK_SUPPORT_UNITTEST - SkMetaData m1; - - SkASSERT(!m1.findS32("int")); - SkASSERT(!m1.findScalar("scalar")); - SkASSERT(!m1.findString("hello")); - SkASSERT(!m1.removeS32("int")); - SkASSERT(!m1.removeScalar("scalar")); - SkASSERT(!m1.removeString("hello")); - SkASSERT(!m1.removeString("true")); - SkASSERT(!m1.removeString("false")); - - m1.setS32("int", 12345); - m1.setScalar("scalar", SK_Scalar1 * 42); - m1.setString("hello", "world"); - m1.setPtr("ptr", &m1); - m1.setBool("true", true); - m1.setBool("false", false); - - int32_t n; - SkScalar s; - - m1.setScalar("scalar", SK_Scalar1/2); - - SkASSERT(m1.findS32("int", &n) && n == 12345); - SkASSERT(m1.findScalar("scalar", &s) && s == SK_Scalar1/2); - SkASSERT(!strcmp(m1.findString("hello"), "world")); - SkASSERT(m1.hasBool("true", true)); - SkASSERT(m1.hasBool("false", false)); - - Iter iter(m1); - const char* name; - - static const struct { - const char* fName; - SkMetaData::Type fType; - int fCount; - } gElems[] = { - { "int", SkMetaData::kS32_Type, 1 }, - { "scalar", SkMetaData::kScalar_Type, 1 }, - { "ptr", SkMetaData::kPtr_Type, 1 }, - { "hello", SkMetaData::kString_Type, sizeof("world") }, - { "true", SkMetaData::kBool_Type, 1 }, - { "false", SkMetaData::kBool_Type, 1 } - }; - - int loop = 0; - int count; - SkMetaData::Type t; - while ((name = iter.next(&t, &count)) != NULL) - { - int match = 0; - for (unsigned i = 0; i < SK_ARRAY_COUNT(gElems); i++) - { - if (!strcmp(name, gElems[i].fName)) - { - match += 1; - SkASSERT(gElems[i].fType == t); - SkASSERT(gElems[i].fCount == count); - } - } - SkASSERT(match == 1); - loop += 1; - } - SkASSERT(loop == SK_ARRAY_COUNT(gElems)); - - SkASSERT(m1.removeS32("int")); - SkASSERT(m1.removeScalar("scalar")); - SkASSERT(m1.removeString("hello")); - SkASSERT(m1.removeBool("true")); - SkASSERT(m1.removeBool("false")); - - SkASSERT(!m1.findS32("int")); - SkASSERT(!m1.findScalar("scalar")); - SkASSERT(!m1.findString("hello")); - SkASSERT(!m1.findBool("true")); - SkASSERT(!m1.findBool("false")); -#endif -} - -#endif - - diff --git a/tests/MetaDataTest.cpp b/tests/MetaDataTest.cpp new file mode 100644 index 0000000..70829d4 --- /dev/null +++ b/tests/MetaDataTest.cpp @@ -0,0 +1,112 @@ +#include "Test.h" +#include "SkMetaData.h" + +static void test_ptrs(skiatest::Reporter* reporter) { + SkRefCnt ref; + REPORTER_ASSERT(reporter, 1 == ref.getRefCnt()); + + { + SkMetaData md0, md1; + const char name[] = "refcnt"; + + md0.setRefCnt(name, &ref); + REPORTER_ASSERT(reporter, md0.findRefCnt(name)); + REPORTER_ASSERT(reporter, md0.hasRefCnt(name, &ref)); + REPORTER_ASSERT(reporter, 2 == ref.getRefCnt()); + + md1 = md0; + REPORTER_ASSERT(reporter, md1.findRefCnt(name)); + REPORTER_ASSERT(reporter, md1.hasRefCnt(name, &ref)); + REPORTER_ASSERT(reporter, 3 == ref.getRefCnt()); + + REPORTER_ASSERT(reporter, md0.removeRefCnt(name)); + REPORTER_ASSERT(reporter, !md0.findRefCnt(name)); + REPORTER_ASSERT(reporter, !md0.hasRefCnt(name, &ref)); + REPORTER_ASSERT(reporter, 2 == ref.getRefCnt()); + } + REPORTER_ASSERT(reporter, 1 == ref.getRefCnt()); +} + +static void TestMetaData(skiatest::Reporter* reporter) { + SkMetaData m1; + + REPORTER_ASSERT(reporter, !m1.findS32("int")); + REPORTER_ASSERT(reporter, !m1.findScalar("scalar")); + REPORTER_ASSERT(reporter, !m1.findString("hello")); + REPORTER_ASSERT(reporter, !m1.removeS32("int")); + REPORTER_ASSERT(reporter, !m1.removeScalar("scalar")); + REPORTER_ASSERT(reporter, !m1.removeString("hello")); + REPORTER_ASSERT(reporter, !m1.removeString("true")); + REPORTER_ASSERT(reporter, !m1.removeString("false")); + + m1.setS32("int", 12345); + m1.setScalar("scalar", SK_Scalar1 * 42); + m1.setString("hello", "world"); + m1.setPtr("ptr", &m1); + m1.setBool("true", true); + m1.setBool("false", false); + + int32_t n; + SkScalar s; + + m1.setScalar("scalar", SK_Scalar1/2); + + REPORTER_ASSERT(reporter, m1.findS32("int", &n) && n == 12345); + REPORTER_ASSERT(reporter, m1.findScalar("scalar", &s) && s == SK_Scalar1/2); + REPORTER_ASSERT(reporter, !strcmp(m1.findString("hello"), "world")); + REPORTER_ASSERT(reporter, m1.hasBool("true", true)); + REPORTER_ASSERT(reporter, m1.hasBool("false", false)); + + SkMetaData::Iter iter(m1); + const char* name; + + static const struct { + const char* fName; + SkMetaData::Type fType; + int fCount; + } gElems[] = { + { "int", SkMetaData::kS32_Type, 1 }, + { "scalar", SkMetaData::kScalar_Type, 1 }, + { "ptr", SkMetaData::kPtr_Type, 1 }, + { "hello", SkMetaData::kString_Type, sizeof("world") }, + { "true", SkMetaData::kBool_Type, 1 }, + { "false", SkMetaData::kBool_Type, 1 } + }; + + int loop = 0; + int count; + SkMetaData::Type t; + while ((name = iter.next(&t, &count)) != NULL) + { + int match = 0; + for (unsigned i = 0; i < SK_ARRAY_COUNT(gElems); i++) + { + if (!strcmp(name, gElems[i].fName)) + { + match += 1; + REPORTER_ASSERT(reporter, gElems[i].fType == t); + REPORTER_ASSERT(reporter, gElems[i].fCount == count); + } + } + REPORTER_ASSERT(reporter, match == 1); + loop += 1; + } + REPORTER_ASSERT(reporter, loop == SK_ARRAY_COUNT(gElems)); + + REPORTER_ASSERT(reporter, m1.removeS32("int")); + REPORTER_ASSERT(reporter, m1.removeScalar("scalar")); + REPORTER_ASSERT(reporter, m1.removeString("hello")); + REPORTER_ASSERT(reporter, m1.removeBool("true")); + REPORTER_ASSERT(reporter, m1.removeBool("false")); + + REPORTER_ASSERT(reporter, !m1.findS32("int")); + REPORTER_ASSERT(reporter, !m1.findScalar("scalar")); + REPORTER_ASSERT(reporter, !m1.findString("hello")); + REPORTER_ASSERT(reporter, !m1.findBool("true")); + REPORTER_ASSERT(reporter, !m1.findBool("false")); + + test_ptrs(reporter); +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("MetaData", TestMetaDataClass, TestMetaData) diff --git a/tests/tests_files.mk b/tests/tests_files.mk index cee5cfe..9f8d6df 100644 --- a/tests/tests_files.mk +++ b/tests/tests_files.mk @@ -13,6 +13,7 @@ SOURCE := \ InfRectTest.cpp \ MathTest.cpp \ MatrixTest.cpp \ + MetaDataTest.cpp \ PackBitsTest.cpp \ PaintTest.cpp \ ParsePathTest.cpp \ -- 2.7.4