| /* |
| * Copyright 2013 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "SkData.h" |
| #include "SkDataTable.h" |
| #include "SkFlattenableBuffers.h" |
| |
| SK_DEFINE_INST_COUNT(SkDataTable) |
| |
| static void malloc_freeproc(void* context) { |
| sk_free(context); |
| } |
| |
| // 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; |
| } |
| |
| 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; |
| } |
| |
| 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); |
| |
| if (fElemSize) { |
| return fElemSize; |
| } else { |
| return fU.fDir[index].fSize; |
| } |
| } |
| |
| const void* SkDataTable::at(int index, size_t* size) const { |
| SkASSERT((unsigned)index < (unsigned)fCount); |
| |
| if (fElemSize) { |
| if (size) { |
| *size = fElemSize; |
| } |
| return fU.fElems + index * fElemSize; |
| } else { |
| if (size) { |
| *size = fU.fDir[index].fSize; |
| } |
| return fU.fDir[index].fPtr; |
| } |
| } |
| |
| SkDataTable::SkDataTable(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { |
| fElemSize = 0; |
| fU.fElems = NULL; |
| fFreeProc = NULL; |
| fFreeProcContext = NULL; |
| |
| fCount = buffer.read32(); |
| 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); |
| 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); |
| } |
| } |
| } |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| SkDataTable* SkDataTable::NewEmpty() { |
| static SkDataTable* gEmpty; |
| if (NULL == gEmpty) { |
| gEmpty = SkNEW(SkDataTable); |
| } |
| gEmpty->ref(); |
| return gEmpty; |
| } |
| |
| SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs, |
| const size_t sizes[], int count) { |
| if (count <= 0) { |
| return SkDataTable::NewEmpty(); |
| } |
| |
| size_t dataSize = 0; |
| for (int i = 0; i < count; ++i) { |
| dataSize += sizes[i]; |
| } |
| |
| size_t bufferSize = count * sizeof(Dir) + dataSize; |
| void* buffer = sk_malloc_throw(bufferSize); |
| |
| Dir* dir = (Dir*)buffer; |
| char* elem = (char*)(dir + count); |
| for (int i = 0; i < count; ++i) { |
| dir[i].fPtr = elem; |
| dir[i].fSize = sizes[i]; |
| memcpy(elem, ptrs[i], sizes[i]); |
| elem += sizes[i]; |
| } |
| |
| return SkNEW_ARGS(SkDataTable, (dir, count, malloc_freeproc, buffer)); |
| } |
| |
| SkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize, |
| int count) { |
| if (count <= 0) { |
| return SkDataTable::NewEmpty(); |
| } |
| |
| size_t bufferSize = elemSize * count; |
| void* buffer = sk_malloc_throw(bufferSize); |
| memcpy(buffer, array, bufferSize); |
| |
| return SkNEW_ARGS(SkDataTable, |
| (buffer, elemSize, count, malloc_freeproc, buffer)); |
| } |
| |
| 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(NULL) |
| , fMinChunkSize(minChunkSize) {} |
| |
| SkDataTableBuilder::~SkDataTableBuilder() { this->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) { |
| if (NULL == fHeap) { |
| fHeap = SkNEW_ARGS(SkChunkAlloc, (fMinChunkSize)); |
| } |
| |
| void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType); |
| memcpy(dst, src, size); |
| |
| SkDataTable::Dir* dir = fDir.append(); |
| dir->fPtr = dst; |
| dir->fSize = size; |
| } |
| |
| 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; |
| } |