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