diff options
author | 2013-04-21 01:37:46 +0000 | |
---|---|---|
committer | 2013-04-21 01:37:46 +0000 | |
commit | cac3ae37522bf070244c723960d1689e53da4dcd (patch) | |
tree | 775464fdcac7cb93f493b2b6ba8b9b6e5cff612e /src | |
parent | 4309a02bd1aac3250c0a7c7f7378aac36341022d (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.cpp | 230 |
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; } + |