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 11 static void malloc_freeproc(void* context) { 12 sk_free(context); 13 } 14 15 // Makes empty table 16 SkDataTable::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 24 SkDataTable::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 35 SkDataTable::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 45 SkDataTable::~SkDataTable() { 46 if (fFreeProc) { 47 fFreeProc(fFreeProcContext); 48 } 49 } 50 51 size_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 61 const 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 79 SkDataTable* SkDataTable::NewEmpty() { 80 static SkDataTable* gEmpty; 81 if (NULL == gEmpty) { 82 gEmpty = SkNEW(SkDataTable); 83 } 84 gEmpty->ref(); 85 return gEmpty; 86 } 87 88 SkDataTable* 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 114 SkDataTable* 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 128 SkDataTable* 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 138 static void chunkalloc_freeproc(void* context) { 139 SkDELETE((SkChunkAlloc*)context); 140 } 141 142 SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize) 143 : fHeap(NULL) 144 , fMinChunkSize(minChunkSize) {} 145 146 SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); } 147 148 void SkDataTableBuilder::reset(size_t minChunkSize) { 149 fMinChunkSize = minChunkSize; 150 fDir.reset(); 151 if (fHeap) { 152 SkDELETE(fHeap); 153 fHeap = NULL; 154 } 155 } 156 157 void 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 170 SkDataTable* 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