|
1 /* |
|
2 * Copyright 2010 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 #ifndef GrAllocator_DEFINED |
|
9 #define GrAllocator_DEFINED |
|
10 |
|
11 #include "GrConfig.h" |
|
12 #include "GrTypes.h" |
|
13 #include "SkTArray.h" |
|
14 #include "SkTypes.h" |
|
15 |
|
16 class GrAllocator : public SkNoncopyable { |
|
17 public: |
|
18 ~GrAllocator() { |
|
19 reset(); |
|
20 } |
|
21 |
|
22 /** |
|
23 * Create an allocator |
|
24 * |
|
25 * @param itemSize the size of each item to allocate |
|
26 * @param itemsPerBlock the number of items to allocate at once |
|
27 * @param initialBlock optional memory to use for the first block. |
|
28 * Must be at least itemSize*itemsPerBlock sized. |
|
29 * Caller is responsible for freeing this memory. |
|
30 */ |
|
31 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) : |
|
32 fItemSize(itemSize), |
|
33 fItemsPerBlock(itemsPerBlock), |
|
34 fOwnFirstBlock(NULL == initialBlock), |
|
35 fCount(0) { |
|
36 SkASSERT(itemsPerBlock > 0); |
|
37 fBlockSize = fItemSize * fItemsPerBlock; |
|
38 fBlocks.push_back() = initialBlock; |
|
39 SkDEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} ); |
|
40 } |
|
41 |
|
42 /* |
|
43 * Set first block of memory to write into. Must be called before any other methods. |
|
44 * This requires that you have passed NULL in the constructor. |
|
45 * |
|
46 * @param initialBlock optional memory to use for the first block. |
|
47 * Must be at least itemSize*itemsPerBlock sized. |
|
48 * Caller is responsible for freeing this memory. |
|
49 */ |
|
50 void setInitialBlock(void* initialBlock) { |
|
51 SkASSERT(0 == fCount); |
|
52 SkASSERT(1 == fBlocks.count()); |
|
53 SkASSERT(NULL == fBlocks.back()); |
|
54 fOwnFirstBlock = false; |
|
55 fBlocks.back() = initialBlock; |
|
56 } |
|
57 |
|
58 /** |
|
59 * Adds an item and returns pointer to it. |
|
60 * |
|
61 * @return pointer to the added item. |
|
62 */ |
|
63 void* push_back() { |
|
64 int indexInBlock = fCount % fItemsPerBlock; |
|
65 // we always have at least one block |
|
66 if (0 == indexInBlock) { |
|
67 if (0 != fCount) { |
|
68 fBlocks.push_back() = sk_malloc_throw(fBlockSize); |
|
69 } else if (fOwnFirstBlock) { |
|
70 fBlocks[0] = sk_malloc_throw(fBlockSize); |
|
71 } |
|
72 } |
|
73 void* ret = (char*)fBlocks[fCount/fItemsPerBlock] + |
|
74 fItemSize * indexInBlock; |
|
75 ++fCount; |
|
76 return ret; |
|
77 } |
|
78 |
|
79 /** |
|
80 * removes all added items |
|
81 */ |
|
82 void reset() { |
|
83 int blockCount = GrMax((unsigned)1, |
|
84 GrUIDivRoundUp(fCount, fItemsPerBlock)); |
|
85 for (int i = 1; i < blockCount; ++i) { |
|
86 sk_free(fBlocks[i]); |
|
87 } |
|
88 if (fOwnFirstBlock) { |
|
89 sk_free(fBlocks[0]); |
|
90 fBlocks[0] = NULL; |
|
91 } |
|
92 fBlocks.pop_back_n(blockCount-1); |
|
93 fCount = 0; |
|
94 } |
|
95 |
|
96 /** |
|
97 * count of items |
|
98 */ |
|
99 int count() const { |
|
100 return fCount; |
|
101 } |
|
102 |
|
103 /** |
|
104 * is the count 0 |
|
105 */ |
|
106 bool empty() const { return fCount == 0; } |
|
107 |
|
108 /** |
|
109 * access last item, only call if count() != 0 |
|
110 */ |
|
111 void* back() { |
|
112 SkASSERT(fCount); |
|
113 return (*this)[fCount-1]; |
|
114 } |
|
115 |
|
116 /** |
|
117 * access last item, only call if count() != 0 |
|
118 */ |
|
119 const void* back() const { |
|
120 SkASSERT(fCount); |
|
121 return (*this)[fCount-1]; |
|
122 } |
|
123 |
|
124 /** |
|
125 * access item by index. |
|
126 */ |
|
127 void* operator[] (int i) { |
|
128 SkASSERT(i >= 0 && i < fCount); |
|
129 return (char*)fBlocks[i / fItemsPerBlock] + |
|
130 fItemSize * (i % fItemsPerBlock); |
|
131 } |
|
132 |
|
133 /** |
|
134 * access item by index. |
|
135 */ |
|
136 const void* operator[] (int i) const { |
|
137 SkASSERT(i >= 0 && i < fCount); |
|
138 return (const char*)fBlocks[i / fItemsPerBlock] + |
|
139 fItemSize * (i % fItemsPerBlock); |
|
140 } |
|
141 |
|
142 private: |
|
143 static const int NUM_INIT_BLOCK_PTRS = 8; |
|
144 |
|
145 SkSTArray<NUM_INIT_BLOCK_PTRS, void*> fBlocks; |
|
146 size_t fBlockSize; |
|
147 size_t fItemSize; |
|
148 int fItemsPerBlock; |
|
149 bool fOwnFirstBlock; |
|
150 int fCount; |
|
151 |
|
152 typedef SkNoncopyable INHERITED; |
|
153 }; |
|
154 |
|
155 template <typename T> |
|
156 class GrTAllocator : public SkNoncopyable { |
|
157 public: |
|
158 virtual ~GrTAllocator() { this->reset(); }; |
|
159 |
|
160 /** |
|
161 * Create an allocator |
|
162 * |
|
163 * @param itemsPerBlock the number of items to allocate at once |
|
164 */ |
|
165 explicit GrTAllocator(int itemsPerBlock) |
|
166 : fAllocator(sizeof(T), itemsPerBlock, NULL) {} |
|
167 |
|
168 /** |
|
169 * Adds an item and returns it. |
|
170 * |
|
171 * @return the added item. |
|
172 */ |
|
173 T& push_back() { |
|
174 void* item = fAllocator.push_back(); |
|
175 SkASSERT(NULL != item); |
|
176 SkNEW_PLACEMENT(item, T); |
|
177 return *(T*)item; |
|
178 } |
|
179 |
|
180 T& push_back(const T& t) { |
|
181 void* item = fAllocator.push_back(); |
|
182 SkASSERT(NULL != item); |
|
183 SkNEW_PLACEMENT_ARGS(item, T, (t)); |
|
184 return *(T*)item; |
|
185 } |
|
186 |
|
187 /** |
|
188 * removes all added items |
|
189 */ |
|
190 void reset() { |
|
191 int c = fAllocator.count(); |
|
192 for (int i = 0; i < c; ++i) { |
|
193 ((T*)fAllocator[i])->~T(); |
|
194 } |
|
195 fAllocator.reset(); |
|
196 } |
|
197 |
|
198 /** |
|
199 * count of items |
|
200 */ |
|
201 int count() const { |
|
202 return fAllocator.count(); |
|
203 } |
|
204 |
|
205 /** |
|
206 * is the count 0 |
|
207 */ |
|
208 bool empty() const { return fAllocator.empty(); } |
|
209 |
|
210 /** |
|
211 * access last item, only call if count() != 0 |
|
212 */ |
|
213 T& back() { |
|
214 return *(T*)fAllocator.back(); |
|
215 } |
|
216 |
|
217 /** |
|
218 * access last item, only call if count() != 0 |
|
219 */ |
|
220 const T& back() const { |
|
221 return *(const T*)fAllocator.back(); |
|
222 } |
|
223 |
|
224 /** |
|
225 * access item by index. |
|
226 */ |
|
227 T& operator[] (int i) { |
|
228 return *(T*)(fAllocator[i]); |
|
229 } |
|
230 |
|
231 /** |
|
232 * access item by index. |
|
233 */ |
|
234 const T& operator[] (int i) const { |
|
235 return *(const T*)(fAllocator[i]); |
|
236 } |
|
237 |
|
238 protected: |
|
239 /* |
|
240 * Set first block of memory to write into. Must be called before any other methods. |
|
241 * |
|
242 * @param initialBlock optional memory to use for the first block. |
|
243 * Must be at least size(T)*itemsPerBlock sized. |
|
244 * Caller is responsible for freeing this memory. |
|
245 */ |
|
246 void setInitialBlock(void* initialBlock) { |
|
247 fAllocator.setInitialBlock(initialBlock); |
|
248 } |
|
249 |
|
250 private: |
|
251 GrAllocator fAllocator; |
|
252 typedef SkNoncopyable INHERITED; |
|
253 }; |
|
254 |
|
255 template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> { |
|
256 private: |
|
257 typedef GrTAllocator<T> INHERITED; |
|
258 |
|
259 public: |
|
260 GrSTAllocator() : INHERITED(N) { |
|
261 this->setInitialBlock(fStorage.get()); |
|
262 } |
|
263 |
|
264 private: |
|
265 SkAlignedSTStorage<N, T> fStorage; |
|
266 }; |
|
267 |
|
268 #endif |