//----------------------------------------------------------------------------- // Copyright (c) 2013 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #ifndef _VECTOR_H_ #define _VECTOR_H_ //Includes #ifndef _PLATFORM_H_ #include "platform/platform.h" #endif //----------------------------------------------------------------------------- /// Size of memory blocks to allocate at a time for vectors. const static S32 VectorBlockSize = 16; #ifdef TORQUE_DEBUG extern bool VectorResize(U32 *aSize, U32 *aCount, void **arrayPtr, U32 newCount, U32 elemSize, const char* fileName, const U32 lineNum); #else extern bool VectorResize(U32 *aSize, U32 *aCount, void **arrayPtr, U32 newCount, U32 elemSize); #endif /// Use the following macro to bind a vector to a particular line /// of the owning class for memory tracking purposes #ifdef TORQUE_DEBUG #define VECTOR_SET_ASSOCIATION(x) x.setFileAssociation(__FILE__, __LINE__) #else #define VECTOR_SET_ASSOCIATION(x) #endif //----------------------------------------------------------------------------- /// A dynamic array class. /// /// The vector grows as you insert or append /// elements. Insertion is fastest at the end of the array. Resizing /// of the array can be avoided by pre-allocating space using the /// reserve() method. /// /// ***WARNING*** /// /// This template does not initialize, construct or destruct any of /// it's elements. This means don't use this template for elements /// (classes) that need these operations. This template is intended /// to be used for simple structures that have no constructors or /// destructors. /// /// @nosubgrouping template class Vector { protected: U32 mElementCount; U32 mArraySize; T* mArray; #ifdef TORQUE_DEBUG const char* mFileAssociation; U32 mLineAssociation; #endif bool resize(U32); // resizes, but does no construction/destruction void destroy(U32 start, U32 end); ///< Destructs elements from start to end-1 void construct(U32 start, U32 end); ///< Constructs elements from start to end-1 void construct(U32 start, U32 end, const T* array); public: Vector(const U32 initialSize = 0); Vector(const U32 initialSize, const char* fileName, const U32 lineNum); Vector(const char* fileName, const U32 lineNum); Vector(const Vector&); ~Vector(); #ifdef TORQUE_DEBUG void setFileAssociation(const char* file, const U32 line); #endif /// @name STL interface /// @{ typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef T* iterator; typedef const T* const_iterator; typedef S32 difference_type; typedef U32 size_type; typedef difference_type (QSORT_CALLBACK *compare_func)(const T *a, const T *b); Vector& operator=(const Vector& p); iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; S32 size() const; bool empty() const; bool contains(const T&) const; void insert(iterator, const T&); void erase(iterator); T& front(); const T& front() const; T& back(); const T& back() const; void push_front(const T&); void push_back(const T&); U32 push_front_unique(const T&); U32 push_back_unique(const T&); S32 find_next( const T&, U32 start = 0 ) const; void pop_front(); void pop_back(); T& operator[](U32); const T& operator[](U32) const; T& operator[](S32 i) { return operator[](U32(i)); } const T& operator[](S32 i ) const { return operator[](U32(i)); } T& at(U32); const T& at(U32) const; void reserve(U32); U32 capacity() const; /// @} /// @name Extended interface /// @{ U32 memSize() const; T* address() const; U32 setSize(U32); void increment( U32 = 1); void increment(const T* array, U32 = 1); void decrement(U32 = 1); void insert(U32); void erase(U32); void erase_fast(U32); void erase_fast(iterator); void clear(); void compact(); void sort(compare_func f); T& first(); T& last(); const T& first() const; const T& last() const; void set(void * addr, U32 sz); void merge(const Vector& p); /// @} }; template inline Vector::~Vector() { dFree(mArray); } template inline Vector::Vector(const U32 initialSize) { #ifdef TORQUE_DEBUG mFileAssociation = NULL; mLineAssociation = 0; #endif mArray = 0; mElementCount = 0; mArraySize = 0; if(initialSize) reserve(initialSize); } template inline Vector::Vector(const U32 initialSize, const char* fileName, const U32 lineNum) { #ifdef TORQUE_DEBUG mFileAssociation = fileName; mLineAssociation = lineNum; #else TORQUE_UNUSED( fileName ); TORQUE_UNUSED( lineNum ); #endif mArray = 0; mElementCount = 0; mArraySize = 0; if(initialSize) reserve(initialSize); } template inline Vector::Vector(const char* fileName, const U32 lineNum) { #ifdef TORQUE_DEBUG mFileAssociation = fileName; mLineAssociation = lineNum; #else TORQUE_UNUSED( fileName ); TORQUE_UNUSED( lineNum ); #endif mArray = 0; mElementCount = 0; mArraySize = 0; } template inline Vector::Vector(const Vector& p) { #ifdef TORQUE_DEBUG mFileAssociation = p.mFileAssociation; mLineAssociation = p.mLineAssociation; #endif mArray = 0; resize(p.mElementCount); if (p.mElementCount) dMemcpy(mArray,p.mArray,mElementCount * sizeof(value_type)); } #ifdef TORQUE_DEBUG template inline void Vector::setFileAssociation(const char* file, const U32 line) { mFileAssociation = file; mLineAssociation = line; } #endif template inline void Vector::destroy(U32 start, U32 end) // destroys from start to end-1 { // This check is a little generous as we can legitimately get (0,0) as // our parameters... so it won't detect every invalid case but it does // remain simple. AssertFatal(start <= mElementCount && end <= mElementCount, "Vector::destroy - out of bounds start/end."); // destroys from start to end-1 while(start < end) destructInPlace(&mArray[start++]); } template inline void Vector::construct(U32 start, U32 end) // destroys from start to end-1 { AssertFatal(start <= mElementCount && end <= mElementCount, "Vector::construct - out of bounds start/end."); while(start < end) constructInPlace(&mArray[start++]); } template inline void Vector::construct(U32 start, U32 end, const T* array) // destroys from start to end-1 { AssertFatal(start <= mElementCount && end <= mElementCount, "Vector::construct - out of bounds start/end."); for (int i = 0; start + i < end; i++) { constructInPlace(&mArray[start+i], &array[i]); } } template inline U32 Vector::memSize() const { return capacity() * sizeof(T); } template inline T* Vector::address() const { return mArray; } template inline U32 Vector::setSize(U32 size) { if (size > mArraySize) resize(size); else mElementCount = size; return mElementCount; } template inline void Vector::increment( U32 delta) { U32 count = mElementCount; if ((mElementCount += delta) > mArraySize) resize(mElementCount); construct(count, mElementCount); } template inline void Vector::increment(const T* array, U32 delta) { U32 count = mElementCount; if ((mElementCount += delta) > mArraySize) resize(mElementCount); construct(count, mElementCount, array); } template inline void Vector::decrement(U32 delta) { AssertFatal(mElementCount != 0, "Vector::decrement - cannot decrement zero-length vector."); const U32 count = mElementCount; // Determine new count after decrement... U32 newCount = mElementCount; if (mElementCount > delta) newCount -= delta; else newCount = 0; // Destruct removed items... destroy(newCount, count); // Note new element count. mElementCount = newCount; } template inline void Vector::insert(U32 index) { // Assert: index >= 0 && index < mElementCount increment(); dMemmove(&mArray[index + 1], &mArray[index], (mElementCount - index - 1) * sizeof(value_type)); } template inline void Vector::erase(U32 index) { AssertFatal(index < mElementCount, "Vector::erase - out of bounds index!"); if (index < (mElementCount - 1)) { dMemmove(&mArray[index], &mArray[index + 1], (mElementCount - index - 1) * sizeof(value_type)); } mElementCount--; } template inline void Vector::erase_fast(U32 index) { AssertFatal(index < mElementCount, "Vector::erase_fast - out of bounds index."); // CAUTION: this operator does NOT maintain list order // Copy the last element into the deleted 'hole' and decrement the // size of the vector. // Assert: index >= 0 && index < mElementCount if (index < (mElementCount - 1)) dMemmove(&mArray[index], &mArray[mElementCount - 1], sizeof(value_type)); decrement(); } template inline T& Vector::first() { AssertFatal(mElementCount != 0, "Vector::first - Error, no first element of a zero sized array!"); return mArray[0]; } template inline const T& Vector::first() const { AssertFatal(mElementCount != 0, "Vector::first - Error, no first element of a zero sized array! (const)"); return mArray[0]; } template inline T& Vector::last() { AssertFatal(mElementCount != 0, "Vector::last - Error, no last element of a zero sized array!"); return mArray[mElementCount - 1]; } template inline const T& Vector::last() const { AssertFatal(mElementCount != 0, "Vector::last - Error, no last element of a zero sized array! (const)"); return mArray[mElementCount - 1]; } template inline void Vector::clear() { mElementCount = 0; } template inline void Vector::compact() { resize(mElementCount); } typedef int (QSORT_CALLBACK *qsort_compare_func)(const void *, const void *); template inline void Vector::sort(compare_func f) { qsort(address(), size(), sizeof(T), (qsort_compare_func) f); } //----------------------------------------------------------------------------- template inline Vector& Vector::operator=(const Vector& p) { resize(p.mElementCount); if (p.mElementCount) dMemcpy(mArray,p.mArray,mElementCount * sizeof(value_type)); return *this; } template inline typename Vector::iterator Vector::begin() { return mArray; } template inline typename Vector::const_iterator Vector::begin() const { return mArray; } template inline typename Vector::iterator Vector::end() { return mArray + mElementCount; } template inline typename Vector::const_iterator Vector::end() const { return mArray + mElementCount; } template inline S32 Vector::size() const { return (S32)mElementCount; } template inline bool Vector::empty() const { return (mElementCount == 0); } template inline bool Vector::contains(const T& t) const { return find_next(t) != -1; } template inline void Vector::insert(iterator p,const T& x) { U32 index = (U32) (p - mArray); insert(index); mArray[index] = x; } template inline void Vector::erase(iterator q) { erase(U32(q - mArray)); } template inline void Vector::erase_fast(iterator q) { erase_fast(U32(q - mArray)); } template inline T& Vector::front() { return *begin(); } template inline const T& Vector::front() const { return *begin(); } template inline T& Vector::back() { AssertFatal(mElementCount != 0, "Vector::end - Error, no end element of a zero sized array!"); return *(end()-1); } template inline const T& Vector::back() const { AssertFatal(mElementCount != 0, "Vector::end - Error, no end element of a zero sized array! (const)"); return *(end()-1); } template inline void Vector::push_front(const T& x) { insert(0); mArray[0] = x; } template inline void Vector::push_back(const T& x) { increment(&x); // mArray[mElementCount - 1] = x; } template inline U32 Vector::push_front_unique(const T& x) { S32 index = find_next(x); if (index == -1) { index = 0; insert(index); mArray[index] = x; } return index; } template inline U32 Vector::push_back_unique(const T& x) { S32 index = find_next(x); if (index == -1) { increment(&x); index = mElementCount - 1; } return index; } template inline S32 Vector::find_next( const T& x, U32 start ) const { S32 index = -1; if (start < mElementCount) { for (U32 i = start; i < mElementCount; i++) { if (mArray[i] == x) { index = i; break; } } } return index; } template inline void Vector::pop_front() { AssertFatal(mElementCount != 0, "Vector::pop_front - cannot pop the front of a zero-length vector."); erase(U32(0)); } template inline void Vector::pop_back() { AssertFatal(mElementCount != 0, "Vector::pop_back - cannot pop the back of a zero-length vector."); decrement(); } template inline T& Vector::operator[](U32 index) { AssertFatal(index < mElementCount, "Vector::operator[] - out of bounds array access!"); return mArray[index]; } template inline const T& Vector::operator[](U32 index) const { AssertFatal(index < mElementCount, "Vector::operator[] - out of bounds array access!"); return mArray[index]; } template inline T& Vector::at(U32 index) { AssertFatal(index < mElementCount, "Vector::at - out of bounds array access!"); return mArray[index]; } template inline const T& Vector::at(U32 index) const { AssertFatal(index < mElementCount, "Vector::at - out of bounds array access!"); return mArray[index]; } template inline void Vector::reserve(U32 size) { if (size <= mArraySize) return; const U32 ec = mElementCount; if (resize(size)) mElementCount = ec; } template inline U32 Vector::capacity() const { return mArraySize; } template inline void Vector::set(void * addr, U32 sz) { setSize(sz); if (addr) dMemcpy(address(),addr,sz*sizeof(T)); } //----------------------------------------------------------------------------- template inline bool Vector::resize(U32 ecount) { #ifdef TORQUE_DEBUG return VectorResize(&mArraySize, &mElementCount, (void**) &mArray, ecount, sizeof(T), mFileAssociation, mLineAssociation); #else return VectorResize(&mArraySize, &mElementCount, (void**) &mArray, ecount, sizeof(T)); #endif } template inline void Vector::merge(const Vector& p) { if (!p.size()) return; const S32 oldsize = size(); resize(oldsize + p.size()); dMemcpy( &mArray[oldsize], p.address(), p.size() * sizeof(T) ); } //----------------------------------------------------------------------------- /// Template for vectors of pointers. template class VectorPtr : public Vector { /// @deprecated Disallowed. VectorPtr(const VectorPtr&); // Disallowed public: VectorPtr(); VectorPtr(const char* fileName, const U32 lineNum); /// @name STL interface /// @{ typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef T* iterator; typedef const T* const_iterator; typedef U32 difference_type; typedef U32 size_type; iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; void insert(iterator,const T&); void insert(int idx) { Parent::insert(idx); } void erase(iterator); T& front(); const T& front() const; T& back(); const T& back() const; void push_front(const T&); void push_back(const T&); T& operator[](U32); const T& operator[](U32) const; /// @} /// @name Extended interface /// @{ typedef Vector Parent; T& first(); T& last(); const T& first() const; const T& last() const; void erase_fast(U32); void erase_fast(iterator); /// @} }; //----------------------------------------------------------------------------- template inline VectorPtr::VectorPtr() { // } template inline VectorPtr::VectorPtr(const char* fileName, const U32 lineNum) : Vector(fileName, lineNum) { // } template inline T& VectorPtr::first() { return (T&)Parent::first(); } template inline const T& VectorPtr::first() const { return (const T)Parent::first(); } template inline T& VectorPtr::last() { return (T&)Parent::last(); } template inline const T& VectorPtr::last() const { return (const T&)Parent::last(); } template inline typename VectorPtr::iterator VectorPtr::begin() { return (iterator)Parent::begin(); } template inline typename VectorPtr::const_iterator VectorPtr::begin() const { return (const_iterator)Parent::begin(); } template inline typename VectorPtr::iterator VectorPtr::end() { return (iterator)Parent::end(); } template inline typename VectorPtr::const_iterator VectorPtr::end() const { return (const_iterator)Parent::end(); } template inline void VectorPtr::insert(iterator i,const T& x) { Parent::insert( (Parent::iterator)i, (Parent::reference)x ); } template inline void VectorPtr::erase(iterator i) { Parent::erase( (Parent::iterator)i ); } template inline void VectorPtr::erase_fast(U32 index) { AssertFatal(index < mElementCount, "VectorPtr::erase_fast - out of bounds index." ); // CAUTION: this operator does not maintain list order // Copy the last element into the deleted 'hole' and decrement the // size of the vector. // Assert: index >= 0 && index < mElementCount if (index < (mElementCount - 1)) mArray[index] = mArray[mElementCount - 1]; decrement(); } template inline void VectorPtr::erase_fast(iterator i) { erase_fast(U32(i - iterator(mArray))); } template inline T& VectorPtr::front() { return *begin(); } template inline const T& VectorPtr::front() const { return *begin(); } template inline T& VectorPtr::back() { return *end(); } template inline const T& VectorPtr::back() const { return *end(); } template inline void VectorPtr::push_front(const T& x) { Parent::push_front((Parent::const_reference)x); } template inline void VectorPtr::push_back(const T& x) { Parent::push_back((Parent::const_reference)x); } template inline T& VectorPtr::operator[](U32 index) { return (T&)Parent::operator[](index); } template inline const T& VectorPtr::operator[](U32 index) const { return (const T&)Parent::operator[](index); } #endif //_VECTOR_H_