blob: a2ad408e072d03b84352f423a6b76a78f55a0f4e [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"
bsalomon@google.com49313f62011-09-14 13:54:05 +000013#include "SkTArray.h"
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +000014#include "SkTypes.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000015
commit-bot@chromium.orge3beb6b2014-04-07 19:34:38 +000016class GrAllocator : SkNoncopyable {
reed@google.comac10a2d2010-12-22 21:39:39 +000017public:
bsalomon@google.com4b90c622011-09-28 17:52:15 +000018 ~GrAllocator() {
reed@google.comac10a2d2010-12-22 21:39:39 +000019 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 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000031 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) :
reed@google.comac10a2d2010-12-22 21:39:39 +000032 fItemSize(itemSize),
33 fItemsPerBlock(itemsPerBlock),
34 fOwnFirstBlock(NULL == initialBlock),
35 fCount(0) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000036 SkASSERT(itemsPerBlock > 0);
reed@google.comac10a2d2010-12-22 21:39:39 +000037 fBlockSize = fItemSize * fItemsPerBlock;
38 fBlocks.push_back() = initialBlock;
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +000039 SkDEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
reed@google.comac10a2d2010-12-22 21:39:39 +000040 }
41
commit-bot@chromium.org845da772013-12-02 22:32:58 +000042 /*
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
reed@google.comac10a2d2010-12-22 21:39:39 +000058 /**
59 * Adds an item and returns pointer to it.
60 *
61 * @return pointer to the added item.
62 */
bsalomon@google.com4fa66942011-09-20 19:06:12 +000063 void* push_back() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000064 int indexInBlock = fCount % fItemsPerBlock;
reed@google.comac10a2d2010-12-22 21:39:39 +000065 // we always have at least one block
66 if (0 == indexInBlock) {
67 if (0 != fCount) {
reed@google.com939ca7c2013-09-26 19:56:51 +000068 fBlocks.push_back() = sk_malloc_throw(fBlockSize);
reed@google.comac10a2d2010-12-22 21:39:39 +000069 } else if (fOwnFirstBlock) {
reed@google.com939ca7c2013-09-26 19:56:51 +000070 fBlocks[0] = sk_malloc_throw(fBlockSize);
reed@google.comac10a2d2010-12-22 21:39:39 +000071 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000072 }
73 void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
reed@google.comac10a2d2010-12-22 21:39:39 +000074 fItemSize * indexInBlock;
75 ++fCount;
76 return ret;
77 }
78
79 /**
80 * removes all added items
81 */
rmistry@google.comd6176b02012-08-23 18:14:13 +000082 void reset() {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000083 int blockCount = SkTMax((unsigned)1,
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000084 GrUIDivRoundUp(fCount, fItemsPerBlock));
85 for (int i = 1; i < blockCount; ++i) {
reed@google.com939ca7c2013-09-26 19:56:51 +000086 sk_free(fBlocks[i]);
reed@google.comac10a2d2010-12-22 21:39:39 +000087 }
88 if (fOwnFirstBlock) {
reed@google.com939ca7c2013-09-26 19:56:51 +000089 sk_free(fBlocks[0]);
reed@google.comac10a2d2010-12-22 21:39:39 +000090 fBlocks[0] = NULL;
91 }
92 fBlocks.pop_back_n(blockCount-1);
93 fCount = 0;
94 }
95
96 /**
97 * count of items
98 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +000099 int count() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000100 return fCount;
101 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000102
reed@google.comac10a2d2010-12-22 21:39:39 +0000103 /**
104 * is the count 0
105 */
106 bool empty() const { return fCount == 0; }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000107
reed@google.comac10a2d2010-12-22 21:39:39 +0000108 /**
109 * access last item, only call if count() != 0
110 */
111 void* back() {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000112 SkASSERT(fCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000113 return (*this)[fCount-1];
114 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000115
reed@google.comac10a2d2010-12-22 21:39:39 +0000116 /**
117 * access last item, only call if count() != 0
118 */
119 const void* back() const {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000120 SkASSERT(fCount);
reed@google.comac10a2d2010-12-22 21:39:39 +0000121 return (*this)[fCount-1];
122 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000123
reed@google.comac10a2d2010-12-22 21:39:39 +0000124 /**
125 * access item by index.
rmistry@google.comd6176b02012-08-23 18:14:13 +0000126 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000127 void* operator[] (int i) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000128 SkASSERT(i >= 0 && i < fCount);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000129 return (char*)fBlocks[i / fItemsPerBlock] +
reed@google.comac10a2d2010-12-22 21:39:39 +0000130 fItemSize * (i % fItemsPerBlock);
131 }
132
133 /**
134 * access item by index.
rmistry@google.comd6176b02012-08-23 18:14:13 +0000135 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000136 const void* operator[] (int i) const {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000137 SkASSERT(i >= 0 && i < fCount);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000138 return (const char*)fBlocks[i / fItemsPerBlock] +
reed@google.comac10a2d2010-12-22 21:39:39 +0000139 fItemSize * (i % fItemsPerBlock);
140 }
141
142private:
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000143 static const int NUM_INIT_BLOCK_PTRS = 8;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000144
bsalomon@google.com92669012011-09-27 19:10:05 +0000145 SkSTArray<NUM_INIT_BLOCK_PTRS, void*> fBlocks;
146 size_t fBlockSize;
147 size_t fItemSize;
148 int fItemsPerBlock;
149 bool fOwnFirstBlock;
150 int fCount;
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000151
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +0000152 typedef SkNoncopyable INHERITED;
reed@google.comac10a2d2010-12-22 21:39:39 +0000153};
154
155template <typename T>
commit-bot@chromium.orge3beb6b2014-04-07 19:34:38 +0000156class GrTAllocator : SkNoncopyable {
reed@google.comac10a2d2010-12-22 21:39:39 +0000157public:
bsalomon@google.com13788bf2011-10-27 17:17:44 +0000158 virtual ~GrTAllocator() { this->reset(); };
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000159
reed@google.comac10a2d2010-12-22 21:39:39 +0000160 /**
161 * Create an allocator
162 *
163 * @param itemsPerBlock the number of items to allocate at once
reed@google.comac10a2d2010-12-22 21:39:39 +0000164 */
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000165 explicit GrTAllocator(int itemsPerBlock)
166 : fAllocator(sizeof(T), itemsPerBlock, NULL) {}
bsalomon@google.coma55847b2011-04-20 15:47:04 +0000167
168 /**
reed@google.comac10a2d2010-12-22 21:39:39 +0000169 * Adds an item and returns it.
170 *
171 * @return the added item.
172 */
173 T& push_back() {
174 void* item = fAllocator.push_back();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000175 SkASSERT(NULL != item);
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000176 SkNEW_PLACEMENT(item, T);
reed@google.comac10a2d2010-12-22 21:39:39 +0000177 return *(T*)item;
178 }
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000179
180 T& push_back(const T& t) {
181 void* item = fAllocator.push_back();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000182 SkASSERT(NULL != item);
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000183 SkNEW_PLACEMENT_ARGS(item, T, (t));
bsalomon@google.com4fa66942011-09-20 19:06:12 +0000184 return *(T*)item;
185 }
186
reed@google.comac10a2d2010-12-22 21:39:39 +0000187 /**
188 * removes all added items
189 */
190 void reset() {
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000191 int c = fAllocator.count();
192 for (int i = 0; i < c; ++i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000193 ((T*)fAllocator[i])->~T();
194 }
195 fAllocator.reset();
196 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000197
reed@google.comac10a2d2010-12-22 21:39:39 +0000198 /**
199 * count of items
200 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000201 int count() const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000202 return fAllocator.count();
203 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000204
reed@google.comac10a2d2010-12-22 21:39:39 +0000205 /**
206 * is the count 0
207 */
208 bool empty() const { return fAllocator.empty(); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000209
reed@google.comac10a2d2010-12-22 21:39:39 +0000210 /**
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.
rmistry@google.comd6176b02012-08-23 18:14:13 +0000226 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000227 T& operator[] (int i) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000228 return *(T*)(fAllocator[i]);
229 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000230
reed@google.comac10a2d2010-12-22 21:39:39 +0000231 /**
232 * access item by index.
233 */
bsalomon@google.com6a77cc52011-04-28 17:33:34 +0000234 const T& operator[] (int i) const {
reed@google.comac10a2d2010-12-22 21:39:39 +0000235 return *(const T*)(fAllocator[i]);
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000236 }
237
238protected:
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000239 /*
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);
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000248 }
249
250private:
251 GrAllocator fAllocator;
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +0000252 typedef SkNoncopyable INHERITED;
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000253};
254
255template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> {
256private:
257 typedef GrTAllocator<T> INHERITED;
258
259public:
commit-bot@chromium.org845da772013-12-02 22:32:58 +0000260 GrSTAllocator() : INHERITED(N) {
261 this->setInitialBlock(fStorage.get());
bsalomon@google.com4b90c622011-09-28 17:52:15 +0000262 }
263
264private:
265 SkAlignedSTStorage<N, T> fStorage;
reed@google.comac10a2d2010-12-22 21:39:39 +0000266};
267
268#endif