michael@0: /* michael@0: * Copyright 2013 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkData.h" michael@0: #include "SkDataTable.h" michael@0: michael@0: static void malloc_freeproc(void* context) { michael@0: sk_free(context); michael@0: } michael@0: michael@0: // Makes empty table michael@0: SkDataTable::SkDataTable() { michael@0: fCount = 0; michael@0: fElemSize = 0; // 0 signals that we use fDir instead of fElems michael@0: fU.fDir = NULL; michael@0: fFreeProc = NULL; michael@0: fFreeProcContext = NULL; michael@0: } michael@0: michael@0: SkDataTable::SkDataTable(const void* array, size_t elemSize, int count, michael@0: FreeProc proc, void* context) { michael@0: SkASSERT(count > 0); michael@0: michael@0: fCount = count; michael@0: fElemSize = elemSize; // non-zero signals we use fElems instead of fDir michael@0: fU.fElems = (const char*)array; michael@0: fFreeProc = proc; michael@0: fFreeProcContext = context; michael@0: } michael@0: michael@0: SkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) { michael@0: SkASSERT(count > 0); michael@0: michael@0: fCount = count; michael@0: fElemSize = 0; // 0 signals that we use fDir instead of fElems michael@0: fU.fDir = dir; michael@0: fFreeProc = proc; michael@0: fFreeProcContext = ctx; michael@0: } michael@0: michael@0: SkDataTable::~SkDataTable() { michael@0: if (fFreeProc) { michael@0: fFreeProc(fFreeProcContext); michael@0: } michael@0: } michael@0: michael@0: size_t SkDataTable::atSize(int index) const { michael@0: SkASSERT((unsigned)index < (unsigned)fCount); michael@0: michael@0: if (fElemSize) { michael@0: return fElemSize; michael@0: } else { michael@0: return fU.fDir[index].fSize; michael@0: } michael@0: } michael@0: michael@0: const void* SkDataTable::at(int index, size_t* size) const { michael@0: SkASSERT((unsigned)index < (unsigned)fCount); michael@0: michael@0: if (fElemSize) { michael@0: if (size) { michael@0: *size = fElemSize; michael@0: } michael@0: return fU.fElems + index * fElemSize; michael@0: } else { michael@0: if (size) { michael@0: *size = fU.fDir[index].fSize; michael@0: } michael@0: return fU.fDir[index].fPtr; michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkDataTable* SkDataTable::NewEmpty() { michael@0: static SkDataTable* gEmpty; michael@0: if (NULL == gEmpty) { michael@0: gEmpty = SkNEW(SkDataTable); michael@0: } michael@0: gEmpty->ref(); michael@0: return gEmpty; michael@0: } michael@0: michael@0: SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs, michael@0: const size_t sizes[], int count) { michael@0: if (count <= 0) { michael@0: return SkDataTable::NewEmpty(); michael@0: } michael@0: michael@0: size_t dataSize = 0; michael@0: for (int i = 0; i < count; ++i) { michael@0: dataSize += sizes[i]; michael@0: } michael@0: michael@0: size_t bufferSize = count * sizeof(Dir) + dataSize; michael@0: void* buffer = sk_malloc_throw(bufferSize); michael@0: michael@0: Dir* dir = (Dir*)buffer; michael@0: char* elem = (char*)(dir + count); michael@0: for (int i = 0; i < count; ++i) { michael@0: dir[i].fPtr = elem; michael@0: dir[i].fSize = sizes[i]; michael@0: memcpy(elem, ptrs[i], sizes[i]); michael@0: elem += sizes[i]; michael@0: } michael@0: michael@0: return SkNEW_ARGS(SkDataTable, (dir, count, malloc_freeproc, buffer)); michael@0: } michael@0: michael@0: SkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize, michael@0: int count) { michael@0: if (count <= 0) { michael@0: return SkDataTable::NewEmpty(); michael@0: } michael@0: michael@0: size_t bufferSize = elemSize * count; michael@0: void* buffer = sk_malloc_throw(bufferSize); michael@0: memcpy(buffer, array, bufferSize); michael@0: michael@0: return SkNEW_ARGS(SkDataTable, michael@0: (buffer, elemSize, count, malloc_freeproc, buffer)); michael@0: } michael@0: michael@0: SkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize, michael@0: int count, FreeProc proc, void* ctx) { michael@0: if (count <= 0) { michael@0: return SkDataTable::NewEmpty(); michael@0: } michael@0: return SkNEW_ARGS(SkDataTable, (array, elemSize, count, proc, ctx)); michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static void chunkalloc_freeproc(void* context) { michael@0: SkDELETE((SkChunkAlloc*)context); michael@0: } michael@0: michael@0: SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize) michael@0: : fHeap(NULL) michael@0: , fMinChunkSize(minChunkSize) {} michael@0: michael@0: SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); } michael@0: michael@0: void SkDataTableBuilder::reset(size_t minChunkSize) { michael@0: fMinChunkSize = minChunkSize; michael@0: fDir.reset(); michael@0: if (fHeap) { michael@0: SkDELETE(fHeap); michael@0: fHeap = NULL; michael@0: } michael@0: } michael@0: michael@0: void SkDataTableBuilder::append(const void* src, size_t size) { michael@0: if (NULL == fHeap) { michael@0: fHeap = SkNEW_ARGS(SkChunkAlloc, (fMinChunkSize)); michael@0: } michael@0: michael@0: void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType); michael@0: memcpy(dst, src, size); michael@0: michael@0: SkDataTable::Dir* dir = fDir.append(); michael@0: dir->fPtr = dst; michael@0: dir->fSize = size; michael@0: } michael@0: michael@0: SkDataTable* SkDataTableBuilder::detachDataTable() { michael@0: const int count = fDir.count(); michael@0: if (0 == count) { michael@0: return SkDataTable::NewEmpty(); michael@0: } michael@0: michael@0: // Copy the dir into the heap; michael@0: void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir), michael@0: SkChunkAlloc::kThrow_AllocFailType); michael@0: memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir)); michael@0: michael@0: SkDataTable* table = SkNEW_ARGS(SkDataTable, michael@0: ((SkDataTable::Dir*)dir, count, michael@0: chunkalloc_freeproc, fHeap)); michael@0: // we have to detach our fHeap, since we are giving that to the table michael@0: fHeap = NULL; michael@0: fDir.reset(); michael@0: return table; michael@0: }