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