| Index: src/gpu/GrAllocator.h
|
| diff --git a/src/gpu/GrAllocator.h b/src/gpu/GrAllocator.h
|
| index a2ad408e072d03b84352f423a6b76a78f55a0f4e..50d9a6cdad6f661f03d21d5105f2d4efce24fc98 100644
|
| --- a/src/gpu/GrAllocator.h
|
| +++ b/src/gpu/GrAllocator.h
|
| @@ -15,9 +15,7 @@
|
|
|
| class GrAllocator : SkNoncopyable {
|
| public:
|
| - ~GrAllocator() {
|
| - reset();
|
| - }
|
| + ~GrAllocator() { this->reset(); }
|
|
|
| /**
|
| * Create an allocator
|
| @@ -28,31 +26,21 @@ public:
|
| * 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) {
|
| + GrAllocator(size_t itemSize, int itemsPerBlock, void* initialBlock)
|
| + : fItemSize(itemSize)
|
| + , fItemsPerBlock(itemsPerBlock)
|
| + , fOwnFirstBlock(NULL == initialBlock)
|
| + , fCount(0)
|
| + , fInsertionIndexInBlock(0) {
|
| SkASSERT(itemsPerBlock > 0);
|
| fBlockSize = fItemSize * fItemsPerBlock;
|
| - fBlocks.push_back() = initialBlock;
|
| - SkDEBUGCODE(if (!fOwnFirstBlock) {*((char*)initialBlock+fBlockSize-1)='a';} );
|
| - }
|
| -
|
| - /*
|
| - * Set first block of memory to write into. Must be called before any other methods.
|
| - * This requires that you have passed NULL in the constructor.
|
| - *
|
| - * @param initialBlock optional memory to use for the first block.
|
| - * Must be at least itemSize*itemsPerBlock sized.
|
| - * Caller is responsible for freeing this memory.
|
| - */
|
| - void setInitialBlock(void* initialBlock) {
|
| - SkASSERT(0 == fCount);
|
| - SkASSERT(1 == fBlocks.count());
|
| - SkASSERT(NULL == fBlocks.back());
|
| - fOwnFirstBlock = false;
|
| - fBlocks.back() = initialBlock;
|
| + if (fOwnFirstBlock) {
|
| + // This force us to allocate a new block on push_back().
|
| + fInsertionIndexInBlock = fItemsPerBlock;
|
| + } else {
|
| + fBlocks.push_back() = initialBlock;
|
| + fInsertionIndexInBlock = 0;
|
| + }
|
| }
|
|
|
| /**
|
| @@ -61,68 +49,113 @@ public:
|
| * @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() = sk_malloc_throw(fBlockSize);
|
| - } else if (fOwnFirstBlock) {
|
| - fBlocks[0] = sk_malloc_throw(fBlockSize);
|
| - }
|
| + if (fItemsPerBlock == fInsertionIndexInBlock) {
|
| + fBlocks.push_back() = sk_malloc_throw(fBlockSize);
|
| + fInsertionIndexInBlock = 0;
|
| }
|
| - void* ret = (char*)fBlocks[fCount/fItemsPerBlock] +
|
| - fItemSize * indexInBlock;
|
| + void* ret = (char*)fBlocks.back() + fItemSize * fInsertionIndexInBlock;
|
| ++fCount;
|
| + ++fInsertionIndexInBlock;
|
| return ret;
|
| }
|
|
|
| /**
|
| - * removes all added items
|
| + * Removes all added items.
|
| */
|
| void reset() {
|
| - int blockCount = SkTMax((unsigned)1,
|
| - GrUIDivRoundUp(fCount, fItemsPerBlock));
|
| - for (int i = 1; i < blockCount; ++i) {
|
| + int firstBlockToFree = fOwnFirstBlock ? 0 : 1;
|
| + for (int i = firstBlockToFree; i < fBlocks.count(); ++i) {
|
| sk_free(fBlocks[i]);
|
| }
|
| if (fOwnFirstBlock) {
|
| - sk_free(fBlocks[0]);
|
| - fBlocks[0] = NULL;
|
| + fBlocks.reset();
|
| + // This force us to allocate a new block on push_back().
|
| + fInsertionIndexInBlock = fItemsPerBlock;
|
| + } else {
|
| + fBlocks.pop_back_n(fBlocks.count() - 1);
|
| + fInsertionIndexInBlock = 0;
|
| }
|
| - fBlocks.pop_back_n(blockCount-1);
|
| fCount = 0;
|
| }
|
|
|
| /**
|
| - * count of items
|
| + * Returns the item count.
|
| */
|
| int count() const {
|
| return fCount;
|
| }
|
|
|
| /**
|
| - * is the count 0
|
| + * Is the count 0?
|
| */
|
| - bool empty() const { return fCount == 0; }
|
| + bool empty() const { return 0 == fCount; }
|
|
|
| /**
|
| - * access last item, only call if count() != 0
|
| + * Access last item, only call if count() != 0
|
| */
|
| void* back() {
|
| SkASSERT(fCount);
|
| - return (*this)[fCount-1];
|
| + SkASSERT(fInsertionIndexInBlock > 0);
|
| + return (char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
|
| }
|
|
|
| /**
|
| - * access last item, only call if count() != 0
|
| + * Access last item, only call if count() != 0
|
| */
|
| const void* back() const {
|
| SkASSERT(fCount);
|
| - return (*this)[fCount-1];
|
| + SkASSERT(fInsertionIndexInBlock > 0);
|
| + return (const char*)(fBlocks.back()) + (fInsertionIndexInBlock - 1) * fItemSize;
|
| }
|
|
|
| +
|
| + /**
|
| + * Iterates through the allocator. This is faster than using operator[] when walking linearly
|
| + * through the allocator.
|
| + */
|
| + class Iter {
|
| + public:
|
| + /**
|
| + * Initializes the iterator. next() must be called before get().
|
| + */
|
| + Iter(const GrAllocator* allocator)
|
| + : fAllocator(allocator)
|
| + , fBlockIndex(-1)
|
| + , fIndexInBlock(allocator->fItemsPerBlock - 1)
|
| + , fItemIndex(-1) {}
|
| +
|
| + /**
|
| + * Advances the iterator. Iteration is finished when next() returns false.
|
| + */
|
| + bool next() {
|
| + ++fIndexInBlock;
|
| + ++fItemIndex;
|
| + if (fIndexInBlock == fAllocator->fItemsPerBlock) {
|
| + ++fBlockIndex;
|
| + fIndexInBlock = 0;
|
| + }
|
| + return fItemIndex < fAllocator->fCount;
|
| + }
|
| +
|
| + /**
|
| + * Gets the current iterator value. Call next() at least once before calling. Don't call
|
| + * after next() returns false.
|
| + */
|
| + const void* get() const {
|
| + SkASSERT(fItemIndex >= 0 && fItemIndex < fAllocator->fCount);
|
| + return (char*) fAllocator->fBlocks[fBlockIndex] + fIndexInBlock * fAllocator->fItemSize;
|
| + }
|
| +
|
| + private:
|
| + const GrAllocator* fAllocator;
|
| + int fBlockIndex;
|
| + int fIndexInBlock;
|
| + int fItemIndex;
|
| + };
|
| +
|
| /**
|
| - * access item by index.
|
| + * Access item by index.
|
| */
|
| void* operator[] (int i) {
|
| SkASSERT(i >= 0 && i < fCount);
|
| @@ -131,7 +164,7 @@ public:
|
| }
|
|
|
| /**
|
| - * access item by index.
|
| + * Access item by index.
|
| */
|
| const void* operator[] (int i) const {
|
| SkASSERT(i >= 0 && i < fCount);
|
| @@ -139,15 +172,37 @@ public:
|
| fItemSize * (i % fItemsPerBlock);
|
| }
|
|
|
| +protected:
|
| + /**
|
| + * Set first block of memory to write into. Must be called before any other methods.
|
| + * This requires that you have passed NULL in the constructor.
|
| + *
|
| + * @param initialBlock optional memory to use for the first block.
|
| + * Must be at least itemSize*itemsPerBlock sized.
|
| + * Caller is responsible for freeing this memory.
|
| + */
|
| + void setInitialBlock(void* initialBlock) {
|
| + SkASSERT(0 == fCount);
|
| + SkASSERT(0 == fBlocks.count());
|
| + SkASSERT(fItemsPerBlock == fInsertionIndexInBlock);
|
| + fOwnFirstBlock = false;
|
| + fBlocks.push_back() = initialBlock;
|
| + fInsertionIndexInBlock = 0;
|
| + }
|
| +
|
| + // For access to above function.
|
| + template <typename T> friend class GrTAllocator;
|
| +
|
| 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;
|
| + SkSTArray<NUM_INIT_BLOCK_PTRS, void*, true> fBlocks;
|
| + size_t fBlockSize;
|
| + size_t fItemSize;
|
| + int fItemsPerBlock;
|
| + bool fOwnFirstBlock;
|
| + int fCount;
|
| + int fInsertionIndexInBlock;
|
|
|
| typedef SkNoncopyable INHERITED;
|
| };
|
| @@ -185,7 +240,7 @@ public:
|
| }
|
|
|
| /**
|
| - * removes all added items
|
| + * Removes all added items.
|
| */
|
| void reset() {
|
| int c = fAllocator.count();
|
| @@ -196,40 +251,72 @@ public:
|
| }
|
|
|
| /**
|
| - * count of items
|
| + * Returns the item count.
|
| */
|
| int count() const {
|
| return fAllocator.count();
|
| }
|
|
|
| /**
|
| - * is the count 0
|
| + * Is the count 0?
|
| */
|
| bool empty() const { return fAllocator.empty(); }
|
|
|
| /**
|
| - * access last item, only call if count() != 0
|
| + * Access last item, only call if count() != 0
|
| */
|
| T& back() {
|
| return *(T*)fAllocator.back();
|
| }
|
|
|
| /**
|
| - * access last item, only call if count() != 0
|
| + * Access last item, only call if count() != 0
|
| */
|
| const T& back() const {
|
| return *(const T*)fAllocator.back();
|
| }
|
|
|
| /**
|
| - * access item by index.
|
| + * Iterates through the allocator. This is faster than using operator[] when walking linearly
|
| + * through the allocator.
|
| + */
|
| + class Iter {
|
| + public:
|
| + /**
|
| + * Initializes the iterator. next() must be called before get() or ops * and ->.
|
| + */
|
| + Iter(const GrTAllocator* allocator) : fImpl(&allocator->fAllocator) {}
|
| +
|
| + /**
|
| + * Advances the iterator. Iteration is finished when next() returns false.
|
| + */
|
| + bool next() { return fImpl.next(); }
|
| +
|
| + /**
|
| + * Gets the current iterator value. Call next() at least once before calling. Don't call
|
| + * after next() returns false.
|
| + */
|
| + const T* get() const { return (const T*) fImpl.get(); }
|
| +
|
| + /**
|
| + * Convenience operators. Same rules for calling apply as get().
|
| + */
|
| + const T& operator*() const { return *this->get(); }
|
| + const T* operator->() const { return this->get(); }
|
| +
|
| + private:
|
| + GrAllocator::Iter fImpl;
|
| + };
|
| +
|
| + /**
|
| + * Access item by index.
|
| */
|
| T& operator[] (int i) {
|
| return *(T*)(fAllocator[i]);
|
| }
|
|
|
| /**
|
| - * access item by index.
|
| + * Access item by index.
|
| */
|
| const T& operator[] (int i) const {
|
| return *(const T*)(fAllocator[i]);
|
|
|