genesis-3d_engine/Engine/foundation/util/array.h
zhongdaohuan 6e8fbca745 genesis-3d engine version 1.3.
match the genesis editor version 1.3.0.653.
2014-05-05 14:50:33 +08:00

1184 lines
30 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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
//------------------------------------------------------------------------------