blob: deed2dc8096d233f8ea3fb3c8ab650ffd8088101 [file] [log] [blame]
reed@google.comac10a2d2010-12-22 21:39:39 +00001/*
2 Copyright 2010 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17
18#ifndef GrAllocator_DEFINED
19#define GrAllocator_DEFINED
20
21#include "GrConfig.h"
22#include "GrTArray.h"
23
24class GrAllocator {
25public:
26 virtual ~GrAllocator() {
27 reset();
28 }
29
30 /**
31 * Create an allocator
32 *
33 * @param itemSize the size of each item to allocate
34 * @param itemsPerBlock the number of items to allocate at once
35 * @param initialBlock optional memory to use for the first block.
36 * Must be at least itemSize*itemsPerBlock sized.
37 * Caller is responsible for freeing this memory.
38 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000039 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
reed@google.comac10a2d2010-12-22 21:39:39 +000040 fBlocks(fBlockInitialStorage, NUM_INIT_BLOCK_PTRS),
41 fItemSize(itemSize),
42 fItemsPerBlock(itemsPerBlock),
43 fOwnFirstBlock(NULL == initialBlock),
44 fCount(0) {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000045 GrAssert(itemsPerBlock > 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000046 fBlockSize = fItemSize * fItemsPerBlock;
47 fBlocks.push_back() = initialBlock;
48 GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
49 }
50
51 /**
52 * Adds an item and returns pointer to it.
53 *
54 * @return pointer to the added item.
55 */
56 void* push_back() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000057 int indexInBlock = fCount % fItemsPerBlock;
reed@google.comac10a2d2010-12-22 21:39:39 +000058 // we always have at least one block
59 if (0 == indexInBlock) {
60 if (0 != fCount) {
61 fBlocks.push_back() = GrMalloc(fBlockSize);
62 } else if (fOwnFirstBlock) {
63 fBlocks[0] = GrMalloc(fBlockSize);
64 }
65 }
66 void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
67 fItemSize * indexInBlock;
68 ++fCount;
69 return ret;
70 }
71
72 /**
73 * removes all added items
74 */
75 void reset() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000076 int blockCount = GrMax((unsigned)1,
77 GrUIDivRoundUp(fCount, fItemsPerBlock));
78 for (int i = 1; i < blockCount; ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +000079 GrFree(fBlocks[i]);
80 }
81 if (fOwnFirstBlock) {
82 GrFree(fBlocks[0]);
83 fBlocks[0] = NULL;
84 }
85 fBlocks.pop_back_n(blockCount-1);
86 fCount = 0;
87 }
88
89 /**
90 * count of items
91 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000092 int count() const {
reed@google.comac10a2d2010-12-22 21:39:39 +000093 return fCount;
94 }
95
96 /**
97 * is the count 0
98 */
99 bool empty() const { return fCount == 0; }
100
101 /**
102 * access last item, only call if count() != 0
103 */
104 void* back() {
105 GrAssert(fCount);
106 return (*this)[fCount-1];
107 }
108
109 /**
110 * access last item, only call if count() != 0
111 */
112 const void* back() const {
113 GrAssert(fCount);
114 return (*this)[fCount-1];
115 }
116
117 /**
118 * access item by index.
119 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000120 void* operator[] (int i) {
121 GrAssert(i >= 0 && i < fCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000122 return (char*)fBlocks[i / fItemsPerBlock] +
123 fItemSize * (i % fItemsPerBlock);
124 }
125
126 /**
127 * access item by index.
128 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000129 const void* operator[] (int i) const {
130 GrAssert(i >= 0 && i < fCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000131 return (const char*)fBlocks[i / fItemsPerBlock] +
132 fItemSize * (i % fItemsPerBlock);
133 }
134
135private:
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000136 static const int NUM_INIT_BLOCK_PTRS = 8;
reed@google.comac10a2d2010-12-22 21:39:39 +0000137
138 GrTArray<void*> fBlocks;
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000139 size_t fBlockSize;
140 char fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)];
reed@google.comac10a2d2010-12-22 21:39:39 +0000141 size_t fItemSize;
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000142 int fItemsPerBlock;
reed@google.comac10a2d2010-12-22 21:39:39 +0000143 bool fOwnFirstBlock;
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000144 int fCount;
reed@google.comac10a2d2010-12-22 21:39:39 +0000145};
146
147template <typename T>
148class GrTAllocator {
149private:
150 GrAllocator fAllocator;
151
152public:
153 virtual ~GrTAllocator() {};
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000154
reed@google.comac10a2d2010-12-22 21:39:39 +0000155 /**
156 * Create an allocator
157 *
158 * @param itemsPerBlock the number of items to allocate at once
159 * @param initialBlock optional memory to use for the first block.
160 * Must be at least size(T)*itemsPerBlock sized.
161 * Caller is responsible for freeing this memory.
162 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000163 GrTAllocator(int itemsPerBlock, void* initialBlock)
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000164 : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {}
165
166 /**
167 * Create an allocator using a GrAlignedTAlloc as the initial block.
168 *
169 * @param initialBlock specifies the storage for the initial block
170 * and the size of subsequent blocks.
171 */
172 template <int N>
173 GrTAllocator(GrAlignedSTStorage<N,T>* initialBlock)
174 : fAllocator(sizeof(T), N, initialBlock->get()) {}
reed@google.comac10a2d2010-12-22 21:39:39 +0000175
176 /**
177 * Adds an item and returns it.
178 *
179 * @return the added item.
180 */
181 T& push_back() {
182 void* item = fAllocator.push_back();
183 GrAssert(NULL != item);
184 new (item) T;
185 return *(T*)item;
186 }
187
188 /**
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