|
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 } |