add refcnt helper to metadata
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 30 Mar 2011 18:23:21 +0000 (18:23 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 30 Mar 2011 18:23:21 +0000 (18:23 +0000)
add unittests for metadata

git-svn-id: http://skia.googlecode.com/svn/trunk@1019 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkMetaData.h
src/core/SkMetaData.cpp
tests/MetaDataTest.cpp [new file with mode: 0644]
tests/tests_files.mk

index 9509710..5e6f376 100644 (file)
 
 #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<void**>(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); }
index c871efb..b1901dc 100644 (file)
 */
 
 #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<SkRefCnt*>(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 (file)
index 0000000..70829d4
--- /dev/null
@@ -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)
index cee5cfe..9f8d6df 100644 (file)
@@ -13,6 +13,7 @@ SOURCE := \
     InfRectTest.cpp \
     MathTest.cpp \
     MatrixTest.cpp \
+    MetaDataTest.cpp \
     PackBitsTest.cpp \
     PaintTest.cpp \
     ParsePathTest.cpp \