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 = nullptr;
20     fFreeProc = nullptr;
21     fFreeProcContext = nullptr;
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 (nullptr == gEmpty) {
82         gEmpty = new 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 new 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 new SkDataTable(buffer, elemSize, count, malloc_freeproc, buffer);
125 }
126 
NewArrayProc(const void * array,size_t elemSize,int count,FreeProc proc,void * ctx)127 SkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize,
128                                        int count, FreeProc proc, void* ctx) {
129     if (count <= 0) {
130         return SkDataTable::NewEmpty();
131     }
132     return new SkDataTable(array, elemSize, count, proc, ctx);
133 }
134 
135 ///////////////////////////////////////////////////////////////////////////////
136 
chunkalloc_freeproc(void * context)137 static void chunkalloc_freeproc(void* context) { delete (SkChunkAlloc*)context; }
138 
SkDataTableBuilder(size_t minChunkSize)139 SkDataTableBuilder::SkDataTableBuilder(size_t minChunkSize)
140     : fHeap(nullptr)
141     , fMinChunkSize(minChunkSize) {}
142 
~SkDataTableBuilder()143 SkDataTableBuilder::~SkDataTableBuilder() { this->reset(); }
144 
reset(size_t minChunkSize)145 void SkDataTableBuilder::reset(size_t minChunkSize) {
146     fMinChunkSize = minChunkSize;
147     fDir.reset();
148     if (fHeap) {
149         delete fHeap;
150         fHeap = nullptr;
151     }
152 }
153 
append(const void * src,size_t size)154 void SkDataTableBuilder::append(const void* src, size_t size) {
155     if (nullptr == fHeap) {
156         fHeap = new SkChunkAlloc(fMinChunkSize);
157     }
158 
159     void* dst = fHeap->alloc(size, SkChunkAlloc::kThrow_AllocFailType);
160     memcpy(dst, src, size);
161 
162     SkDataTable::Dir* dir = fDir.append();
163     dir->fPtr = dst;
164     dir->fSize = size;
165 }
166 
detachDataTable()167 SkDataTable* SkDataTableBuilder::detachDataTable() {
168     const int count = fDir.count();
169     if (0 == count) {
170         return SkDataTable::NewEmpty();
171     }
172 
173     // Copy the dir into the heap;
174     void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir),
175                              SkChunkAlloc::kThrow_AllocFailType);
176     memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir));
177 
178     SkDataTable* table = new SkDataTable((SkDataTable::Dir*)dir, count, chunkalloc_freeproc, fHeap);
179     // we have to detach our fHeap, since we are giving that to the table
180     fHeap = nullptr;
181     fDir.reset();
182     return table;
183 }
184