| /* | |
| * 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" | |
| 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::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; | |
| } |