aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar mike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-21 01:37:46 +0000
committerGravatar mike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-21 01:37:46 +0000
commitcac3ae37522bf070244c723960d1689e53da4dcd (patch)
tree775464fdcac7cb93f493b2b6ba8b9b6e5cff612e /src
parent4309a02bd1aac3250c0a7c7f7378aac36341022d (diff)
specialize SkDataTable for arrays where all elements are the same size.
optimize impl to not require another level of indirection (SkData) for storage. add unittests for flattening. optimize builder to not make a deepcopy of its chunkalloc heap. git-svn-id: http://skia.googlecode.com/svn/trunk@8790 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r--src/core/SkDataTable.cpp230
1 files changed, 168 insertions, 62 deletions
diff --git a/src/core/SkDataTable.cpp b/src/core/SkDataTable.cpp
index 5c3bfefe2c..e5dbd8472b 100644
--- a/src/core/SkDataTable.cpp
+++ b/src/core/SkDataTable.cpp
@@ -11,46 +11,129 @@
SK_DEFINE_INST_COUNT(SkDataTable)
-SkDataTable::SkDataTable(int count, SkData* data)
- : fCount(count)
- , fData(data) {}
+static void malloc_freeproc(void* context) {
+ sk_free(context);
+}
-SkDataTable::~SkDataTable() {
- fData->unref();
+// Makes empty table
+SkDataTable::SkDataTable() {
+ fCount = 0;
+ fElemSize = 0; // 0 signals that we use fDir instead of fElems
+ fU.fDir = NULL;
+ fFreeProc = NULL;
+ fFreeProcContext = NULL;
}
-struct ElemHead {
- const void* fPtr;
- uintptr_t fSize;
+SkDataTable::SkDataTable(const void* array, size_t elemSize, int count,
+ FreeProc proc, void* context) {
+ SkASSERT(count > 0);
+
+ fCount = count;
+ fElemSize = elemSize; // non-zero signals we use fElems instead of fDir
+ fU.fElems = (const char*)array;
+ fFreeProc = proc;
+ fFreeProcContext = context;
+}
- static const ElemHead* Get(SkData* data) {
- return (const ElemHead*)(data->data());
+SkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) {
+ SkASSERT(count > 0);
+
+ fCount = count;
+ fElemSize = 0; // 0 signals that we use fDir instead of fElems
+ fU.fDir = dir;
+ fFreeProc = proc;
+ fFreeProcContext = ctx;
+}
+
+SkDataTable::~SkDataTable() {
+ if (fFreeProc) {
+ fFreeProc(fFreeProcContext);
}
-};
+}
size_t SkDataTable::atSize(int index) const {
SkASSERT((unsigned)index < (unsigned)fCount);
- return ElemHead::Get(fData)[index].fSize;
+
+ if (fElemSize) {
+ return fElemSize;
+ } else {
+ return fU.fDir[index].fSize;
+ }
}
-const void* SkDataTable::atData(int index, size_t* size) const {
+const void* SkDataTable::at(int index, size_t* size) const {
SkASSERT((unsigned)index < (unsigned)fCount);
- const ElemHead& head = ElemHead::Get(fData)[index];
- if (size) {
- *size = head.fSize;
+
+ if (fElemSize) {
+ if (size) {
+ *size = fElemSize;
+ }
+ return fU.fElems + index * fElemSize;
+ } else {
+ if (size) {
+ *size = fU.fDir[index].fSize;
+ }
+ return fU.fDir[index].fPtr;
}
- return head.fPtr;
}
SkDataTable::SkDataTable(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
+ fElemSize = 0;
+ fU.fElems = NULL;
+ fFreeProc = NULL;
+ fFreeProcContext = NULL;
+
fCount = buffer.read32();
- fData = buffer.readFlattenableT<SkData>();
+ if (fCount) {
+ fElemSize = buffer.read32();
+ if (fElemSize) {
+ size_t size = buffer.getArrayCount();
+ // size is the size of our elems data
+ SkASSERT(fCount * fElemSize == size);
+ void* addr = sk_malloc_throw(size);
+ if (buffer.readByteArray(addr) != size) {
+ sk_throw();
+ }
+ fU.fElems = (const char*)addr;
+ fFreeProcContext = addr;
+ } else {
+ size_t dataSize = buffer.read32();
+
+ size_t allocSize = fCount * sizeof(Dir) + dataSize;
+ void* addr = sk_malloc_throw(allocSize);
+ Dir* dir = (Dir*)addr;
+ char* elem = (char*)(dir + fCount);
+ for (int i = 0; i < fCount; ++i) {
+ dir[i].fPtr = elem;
+ dir[i].fSize = buffer.readByteArray(elem);
+ elem += dir[i].fSize;
+ }
+ fU.fDir = dir;
+ fFreeProcContext = addr;
+ }
+ fFreeProc = malloc_freeproc;
+ }
}
void SkDataTable::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
+
buffer.write32(fCount);
- buffer.writeFlattenable(fData);
+ if (fCount) {
+ buffer.write32(fElemSize);
+ if (fElemSize) {
+ buffer.writeByteArray(fU.fElems, fCount * fElemSize);
+ } else {
+ size_t dataSize = 0;
+ for (int i = 0; i < fCount; ++i) {
+ dataSize += fU.fDir[i].fSize;
+ }
+ buffer.write32(dataSize);
+ for (int i = 0; i < fCount; ++i) {
+ buffer.writeByteArray(fU.fDir[i].fPtr, fU.fDir[i].fSize);
+ }
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////////
@@ -58,7 +141,7 @@ void SkDataTable::flatten(SkFlattenableWriteBuffer& buffer) const {
SkDataTable* SkDataTable::NewEmpty() {
static SkDataTable* gEmpty;
if (NULL == gEmpty) {
- gEmpty = SkNEW_ARGS(SkDataTable, (0, SkData::NewEmpty()));
+ gEmpty = SkNEW(SkDataTable);
}
gEmpty->ref();
return gEmpty;
@@ -66,80 +149,103 @@ SkDataTable* SkDataTable::NewEmpty() {
SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs,
const size_t sizes[], int count) {
- if (count < 0) {
- count = 0;
+ if (count <= 0) {
+ return SkDataTable::NewEmpty();
}
- size_t headerSize = count * sizeof(ElemHead);
size_t dataSize = 0;
for (int i = 0; i < count; ++i) {
dataSize += sizes[i];
}
- size_t bufferSize = headerSize + dataSize;
+ size_t bufferSize = count * sizeof(Dir) + dataSize;
void* buffer = sk_malloc_throw(bufferSize);
- ElemHead* headerCurr = (ElemHead*)buffer;
- char* dataCurr = (char*)buffer + headerSize;
+ Dir* dir = (Dir*)buffer;
+ char* elem = (char*)(dir + count);
for (int i = 0; i < count; ++i) {
- headerCurr[i].fPtr = dataCurr;
- headerCurr[i].fSize = sizes[i];
- memcpy(dataCurr, ptrs[i], sizes[i]);
- dataCurr += sizes[i];
+ dir[i].fPtr = elem;
+ dir[i].fSize = sizes[i];
+ memcpy(elem, ptrs[i], sizes[i]);
+ elem += sizes[i];
}
-
- return SkNEW_ARGS(SkDataTable, (count,
- SkData::NewFromMalloc(buffer, bufferSize)));
+
+ return SkNEW_ARGS(SkDataTable, (dir, count, malloc_freeproc, buffer));
}
SkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize,
int count) {
- if (count < 0) {
- count = 0;
+ if (count <= 0) {
+ return SkDataTable::NewEmpty();
}
- size_t headerSize = count * sizeof(ElemHead);
- size_t dataSize = count * elemSize;
-
- size_t bufferSize = headerSize + dataSize;
+ size_t bufferSize = elemSize * count;
void* buffer = sk_malloc_throw(bufferSize);
+ memcpy(buffer, array, bufferSize);
- ElemHead* headerCurr = (ElemHead*)buffer;
- char* dataCurr = (char*)buffer + headerSize;
- for (int i = 0; i < count; ++i) {
- headerCurr[i].fPtr = dataCurr;
- headerCurr[i].fSize = elemSize;
- dataCurr += elemSize;
- }
- memcpy((char*)buffer + headerSize, array, dataSize);
+ return SkNEW_ARGS(SkDataTable,
+ (buffer, elemSize, count, malloc_freeproc, buffer));
+}
- return SkNEW_ARGS(SkDataTable, (count,
- SkData::NewFromMalloc(buffer, bufferSize)));
+SkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize,
+ int count, FreeProc proc, void* ctx) {
+ if (count <= 0) {
+ return SkDataTable::NewEmpty();
+ }
+ return SkNEW_ARGS(SkDataTable, (array, elemSize, count, proc, ctx));
}
///////////////////////////////////////////////////////////////////////////////
+static void chunkalloc_freeproc(void* context) {
+ SkDELETE((SkChunkAlloc*)context);
+}
+
SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize)
- : fHeap(minChunkSize) {}
+ : fHeap(NULL)
+ , fMinChunkSize(minChunkSize) {}
-SkDataTableBuilder::~SkDataTableBuilder() {}
+SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); }
-void SkDataTableBuilder::reset() {
- fSizes.reset();
- fPtrs.reset();
- fHeap.reset();
+void SkDataTableBuilder::reset(size_t minChunkSize) {
+ fMinChunkSize = minChunkSize;
+ fDir.reset();
+ if (fHeap) {
+ SkDELETE(fHeap);
+ fHeap = NULL;
+ }
}
void SkDataTableBuilder::append(const void* src, size_t size) {
- void* dst = fHeap.alloc(size, SkChunkAlloc::kThrow_AllocFailType);
+ if (NULL == fHeap) {
+ fHeap = SkNEW_ARGS(SkChunkAlloc, (fMinChunkSize));
+ }
+
+ void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType);
memcpy(dst, src, size);
- *fSizes.append() = size;
- *fPtrs.append() = dst;
+ SkDataTable::Dir* dir = fDir.append();
+ dir->fPtr = dst;
+ dir->fSize = size;
}
-SkDataTable* SkDataTableBuilder::createDataTable() {
- SkASSERT(fSizes.count() == fPtrs.count());
- return SkDataTable::NewCopyArrays(fPtrs.begin(), fSizes.begin(),
- fSizes.count());
+SkDataTable* SkDataTableBuilder::detachDataTable() {
+ const int count = fDir.count();
+ if (0 == count) {
+ return SkDataTable::NewEmpty();
+ }
+
+ // Copy the dir into the heap;
+ void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir),
+ SkChunkAlloc::kThrow_AllocFailType);
+ memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir));
+
+ SkDataTable* table = SkNEW_ARGS(SkDataTable,
+ ((SkDataTable::Dir*)dir, count,
+ chunkalloc_freeproc, fHeap));
+ // we have to detach our fHeap, since we are giving that to the table
+ fHeap = NULL;
+ fDir.reset();
+ return table;
}
+