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
malloc_freeproc(void * context)11 static void malloc_freeproc(void* context) {
12 sk_free(context);
13 }
14
15 // Makes empty table
SkDataTable()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
SkDataTable(const void * array,size_t elemSize,int count,FreeProc proc,void * context)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
SkDataTable(const Dir * dir,int count,FreeProc proc,void * ctx)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
~SkDataTable()45 SkDataTable::~SkDataTable() {
46 if (fFreeProc) {
47 fFreeProc(fFreeProcContext);
48 }
49 }
50
atSize(int index) const51 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
at(int index,size_t * size) const61 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
NewEmpty()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
NewCopyArrays(const void * const * ptrs,const size_t sizes[],int count)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
NewCopyArray(const void * array,size_t elemSize,int count)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
NewArrayProc(const void * array,size_t elemSize,int count,FreeProc proc,void * ctx)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
chunkalloc_freeproc(void * context)138 static void chunkalloc_freeproc(void* context) {
139 SkDELETE((SkChunkAlloc*)context);
140 }
141
SkDataTableBuilder(size_t minChunkSize)142 SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize)
143 : fHeap(NULL)
144 , fMinChunkSize(minChunkSize) {}
145
~SkDataTableBuilder()146 SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); }
147
reset(size_t minChunkSize)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
append(const void * src,size_t size)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
detachDataTable()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