6e8fbca745
match the genesis editor version 1.3.0.653.
1184 lines
30 KiB
C++
1184 lines
30 KiB
C++
#pragma once
|
||
/****************************************************************************
|
||
Copyright (c) 2006, Radon Labs GmbH
|
||
Copyright (c) 2011-2013,WebJet Business Division,CYOU
|
||
|
||
http://www.genesis-3d.com.cn
|
||
|
||
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.
|
||
****************************************************************************/
|
||
|
||
#include "core/types.h"
|
||
|
||
#if __ANDROID__
|
||
#include <algorithm>
|
||
#endif
|
||
|
||
//------------------------------------------------------------------------------
|
||
namespace Util
|
||
{
|
||
template<class TYPE> class Array
|
||
{
|
||
public:
|
||
|
||
typedef TYPE value_type;
|
||
|
||
|
||
/// define iterator
|
||
typedef TYPE* Iterator;
|
||
|
||
/// constructor with default parameters
|
||
Array();
|
||
/// constuctor with initial size and grow size
|
||
Array(SizeT initialCapacity, SizeT initialGrow);
|
||
/// constructor with initial size, grow size and initial values
|
||
Array(SizeT initialSize, SizeT initialGrow, const TYPE& initialValue);
|
||
/// copy constructor
|
||
Array(const Array<TYPE>& rhs);
|
||
/// destructor
|
||
~Array();
|
||
|
||
/// assignment operator
|
||
void operator=(const Array<TYPE>& rhs);
|
||
void Assign( const TYPE* vBegin, const TYPE* vEnd );
|
||
|
||
/// [] operator
|
||
TYPE& operator[](IndexT index) const;
|
||
/// equality operator
|
||
bool operator==(const Array<TYPE>& rhs) const;
|
||
/// inequality operator
|
||
bool operator!=(const Array<TYPE>& rhs) const;
|
||
/// convert to "anything"
|
||
template<typename T> T As() const;
|
||
|
||
/// append element to end of array
|
||
void Append(const TYPE& elm);
|
||
/// append the contents of an array to this array
|
||
void AppendArray(const Array<TYPE>& rhs);
|
||
/// increase capacity to fit N more elements into the array
|
||
void Reserve(SizeT num);
|
||
/// get number of elements in array
|
||
SizeT Size() const;
|
||
/// get overall allocated size of array in number of elements
|
||
SizeT Capacity() const;
|
||
/// return reference to first element
|
||
TYPE& Front() const;
|
||
/// return reference to last element
|
||
TYPE& Back() const;
|
||
/// return true if array empty
|
||
bool IsEmpty() const;
|
||
/// erase element at index, keep sorting intact
|
||
void EraseIndex(IndexT index);
|
||
/// erase element pointed to by iterator, keep sorting intact
|
||
Iterator Erase(Iterator iter);
|
||
/// erase element at index, fill gap by swapping in last element, destroys sorting!
|
||
void EraseIndexSwap(IndexT index);
|
||
/// erase element at iterator, fill gap by swapping in last element, destroys sorting!
|
||
Iterator EraseSwap(Iterator iter);
|
||
/// insert element before element at index
|
||
void Insert(IndexT index, const TYPE& elm);
|
||
/// insert element into sorted array, return index where element was included
|
||
IndexT InsertSorted(const TYPE& elm);
|
||
/// insert element at the first non-identical position, return index of inclusion position
|
||
IndexT InsertAtEndOfIdenticalRange(IndexT startIndex, const TYPE& elm);
|
||
/// test if the array is sorted, this is a slow operation!
|
||
bool IsSorted() const;
|
||
/// clear array (calls destructors, if clearMem = true, will dealloc memory)
|
||
void Clear(bool clearMem = true );
|
||
/// reset array (does NOT call destructors)
|
||
void Reset();
|
||
/// Resize the array
|
||
void Resize(SizeT count, const TYPE& elm);
|
||
/// return iterator to beginning of array
|
||
Iterator Begin() const;
|
||
/// return iterator to end of array
|
||
Iterator End() const;
|
||
/// find identical element in array, return iterator
|
||
Iterator Find(const TYPE& elm) const;
|
||
/// find identical element in array, return index, InvalidIndex if not found
|
||
IndexT FindIndex(const TYPE& elm) const;
|
||
/// fill array range with element
|
||
void Fill(IndexT first, SizeT num, const TYPE& elm);
|
||
/// clear contents and preallocate with new attributes
|
||
void Realloc(SizeT capacity, SizeT grow);
|
||
/// returns new array with elements which are not in rhs (slow!)
|
||
Array<TYPE> Difference(const Array<TYPE>& rhs);
|
||
/// sort the array
|
||
void Sort();
|
||
/// do a binary search, requires a sorted array
|
||
IndexT BinarySearchIndex(const TYPE& elm) const;
|
||
/// swap with another array
|
||
void Swap(Array<TYPE>& rhs);
|
||
|
||
private:
|
||
/// destroy an element (call destructor without freeing memory)
|
||
void Destroy(TYPE* elm);
|
||
/// copy content
|
||
void Copy(const Array<TYPE>& src);
|
||
/// delete content
|
||
void Delete();
|
||
/// grow array
|
||
void Grow();
|
||
/// grow array to target size
|
||
void GrowTo(SizeT newCapacity);
|
||
/// move elements, grows array if needed
|
||
void Move(IndexT fromIndex, IndexT toIndex);
|
||
|
||
static const SizeT MinGrowSize = 16;
|
||
static const SizeT MaxGrowSize = 65536; // FIXME: big grow size needed for mesh tools
|
||
SizeT grow; // grow by this number of elements if array exhausted
|
||
SizeT capacity; // number of elements allocated
|
||
SizeT size; // number of elements in array
|
||
TYPE* elements; // pointer to element array
|
||
};
|
||
|
||
//------------------------------------------------------------------------------
|
||
/** custom sort the array. CMPTYPE is a struct used for comparing
|
||
*/
|
||
template<class TYPE,typename CMPTYPE> void CustomSortArray(const Array<TYPE> &arr)
|
||
{
|
||
std::sort(arr.Begin(), arr.End(), CMPTYPE());
|
||
|
||
}
|
||
|
||
template<class TYPE,typename CMPTYPE> void CustomSortArray(const Array<TYPE> &arr, const CMPTYPE& _t)
|
||
{
|
||
std::sort(arr.Begin(), arr.End(), _t);
|
||
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE>
|
||
Array<TYPE>::Array() :
|
||
grow(8),
|
||
capacity(0),
|
||
size(0),
|
||
elements(0)
|
||
{
|
||
// empty
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE>
|
||
Array<TYPE>::Array(SizeT _capacity, SizeT _grow) :
|
||
grow(_grow),
|
||
capacity(_capacity),
|
||
size(0)
|
||
{
|
||
if (0 == this->grow)
|
||
{
|
||
this->grow = 16;
|
||
}
|
||
if (this->capacity > 0)
|
||
{
|
||
this->elements = n_new_array(TYPE, this->capacity);
|
||
}
|
||
else
|
||
{
|
||
this->elements = 0;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE>
|
||
Array<TYPE>::Array(SizeT initialSize, SizeT _grow, const TYPE& initialValue) :
|
||
grow(_grow),
|
||
capacity(initialSize),
|
||
size(initialSize)
|
||
{
|
||
if (0 == this->grow)
|
||
{
|
||
this->grow = 16;
|
||
}
|
||
if (initialSize > 0)
|
||
{
|
||
this->elements = n_new_array(TYPE, this->capacity);
|
||
IndexT i;
|
||
for (i = 0; i < initialSize; i++)
|
||
{
|
||
this->elements[i] = initialValue;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
this->elements = 0;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Copy(const Array<TYPE>& src)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(0 == this->elements);
|
||
#endif
|
||
|
||
this->grow = src.grow;
|
||
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert( this->grow > 0 );
|
||
#endif
|
||
|
||
this->capacity = src.capacity;
|
||
this->size = src.size;
|
||
if (this->capacity > 0)
|
||
{
|
||
this->elements = n_new_array(TYPE, this->capacity);
|
||
IndexT i;
|
||
for (i = 0; i < this->size; i++)
|
||
{
|
||
this->elements[i] = src.elements[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Delete()
|
||
{
|
||
//this->grow = 0; // the grow never be 0.
|
||
this->capacity = 0;
|
||
this->size = 0;
|
||
if (this->elements)
|
||
{
|
||
n_delete_array(this->elements);
|
||
this->elements = 0;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Destroy(TYPE* elm)
|
||
{
|
||
elm->~TYPE();
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE>
|
||
Array<TYPE>::Array(const Array<TYPE>& rhs) :
|
||
grow(0),
|
||
capacity(0),
|
||
size(0),
|
||
elements(0)
|
||
{
|
||
this->Copy(rhs);
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE>
|
||
Array<TYPE>::~Array()
|
||
{
|
||
this->Delete();
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Realloc(SizeT _capacity, SizeT _grow)
|
||
{
|
||
this->Delete();
|
||
this->grow = _grow;
|
||
if ( this->grow <= 0 )
|
||
{
|
||
this->grow = 8;
|
||
}
|
||
|
||
this->capacity = _capacity;
|
||
this->size = 0;
|
||
if (this->capacity > 0)
|
||
{
|
||
this->elements = n_new_array(TYPE, this->capacity);
|
||
}
|
||
else
|
||
{
|
||
this->elements = 0;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::operator=(const Array<TYPE>& rhs)
|
||
{
|
||
if (this != &rhs)
|
||
{
|
||
if ((this->capacity > 0) && (rhs.size <= this->capacity))
|
||
{
|
||
// source array fits into our capacity, copy in place
|
||
n_assert(0 != this->elements);
|
||
IndexT i;
|
||
for (i = 0; i < rhs.size; i++)
|
||
{
|
||
this->elements[i] = rhs.elements[i];
|
||
}
|
||
|
||
// properly destroy remaining original elements
|
||
for (; i < this->size; i++)
|
||
{
|
||
this->Destroy(&(this->elements[i]));
|
||
}
|
||
this->grow = rhs.grow;
|
||
n_assert(this->grow > 0 );
|
||
this->size = rhs.size;
|
||
}
|
||
else
|
||
{
|
||
// source array doesn't fit into our capacity, need to reallocate
|
||
this->Delete();
|
||
this->Copy(rhs);
|
||
}
|
||
}
|
||
}
|
||
//------------------------------------------------------------------------
|
||
template<class TYPE> void
|
||
Array<TYPE>::Assign( const TYPE* vBegin, const TYPE* vEnd )
|
||
{
|
||
SizeT count = vEnd - vBegin;
|
||
if ( vBegin == NULL || count <= 0 )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ((this->capacity > 0) && (count <= this->capacity))
|
||
{
|
||
// source array fits into our capacity, copy in place
|
||
n_assert(0 != this->elements);
|
||
IndexT i;
|
||
for (i = 0; i < count; i++)
|
||
{
|
||
this->elements[i] = vBegin[i];
|
||
}
|
||
|
||
// properly destroy remaining original elements
|
||
for (; i < this->size; i++)
|
||
{
|
||
this->Destroy(&(this->elements[i]));
|
||
}
|
||
this->size = count;
|
||
}
|
||
else
|
||
{
|
||
// source array doesn't fit into our capacity, need to reallocate
|
||
this->Delete();
|
||
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(0 == this->elements);
|
||
#endif
|
||
|
||
this->capacity = count;
|
||
this->size = count;
|
||
if (this->capacity > 0)
|
||
{
|
||
this->elements = n_new_array(TYPE, this->capacity);
|
||
IndexT i;
|
||
for (i = 0; i < this->size; i++)
|
||
{
|
||
this->elements[i] = vBegin[i];
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::GrowTo(SizeT newCapacity)
|
||
{
|
||
TYPE* newArray = n_new_array(TYPE, newCapacity);
|
||
if (this->elements)
|
||
{
|
||
// copy over contents
|
||
IndexT i;
|
||
for (i = 0; i < this->size; i++)
|
||
{
|
||
newArray[i] = this->elements[i];
|
||
}
|
||
|
||
// discard old array and update contents
|
||
n_delete_array(this->elements);
|
||
}
|
||
this->elements = newArray;
|
||
this->capacity = newCapacity;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Grow()
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->grow > 0);
|
||
#endif
|
||
|
||
SizeT growToSize;
|
||
if (0 == this->capacity)
|
||
{
|
||
growToSize = this->grow;
|
||
}
|
||
else
|
||
{
|
||
// grow by half of the current capacity, but never more then MaxGrowSize
|
||
SizeT growBy = this->capacity >> 1;
|
||
if (growBy == 0)
|
||
{
|
||
growBy = MinGrowSize;
|
||
}
|
||
else if (growBy > MaxGrowSize)
|
||
{
|
||
growBy = MaxGrowSize;
|
||
}
|
||
growToSize = this->capacity + growBy;
|
||
}
|
||
this->GrowTo(growToSize);
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
30-Jan-03 floh serious bugfixes!
|
||
07-Dec-04 jo bugfix: neededSize >= this->capacity => neededSize > capacity
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Move(IndexT fromIndex, IndexT toIndex)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements);
|
||
n_assert(fromIndex < this->size);
|
||
#endif
|
||
|
||
// nothing to move?
|
||
if (fromIndex == toIndex)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// compute number of elements to move
|
||
SizeT num = this->size - fromIndex;
|
||
|
||
// check if array needs to grow
|
||
SizeT neededSize = toIndex + num;
|
||
while (neededSize > this->capacity)
|
||
{
|
||
this->Grow();
|
||
}
|
||
|
||
if (fromIndex > toIndex)
|
||
{
|
||
// this is a backward move
|
||
IndexT i;
|
||
for (i = 0; i < num; i++)
|
||
{
|
||
this->elements[toIndex + i] = this->elements[fromIndex + i];
|
||
}
|
||
|
||
// destroy remaining elements
|
||
for (i = (fromIndex + i) - 1; i < this->size; i++)
|
||
{
|
||
this->Destroy(&(this->elements[i]));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// this is a forward move
|
||
int i; // NOTE: this must remain signed for the following loop to work!!!
|
||
for (i = num - 1; i >= 0; --i)
|
||
{
|
||
this->elements[toIndex + i] = this->elements[fromIndex + i];
|
||
}
|
||
|
||
// destroy freed elements
|
||
for (i = int(fromIndex); i < int(toIndex); i++)
|
||
{
|
||
this->Destroy(&(this->elements[i]));
|
||
}
|
||
}
|
||
|
||
// adjust array size
|
||
this->size = toIndex + num;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Append(const TYPE& elm)
|
||
{
|
||
// grow allocated space if exhausted
|
||
if (this->size == this->capacity)
|
||
{
|
||
this->Grow();
|
||
}
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements);
|
||
#endif
|
||
this->elements[this->size++] = elm;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::AppendArray(const Array<TYPE>& rhs)
|
||
{
|
||
IndexT i;
|
||
SizeT num = rhs.Size();
|
||
for (i = 0; i < num; i++)
|
||
{
|
||
this->Append(rhs[i]);
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
This increases the capacity to make room for N elements. If the
|
||
number of elements is known before appending the elements, this
|
||
method can be used to prevent reallocation. If there is already
|
||
enough room for N more elements, nothing will happen.
|
||
|
||
NOTE: the functionality of this method has been changed as of 26-Apr-08,
|
||
it will now only change the capacity of the array, not its size.
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Reserve(SizeT num)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(num > 0);
|
||
#endif
|
||
SizeT neededCapacity = this->size + num;
|
||
if (neededCapacity > this->capacity)
|
||
{
|
||
this->GrowTo(neededCapacity);
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> SizeT
|
||
Array<TYPE>::Size() const
|
||
{
|
||
return this->size;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> SizeT
|
||
Array<TYPE>::Capacity() const
|
||
{
|
||
return this->capacity;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
Access an element. This method will NOT grow the array, and instead do
|
||
a range check, which may throw an assertion.
|
||
*/
|
||
template<class TYPE> TYPE&
|
||
Array<TYPE>::operator[](IndexT index) const
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements && (index < this->size));
|
||
#endif
|
||
return this->elements[index];
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
The equality operator returns true if all elements are identical. The
|
||
TYPE class must support the equality operator.
|
||
*/
|
||
template<class TYPE> bool
|
||
Array<TYPE>::operator==(const Array<TYPE>& rhs) const
|
||
{
|
||
if (rhs.Size() == this->Size())
|
||
{
|
||
IndexT i;
|
||
SizeT num = this->Size();
|
||
for (i = 0; i < num; i++)
|
||
{
|
||
if (!(this->elements[i] == rhs.elements[i]))
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
The inequality operator returns true if at least one element in the
|
||
array is different, or the array sizes are different.
|
||
*/
|
||
template<class TYPE> bool
|
||
Array<TYPE>::operator!=(const Array<TYPE>& rhs) const
|
||
{
|
||
return !(*this == rhs);
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> TYPE&
|
||
Array<TYPE>::Front() const
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements && (this->size > 0));
|
||
#endif
|
||
return this->elements[0];
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> TYPE&
|
||
Array<TYPE>::Back() const
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements && (this->size > 0));
|
||
#endif
|
||
return this->elements[this->size - 1];
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> bool
|
||
Array<TYPE>::IsEmpty() const
|
||
{
|
||
return (this->size == 0);
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::EraseIndex(IndexT index)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements && (index < this->size));
|
||
#endif
|
||
if (index == (this->size - 1))
|
||
{
|
||
// special case: last element
|
||
this->Destroy(&(this->elements[index]));
|
||
this->size--;
|
||
}
|
||
else
|
||
{
|
||
this->Move(index + 1, index);
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
NOTE: this method is fast but destroys the sorting order!
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::EraseIndexSwap(IndexT index)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements && (index < this->size));
|
||
#endif
|
||
|
||
// swap with last element, and destroy last element
|
||
IndexT lastElementIndex = this->size - 1;
|
||
if (index < lastElementIndex)
|
||
{
|
||
this->elements[index] = this->elements[lastElementIndex];
|
||
}
|
||
this->Destroy(&(this->elements[lastElementIndex]));
|
||
this->size--;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> typename Array<TYPE>::Iterator
|
||
Array<TYPE>::Erase(typename Array<TYPE>::Iterator iter)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements && (iter >= this->elements) && (iter < (this->elements + this->size)));
|
||
#endif
|
||
this->EraseIndex(IndexT(iter - this->elements));
|
||
return iter;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
NOTE: this method is fast but destroys the sorting order!
|
||
*/
|
||
template<class TYPE> typename Array<TYPE>::Iterator
|
||
Array<TYPE>::EraseSwap(typename Array<TYPE>::Iterator iter)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(this->elements && (iter >= this->elements) && (iter < (this->elements + this->size)));
|
||
#endif
|
||
this->EraseSwapIndex(IndexT(iter - this->elements));
|
||
return iter;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Insert(IndexT index, const TYPE& elm)
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(index <= this->size);
|
||
#endif
|
||
if (index == this->size)
|
||
{
|
||
// special case: append element to back
|
||
this->Append(elm);
|
||
}
|
||
else
|
||
{
|
||
this->Move(index, index + 1);
|
||
this->elements[index] = elm;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
The current implementation of this method will shrink the
|
||
preallocated space if clearMem == true ( defalut action ). It sets the array size to 0.
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Clear(bool clearMem)
|
||
{
|
||
if ( clearMem )
|
||
{
|
||
this->Delete();
|
||
}
|
||
else
|
||
{
|
||
IndexT i;
|
||
for (i = 0; i < this->size; i++)
|
||
{
|
||
this->Destroy(&(this->elements[i]));
|
||
}
|
||
}
|
||
this->size = 0;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
This is identical with Clear(), but does NOT call destructors (it just
|
||
resets the size member. USE WITH CARE!
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Reset()
|
||
{
|
||
this->size = 0;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> typename Array<TYPE>::Iterator
|
||
Array<TYPE>::Begin() const
|
||
{
|
||
return this->elements;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
*/
|
||
template<class TYPE> typename Array<TYPE>::Iterator
|
||
Array<TYPE>::End() const
|
||
{
|
||
return this->elements + this->size;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
Find element in array, return iterator, or 0 if element not
|
||
found.
|
||
|
||
@param elm element to find
|
||
@return element iterator, or 0 if not found
|
||
*/
|
||
template<class TYPE> typename Array<TYPE>::Iterator
|
||
Array<TYPE>::Find(const TYPE& elm) const
|
||
{
|
||
IndexT index;
|
||
for (index = 0; index < this->size; index++)
|
||
{
|
||
if (this->elements[index] == elm)
|
||
{
|
||
return &(this->elements[index]);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
Find element in array, return element index, or InvalidIndex if element not
|
||
found.
|
||
|
||
@param elm element to find
|
||
@return index to element, or InvalidIndex if not found
|
||
*/
|
||
template<class TYPE> IndexT
|
||
Array<TYPE>::FindIndex(const TYPE& elm) const
|
||
{
|
||
IndexT index;
|
||
for (index = 0; index < this->size; index++)
|
||
{
|
||
if (this->elements[index] == elm)
|
||
{
|
||
return index;
|
||
}
|
||
}
|
||
return InvalidIndex;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
Fills an array range with the given element value. Will grow the
|
||
array if necessary
|
||
|
||
@param first index of first element to start fill
|
||
@param num num elements to fill
|
||
@param elm fill value
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Fill(IndexT first, SizeT num, const TYPE& elm)
|
||
{
|
||
if ((first + num) > this->size)
|
||
{
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD>·<EFBFBD><C2B7><EFBFBD>
|
||
if ( (first + num) > this->capacity )
|
||
{
|
||
this->GrowTo(first + num);
|
||
}
|
||
|
||
//<2F><>Ȼ<EFBFBD><C8BB>fill<6C><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>СҲ<D0A1><D2B2>Ҫ<EFBFBD>仯<EFBFBD><E4BBAF>Fill<6C><6C><EFBFBD><EFBFBD> Reserve
|
||
this->size = first + num;
|
||
}
|
||
|
||
IndexT i;
|
||
for (i = first; i < (first + num); i++)
|
||
{
|
||
this->elements[i] = elm;
|
||
}
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
Returns a new array with all element which are in rhs, but not in this.
|
||
Carefull, this method may be very slow with large arrays!
|
||
|
||
@todo this method is broken, check test case to see why!
|
||
*/
|
||
template<class TYPE> Array<TYPE>
|
||
Array<TYPE>::Difference(const Array<TYPE>& rhs)
|
||
{
|
||
Array<TYPE> diff;
|
||
IndexT i;
|
||
SizeT num = rhs.Size();
|
||
for (i = 0; i < num; i++)
|
||
{
|
||
if (0 == this->Find(rhs[i]))
|
||
{
|
||
diff.Append(rhs[i]);
|
||
}
|
||
}
|
||
return diff;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
Sorts the array. This just calls the STL sort algorithm.
|
||
*/
|
||
template<class TYPE> void
|
||
Array<TYPE>::Sort()
|
||
{
|
||
std::sort(this->Begin(), this->End());
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
Does a binary search on the array, returns the index of the identical
|
||
element, or InvalidIndex if not found
|
||
*/
|
||
template<class TYPE> IndexT
|
||
Array<TYPE>::BinarySearchIndex(const TYPE& elm) const
|
||
{
|
||
SizeT num = this->Size();
|
||
if (num > 0)
|
||
{
|
||
IndexT half;
|
||
IndexT lo = 0;
|
||
IndexT hi = num - 1;
|
||
IndexT mid;
|
||
while (lo <= hi)
|
||
{
|
||
if (0 != (half = num/2))
|
||
{
|
||
mid = lo + ((num & 1) ? half : (half - 1));
|
||
if (elm < this->elements[mid])
|
||
{
|
||
hi = mid - 1;
|
||
num = num & 1 ? half : half - 1;
|
||
}
|
||
else if (elm > this->elements[mid])
|
||
{
|
||
lo = mid + 1;
|
||
num = half;
|
||
}
|
||
else
|
||
{
|
||
return mid;
|
||
}
|
||
}
|
||
else if (0 != num)
|
||
{
|
||
if (elm != this->elements[lo])
|
||
{
|
||
return InvalidIndex;
|
||
}
|
||
else
|
||
{
|
||
return lo;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return InvalidIndex;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
This tests, whether the array is sorted. This is a slow operation
|
||
O(n).
|
||
*/
|
||
template<class TYPE> bool
|
||
Array<TYPE>::IsSorted() const
|
||
{
|
||
if (this->size > 1)
|
||
{
|
||
IndexT i;
|
||
for (i = 0; i < this->size - 1; i++)
|
||
{
|
||
if (this->elements[i] > this->elements[i + 1])
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
This inserts an element at the end of a range of identical elements
|
||
starting at a given index. Performance is O(n). Returns the index
|
||
at which the element was added.
|
||
*/
|
||
template<class TYPE> IndexT
|
||
Array<TYPE>::InsertAtEndOfIdenticalRange(IndexT startIndex, const TYPE& elm)
|
||
{
|
||
IndexT i = startIndex + 1;
|
||
for (; i < this->size; i++)
|
||
{
|
||
if (this->elements[i] != elm)
|
||
{
|
||
this->Insert(i, elm);
|
||
return i;
|
||
}
|
||
}
|
||
|
||
// fallthrough: new element needs to be appended to end
|
||
this->Append(elm);
|
||
return (this->Size() - 1);
|
||
}
|
||
|
||
//------------------------------------------------------------------------------
|
||
/**
|
||
This inserts the element into a sorted array. Returns the index
|
||
at which the element was inserted.
|
||
*/
|
||
template<class TYPE> IndexT
|
||
Array<TYPE>::InsertSorted(const TYPE& elm)
|
||
{
|
||
SizeT num = this->Size();
|
||
if (num == 0)
|
||
{
|
||
// array is currently empty
|
||
this->Append(elm);
|
||
return this->Size() - 1;
|
||
}
|
||
else
|
||
{
|
||
IndexT half;
|
||
IndexT lo = 0;
|
||
IndexT hi = num - 1;
|
||
IndexT mid;
|
||
while (lo <= hi)
|
||
{
|
||
if (0 != (half = num/2))
|
||
{
|
||
mid = lo + ((num & 1) ? half : (half - 1));
|
||
if (elm < this->elements[mid])
|
||
{
|
||
hi = mid - 1;
|
||
num = num & 1 ? half : half - 1;
|
||
}
|
||
else if (elm > this->elements[mid])
|
||
{
|
||
lo = mid + 1;
|
||
num = half;
|
||
}
|
||
else
|
||
{
|
||
// element already exists at [mid], append the
|
||
// new element to the end of the range
|
||
return this->InsertAtEndOfIdenticalRange(mid, elm);
|
||
}
|
||
}
|
||
else if (0 != num)
|
||
{
|
||
if (elm < this->elements[lo])
|
||
{
|
||
this->Insert(lo, elm);
|
||
return lo;
|
||
}
|
||
else if (elm > this->elements[lo])
|
||
{
|
||
this->Insert(lo + 1, elm);
|
||
return lo + 1;
|
||
}
|
||
else
|
||
{
|
||
// element already exists at [low], append
|
||
// the new element to the end of the range
|
||
return this->InsertAtEndOfIdenticalRange(lo, elm);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
#if NEBULA3_BOUNDSCHECKS
|
||
n_assert(0 == lo);
|
||
#endif
|
||
this->Insert(lo, elm);
|
||
return lo;
|
||
}
|
||
}
|
||
if (elm < this->elements[lo])
|
||
{
|
||
this->Insert(lo, elm);
|
||
return lo;
|
||
}
|
||
else if (elm > this->elements[lo])
|
||
{
|
||
this->Insert(lo + 1, elm);
|
||
return lo + 1;
|
||
}
|
||
else
|
||
{
|
||
// can't happen(?)
|
||
}
|
||
}
|
||
// can't happen
|
||
n_error("Array::InsertSorted: Can't happen!");
|
||
return InvalidIndex;
|
||
}
|
||
//-----------------------------------------------------------------------
|
||
template<class TYPE> void
|
||
Array<TYPE>::Swap(Array<TYPE>& rhs)
|
||
{
|
||
// cache
|
||
SizeT temp_grow = rhs.grow;
|
||
SizeT temp_capacity = rhs.capacity;
|
||
SizeT temp_size = rhs.size;
|
||
TYPE* temp_elements = rhs.elements;
|
||
|
||
// this->rhs
|
||
rhs.grow = this->grow;
|
||
rhs.capacity = this->capacity;
|
||
rhs.size = this->size;
|
||
rhs.elements = this->elements;
|
||
|
||
// cache(rhs)->this
|
||
this->grow = temp_grow;
|
||
n_assert( this->grow > 0 );
|
||
this->capacity = temp_capacity;
|
||
this->size = temp_size;
|
||
this->elements = temp_elements;
|
||
}
|
||
//------------------------------------------------------------------------
|
||
/// Resize the array
|
||
template<class TYPE> void
|
||
Array<TYPE>::Resize(SizeT count, const TYPE& elm)
|
||
{
|
||
n_assert( this->capacity >= this->size );
|
||
if ( count < 0 || count == this->size )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ( count < this->size )
|
||
{
|
||
for ( IndexT i = count ; i < this->size; ++i )
|
||
{
|
||
this->Destroy(&(this->elements[i]));
|
||
}
|
||
this->size = count;
|
||
}
|
||
else // count > size
|
||
{
|
||
Fill(this->size, count - this->size, elm);
|
||
}
|
||
}
|
||
|
||
} // namespace Core
|
||
//------------------------------------------------------------------------------
|