| 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 |