/* * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef _ARRAY_H #define _ARRAY_H #include #include #include #include #if DEBUG # include #endif namespace BPrivate { template class Array { public: inline Array(); Array(const Array& other); inline ~Array(); inline int32 Size() const { return fSize; } inline int32 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 AddUninitialized(int32 elementCount); inline bool Insert(const Element& element, int32 index); inline bool InsertUninitialized(int32 index, int32 count); inline bool Remove(int32 index, int32 count = 1); void Clear(); inline void MakeEmpty(); inline Element& ElementAt(int32 index); inline const Element& ElementAt(int32 index) const; inline Element& operator[](int32 index); inline const Element& operator[](int32 index) const; Array& operator=(const Array& other); private: static const int32 kMinCapacity = 8; bool _Resize(int32 index, int32 delta); private: Element* fElements; int32 fSize; int32 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 (!_Resize(fSize, 1)) return false; fElements[fSize] = element; fSize++; return true; } template inline bool Array::AddUninitialized(int32 elementCount) { return InsertUninitialized(fSize, elementCount); } template bool Array::Insert(const Element& element, int32 index) { if (index < 0 || index > fSize) index = fSize; if (!_Resize(index, 1)) return false; fElements[index] = element; fSize++; return true; } template bool Array::InsertUninitialized(int32 index, int32 count) { if (index < 0 || index > fSize || count < 0) return false; if (count == 0) return true; if (!_Resize(index, count)) return false; fSize += count; return true; } template bool Array::Remove(int32 index, int32 count) { if (index < 0 || count < 0 || index + count > fSize) { #if DEBUG char buffer[128]; snprintf(buffer, sizeof(buffer), "Array::Remove(): index: %" B_PRId32 ", count: %" B_PRId32 ", size: %" B_PRId32, index, count, fSize); debugger(buffer); #endif return false; } if (count == 0) return true; if (index + count < fSize) { memmove(fElements + index, fElements + index + count, sizeof(Element) * (fSize - index - count)); } _Resize(index, -count); fSize -= count; 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(int32 index) { return fElements[index]; } template const Element& Array::ElementAt(int32 index) const { return fElements[index]; } template Element& Array::operator[](int32 index) { return fElements[index]; } template const Element& Array::operator[](int32 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(int32 index, int32 delta) { // determine new capacity int32 newSize = fSize + delta; int32 newCapacity = kMinCapacity; while (newCapacity < newSize) newCapacity *= 2; if (newCapacity == fCapacity) { // the capacity doesn't change -- still make room for/remove elements if (index < fSize) { if (delta > 0) { // leave a gap of delta elements memmove(fElements + index + delta, fElements + index, (fSize - index) * sizeof(Element)); } else if (index < fSize + delta) { // drop -delta elements memcpy(fElements + index, fElements + index - delta, (fSize - index + delta) * sizeof(Element)); } } 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; } } // namespace BPrivate using BPrivate::Array; #endif // _ARRAY_H