blob: 72df8b6df1e14bee4a7fba0f1ffead19ad3de166 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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.
reed@google.comac10a2d2010-12-22 21:39:39 +00006 */
7
reed@google.comac10a2d2010-12-22 21:39:39 +00008#ifndef GrAllocator_DEFINED
9#define GrAllocator_DEFINED
10
11#include "GrConfig.h"
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +000012#include "GrTypes.h"
Ben Wagnerd5148e32018-07-16 17:44:06 -040013#include "SkNoncopyable.h"
bsalomon@google.com49313f62011-09-14 13:54:05 +000014#include "SkTArray.h"
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +000015#include "SkTypes.h"
Mike Klein79aea6a2018-06-11 10:45:26 -040016#include <new>
reed@google.comac10a2d2010-12-22 21:39:39 +000017
commit-bot@chromium.orge3beb6b2014-04-07 19:34:38 +000018class GrAllocator : SkNoncopyable {
reed@google.comac10a2d2010-12-22 21:39:39 +000019public:
bsalomonbce3d6d2014-07-02 07:54:42 -070020 ~GrAllocator() { this->reset(); }
reed@google.comac10a2d2010-12-22 21:39:39 +000021
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 */
bsalomonbce3d6d2014-07-02 07:54:42 -070031 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock)
32 : fItemSize(itemSize)
33 , fItemsPerBlock(itemsPerBlock)
halcanary96fcdcc2015-08-27 07:41:13 -070034 , fOwnFirstBlock(nullptr == initialBlock)
bsalomonbce3d6d2014-07-02 07:54:42 -070035 , fCount(0)
36 , fInsertionIndexInBlock(0) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000037 SkASSERT(itemsPerBlock > 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000038 fBlockSize = fItemSize * fItemsPerBlock;
bsalomonbce3d6d2014-07-02 07:54:42 -070039 if (fOwnFirstBlock) {
40 // This force us to allocate a new block on push_back().
41 fInsertionIndexInBlock = fItemsPerBlock;
42 } else {
43 fBlocks.push_back() = initialBlock;
44 fInsertionIndexInBlock = 0;
45 }
reed@google.comac10a2d2010-12-22 21:39:39 +000046 }
47
bsalomonbce3d6d2014-07-02 07:54:42 -070048 /**
49 * Adds an item and returns pointer to it.
50 *
51 * @return pointer to the added item.
52 */
53 void* push_back() {
54 // we always have at least one block
55 if (fItemsPerBlock == fInsertionIndexInBlock) {
56 fBlocks.push_back() = sk_malloc_throw(fBlockSize);
57 fInsertionIndexInBlock = 0;
58 }
59 void* ret = (char*)fBlocks.back() + fItemSize * fInsertionIndexInBlock;
60 ++fCount;
61 ++fInsertionIndexInBlock;
62 return ret;
63 }
64
65 /**
bsalomona1ae66d2014-09-05 06:13:43 -070066 * Remove the last item, only call if count() != 0
67 */
68 void pop_back() {
69 SkASSERT(fCount);
70 SkASSERT(fInsertionIndexInBlock > 0);
71 --fInsertionIndexInBlock;
72 --fCount;
73 if (0 == fInsertionIndexInBlock) {
74 // Never delete the first block
75 if (fBlocks.count() > 1) {
76 sk_free(fBlocks.back());
77 fBlocks.pop_back();
78 fInsertionIndexInBlock = fItemsPerBlock;
79 }
80 }
81 }
82
83 /**
bsalomonbce3d6d2014-07-02 07:54:42 -070084 * Removes all added items.
85 */
86 void reset() {
87 int firstBlockToFree = fOwnFirstBlock ? 0 : 1;
88 for (int i = firstBlockToFree; i < fBlocks.count(); ++i) {
89 sk_free(fBlocks[i]);
90 }
91 if (fOwnFirstBlock) {
92 fBlocks.reset();
93 // This force us to allocate a new block on push_back().
94 fInsertionIndexInBlock = fItemsPerBlock;
95 } else {
96 fBlocks.pop_back_n(fBlocks.count() - 1);
97 fInsertionIndexInBlock = 0;
98 }
99 fCount = 0;
100 }
101
102 /**
103 * Returns the item count.
104 */
105 int count() const {
106 return fCount;
107 }
108
109 /**
110 * Is the count 0?
111 */
112 bool empty() const { return 0 == fCount; }
113
114 /**
Chris Daltond0d409d2018-06-08 11:51:39 -0600115 * Access first item, only call if count() != 0
116 */
117 void* front() {
118 SkASSERT(fCount);
119 SkASSERT(fInsertionIndexInBlock > 0);
120 return (char*)(fBlocks.front());
121 }
122
123 /**
124 * Access first item, only call if count() != 0
125 */
126 const void* front() const {
127 SkASSERT(fCount);
128 SkASSERT(fInsertionIndexInBlock > 0);
129 return (const char*)(fBlocks.front());
130 }
131
132 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700133 * Access last item, only call if count() != 0
134 */
135 void* back() {
136 SkASSERT(fCount);
137 SkASSERT(fInsertionIndexInBlock > 0);
138 return (char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
139 }
140
141 /**
142 * Access last item, only call if count() != 0
143 */
144 const void* back() const {
145 SkASSERT(fCount);
146 SkASSERT(fInsertionIndexInBlock > 0);
147 return (const char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
148 }
149
bsalomonbce3d6d2014-07-02 07:54:42 -0700150 /**
151 * Iterates through the allocator. This is faster than using operator[] when walking linearly
152 * through the allocator.
153 */
154 class Iter {
155 public:
156 /**
157 * Initializes the iterator. next() must be called before get().
158 */
159 Iter(const GrAllocator* allocator)
160 : fAllocator(allocator)
161 , fBlockIndex(-1)
162 , fIndexInBlock(allocator->fItemsPerBlock - 1)
163 , fItemIndex(-1) {}
164
165 /**
166 * Advances the iterator. Iteration is finished when next() returns false.
167 */
168 bool next() {
169 ++fIndexInBlock;
170 ++fItemIndex;
171 if (fIndexInBlock == fAllocator->fItemsPerBlock) {
172 ++fBlockIndex;
173 fIndexInBlock = 0;
174 }
175 return fItemIndex < fAllocator->fCount;
176 }
177
178 /**
179 * Gets the current iterator value. Call next() at least once before calling. Don't call
180 * after next() returns false.
181 */
bsalomone1bc1c62014-07-02 13:44:57 -0700182 void* get() const {
bsalomonbce3d6d2014-07-02 07:54:42 -0700183 SkASSERT(fItemIndex >= 0 && fItemIndex < fAllocator->fCount);
184 return (char*) fAllocator->fBlocks[fBlockIndex] + fIndexInBlock * fAllocator->fItemSize;
185 }
186
187 private:
188 const GrAllocator* fAllocator;
189 int fBlockIndex;
190 int fIndexInBlock;
191 int fItemIndex;
192 };
193
194 /**
195 * Access item by index.
196 */
197 void* operator[] (int i) {
198 SkASSERT(i >= 0 && i < fCount);
199 return (char*)fBlocks[i / fItemsPerBlock] +
200 fItemSize * (i % fItemsPerBlock);
201 }
202
203 /**
204 * Access item by index.
205 */
206 const void* operator[] (int i) const {
207 SkASSERT(i >= 0 && i < fCount);
208 return (const char*)fBlocks[i / fItemsPerBlock] +
209 fItemSize * (i % fItemsPerBlock);
210 }
211
212protected:
213 /**
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000214 * Set first block of memory to write into. Must be called before any other methods.
halcanary96fcdcc2015-08-27 07:41:13 -0700215 * This requires that you have passed nullptr in the constructor.
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000216 *
217 * @param initialBlock optional memory to use for the first block.
218 * Must be at least itemSize*itemsPerBlock sized.
219 * Caller is responsible for freeing this memory.
220 */
221 void setInitialBlock(void* initialBlock) {
222 SkASSERT(0 == fCount);
bsalomonbce3d6d2014-07-02 07:54:42 -0700223 SkASSERT(0 == fBlocks.count());
224 SkASSERT(fItemsPerBlock == fInsertionIndexInBlock);
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000225 fOwnFirstBlock = false;
bsalomonbce3d6d2014-07-02 07:54:42 -0700226 fBlocks.push_back() = initialBlock;
227 fInsertionIndexInBlock = 0;
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000228 }
229
bsalomonbce3d6d2014-07-02 07:54:42 -0700230 // For access to above function.
231 template <typename T> friend class GrTAllocator;
reed@google.comac10a2d2010-12-22 21:39:39 +0000232
233private:
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000234 static const int NUM_INIT_BLOCK_PTRS = 8;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000235
bsalomonbce3d6d2014-07-02 07:54:42 -0700236 SkSTArray<NUM_INIT_BLOCK_PTRS, void*, true> fBlocks;
237 size_t fBlockSize;
238 size_t fItemSize;
239 int fItemsPerBlock;
240 bool fOwnFirstBlock;
241 int fCount;
242 int fInsertionIndexInBlock;
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000243
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +0000244 typedef SkNoncopyable INHERITED;
reed@google.comac10a2d2010-12-22 21:39:39 +0000245};
246
bsalomonb3e3a952014-09-19 11:10:40 -0700247template <typename T> class GrTAllocator;
248template <typename T> void* operator new(size_t, GrTAllocator<T>*);
249
250template <typename T> class GrTAllocator : SkNoncopyable {
reed@google.comac10a2d2010-12-22 21:39:39 +0000251public:
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400252 virtual ~GrTAllocator() { this->reset(); }
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000253
reed@google.comac10a2d2010-12-22 21:39:39 +0000254 /**
255 * Create an allocator
256 *
257 * @param itemsPerBlock the number of items to allocate at once
reed@google.comac10a2d2010-12-22 21:39:39 +0000258 */
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000259 explicit GrTAllocator(int itemsPerBlock)
halcanary96fcdcc2015-08-27 07:41:13 -0700260 : fAllocator(sizeof(T), itemsPerBlock, nullptr) {}
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000261
262 /**
reed@google.comac10a2d2010-12-22 21:39:39 +0000263 * Adds an item and returns it.
264 *
265 * @return the added item.
266 */
267 T& push_back() {
268 void* item = fAllocator.push_back();
bsalomon49f085d2014-09-05 13:34:00 -0700269 SkASSERT(item);
halcanary385fe4d2015-08-26 13:07:48 -0700270 new (item) T;
reed@google.comac10a2d2010-12-22 21:39:39 +0000271 return *(T*)item;
272 }
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000273
274 T& push_back(const T& t) {
275 void* item = fAllocator.push_back();
bsalomon49f085d2014-09-05 13:34:00 -0700276 SkASSERT(item);
halcanary385fe4d2015-08-26 13:07:48 -0700277 new (item) T(t);
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000278 return *(T*)item;
279 }
280
Brian Salomonbc6b99d2017-01-11 10:32:34 -0500281 template <typename... Args> T& emplace_back(Args&&... args) {
282 void* item = fAllocator.push_back();
283 SkASSERT(item);
284 new (item) T(std::forward<Args>(args)...);
285 return *(T*)item;
286 }
287
reed@google.comac10a2d2010-12-22 21:39:39 +0000288 /**
bsalomona1ae66d2014-09-05 06:13:43 -0700289 * Remove the last item, only call if count() != 0
290 */
291 void pop_back() {
292 this->back().~T();
293 fAllocator.pop_back();
294 }
295
296 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700297 * Removes all added items.
reed@google.comac10a2d2010-12-22 21:39:39 +0000298 */
299 void reset() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000300 int c = fAllocator.count();
301 for (int i = 0; i < c; ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000302 ((T*)fAllocator[i])->~T();
303 }
304 fAllocator.reset();
305 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000306
reed@google.comac10a2d2010-12-22 21:39:39 +0000307 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700308 * Returns the item count.
reed@google.comac10a2d2010-12-22 21:39:39 +0000309 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000310 int count() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000311 return fAllocator.count();
312 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000313
reed@google.comac10a2d2010-12-22 21:39:39 +0000314 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700315 * Is the count 0?
reed@google.comac10a2d2010-12-22 21:39:39 +0000316 */
317 bool empty() const { return fAllocator.empty(); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000318
reed@google.comac10a2d2010-12-22 21:39:39 +0000319 /**
Chris Daltond0d409d2018-06-08 11:51:39 -0600320 * Access first item, only call if count() != 0
321 */
322 T& front() {
323 return *(T*)fAllocator.front();
324 }
325
326 /**
327 * Access first item, only call if count() != 0
328 */
329 const T& front() const {
330 return *(T*)fAllocator.front();
331 }
332
333 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700334 * Access last item, only call if count() != 0
reed@google.comac10a2d2010-12-22 21:39:39 +0000335 */
336 T& back() {
337 return *(T*)fAllocator.back();
338 }
339
340 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700341 * Access last item, only call if count() != 0
reed@google.comac10a2d2010-12-22 21:39:39 +0000342 */
343 const T& back() const {
344 return *(const T*)fAllocator.back();
345 }
346
347 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700348 * Iterates through the allocator. This is faster than using operator[] when walking linearly
349 * through the allocator.
350 */
351 class Iter {
352 public:
353 /**
354 * Initializes the iterator. next() must be called before get() or ops * and ->.
355 */
356 Iter(const GrTAllocator* allocator) : fImpl(&allocator->fAllocator) {}
357
358 /**
359 * Advances the iterator. Iteration is finished when next() returns false.
360 */
361 bool next() { return fImpl.next(); }
362
363 /**
364 * Gets the current iterator value. Call next() at least once before calling. Don't call
365 * after next() returns false.
366 */
bsalomone1bc1c62014-07-02 13:44:57 -0700367 T* get() const { return (T*) fImpl.get(); }
bsalomonbce3d6d2014-07-02 07:54:42 -0700368
369 /**
370 * Convenience operators. Same rules for calling apply as get().
371 */
bsalomone1bc1c62014-07-02 13:44:57 -0700372 T& operator*() const { return *this->get(); }
373 T* operator->() const { return this->get(); }
bsalomonbce3d6d2014-07-02 07:54:42 -0700374
375 private:
376 GrAllocator::Iter fImpl;
377 };
378
379 /**
380 * Access item by index.
rmistry@google.comd6176b02012-08-23 18:14:13 +0000381 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000382 T& operator[] (int i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000383 return *(T*)(fAllocator[i]);
384 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000385
reed@google.comac10a2d2010-12-22 21:39:39 +0000386 /**
bsalomonbce3d6d2014-07-02 07:54:42 -0700387 * Access item by index.
reed@google.comac10a2d2010-12-22 21:39:39 +0000388 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000389 const T& operator[] (int i) const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000390 return *(const T*)(fAllocator[i]);
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000391 }
392
393protected:
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000394 /*
395 * Set first block of memory to write into. Must be called before any other methods.
396 *
397 * @param initialBlock optional memory to use for the first block.
398 * Must be at least size(T)*itemsPerBlock sized.
399 * Caller is responsible for freeing this memory.
400 */
401 void setInitialBlock(void* initialBlock) {
402 fAllocator.setInitialBlock(initialBlock);
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000403 }
404
405private:
bsalomonb3e3a952014-09-19 11:10:40 -0700406 friend void* operator new<T>(size_t, GrTAllocator*);
407
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000408 GrAllocator fAllocator;
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +0000409 typedef SkNoncopyable INHERITED;
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000410};
411
412template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
413private:
414 typedef GrTAllocator<T> INHERITED;
415
416public:
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000417 GrSTAllocator() : INHERITED(N) {
418 this->setInitialBlock(fStorage.get());
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000419 }
420
421private:
422 SkAlignedSTStorage<N, T> fStorage;
reed@google.comac10a2d2010-12-22 21:39:39 +0000423};
424
bsalomonb3e3a952014-09-19 11:10:40 -0700425template <typename T> void* operator new(size_t size, GrTAllocator<T>* allocator) {
426 return allocator->fAllocator.push_back();
427}
428
429// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
430// to match the op new silences warnings about missing op delete when a constructor throws an
431// exception.
432template <typename T> void operator delete(void*, GrTAllocator<T>*) {
djsollenf2b340f2016-01-29 08:51:04 -0800433 SK_ABORT("Invalid Operation");
bsalomonb3e3a952014-09-19 11:10:40 -0700434}
435
436#define GrNEW_APPEND_TO_ALLOCATOR(allocator_ptr, type_name, args) \
437 new (allocator_ptr) type_name args
438
reed@google.comac10a2d2010-12-22 21:39:39 +0000439#endif