//-----------------------------------------------------------------------------
// 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)
{
if(index >= mElementCount)
{
AssertFatal(index < mElementCount, "Vector::operator[] - out of bounds array access!");
}
return mArray[index];
}
template inline const T& Vector::operator[](U32 index) const
{
if(index >= mElementCount)
{
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_