Chromium Code Reviews| Index: include/core/SkTDArray.h |
| diff --git a/include/core/SkTDArray.h b/include/core/SkTDArray.h |
| index 31a11c7f3ea0c9a23e8d4f45f97a8a597873eee9..f62c3de62ff25f68041c889d37d2d7812e2fc647 100644 |
| --- a/include/core/SkTDArray.h |
| +++ b/include/core/SkTDArray.h |
| @@ -11,43 +11,43 @@ |
| #define SkTDArray_DEFINED |
| #include "SkTypes.h" |
| +#include "SkTemplates.h" |
| template <typename T> class SkTDArray { |
| public: |
| SkTDArray() { |
| - fReserve = fCount = 0; |
| - fArray = NULL; |
| + this->init(NULL, 0, NULL, 0); |
| } |
| - SkTDArray(const T src[], int count) { |
| - SkASSERT(src || count == 0); |
| - |
| - fReserve = fCount = 0; |
| - fArray = NULL; |
| - if (count) { |
| - fArray = (T*)sk_malloc_throw(count * sizeof(T)); |
| - memcpy(fArray, src, sizeof(T) * count); |
| - fReserve = fCount = count; |
| - } |
| + SkTDArray(const T src[], size_t count) { |
| + this->init(src, count, NULL, 0); |
| } |
| - SkTDArray(const SkTDArray<T>& src) { |
| - fReserve = fCount = 0; |
| - fArray = NULL; |
| - SkTDArray<T> tmp(src.fArray, src.fCount); |
| - this->swap(tmp); |
| + SkTDArray(const SkTDArray<T>& that) { |
| + this->init(that.fArray, that.fCount, NULL, 0); |
| } |
| + |
| ~SkTDArray() { |
| - sk_free(fArray); |
| + if (fArray != fPreAllocMemArray) { |
| + sk_free(fArray); |
| + } |
| } |
| - SkTDArray<T>& operator=(const SkTDArray<T>& src) { |
| - if (this != &src) { |
| - if (src.fCount > fReserve) { |
| - SkTDArray<T> tmp(src.fArray, src.fCount); |
| - this->swap(tmp); |
| + SkTDArray<T>& operator=(const SkTDArray<T>& that) { |
| + if (this != &that) { |
| + if (that.fCount > fReserve) { |
| + T* oldArray = fArray; |
| + |
| + T* newArray = (T*)sk_malloc_throw(that.fCount * sizeof(T)); |
| + memcpy(newArray, that.fArray, sizeof(T) * that.fCount); |
| + SkTSwap(newArray, fArray); |
| + fReserve = that.fCount; |
| + |
| + if (oldArray != fPreAllocMemArray) { |
| + sk_free(oldArray); |
| + } |
| } else { |
| - memcpy(fArray, src.fArray, sizeof(T) * src.fCount); |
| - fCount = src.fCount; |
| + memcpy(fArray, that.fArray, sizeof(T) * that.fCount); |
| } |
| + fCount = that.fCount; |
| } |
| return *this; |
| } |
| @@ -67,13 +67,18 @@ public: |
| SkTSwap(fCount, other.fCount); |
| } |
| - /** Return a ptr to the array of data, to be freed with sk_free. This also |
| - resets the SkTDArray to be empty. |
| + /** Returns a pointer to the array of data, to be freed with sk_free. |
| + * This also resets the SkTDArray to be empty. |
| + * Note that the value returned may differ from begin(). |
| */ |
| T* detach() { |
| T* array = fArray; |
| - fArray = NULL; |
| - fReserve = fCount = 0; |
| + if (fArray == fPreAllocMemArray && fCount > 0) { |
| + array = (T*)sk_malloc_throw(fCount * sizeof(T)); |
| + memcpy(array, fPreAllocMemArray, fCount * sizeof(T)); |
| + } |
| + // The following line will not throw because the second parameter is 0. |
| + this->init(NULL, 0, fPreAllocMemArray, fPreAllocMemArraySize); |
| return array; |
| } |
| @@ -102,11 +107,11 @@ public: |
| const T* end() const { return fArray ? fArray + fCount : NULL; } |
| T& operator[](int index) { |
| - SkASSERT(index < fCount); |
| + SkASSERT((size_t)index < fCount); |
| return fArray[index]; |
| } |
| const T& operator[](int index) const { |
| - SkASSERT(index < fCount); |
| + SkASSERT((size_t)index < fCount); |
| return fArray[index]; |
| } |
| @@ -118,12 +123,10 @@ public: |
| } |
| void reset() { |
| - if (fArray) { |
| - sk_free(fArray); |
| - fArray = NULL; |
| - fReserve = fCount = 0; |
| - } else { |
| - SkASSERT(fReserve == 0 && fCount == 0); |
| + T* oldArray = fArray; |
| + this->init(NULL, 0, fPreAllocMemArray, fPreAllocMemArraySize); |
| + if (oldArray != fPreAllocMemArray) { |
| + sk_free(oldArray); |
| } |
| } |
| @@ -140,20 +143,21 @@ public: |
| */ |
| void setCount(int count) { |
| SkASSERT(count >= 0); |
| - if (count > fReserve) { |
| - this->resizeStorageToAtLeast(count); |
| + if ((size_t)count > fReserve) { |
| + this->growReserveTo(count); |
| } |
| fCount = count; |
| } |
| void setReserve(int reserve) { |
| - if (reserve > fReserve) { |
| - this->resizeStorageToAtLeast(reserve); |
| + if ((size_t)reserve > fReserve) { |
| + SkASSERT((size_t)reserve > fCount); |
| + this->growReserveTo(reserve); |
| } |
| } |
| T* prepend() { |
| - this->adjustCount(1); |
| + this->growBy(1); |
| memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T)); |
| return fArray; |
| } |
| @@ -167,7 +171,7 @@ public: |
| SkASSERT(src == NULL || fArray == NULL || |
| src + count <= fArray || fArray + oldCount <= src); |
| - this->adjustCount(count); |
| + this->growBy(count); |
| if (src) { |
| memcpy(fArray + oldCount, src, sizeof(T) * count); |
| } |
| @@ -186,9 +190,9 @@ public: |
| } |
| T* insert(int index, int count, const T* src = NULL) { |
| SkASSERT(count); |
| - SkASSERT(index <= fCount); |
| + SkASSERT((size_t)index <= fCount); |
| size_t oldCount = fCount; |
| - this->adjustCount(count); |
| + this->growBy(count); |
| T* dst = fArray + index; |
| memmove(dst + count, dst, sizeof(T) * (oldCount - index)); |
| if (src) { |
| @@ -198,13 +202,13 @@ public: |
| } |
| void remove(int index, int count = 1) { |
| - SkASSERT(index + count <= fCount); |
| + SkASSERT((size_t)(index + count) <= fCount); |
| fCount = fCount - count; |
| memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index)); |
| } |
| void removeShuffle(int index) { |
| - SkASSERT(index < fCount); |
| + SkASSERT((size_t)index < fCount); |
| int newCount = fCount - 1; |
| fCount = newCount; |
| if (index != newCount) { |
| @@ -250,7 +254,7 @@ public: |
| int copyRange(T* dst, int index, int max) const { |
| SkASSERT(max >= 0); |
| SkASSERT(!max || dst); |
| - if (index >= fCount) { |
| + if ((size_t)index >= fCount) { |
| return 0; |
| } |
| int count = SkMin32(max, fCount - index); |
| @@ -321,44 +325,146 @@ public: |
| #ifdef SK_DEBUG |
| void validate() const { |
| - SkASSERT((fReserve == 0 && fArray == NULL) || |
| - (fReserve > 0 && fArray != NULL)); |
| + SkASSERT((fArray == NULL && fReserve == 0) || |
| + (fArray == fPreAllocMemArray && fReserve == fPreAllocMemArraySize) || |
| + (fArray != NULL && fArray != fPreAllocMemArray && fReserve > 0)); |
| SkASSERT(fCount <= fReserve); |
| + SkASSERT(fReserve <= fPreAllocMemArraySize || fArray != fPreAllocMemArray); |
| } |
| #endif |
| - void shrinkToFit() { |
| - fReserve = fCount; |
| - fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T)); |
| +protected: |
| + template <int N> SkTDArray(SkAlignedSTStorage<N, T>* storage) { |
| + this->init(NULL, 0, (T*)storage->get(), N); |
| + } |
| + template <int N> SkTDArray(const T src[], size_t count, SkAlignedSTStorage<N, T>* storage) { |
| + this->init(src, count, (T*)storage->get(), N); |
| + } |
| + template <int N> SkTDArray(const SkTDArray<T>& that, SkAlignedSTStorage<N, T>* storage) { |
| + this->init(that.fArray, that.fCount, (T*)storage->get(), N); |
| + } |
| + |
| + void init(const T* src, size_t count, T* preAllocStorage, size_t preAllocCount) { |
| + SkASSERT(src || count == 0); |
| + |
| + fArray = preAllocStorage; |
| + fPreAllocMemArray = preAllocStorage; |
| + fReserve = preAllocCount; |
| + fCount = count; |
| + fPreAllocMemArraySize = preAllocCount; |
| + |
| + // The following is almost equivalent to calling this->append(count, src). |
| + // This creates a tight fit instead of allocating extra room. |
| + if (count) { |
| + if (NULL == fArray || count > fReserve) { |
| + fArray = (T*)sk_malloc_throw(count * sizeof(T)); |
| + fReserve = count; |
| + } |
| + memcpy(fArray, src, sizeof(T) * count); |
| + fCount = count; |
| + } |
| } |
| private: |
| - T* fArray; |
| - int fReserve; |
| - int fCount; |
| + /** The underlying storage. |
| + * If fArray == NULL; fReserve == 0, fCount == 0. |
| + * If fArray == fPreAllocMemArray; fReserve = fPreAllocMemArraySize. |
| + * Otherwise fArray points to sk_malloc memory. |
| + */ |
| + T* fArray; |
| + |
| + /** Fixed-size storage which may be used as underlying storage. |
| + * Once out of init, this value is constant. |
| + * If fPreAllocMemArray == NULL; fPreAllocMemArraySize == 0. |
| + * If fPreAllocMemArray == fArray; fReserve = fPreAllocMemArraySize. |
| + */ |
| + T* fPreAllocMemArray; |
| + |
| + /** The current total size of the underlying storage in elements. |
| + * If fReserve == 0; fArray == NULL, fCount == 0. |
| + * If fReserve > 0; fArray != NULL. |
| + * If fReserve > fPreAllocMemArraySize; fArray != fPreAllocMemArray. |
| + * fReserve >= fCount. |
| + */ |
| + size_t fReserve; |
|
reed1
2015/04/22 23:02:12
Why change fReserve and fCount from int to size_t?
|
| + |
| + /** The current logical number of elements. |
| + * fCount <= fReserve. |
| + * Note that 'If fCount == 0; fArray == NULL' is not maintained. |
| + */ |
| + size_t fCount; |
| + |
| + /** The total size of the fixed size storage in elements. |
| + * Once out of init, this value is constant. |
| + * If fPreAllocMemArraySize == 0; fPreAllocMemArray == NULL. |
| + */ |
| + size_t fPreAllocMemArraySize; |
| /** |
| * Adjusts the number of elements in the array. |
| - * This is the same as calling setCount(count() + delta). |
| + * This is the same as calling setCount(count() + extra). |
| */ |
| - void adjustCount(int delta) { |
| - this->setCount(fCount + delta); |
| + void growBy(size_t extra) { |
| + SkASSERT(extra); |
| + |
| + size_t newCount = fCount + extra; |
| + if (newCount > fReserve) { |
| + size_t size = newCount + 4; |
| + size += size >> 2; |
| + |
| + growReserveTo(size); |
| + } |
| + fCount = newCount; |
| } |
| /** |
| - * Increase the storage allocation such that it can hold (fCount + extra) |
| - * elements. |
| + * Increase the storage allocation such that it can hold size) elements. |
| * It never shrinks the allocation, and it may increase the allocation by |
| * more than is strictly required, based on a private growth heuristic. |
| * |
| - * note: does NOT modify fCount |
| + * Note: does NOT modify fCount. |
| */ |
| - void resizeStorageToAtLeast(int count) { |
| - SkASSERT(count > fReserve); |
| - fReserve = count + 4; |
| - fReserve += fReserve / 4; |
| - fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T)); |
| + void growReserveTo(size_t size) { |
| + SkASSERT(size > fReserve); |
| + |
| + if (fArray == fPreAllocMemArray) { |
| + fArray = (T*)sk_malloc_throw(size * sizeof(T)); |
| + memcpy(fArray, fPreAllocMemArray, fCount * sizeof(T)); |
| + } else { |
| + fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T)); |
| + } |
| + fReserve = size; |
| + } |
| +}; |
| + |
| + |
| +/** |
| + * Subclass of SkTDArray that contains a preallocated memory block for the array. |
| + * @param N the number of T elements to store in the preallocated memory block. |
| + */ |
| +template <size_t N, typename T> |
| +class SkSTDArray : public SkTDArray<T> { |
| +private: |
| + typedef SkTDArray<T> INHERITED; |
| + |
| +public: |
| + SkSTDArray() : INHERITED(&fStorage) { } |
| + SkSTDArray(const T* src, int count) : INHERITED(src, count, &fStorage) { } |
| + SkSTDArray(const SkSTDArray& that) : INHERITED(that, &fStorage) { } |
| + |
| + explicit SkSTDArray(const INHERITED& that) : INHERITED(that, &fStorage) { } |
| + |
| + SkSTDArray& operator= (const SkSTDArray& that) { |
| + return *this = *(const INHERITED*)&that; |
| } |
| + |
| + SkSTDArray& operator= (const INHERITED& that) { |
| + INHERITED::operator=(that); |
| + return *this; |
| + } |
| + |
| +private: |
| + SkAlignedSTStorage<N, T> fStorage; |
| }; |
| #endif |