blob: eca2ab029f58a7bec4f1f9a32af3a869f7b75b14 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
epoger@google.comec3ed6a2011-07-28 14:26:00 +000010
reed@google.comac10a2d2010-12-22 21:39:39 +000011#ifndef GrAllocator_DEFINED
12#define GrAllocator_DEFINED
13
14#include "GrConfig.h"
bsalomon@google.com49313f62011-09-14 13:54:05 +000015#include "SkTArray.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000016
17class GrAllocator {
18public:
19 virtual ~GrAllocator() {
20 reset();
21 }
22
23 /**
24 * Create an allocator
25 *
26 * @param itemSize the size of each item to allocate
27 * @param itemsPerBlock the number of items to allocate at once
28 * @param initialBlock optional memory to use for the first block.
29 * Must be at least itemSize*itemsPerBlock sized.
30 * Caller is responsible for freeing this memory.
31 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000032 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
reed@google.comac10a2d2010-12-22 21:39:39 +000033 fBlocks(fBlockInitialStorage, NUM_INIT_BLOCK_PTRS),
34 fItemSize(itemSize),
35 fItemsPerBlock(itemsPerBlock),
36 fOwnFirstBlock(NULL == initialBlock),
37 fCount(0) {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000038 GrAssert(itemsPerBlock > 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000039 fBlockSize = fItemSize * fItemsPerBlock;
40 fBlocks.push_back() = initialBlock;
41 GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
42 }
43
44 /**
45 * Adds an item and returns pointer to it.
46 *
47 * @return pointer to the added item.
48 */
bsalomon@google.com4fa66942011-09-20 19:06:12 +000049 void* push_back() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000050 int indexInBlock = fCount % fItemsPerBlock;
reed@google.comac10a2d2010-12-22 21:39:39 +000051 // we always have at least one block
52 if (0 == indexInBlock) {
53 if (0 != fCount) {
54 fBlocks.push_back() = GrMalloc(fBlockSize);
55 } else if (fOwnFirstBlock) {
56 fBlocks[0] = GrMalloc(fBlockSize);
57 }
58 }
59 void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
60 fItemSize * indexInBlock;
61 ++fCount;
62 return ret;
63 }
64
65 /**
66 * removes all added items
67 */
68 void reset() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000069 int blockCount = GrMax((unsigned)1,
70 GrUIDivRoundUp(fCount, fItemsPerBlock));
71 for (int i = 1; i < blockCount; ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +000072 GrFree(fBlocks[i]);
73 }
74 if (fOwnFirstBlock) {
75 GrFree(fBlocks[0]);
76 fBlocks[0] = NULL;
77 }
78 fBlocks.pop_back_n(blockCount-1);
79 fCount = 0;
80 }
81
82 /**
83 * count of items
84 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000085 int count() const {
reed@google.comac10a2d2010-12-22 21:39:39 +000086 return fCount;
87 }
88
89 /**
90 * is the count 0
91 */
92 bool empty() const { return fCount == 0; }
93
94 /**
95 * access last item, only call if count() != 0
96 */
97 void* back() {
98 GrAssert(fCount);
99 return (*this)[fCount-1];
100 }
101
102 /**
103 * access last item, only call if count() != 0
104 */
105 const void* back() const {
106 GrAssert(fCount);
107 return (*this)[fCount-1];
108 }
109
110 /**
111 * access item by index.
112 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000113 void* operator[] (int i) {
114 GrAssert(i >= 0 && i < fCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000115 return (char*)fBlocks[i / fItemsPerBlock] +
116 fItemSize * (i % fItemsPerBlock);
117 }
118
119 /**
120 * access item by index.
121 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000122 const void* operator[] (int i) const {
123 GrAssert(i >= 0 && i < fCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000124 return (const char*)fBlocks[i / fItemsPerBlock] +
125 fItemSize * (i % fItemsPerBlock);
126 }
127
128private:
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000129 static const int NUM_INIT_BLOCK_PTRS = 8;
reed@google.comac10a2d2010-12-22 21:39:39 +0000130
bsalomon@google.com49313f62011-09-14 13:54:05 +0000131 SkTArray<void*> fBlocks;
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000132 size_t fBlockSize;
133 char fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)];
reed@google.comac10a2d2010-12-22 21:39:39 +0000134 size_t fItemSize;
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000135 int fItemsPerBlock;
reed@google.comac10a2d2010-12-22 21:39:39 +0000136 bool fOwnFirstBlock;
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000137 int fCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000138};
139
140template <typename T>
141class GrTAllocator {
142private:
143 GrAllocator fAllocator;
144
145public:
146 virtual ~GrTAllocator() {};
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000147
reed@google.comac10a2d2010-12-22 21:39:39 +0000148 /**
149 * Create an allocator
150 *
151 * @param itemsPerBlock the number of items to allocate at once
152 * @param initialBlock optional memory to use for the first block.
153 * Must be at least size(T)*itemsPerBlock sized.
154 * Caller is responsible for freeing this memory.
155 */
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000156 explicit GrTAllocator(int itemsPerBlock, void* initialBlock = NULL)
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000157 : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {}
158
159 /**
160 * Create an allocator using a GrAlignedTAlloc as the initial block.
161 *
162 * @param initialBlock specifies the storage for the initial block
163 * and the size of subsequent blocks.
164 */
165 template <int N>
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000166 explicit GrTAllocator(SkAlignedSTStorage<N,T>* initialBlock)
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000167 : fAllocator(sizeof(T), N, initialBlock->get()) {}
reed@google.comac10a2d2010-12-22 21:39:39 +0000168
169 /**
170 * Adds an item and returns it.
171 *
172 * @return the added item.
173 */
174 T& push_back() {
175 void* item = fAllocator.push_back();
176 GrAssert(NULL != item);
177 new (item) T;
178 return *(T*)item;
179 }
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000180
181 T& push_back(const T& t) {
182 void* item = fAllocator.push_back();
183 GrAssert(NULL != item);
184 new (item) T(t);
185 return *(T*)item;
186 }
187
reed@google.comac10a2d2010-12-22 21:39:39 +0000188 /**
189 * removes all added items
190 */
191 void reset() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000192 int c = fAllocator.count();
193 for (int i = 0; i < c; ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000194 ((T*)fAllocator[i])->~T();
195 }
196 fAllocator.reset();
197 }
198
199 /**
200 * count of items
201 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000202 int count() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000203 return fAllocator.count();
204 }
205
206 /**
207 * is the count 0
208 */
209 bool empty() const { return fAllocator.empty(); }
210
211 /**
212 * access last item, only call if count() != 0
213 */
214 T& back() {
215 return *(T*)fAllocator.back();
216 }
217
218 /**
219 * access last item, only call if count() != 0
220 */
221 const T& back() const {
222 return *(const T*)fAllocator.back();
223 }
224
225 /**
226 * access item by index.
227 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000228 T& operator[] (int i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000229 return *(T*)(fAllocator[i]);
230 }
231
232 /**
233 * access item by index.
234 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000235 const T& operator[] (int i) const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000236 return *(const T*)(fAllocator[i]);
237 }
238};
239
240#endif