| |
| /* |
| * Copyright 2010 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| |
| #ifndef GrAllocator_DEFINED |
| #define GrAllocator_DEFINED |
| |
| #include "GrNoncopyable.h" |
| #include "GrConfig.h" |
| #include "SkTArray.h" |
| |
| class GrAllocator : GrNoncopyable { |
| public: |
| ~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) : |
| 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; |
| |
| SkSTArray<NUM_INIT_BLOCK_PTRS, void*> fBlocks; |
| size_t fBlockSize; |
| size_t fItemSize; |
| int fItemsPerBlock; |
| bool fOwnFirstBlock; |
| int fCount; |
| |
| typedef GrNoncopyable INHERITED; |
| }; |
| |
| template <typename T> |
| class GrTAllocator : GrNoncopyable { |
| |
| public: |
| virtual ~GrTAllocator() { this->reset(); }; |
| |
| /** |
| * 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. |
| */ |
| explicit GrTAllocator(int itemsPerBlock) |
| : fAllocator(sizeof(T), itemsPerBlock, NULL) {} |
| |
| /** |
| * Adds an item and returns it. |
| * |
| * @return the added item. |
| */ |
| T& push_back() { |
| void* item = fAllocator.push_back(); |
| GrAssert(NULL != item); |
| SkNEW_PLACEMENT(item, T); |
| return *(T*)item; |
| } |
| |
| T& push_back(const T& t) { |
| void* item = fAllocator.push_back(); |
| GrAssert(NULL != item); |
| SkNEW_PLACEMENT_ARGS(item, T, (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]); |
| } |
| |
| protected: |
| GrTAllocator(int itemsPerBlock, void* initialBlock) |
| : fAllocator(sizeof(T), itemsPerBlock, initialBlock) { |
| } |
| |
| private: |
| GrAllocator fAllocator; |
| typedef GrNoncopyable INHERITED; |
| }; |
| |
| template <int N, typename T> class GrSTAllocator : public GrTAllocator<T> { |
| private: |
| typedef GrTAllocator<T> INHERITED; |
| |
| public: |
| GrSTAllocator() : INHERITED(N, fStorage.get()) { |
| } |
| |
| private: |
| SkAlignedSTStorage<N, T> fStorage; |
| }; |
| |
| #endif |