/* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef ARRAY_H #define ARRAY_H #include #include #include template class Array { public: inline Array(); Array(const Array& other); ~Array(); inline int Size() const { return fSize; } inline int Count() const { return fSize; } inline bool IsEmpty() const { return fSize == 0; } inline Element* Elements() const { return fElements; } inline bool Add(const Element& element); inline bool Insert(const Element& element, int index); inline bool Remove(int index); void Clear(); inline void MakeEmpty(); inline Element& ElementAt(int index); inline const Element& ElementAt(int index) const; inline Element& operator[](int index); inline const Element& operator[](int index) const; Array& operator=(const Array& other); private: static const int kMinCapacity = 8; bool _Resize(int index, int delta); private: Element* fElements; int fSize; int fCapacity; }; template Array::Array() : fElements(NULL), fSize(0), fCapacity(0) { } template Array::Array(const Array& other) : fElements(NULL), fSize(0), fCapacity(0) { *this = other; } template Array::~Array() { free(fElements); } template bool Array::Add(const Element& element) { if (fSize == fCapacity) { if (!_Resize(fSize, 1)) return false; } fElements[fSize] = element; fSize++; return true; } template bool Array::Insert(const Element& element, int index) { if (index < 0 || index > fSize) index = fSize; if (fSize == fCapacity) { if (!_Resize(index, 1)) return false; } else if (index < fSize) { memmove(fElements + index + 1, fElements + index, sizeof(Element) * (fSize - index)); } fElements[index] = element; fSize++; return true; } template bool Array::Remove(int index) { if (index < 0 || index >= fSize) { char buffer[128]; snprintf(buffer, sizeof(buffer), "Array::Remove(): index: %d, size: %d", index, fSize); return false; } if (fSize <= fCapacity / 2 && fCapacity > kMinCapacity) { _Resize(index, -1); } else if (index < fSize) { memmove(fElements + index, fElements + index + 1, sizeof(Element) * (fSize - index - 1)); } fSize--; return true; } template void Array::Clear() { if (fSize == 0) return; free(fElements); fElements = NULL; fSize = 0; fCapacity = 0; } template void Array::MakeEmpty() { Clear(); } template Element& Array::ElementAt(int index) { return fElements[index]; } template const Element& Array::ElementAt(int index) const { return fElements[index]; } template Element& Array::operator[](int index) { return fElements[index]; } template const Element& Array::operator[](int index) const { return fElements[index]; } template Array& Array::operator=(const Array& other) { Clear(); if (other.fSize > 0 && _Resize(0, other.fSize)) { fSize = other.fSize; memcpy(fElements, other.fElements, fSize * sizeof(Element)); } return *this; } template bool Array::_Resize(int index, int delta) { // determine new capacity int newSize = fSize + delta; int newCapacity = kMinCapacity; while (newCapacity < newSize) newCapacity *= 2; if (newCapacity == fCapacity) return true; // allocate new array Element* elements = (Element*)malloc(newCapacity * sizeof(Element)); if (elements == NULL) return false; if (index > 0) memcpy(elements, fElements, index * sizeof(Element)); if (index < fSize) { if (delta > 0) { // leave a gap of delta elements memcpy(elements + index + delta, fElements + index, (fSize - index) * sizeof(Element)); } else if (index < fSize + delta) { // drop -delta elements memcpy(elements + index, fElements + index - delta, (fSize - index + delta) * sizeof(Element)); } } free(fElements); fElements = elements; fCapacity = newCapacity; return true; } #endif // ARRAY_H