2 * Copyright 2010 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef GrAllocator_DEFINED
9 #define GrAllocator_DEFINED
16 class GrAllocator : SkNoncopyable {
18 ~GrAllocator() { this->reset(); }
23 * @param itemSize the size of each item to allocate
24 * @param itemsPerBlock the number of items to allocate at once
25 * @param initialBlock optional memory to use for the first block.
26 * Must be at least itemSize*itemsPerBlock sized.
27 * Caller is responsible for freeing this memory.
29 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock)
31 , fItemsPerBlock(itemsPerBlock)
32 , fOwnFirstBlock(NULL == initialBlock)
34 , fInsertionIndexInBlock(0) {
35 SkASSERT(itemsPerBlock > 0);
36 fBlockSize = fItemSize * fItemsPerBlock;
38 // This force us to allocate a new block on push_back().
39 fInsertionIndexInBlock = fItemsPerBlock;
41 fBlocks.push_back() = initialBlock;
42 fInsertionIndexInBlock = 0;
47 * Adds an item and returns pointer to it.
49 * @return pointer to the added item.
52 // we always have at least one block
53 if (fItemsPerBlock == fInsertionIndexInBlock) {
54 fBlocks.push_back() = sk_malloc_throw(fBlockSize);
55 fInsertionIndexInBlock = 0;
57 void* ret = (char*)fBlocks.back() + fItemSize * fInsertionIndexInBlock;
59 ++fInsertionIndexInBlock;
64 * Remove the last item, only call if count() != 0
68 SkASSERT(fInsertionIndexInBlock > 0);
69 --fInsertionIndexInBlock;
71 if (0 == fInsertionIndexInBlock) {
72 // Never delete the first block
73 if (fBlocks.count() > 1) {
74 sk_free(fBlocks.back());
76 fInsertionIndexInBlock = fItemsPerBlock;
82 * Removes all added items.
85 int firstBlockToFree = fOwnFirstBlock ? 0 : 1;
86 for (int i = firstBlockToFree; i < fBlocks.count(); ++i) {
91 // This force us to allocate a new block on push_back().
92 fInsertionIndexInBlock = fItemsPerBlock;
94 fBlocks.pop_back_n(fBlocks.count() - 1);
95 fInsertionIndexInBlock = 0;
101 * Returns the item count.
110 bool empty() const { return 0 == fCount; }
113 * Access last item, only call if count() != 0
117 SkASSERT(fInsertionIndexInBlock > 0);
118 return (char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
122 * Access last item, only call if count() != 0
124 const void* back() const {
126 SkASSERT(fInsertionIndexInBlock > 0);
127 return (const char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
131 * Iterates through the allocator. This is faster than using operator[] when walking linearly
132 * through the allocator.
137 * Initializes the iterator. next() must be called before get().
139 Iter(const GrAllocator* allocator)
140 : fAllocator(allocator)
142 , fIndexInBlock(allocator->fItemsPerBlock - 1)
146 * Advances the iterator. Iteration is finished when next() returns false.
151 if (fIndexInBlock == fAllocator->fItemsPerBlock) {
155 return fItemIndex < fAllocator->fCount;
159 * Gets the current iterator value. Call next() at least once before calling. Don't call
160 * after next() returns false.
163 SkASSERT(fItemIndex >= 0 && fItemIndex < fAllocator->fCount);
164 return (char*) fAllocator->fBlocks[fBlockIndex] + fIndexInBlock * fAllocator->fItemSize;
168 const GrAllocator* fAllocator;
175 * Access item by index.
177 void* operator[] (int i) {
178 SkASSERT(i >= 0 && i < fCount);
179 return (char*)fBlocks[i / fItemsPerBlock] +
180 fItemSize * (i % fItemsPerBlock);
184 * Access item by index.
186 const void* operator[] (int i) const {
187 SkASSERT(i >= 0 && i < fCount);
188 return (const char*)fBlocks[i / fItemsPerBlock] +
189 fItemSize * (i % fItemsPerBlock);
194 * Set first block of memory to write into. Must be called before any other methods.
195 * This requires that you have passed NULL in the constructor.
197 * @param initialBlock optional memory to use for the first block.
198 * Must be at least itemSize*itemsPerBlock sized.
199 * Caller is responsible for freeing this memory.
201 void setInitialBlock(void* initialBlock) {
202 SkASSERT(0 == fCount);
203 SkASSERT(0 == fBlocks.count());
204 SkASSERT(fItemsPerBlock == fInsertionIndexInBlock);
205 fOwnFirstBlock = false;
206 fBlocks.push_back() = initialBlock;
207 fInsertionIndexInBlock = 0;
210 // For access to above function.
211 template <typename T> friend class GrTAllocator;
214 static const int NUM_INIT_BLOCK_PTRS = 8;
216 SkSTArray<NUM_INIT_BLOCK_PTRS, void*, true> fBlocks;
222 int fInsertionIndexInBlock;
224 typedef SkNoncopyable INHERITED;
227 template <typename T> class GrTAllocator;
228 template <typename T> void* operator new(size_t, GrTAllocator<T>*);
230 template <typename T> class GrTAllocator : SkNoncopyable {
232 virtual ~GrTAllocator() { this->reset(); };
235 * Create an allocator
237 * @param itemsPerBlock the number of items to allocate at once
239 explicit GrTAllocator(int itemsPerBlock)
240 : fAllocator(sizeof(T), itemsPerBlock, NULL) {}
243 * Adds an item and returns it.
245 * @return the added item.
248 void* item = fAllocator.push_back();
250 SkNEW_PLACEMENT(item, T);
254 T& push_back(const T& t) {
255 void* item = fAllocator.push_back();
257 SkNEW_PLACEMENT_ARGS(item, T, (t));
262 * Remove the last item, only call if count() != 0
266 fAllocator.pop_back();
270 * Removes all added items.
273 int c = fAllocator.count();
274 for (int i = 0; i < c; ++i) {
275 ((T*)fAllocator[i])->~T();
281 * Returns the item count.
284 return fAllocator.count();
290 bool empty() const { return fAllocator.empty(); }
293 * Access last item, only call if count() != 0
296 return *(T*)fAllocator.back();
300 * Access last item, only call if count() != 0
302 const T& back() const {
303 return *(const T*)fAllocator.back();
307 * Iterates through the allocator. This is faster than using operator[] when walking linearly
308 * through the allocator.
313 * Initializes the iterator. next() must be called before get() or ops * and ->.
315 Iter(const GrTAllocator* allocator) : fImpl(&allocator->fAllocator) {}
318 * Advances the iterator. Iteration is finished when next() returns false.
320 bool next() { return fImpl.next(); }
323 * Gets the current iterator value. Call next() at least once before calling. Don't call
324 * after next() returns false.
326 T* get() const { return (T*) fImpl.get(); }
329 * Convenience operators. Same rules for calling apply as get().
331 T& operator*() const { return *this->get(); }
332 T* operator->() const { return this->get(); }
335 GrAllocator::Iter fImpl;
339 * Access item by index.
341 T& operator[] (int i) {
342 return *(T*)(fAllocator[i]);
346 * Access item by index.
348 const T& operator[] (int i) const {
349 return *(const T*)(fAllocator[i]);
354 * Set first block of memory to write into. Must be called before any other methods.
356 * @param initialBlock optional memory to use for the first block.
357 * Must be at least size(T)*itemsPerBlock sized.
358 * Caller is responsible for freeing this memory.
360 void setInitialBlock(void* initialBlock) {
361 fAllocator.setInitialBlock(initialBlock);
365 friend void* operator new<T>(size_t, GrTAllocator*);
367 GrAllocator fAllocator;
368 typedef SkNoncopyable INHERITED;
371 template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
373 typedef GrTAllocator<T> INHERITED;
376 GrSTAllocator() : INHERITED(N) {
377 this->setInitialBlock(fStorage.get());
381 SkAlignedSTStorage<N, T> fStorage;
384 template <typename T> void* operator new(size_t size, GrTAllocator<T>* allocator) {
385 return allocator->fAllocator.push_back();
388 // Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
389 // to match the op new silences warnings about missing op delete when a constructor throws an
391 template <typename T> void operator delete(void*, GrTAllocator<T>*) {
395 #define GrNEW_APPEND_TO_ALLOCATOR(allocator_ptr, type_name, args) \
396 new (allocator_ptr) type_name args