michael@0: /* michael@0: * Copyright 2010 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef GrAllocator_DEFINED michael@0: #define GrAllocator_DEFINED michael@0: michael@0: #include "GrConfig.h" michael@0: #include "GrTypes.h" michael@0: #include "SkTArray.h" michael@0: #include "SkTypes.h" michael@0: michael@0: class GrAllocator : public SkNoncopyable { michael@0: public: michael@0: ~GrAllocator() { michael@0: reset(); michael@0: } michael@0: michael@0: /** michael@0: * Create an allocator michael@0: * michael@0: * @param itemSize the size of each item to allocate michael@0: * @param itemsPerBlock the number of items to allocate at once michael@0: * @param initialBlock optional memory to use for the first block. michael@0: * Must be at least itemSize*itemsPerBlock sized. michael@0: * Caller is responsible for freeing this memory. michael@0: */ michael@0: GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock) : michael@0: fItemSize(itemSize), michael@0: fItemsPerBlock(itemsPerBlock), michael@0: fOwnFirstBlock(NULL == initialBlock), michael@0: fCount(0) { michael@0: SkASSERT(itemsPerBlock > 0); michael@0: fBlockSize = fItemSize * fItemsPerBlock; michael@0: fBlocks.push_back() = initialBlock; michael@0: SkDEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} ); michael@0: } michael@0: michael@0: /* michael@0: * Set first block of memory to write into. Must be called before any other methods. michael@0: * This requires that you have passed NULL in the constructor. michael@0: * michael@0: * @param initialBlock optional memory to use for the first block. michael@0: * Must be at least itemSize*itemsPerBlock sized. michael@0: * Caller is responsible for freeing this memory. michael@0: */ michael@0: void setInitialBlock(void* initialBlock) { michael@0: SkASSERT(0 == fCount); michael@0: SkASSERT(1 == fBlocks.count()); michael@0: SkASSERT(NULL == fBlocks.back()); michael@0: fOwnFirstBlock = false; michael@0: fBlocks.back() = initialBlock; michael@0: } michael@0: michael@0: /** michael@0: * Adds an item and returns pointer to it. michael@0: * michael@0: * @return pointer to the added item. michael@0: */ michael@0: void* push_back() { michael@0: int indexInBlock = fCount % fItemsPerBlock; michael@0: // we always have at least one block michael@0: if (0 == indexInBlock) { michael@0: if (0 != fCount) { michael@0: fBlocks.push_back() = sk_malloc_throw(fBlockSize); michael@0: } else if (fOwnFirstBlock) { michael@0: fBlocks[0] = sk_malloc_throw(fBlockSize); michael@0: } michael@0: } michael@0: void* ret = (char*)fBlocks[fCount/fItemsPerBlock] + michael@0: fItemSize * indexInBlock; michael@0: ++fCount; michael@0: return ret; michael@0: } michael@0: michael@0: /** michael@0: * removes all added items michael@0: */ michael@0: void reset() { michael@0: int blockCount = GrMax((unsigned)1, michael@0: GrUIDivRoundUp(fCount, fItemsPerBlock)); michael@0: for (int i = 1; i < blockCount; ++i) { michael@0: sk_free(fBlocks[i]); michael@0: } michael@0: if (fOwnFirstBlock) { michael@0: sk_free(fBlocks[0]); michael@0: fBlocks[0] = NULL; michael@0: } michael@0: fBlocks.pop_back_n(blockCount-1); michael@0: fCount = 0; michael@0: } michael@0: michael@0: /** michael@0: * count of items michael@0: */ michael@0: int count() const { michael@0: return fCount; michael@0: } michael@0: michael@0: /** michael@0: * is the count 0 michael@0: */ michael@0: bool empty() const { return fCount == 0; } michael@0: michael@0: /** michael@0: * access last item, only call if count() != 0 michael@0: */ michael@0: void* back() { michael@0: SkASSERT(fCount); michael@0: return (*this)[fCount-1]; michael@0: } michael@0: michael@0: /** michael@0: * access last item, only call if count() != 0 michael@0: */ michael@0: const void* back() const { michael@0: SkASSERT(fCount); michael@0: return (*this)[fCount-1]; michael@0: } michael@0: michael@0: /** michael@0: * access item by index. michael@0: */ michael@0: void* operator[] (int i) { michael@0: SkASSERT(i >= 0 && i < fCount); michael@0: return (char*)fBlocks[i / fItemsPerBlock] + michael@0: fItemSize * (i % fItemsPerBlock); michael@0: } michael@0: michael@0: /** michael@0: * access item by index. michael@0: */ michael@0: const void* operator[] (int i) const { michael@0: SkASSERT(i >= 0 && i < fCount); michael@0: return (const char*)fBlocks[i / fItemsPerBlock] + michael@0: fItemSize * (i % fItemsPerBlock); michael@0: } michael@0: michael@0: private: michael@0: static const int NUM_INIT_BLOCK_PTRS = 8; michael@0: michael@0: SkSTArray fBlocks; michael@0: size_t fBlockSize; michael@0: size_t fItemSize; michael@0: int fItemsPerBlock; michael@0: bool fOwnFirstBlock; michael@0: int fCount; michael@0: michael@0: typedef SkNoncopyable INHERITED; michael@0: }; michael@0: michael@0: template michael@0: class GrTAllocator : public SkNoncopyable { michael@0: public: michael@0: virtual ~GrTAllocator() { this->reset(); }; michael@0: michael@0: /** michael@0: * Create an allocator michael@0: * michael@0: * @param itemsPerBlock the number of items to allocate at once michael@0: */ michael@0: explicit GrTAllocator(int itemsPerBlock) michael@0: : fAllocator(sizeof(T), itemsPerBlock, NULL) {} michael@0: michael@0: /** michael@0: * Adds an item and returns it. michael@0: * michael@0: * @return the added item. michael@0: */ michael@0: T& push_back() { michael@0: void* item = fAllocator.push_back(); michael@0: SkASSERT(NULL != item); michael@0: SkNEW_PLACEMENT(item, T); michael@0: return *(T*)item; michael@0: } michael@0: michael@0: T& push_back(const T& t) { michael@0: void* item = fAllocator.push_back(); michael@0: SkASSERT(NULL != item); michael@0: SkNEW_PLACEMENT_ARGS(item, T, (t)); michael@0: return *(T*)item; michael@0: } michael@0: michael@0: /** michael@0: * removes all added items michael@0: */ michael@0: void reset() { michael@0: int c = fAllocator.count(); michael@0: for (int i = 0; i < c; ++i) { michael@0: ((T*)fAllocator[i])->~T(); michael@0: } michael@0: fAllocator.reset(); michael@0: } michael@0: michael@0: /** michael@0: * count of items michael@0: */ michael@0: int count() const { michael@0: return fAllocator.count(); michael@0: } michael@0: michael@0: /** michael@0: * is the count 0 michael@0: */ michael@0: bool empty() const { return fAllocator.empty(); } michael@0: michael@0: /** michael@0: * access last item, only call if count() != 0 michael@0: */ michael@0: T& back() { michael@0: return *(T*)fAllocator.back(); michael@0: } michael@0: michael@0: /** michael@0: * access last item, only call if count() != 0 michael@0: */ michael@0: const T& back() const { michael@0: return *(const T*)fAllocator.back(); michael@0: } michael@0: michael@0: /** michael@0: * access item by index. michael@0: */ michael@0: T& operator[] (int i) { michael@0: return *(T*)(fAllocator[i]); michael@0: } michael@0: michael@0: /** michael@0: * access item by index. michael@0: */ michael@0: const T& operator[] (int i) const { michael@0: return *(const T*)(fAllocator[i]); michael@0: } michael@0: michael@0: protected: michael@0: /* michael@0: * Set first block of memory to write into. Must be called before any other methods. michael@0: * michael@0: * @param initialBlock optional memory to use for the first block. michael@0: * Must be at least size(T)*itemsPerBlock sized. michael@0: * Caller is responsible for freeing this memory. michael@0: */ michael@0: void setInitialBlock(void* initialBlock) { michael@0: fAllocator.setInitialBlock(initialBlock); michael@0: } michael@0: michael@0: private: michael@0: GrAllocator fAllocator; michael@0: typedef SkNoncopyable INHERITED; michael@0: }; michael@0: michael@0: template class GrSTAllocator : public GrTAllocator { michael@0: private: michael@0: typedef GrTAllocator INHERITED; michael@0: michael@0: public: michael@0: GrSTAllocator() : INHERITED(N) { michael@0: this->setInitialBlock(fStorage.get()); michael@0: } michael@0: michael@0: private: michael@0: SkAlignedSTStorage fStorage; michael@0: }; michael@0: michael@0: #endif