OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2010 Google Inc. | 2 * Copyright 2010 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef GrAllocator_DEFINED | 8 #ifndef GrAllocator_DEFINED |
9 #define GrAllocator_DEFINED | 9 #define GrAllocator_DEFINED |
10 | 10 |
11 #include "GrConfig.h" | 11 #include "GrConfig.h" |
12 #include "GrTypes.h" | 12 #include "GrTypes.h" |
13 #include "SkTArray.h" | 13 #include "SkTArray.h" |
14 #include "SkTypes.h" | 14 #include "SkTypes.h" |
15 | 15 |
16 class GrAllocator : SkNoncopyable { | 16 class GrAllocator : SkNoncopyable { |
17 public: | 17 public: |
18 ~GrAllocator() { | 18 ~GrAllocator() { this->reset(); } |
19 reset(); | |
20 } | |
21 | 19 |
22 /** | 20 /** |
23 * Create an allocator | 21 * Create an allocator |
24 * | 22 * |
25 * @param itemSize the size of each item to allocate | 23 * @param itemSize the size of each item to allocate |
26 * @param itemsPerBlock the number of items to allocate at once | 24 * @param itemsPerBlock the number of items to allocate at once |
27 * @param initialBlock optional memory to use for the first block. | 25 * @param initialBlock optional memory to use for the first block. |
28 * Must be at least itemSize*itemsPerBlock sized. | 26 * Must be at least itemSize*itemsPerBlock sized. |
29 * Caller is responsible for freeing this memory. | 27 * Caller is responsible for freeing this memory. |
30 */ | 28 */ |
31 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) : | 29 GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) |
32 fItemSize(itemSize), | 30 : fItemSize(itemSize) |
33 fItemsPerBlock(itemsPerBlock), | 31 , fItemsPerBlock(itemsPerBlock) |
34 fOwnFirstBlock(NULL == initialBlock), | 32 , fOwnFirstBlock(NULL == initialBlock) |
35 fCount(0) { | 33 , fCount(0) |
| 34 , fInsertionIndexInBlock(0) { |
36 SkASSERT(itemsPerBlock > 0); | 35 SkASSERT(itemsPerBlock > 0); |
37 fBlockSize = fItemSize * fItemsPerBlock; | 36 fBlockSize = fItemSize * fItemsPerBlock; |
38 fBlocks.push_back() = initialBlock; | 37 if (fOwnFirstBlock) { |
39 SkDEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a
';} ); | 38 // This force us to allocate a new block on push_back(). |
40 } | 39 fInsertionIndexInBlock = fItemsPerBlock; |
41 | 40 } else { |
42 /* | 41 fBlocks.push_back() = initialBlock; |
43 * Set first block of memory to write into. Must be called before any other
methods. | 42 fInsertionIndexInBlock = 0; |
44 * This requires that you have passed NULL in the constructor. | 43 } |
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 } | 44 } |
57 | 45 |
58 /** | 46 /** |
59 * Adds an item and returns pointer to it. | 47 * Adds an item and returns pointer to it. |
60 * | 48 * |
61 * @return pointer to the added item. | 49 * @return pointer to the added item. |
62 */ | 50 */ |
63 void* push_back() { | 51 void* push_back() { |
64 int indexInBlock = fCount % fItemsPerBlock; | |
65 // we always have at least one block | 52 // we always have at least one block |
66 if (0 == indexInBlock) { | 53 if (fItemsPerBlock == fInsertionIndexInBlock) { |
67 if (0 != fCount) { | 54 fBlocks.push_back() = sk_malloc_throw(fBlockSize); |
68 fBlocks.push_back() = sk_malloc_throw(fBlockSize); | 55 fInsertionIndexInBlock = 0; |
69 } else if (fOwnFirstBlock) { | |
70 fBlocks[0] = sk_malloc_throw(fBlockSize); | |
71 } | |
72 } | 56 } |
73 void* ret = (char*)fBlocks[fCount/fItemsPerBlock] + | 57 void* ret = (char*)fBlocks.back() + fItemSize * fInsertionIndexInBlock; |
74 fItemSize * indexInBlock; | |
75 ++fCount; | 58 ++fCount; |
| 59 ++fInsertionIndexInBlock; |
76 return ret; | 60 return ret; |
77 } | 61 } |
78 | 62 |
79 /** | 63 /** |
80 * removes all added items | 64 * Removes all added items. |
81 */ | 65 */ |
82 void reset() { | 66 void reset() { |
83 int blockCount = SkTMax((unsigned)1, | 67 int firstBlockToFree = fOwnFirstBlock ? 0 : 1; |
84 GrUIDivRoundUp(fCount, fItemsPerBlock)); | 68 for (int i = firstBlockToFree; i < fBlocks.count(); ++i) { |
85 for (int i = 1; i < blockCount; ++i) { | |
86 sk_free(fBlocks[i]); | 69 sk_free(fBlocks[i]); |
87 } | 70 } |
88 if (fOwnFirstBlock) { | 71 if (fOwnFirstBlock) { |
89 sk_free(fBlocks[0]); | 72 fBlocks.reset(); |
90 fBlocks[0] = NULL; | 73 // This force us to allocate a new block on push_back(). |
| 74 fInsertionIndexInBlock = fItemsPerBlock; |
| 75 } else { |
| 76 fBlocks.pop_back_n(fBlocks.count() - 1); |
| 77 fInsertionIndexInBlock = 0; |
91 } | 78 } |
92 fBlocks.pop_back_n(blockCount-1); | |
93 fCount = 0; | 79 fCount = 0; |
94 } | 80 } |
95 | 81 |
96 /** | 82 /** |
97 * count of items | 83 * Returns the item count. |
98 */ | 84 */ |
99 int count() const { | 85 int count() const { |
100 return fCount; | 86 return fCount; |
101 } | 87 } |
102 | 88 |
103 /** | 89 /** |
104 * is the count 0 | 90 * Is the count 0? |
105 */ | 91 */ |
106 bool empty() const { return fCount == 0; } | 92 bool empty() const { return 0 == fCount; } |
107 | 93 |
108 /** | 94 /** |
109 * access last item, only call if count() != 0 | 95 * Access last item, only call if count() != 0 |
110 */ | 96 */ |
111 void* back() { | 97 void* back() { |
112 SkASSERT(fCount); | 98 SkASSERT(fCount); |
113 return (*this)[fCount-1]; | 99 SkASSERT(fInsertionIndexInBlock > 0); |
| 100 return (char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSiz
e; |
114 } | 101 } |
115 | 102 |
116 /** | 103 /** |
117 * access last item, only call if count() != 0 | 104 * Access last item, only call if count() != 0 |
118 */ | 105 */ |
119 const void* back() const { | 106 const void* back() const { |
120 SkASSERT(fCount); | 107 SkASSERT(fCount); |
121 return (*this)[fCount-1]; | 108 SkASSERT(fInsertionIndexInBlock > 0); |
| 109 return (const char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fI
temSize; |
122 } | 110 } |
123 | 111 |
| 112 |
124 /** | 113 /** |
125 * access item by index. | 114 * Iterates through the allocator. This is faster than using operator[] when
walking linearly |
| 115 * through the allocator. |
| 116 */ |
| 117 class Iter { |
| 118 public: |
| 119 /** |
| 120 * Initializes the iterator. next() must be called before get(). |
| 121 */ |
| 122 Iter(const GrAllocator* allocator) |
| 123 : fAllocator(allocator) |
| 124 , fBlockIndex(-1) |
| 125 , fIndexInBlock(allocator->fItemsPerBlock - 1) |
| 126 , fItemIndex(-1) {} |
| 127 |
| 128 /** |
| 129 * Advances the iterator. Iteration is finished when next() returns fals
e. |
| 130 */ |
| 131 bool next() { |
| 132 ++fIndexInBlock; |
| 133 ++fItemIndex; |
| 134 if (fIndexInBlock == fAllocator->fItemsPerBlock) { |
| 135 ++fBlockIndex; |
| 136 fIndexInBlock = 0; |
| 137 } |
| 138 return fItemIndex < fAllocator->fCount; |
| 139 } |
| 140 |
| 141 /** |
| 142 * Gets the current iterator value. Call next() at least once before cal
ling. Don't call |
| 143 * after next() returns false. |
| 144 */ |
| 145 const void* get() const { |
| 146 SkASSERT(fItemIndex >= 0 && fItemIndex < fAllocator->fCount); |
| 147 return (char*) fAllocator->fBlocks[fBlockIndex] + fIndexInBlock * fA
llocator->fItemSize; |
| 148 } |
| 149 |
| 150 private: |
| 151 const GrAllocator* fAllocator; |
| 152 int fBlockIndex; |
| 153 int fIndexInBlock; |
| 154 int fItemIndex; |
| 155 }; |
| 156 |
| 157 /** |
| 158 * Access item by index. |
126 */ | 159 */ |
127 void* operator[] (int i) { | 160 void* operator[] (int i) { |
128 SkASSERT(i >= 0 && i < fCount); | 161 SkASSERT(i >= 0 && i < fCount); |
129 return (char*)fBlocks[i / fItemsPerBlock] + | 162 return (char*)fBlocks[i / fItemsPerBlock] + |
130 fItemSize * (i % fItemsPerBlock); | 163 fItemSize * (i % fItemsPerBlock); |
131 } | 164 } |
132 | 165 |
133 /** | 166 /** |
134 * access item by index. | 167 * Access item by index. |
135 */ | 168 */ |
136 const void* operator[] (int i) const { | 169 const void* operator[] (int i) const { |
137 SkASSERT(i >= 0 && i < fCount); | 170 SkASSERT(i >= 0 && i < fCount); |
138 return (const char*)fBlocks[i / fItemsPerBlock] + | 171 return (const char*)fBlocks[i / fItemsPerBlock] + |
139 fItemSize * (i % fItemsPerBlock); | 172 fItemSize * (i % fItemsPerBlock); |
140 } | 173 } |
141 | 174 |
| 175 protected: |
| 176 /** |
| 177 * Set first block of memory to write into. Must be called before any other
methods. |
| 178 * This requires that you have passed NULL in the constructor. |
| 179 * |
| 180 * @param initialBlock optional memory to use for the first block. |
| 181 * Must be at least itemSize*itemsPerBlock sized. |
| 182 * Caller is responsible for freeing this memory. |
| 183 */ |
| 184 void setInitialBlock(void* initialBlock) { |
| 185 SkASSERT(0 == fCount); |
| 186 SkASSERT(0 == fBlocks.count()); |
| 187 SkASSERT(fItemsPerBlock == fInsertionIndexInBlock); |
| 188 fOwnFirstBlock = false; |
| 189 fBlocks.push_back() = initialBlock; |
| 190 fInsertionIndexInBlock = 0; |
| 191 } |
| 192 |
| 193 // For access to above function. |
| 194 template <typename T> friend class GrTAllocator; |
| 195 |
142 private: | 196 private: |
143 static const int NUM_INIT_BLOCK_PTRS = 8; | 197 static const int NUM_INIT_BLOCK_PTRS = 8; |
144 | 198 |
145 SkSTArray<NUM_INIT_BLOCK_PTRS, void*> fBlocks; | 199 SkSTArray<NUM_INIT_BLOCK_PTRS, void*, true> fBlocks; |
146 size_t fBlockSize; | 200 size_t fBlockSize; |
147 size_t fItemSize; | 201 size_t fItemSize; |
148 int fItemsPerBlock; | 202 int fItemsPerBlock; |
149 bool fOwnFirstBlock; | 203 bool fOwnFirstBlock; |
150 int fCount; | 204 int fCount; |
| 205 int fInsertionIndexInBlock; |
151 | 206 |
152 typedef SkNoncopyable INHERITED; | 207 typedef SkNoncopyable INHERITED; |
153 }; | 208 }; |
154 | 209 |
155 template <typename T> | 210 template <typename T> |
156 class GrTAllocator : SkNoncopyable { | 211 class GrTAllocator : SkNoncopyable { |
157 public: | 212 public: |
158 virtual ~GrTAllocator() { this->reset(); }; | 213 virtual ~GrTAllocator() { this->reset(); }; |
159 | 214 |
160 /** | 215 /** |
(...skipping 17 matching lines...) Expand all Loading... |
178 } | 233 } |
179 | 234 |
180 T& push_back(const T& t) { | 235 T& push_back(const T& t) { |
181 void* item = fAllocator.push_back(); | 236 void* item = fAllocator.push_back(); |
182 SkASSERT(NULL != item); | 237 SkASSERT(NULL != item); |
183 SkNEW_PLACEMENT_ARGS(item, T, (t)); | 238 SkNEW_PLACEMENT_ARGS(item, T, (t)); |
184 return *(T*)item; | 239 return *(T*)item; |
185 } | 240 } |
186 | 241 |
187 /** | 242 /** |
188 * removes all added items | 243 * Removes all added items. |
189 */ | 244 */ |
190 void reset() { | 245 void reset() { |
191 int c = fAllocator.count(); | 246 int c = fAllocator.count(); |
192 for (int i = 0; i < c; ++i) { | 247 for (int i = 0; i < c; ++i) { |
193 ((T*)fAllocator[i])->~T(); | 248 ((T*)fAllocator[i])->~T(); |
194 } | 249 } |
195 fAllocator.reset(); | 250 fAllocator.reset(); |
196 } | 251 } |
197 | 252 |
198 /** | 253 /** |
199 * count of items | 254 * Returns the item count. |
200 */ | 255 */ |
201 int count() const { | 256 int count() const { |
202 return fAllocator.count(); | 257 return fAllocator.count(); |
203 } | 258 } |
204 | 259 |
205 /** | 260 /** |
206 * is the count 0 | 261 * Is the count 0? |
207 */ | 262 */ |
208 bool empty() const { return fAllocator.empty(); } | 263 bool empty() const { return fAllocator.empty(); } |
209 | 264 |
210 /** | 265 /** |
211 * access last item, only call if count() != 0 | 266 * Access last item, only call if count() != 0 |
212 */ | 267 */ |
213 T& back() { | 268 T& back() { |
214 return *(T*)fAllocator.back(); | 269 return *(T*)fAllocator.back(); |
215 } | 270 } |
216 | 271 |
217 /** | 272 /** |
218 * access last item, only call if count() != 0 | 273 * Access last item, only call if count() != 0 |
219 */ | 274 */ |
220 const T& back() const { | 275 const T& back() const { |
221 return *(const T*)fAllocator.back(); | 276 return *(const T*)fAllocator.back(); |
222 } | 277 } |
223 | 278 |
224 /** | 279 /** |
225 * access item by index. | 280 * Iterates through the allocator. This is faster than using operator[] when
walking linearly |
| 281 * through the allocator. |
| 282 */ |
| 283 class Iter { |
| 284 public: |
| 285 /** |
| 286 * Initializes the iterator. next() must be called before get() or ops *
and ->. |
| 287 */ |
| 288 Iter(const GrTAllocator* allocator) : fImpl(&allocator->fAllocator) {} |
| 289 |
| 290 /** |
| 291 * Advances the iterator. Iteration is finished when next() returns fals
e. |
| 292 */ |
| 293 bool next() { return fImpl.next(); } |
| 294 |
| 295 /** |
| 296 * Gets the current iterator value. Call next() at least once before cal
ling. Don't call |
| 297 * after next() returns false. |
| 298 */ |
| 299 const T* get() const { return (const T*) fImpl.get(); } |
| 300 |
| 301 /** |
| 302 * Convenience operators. Same rules for calling apply as get(). |
| 303 */ |
| 304 const T& operator*() const { return *this->get(); } |
| 305 const T* operator->() const { return this->get(); } |
| 306 |
| 307 private: |
| 308 GrAllocator::Iter fImpl; |
| 309 }; |
| 310 |
| 311 /** |
| 312 * Access item by index. |
226 */ | 313 */ |
227 T& operator[] (int i) { | 314 T& operator[] (int i) { |
228 return *(T*)(fAllocator[i]); | 315 return *(T*)(fAllocator[i]); |
229 } | 316 } |
230 | 317 |
231 /** | 318 /** |
232 * access item by index. | 319 * Access item by index. |
233 */ | 320 */ |
234 const T& operator[] (int i) const { | 321 const T& operator[] (int i) const { |
235 return *(const T*)(fAllocator[i]); | 322 return *(const T*)(fAllocator[i]); |
236 } | 323 } |
237 | 324 |
238 protected: | 325 protected: |
239 /* | 326 /* |
240 * Set first block of memory to write into. Must be called before any other
methods. | 327 * Set first block of memory to write into. Must be called before any other
methods. |
241 * | 328 * |
242 * @param initialBlock optional memory to use for the first block. | 329 * @param initialBlock optional memory to use for the first block. |
(...skipping 16 matching lines...) Expand all Loading... |
259 public: | 346 public: |
260 GrSTAllocator() : INHERITED(N) { | 347 GrSTAllocator() : INHERITED(N) { |
261 this->setInitialBlock(fStorage.get()); | 348 this->setInitialBlock(fStorage.get()); |
262 } | 349 } |
263 | 350 |
264 private: | 351 private: |
265 SkAlignedSTStorage<N, T> fStorage; | 352 SkAlignedSTStorage<N, T> fStorage; |
266 }; | 353 }; |
267 | 354 |
268 #endif | 355 #endif |
OLD | NEW |