|  | 
 | /* | 
 |  * 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" | 
 |  | 
 | 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 | 
 |  |