| /* |
| Copyright 2010 Google Inc. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| |
| #ifndef GrAllocator_DEFINED |
| #define GrAllocator_DEFINED |
| |
| #include "GrConfig.h" |
| #include "GrTArray.h" |
| |
| class GrAllocator { |
| public: |
| virtual ~GrAllocator() { |
| reset(); |
| } |
| |
| /** |
| * Create an allocator |
| * |
| * @param itemSize the size of each item to allocate |
| * @param itemsPerBlock the number of items to allocate at once |
| * @param initialBlock optional memory to use for the first block. |
| * Must be at least itemSize*itemsPerBlock sized. |
| * Caller is responsible for freeing this memory. |
| */ |
| GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) : |
| fBlocks(fBlockInitialStorage, NUM_INIT_BLOCK_PTRS), |
| fItemSize(itemSize), |
| fItemsPerBlock(itemsPerBlock), |
| fOwnFirstBlock(NULL == initialBlock), |
| fCount(0) { |
| GrAssert(itemsPerBlock > 0); |
| fBlockSize = fItemSize * fItemsPerBlock; |
| fBlocks.push_back() = initialBlock; |
| GR_DEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} ); |
| } |
| |
| /** |
| * Adds an item and returns pointer to it. |
| * |
| * @return pointer to the added item. |
| */ |
| void* push_back() { |
| int indexInBlock = fCount % fItemsPerBlock; |
| // we always have at least one block |
| if (0 == indexInBlock) { |
| if (0 != fCount) { |
| fBlocks.push_back() = GrMalloc(fBlockSize); |
| } else if (fOwnFirstBlock) { |
| fBlocks[0] = GrMalloc(fBlockSize); |
| } |
| } |
| void* ret = (char*)fBlocks[fCount/fItemsPerBlock] + |
| fItemSize * indexInBlock; |
| ++fCount; |
| return ret; |
| } |
| |
| /** |
| * removes all added items |
| */ |
| void reset() { |
| int blockCount = GrMax((unsigned)1, |
| GrUIDivRoundUp(fCount, fItemsPerBlock)); |
| for (int i = 1; i < blockCount; ++i) { |
| GrFree(fBlocks[i]); |
| } |
| if (fOwnFirstBlock) { |
| GrFree(fBlocks[0]); |
| fBlocks[0] = NULL; |
| } |
| fBlocks.pop_back_n(blockCount-1); |
| fCount = 0; |
| } |
| |
| /** |
| * count of items |
| */ |
| int count() const { |
| return fCount; |
| } |
| |
| /** |
| * is the count 0 |
| */ |
| bool empty() const { return fCount == 0; } |
| |
| /** |
| * access last item, only call if count() != 0 |
| */ |
| void* back() { |
| GrAssert(fCount); |
| return (*this)[fCount-1]; |
| } |
| |
| /** |
| * access last item, only call if count() != 0 |
| */ |
| const void* back() const { |
| GrAssert(fCount); |
| return (*this)[fCount-1]; |
| } |
| |
| /** |
| * access item by index. |
| */ |
| void* operator[] (int i) { |
| GrAssert(i >= 0 && i < fCount); |
| return (char*)fBlocks[i / fItemsPerBlock] + |
| fItemSize * (i % fItemsPerBlock); |
| } |
| |
| /** |
| * access item by index. |
| */ |
| const void* operator[] (int i) const { |
| GrAssert(i >= 0 && i < fCount); |
| return (const char*)fBlocks[i / fItemsPerBlock] + |
| fItemSize * (i % fItemsPerBlock); |
| } |
| |
| private: |
| static const int NUM_INIT_BLOCK_PTRS = 8; |
| |
| GrTArray<void*> fBlocks; |
| size_t fBlockSize; |
| char fBlockInitialStorage[NUM_INIT_BLOCK_PTRS*sizeof(void*)]; |
| size_t fItemSize; |
| int fItemsPerBlock; |
| bool fOwnFirstBlock; |
| int fCount; |
| }; |
| |
| template <typename T> |
| class GrTAllocator { |
| private: |
| GrAllocator fAllocator; |
| |
| public: |
| virtual ~GrTAllocator() {}; |
| |
| /** |
| * Create an allocator |
| * |
| * @param itemsPerBlock the number of items to allocate at once |
| * @param initialBlock optional memory to use for the first block. |
| * Must be at least size(T)*itemsPerBlock sized. |
| * Caller is responsible for freeing this memory. |
| */ |
| GrTAllocator(int itemsPerBlock, void* initialBlock) |
| : fAllocator(sizeof(T), itemsPerBlock, initialBlock) {} |
| |
| /** |
| * Create an allocator using a GrAlignedTAlloc as the initial block. |
| * |
| * @param initialBlock specifies the storage for the initial block |
| * and the size of subsequent blocks. |
| */ |
| template <int N> |
| GrTAllocator(GrAlignedSTStorage<N,T>* initialBlock) |
| : fAllocator(sizeof(T), N, initialBlock->get()) {} |
| |
| /** |
| * Adds an item and returns it. |
| * |
| * @return the added item. |
| */ |
| T& push_back() { |
| void* item = fAllocator.push_back(); |
| GrAssert(NULL != item); |
| new (item) T; |
| return *(T*)item; |
| } |
| |
| /** |
| * removes all added items |
| */ |
| void reset() { |
| int c = fAllocator.count(); |
| for (int i = 0; i < c; ++i) { |
| ((T*)fAllocator[i])->~T(); |
| } |
| fAllocator.reset(); |
| } |
| |
| /** |
| * count of items |
| */ |
| int count() const { |
| return fAllocator.count(); |
| } |
| |
| /** |
| * is the count 0 |
| */ |
| bool empty() const { return fAllocator.empty(); } |
| |
| /** |
| * access last item, only call if count() != 0 |
| */ |
| T& back() { |
| return *(T*)fAllocator.back(); |
| } |
| |
| /** |
| * access last item, only call if count() != 0 |
| */ |
| const T& back() const { |
| return *(const T*)fAllocator.back(); |
| } |
| |
| /** |
| * access item by index. |
| */ |
| T& operator[] (int i) { |
| return *(T*)(fAllocator[i]); |
| } |
| |
| /** |
| * access item by index. |
| */ |
| const T& operator[] (int i) const { |
| return *(const T*)(fAllocator[i]); |
| } |
| }; |
| |
| #endif |