/*
Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#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