add refcnt helper to metadata

add unittests for metadata



git-svn-id: http://skia.googlecode.com/svn/trunk@1019 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-03-30 18:23:21 +00:00
parent 5e3496e555
commit e733071abe
4 changed files with 246 additions and 197 deletions

View File

@ -19,8 +19,34 @@
#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();
@ -31,35 +57,31 @@ public:
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 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 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
{
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
{
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;
}
@ -73,7 +95,7 @@ public:
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 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);
@ -85,7 +107,19 @@ public:
bool removeBool(const char name[]);
bool removeData(const char name[]);
SkDEBUGCODE(static void UnitTest();)
// 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,
@ -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); }

View File

@ -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<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

112
tests/MetaDataTest.cpp Normal file
View File

@ -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)

View File

@ -13,6 +13,7 @@ SOURCE := \
InfRectTest.cpp \
MathTest.cpp \
MatrixTest.cpp \
MetaDataTest.cpp \
PackBitsTest.cpp \
PaintTest.cpp \
ParsePathTest.cpp \