1/* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkData.h" 9#include "SkDataTable.h" 10 11static void malloc_freeproc(void* context) { 12 sk_free(context); 13} 14 15// Makes empty table 16SkDataTable::SkDataTable() { 17 fCount = 0; 18 fElemSize = 0; // 0 signals that we use fDir instead of fElems 19 fU.fDir = NULL; 20 fFreeProc = NULL; 21 fFreeProcContext = NULL; 22} 23 24SkDataTable::SkDataTable(const void* array, size_t elemSize, int count, 25 FreeProc proc, void* context) { 26 SkASSERT(count > 0); 27 28 fCount = count; 29 fElemSize = elemSize; // non-zero signals we use fElems instead of fDir 30 fU.fElems = (const char*)array; 31 fFreeProc = proc; 32 fFreeProcContext = context; 33} 34 35SkDataTable::SkDataTable(const Dir* dir, int count, FreeProc proc, void* ctx) { 36 SkASSERT(count > 0); 37 38 fCount = count; 39 fElemSize = 0; // 0 signals that we use fDir instead of fElems 40 fU.fDir = dir; 41 fFreeProc = proc; 42 fFreeProcContext = ctx; 43} 44 45SkDataTable::~SkDataTable() { 46 if (fFreeProc) { 47 fFreeProc(fFreeProcContext); 48 } 49} 50 51size_t SkDataTable::atSize(int index) const { 52 SkASSERT((unsigned)index < (unsigned)fCount); 53 54 if (fElemSize) { 55 return fElemSize; 56 } else { 57 return fU.fDir[index].fSize; 58 } 59} 60 61const void* SkDataTable::at(int index, size_t* size) const { 62 SkASSERT((unsigned)index < (unsigned)fCount); 63 64 if (fElemSize) { 65 if (size) { 66 *size = fElemSize; 67 } 68 return fU.fElems + index * fElemSize; 69 } else { 70 if (size) { 71 *size = fU.fDir[index].fSize; 72 } 73 return fU.fDir[index].fPtr; 74 } 75} 76 77/////////////////////////////////////////////////////////////////////////////// 78 79SkDataTable* SkDataTable::NewEmpty() { 80 static SkDataTable* gEmpty; 81 if (NULL == gEmpty) { 82 gEmpty = SkNEW(SkDataTable); 83 } 84 gEmpty->ref(); 85 return gEmpty; 86} 87 88SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs, 89 const size_t sizes[], int count) { 90 if (count <= 0) { 91 return SkDataTable::NewEmpty(); 92 } 93 94 size_t dataSize = 0; 95 for (int i = 0; i < count; ++i) { 96 dataSize += sizes[i]; 97 } 98 99 size_t bufferSize = count * sizeof(Dir) + dataSize; 100 void* buffer = sk_malloc_throw(bufferSize); 101 102 Dir* dir = (Dir*)buffer; 103 char* elem = (char*)(dir + count); 104 for (int i = 0; i < count; ++i) { 105 dir[i].fPtr = elem; 106 dir[i].fSize = sizes[i]; 107 memcpy(elem, ptrs[i], sizes[i]); 108 elem += sizes[i]; 109 } 110 111 return SkNEW_ARGS(SkDataTable, (dir, count, malloc_freeproc, buffer)); 112} 113 114SkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize, 115 int count) { 116 if (count <= 0) { 117 return SkDataTable::NewEmpty(); 118 } 119 120 size_t bufferSize = elemSize * count; 121 void* buffer = sk_malloc_throw(bufferSize); 122 memcpy(buffer, array, bufferSize); 123 124 return SkNEW_ARGS(SkDataTable, 125 (buffer, elemSize, count, malloc_freeproc, buffer)); 126} 127 128SkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize, 129 int count, FreeProc proc, void* ctx) { 130 if (count <= 0) { 131 return SkDataTable::NewEmpty(); 132 } 133 return SkNEW_ARGS(SkDataTable, (array, elemSize, count, proc, ctx)); 134} 135 136/////////////////////////////////////////////////////////////////////////////// 137 138static void chunkalloc_freeproc(void* context) { 139 SkDELETE((SkChunkAlloc*)context); 140} 141 142SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize) 143 : fHeap(NULL) 144 , fMinChunkSize(minChunkSize) {} 145 146SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); } 147 148void SkDataTableBuilder::reset(size_t minChunkSize) { 149 fMinChunkSize = minChunkSize; 150 fDir.reset(); 151 if (fHeap) { 152 SkDELETE(fHeap); 153 fHeap = NULL; 154 } 155} 156 157void SkDataTableBuilder::append(const void* src, size_t size) { 158 if (NULL == fHeap) { 159 fHeap = SkNEW_ARGS(SkChunkAlloc, (fMinChunkSize)); 160 } 161 162 void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType); 163 memcpy(dst, src, size); 164 165 SkDataTable::Dir* dir = fDir.append(); 166 dir->fPtr = dst; 167 dir->fSize = size; 168} 169 170SkDataTable* SkDataTableBuilder::detachDataTable() { 171 const int count = fDir.count(); 172 if (0 == count) { 173 return SkDataTable::NewEmpty(); 174 } 175 176 // Copy the dir into the heap; 177 void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir), 178 SkChunkAlloc::kThrow_AllocFailType); 179 memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir)); 180 181 SkDataTable* table = SkNEW_ARGS(SkDataTable, 182 ((SkDataTable::Dir*)dir, count, 183 chunkalloc_freeproc, fHeap)); 184 // we have to detach our fHeap, since we are giving that to the table 185 fHeap = NULL; 186 fDir.reset(); 187 return table; 188} 189