/* * 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 GrTDArray_DEFINED #define GrTDArray_DEFINED #include "GrTypes.h" #include "GrRefCnt.h" static int GrInitialArrayAllocationCount() { return 4; } static int GrNextArrayAllocationCount(int count) { return count + ((count + 1) >> 1); } template <typename T> class GrTDArray { public: GrTDArray() : fArray(NULL), fAllocated(0), fCount(0) {} GrTDArray(const GrTDArray& src) { fCount = fAllocated = src.fCount; fArray = (T*)GrMalloc(fAllocated * sizeof(T)); memcpy(fArray, src.fArray, fCount * sizeof(T)); } ~GrTDArray() { if (fArray) { GrFree(fArray); } } bool isEmpty() const { return 0 == fCount; } int count() const { return fCount; } const T& at(int index) const { GrAssert((unsigned)index < (unsigned)fCount); return fArray[index]; } T& at(int index) { GrAssert((unsigned)index < (unsigned)fCount); return fArray[index]; } const T& operator[](int index) const { return this->at(index); } T& operator[](int index) { return this->at(index); } GrTDArray& operator=(const GrTDArray& src) { if (fAllocated < src.fCount) { fAllocated = src.fCount; GrFree(fArray); fArray = (T*)GrMalloc(fAllocated * sizeof(T)); } fCount = src.fCount; memcpy(fArray, src.fArray, fCount * sizeof(T)); return *this; } void reset() { if (fArray) { GrFree(fArray); fArray = NULL; } fAllocated = fCount = 0; } T* begin() const { return fArray; } T* end() const { return fArray + fCount; } T* back() const { GrAssert(fCount); return fArray + (fCount - 1); } T* prepend() { this->growAt(0); return fArray; } T* append() { this->growAt(fCount); return fArray + fCount - 1; } /** * index may be [0..count], so that you can insert at the end (like append) */ T* insert(int index) { GrAssert((unsigned)index <= (unsigned)fCount); this->growAt(index); return fArray + index; } void remove(int index) { GrAssert((unsigned)index < (unsigned)fCount); fCount -= 1; if (index < fCount) { int remaining = fCount - index; memmove(fArray + index, fArray + index + 1, remaining * sizeof(T)); } } void removeShuffle(int index) { GrAssert((unsigned)index < (unsigned)fCount); fCount -= 1; if (index < fCount) { memmove(fArray + index, fArray + fCount, sizeof(T)); } } // Utility iterators /** * Calls GrFree() on each element. Assumes each is NULL or was allocated * with GrMalloc(). */ void freeAll() { T* stop = this->end(); for (T* curr = this->begin(); curr < stop; curr++) { GrFree(*curr); } this->reset(); } /** * Calls delete on each element. Assumes each is NULL or was allocated * with new. */ void deleteAll() { T* stop = this->end(); for (T* curr = this->begin(); curr < stop; curr++) { delete *curr; } this->reset(); } /** * Calls GrSafeUnref() on each element. Assumes each is NULL or is a * subclass of GrRefCnt. */ void unrefAll() { T* stop = this->end(); for (T* curr = this->begin(); curr < stop; curr++) { GrSafeUnref(*curr); } this->reset(); } void visit(void visitor(T&)) const { T* stop = this->end(); for (T* curr = this->begin(); curr < stop; curr++) { if (*curr) { visitor(*curr); } } } int find(const T& elem) const { int count = this->count(); T* curr = this->begin(); for (int i = 0; i < count; i++) { if (elem == curr[i]) { return i; } } return -1; } friend bool operator==(const GrTDArray<T>& a, const GrTDArray<T>& b) { return a.count() == b.count() && (0 == a.count() || 0 == memcmp(a.begin(), b.begin(), a.count() * sizeof(T))); } friend bool operator!=(const GrTDArray<T>& a, const GrTDArray<T>& b) { return !(a == b); } private: T* fArray; int fAllocated, fCount; // growAt will increment fCount, reallocate fArray (as needed), and slide // the contents of fArray to make a hole for new data at index. void growAt(int index) { GrAssert(fCount <= fAllocated); if (0 == fAllocated) { fAllocated = GrInitialArrayAllocationCount(); fArray = (T*)GrMalloc(fAllocated * sizeof(T)); } else if (fCount == fAllocated) { fAllocated = GrNextArrayAllocationCount(fAllocated); T* newArray = (T*)GrMalloc(fAllocated * sizeof(T)); memcpy(newArray, fArray, index * sizeof(T)); memcpy(newArray + index + 1, fArray + index, (fCount - index) * sizeof(T)); GrFree(fArray); fArray = newArray; } else { // check that we're not just appending if (index < fCount) { memmove(fArray + index + 1, fArray + index, (fCount - index) * sizeof(T)); } } GrAssert(fCount < fAllocated); fCount += 1; } }; extern void* GrTDArray_growAt(void*, int* allocated, int& count, int index, size_t); #endif