libnative-utilities/include/raknet/DS_Multilist.hpp

1651 lines
47 KiB
C++
Raw Permalink Normal View History

2024-08-15 18:40:30 +08:00
/*
* Copyright (c) 2014, Oculus VR, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/// \file DS_Multilist.h
/// \internal
/// \brief ADT that can represent an unordered list, ordered list, stack, or queue with a common interface
///
#ifndef __MULTILIST_H
#define __MULTILIST_H
#include "RakAssert.hpp"
#include <string.h> // memmove
#include "Export.hpp"
#include "RakMemoryOverride.hpp"
#include "NativeTypes.hpp"
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#pragma warning( disable : 4512 ) // warning C4512: assignment operator could not be generated
#endif
/// What algorithm to use to store the data for the Multilist
enum MultilistType
{
/// Removing from the middle of the list will swap the end of the list rather than shift the elements. Push and Pop operate on the tail.
ML_UNORDERED_LIST,
/// A normal list, with the list order preserved. Push and Pop operate on the tail.
ML_STACK,
/// A queue. Push and Pop operate on the head
ML_QUEUE,
/// A list that is always kept in order. Elements must be unique, and compare against each other consistently using <, ==, and >
ML_ORDERED_LIST,
/// A list whose type can change at runtime
ML_VARIABLE_DURING_RUNTIME
};
/// The namespace DataStructures was only added to avoid compiler errors for commonly named data structures
/// As these data structures are stand-alone, you can use them outside of RakNet for your own projects if you wish.
namespace DataStructures
{
/// Can be used with Multilist::ForEach
/// Assuming the Multilist holds pointers, will delete those pointers
template <class templateType>
void DeletePtr_RakNet(templateType &ptr, const char *file, unsigned int line ) {RakNet::OP_DELETE(ptr, file, line);}
/// Can be used with Multilist::ForEach
/// Assuming the Multilist holds pointers, will delete those pointers
template <class templateType>
void DeletePtr(templateType &ptr) {delete ptr;}
/// The following is invalid.
/// bool operator<( const MyClass *myClass, const int &inputKey ) {return myClass->value < inputKey;}
/// At least one type has to be a reference to a class
/// MLKeyRef is a helper class to turn a native type into a class, so you can compare that native type against a pointer to a different class
/// Used for he Multilist, when _DataType != _KeyType
template < class templateType >
class MLKeyRef
{
public:
MLKeyRef(const templateType& input) : val(input) {}
const templateType &Get(void) const {return val;}
bool operator<( const templateType &right ) {return val < right;}
bool operator>( const templateType &right ) {return val > right;}
bool operator==( const templateType &right ) {return val == right;}
protected:
const templateType &val;
};
/// For the Multilist, when _DataType != _KeyType, you must define the comparison operators between the key and the data
/// This is non-trivial due to the need to use MLKeyRef in case the type held is a pointer to a structure or class and the key type is not a class
/// For convenience, this macro will implement the comparison operators under the following conditions
/// 1. _DataType is a pointer to a class or structure
/// 2. The key is a member variable of _DataType
#define DEFINE_MULTILIST_PTR_TO_MEMBER_COMPARISONS( _CLASS_NAME_, _KEY_TYPE_, _MEMBER_VARIABLE_NAME_ ) \
bool operator<( const DataStructures::MLKeyRef<_KEY_TYPE_> &inputKey, const _CLASS_NAME_ *cls ) {return inputKey.Get() < cls->_MEMBER_VARIABLE_NAME_;} \
bool operator>( const DataStructures::MLKeyRef<_KEY_TYPE_> &inputKey, const _CLASS_NAME_ *cls ) {return inputKey.Get() > cls->_MEMBER_VARIABLE_NAME_;} \
bool operator==( const DataStructures::MLKeyRef<_KEY_TYPE_> &inputKey, const _CLASS_NAME_ *cls ) {return inputKey.Get() == cls->_MEMBER_VARIABLE_NAME_;}
typedef uint32_t DefaultIndexType;
/// \brief The multilist, representing an abstract data type that generally holds lists.
/// \param[in] _MultilistType What type of list this is, \sa MultilistType
/// \param[in] _DataType What type of data this list holds.
/// \param[in] _KeyType If a function takes a key to sort on, what type of key this is. The comparison operator between _DataType and _KeyType must be defined
/// \param[in] _IndexType What variable type to use for indices
template <const MultilistType _MultilistType, class _DataType, class _KeyType=_DataType, class _IndexType=DefaultIndexType>
class RAK_DLL_EXPORT Multilist
{
public:
Multilist();
~Multilist();
Multilist( const Multilist& source );
Multilist& operator= ( const Multilist& source );
_DataType& operator[] ( const _IndexType position ) const;
/// Unordered list, stack is LIFO
/// QUEUE is FIFO
/// Ordered list is inserted in order
void Push(const _DataType &d, const char *file=__FILE__, unsigned int line=__LINE__ );
void Push(const _DataType &d, const _KeyType &key, const char *file=__FILE__, unsigned int line=__LINE__ );
/// \brief Gets or removes and gets an element from the list, according to the same rules as Push().
/// Ordered list is LIFO for the purposes of Pop and Peek.
_DataType &Pop(const char *file=__FILE__, unsigned int line=__LINE__);
_DataType &Peek(void) const;
/// \brief Same as Push(), except FIFO and LIFO are reversed.
/// Ordered list still inserts in order.
void PushOpposite(const _DataType &d, const char *file=__FILE__, unsigned int line=__LINE__ );
void PushOpposite(const _DataType &d, const _KeyType &key, const char *file=__FILE__, unsigned int line=__LINE__ );
/// \brief Same as Pop() and Peek(), except FIFO and LIFO are reversed.
_DataType &PopOpposite(const char *file=__FILE__, unsigned int line=__LINE__);
_DataType &PeekOpposite(void) const;
/// \brief Stack,Queue: Inserts at index indicated, elements are shifted.
/// Ordered list: Inserts, position is ignored
void InsertAtIndex(const _DataType &d, _IndexType index, const char *file=__FILE__, unsigned int line=__LINE__);
/// \brief Unordered list, removes at index indicated, swaps last element with that element.
/// Otherwise, array is shifted left to overwrite removed element
/// \details Index[0] returns the same as Pop() for a queue.
/// Same as PopOpposite() for the list and ordered list
void RemoveAtIndex(_IndexType position, const char *file=__FILE__, unsigned int line=__LINE__);
/// \brief Find the index of \a key, and remove at that index.
bool RemoveAtKey(_KeyType key, bool assertIfDoesNotExist, const char *file=__FILE__, unsigned int line=__LINE__);
/// \brief Finds the index of \a key. Return -1 if the key is not found.
_IndexType GetIndexOf(_KeyType key) const;
/// \brief Returns where in the list we should insert the item, to preserve list order.
/// Returns -1 if the item is already in the list
_IndexType GetInsertionIndex(_KeyType key) const;
/// \brief Finds the index of \a key. Return 0 if the key is not found. Useful if _DataType is always non-zero pointers.
_DataType GetPtr(_KeyType key) const;
/// \brief Iterate over the list, calling the function pointer on each element.
void ForEach(void (*func)(_DataType &item, const char *file, unsigned int line), const char *file, unsigned int line);
void ForEach(void (*func)(_DataType &item));
/// \brief Returns if the list is empty.
bool IsEmpty(void) const;
/// \brief Returns the number of elements used in the list.
_IndexType GetSize(void) const;
/// \brief Empties the list. The list is not deallocated if it is small,
/// unless \a deallocateSmallBlocks is true
void Clear( bool deallocateSmallBlocks=true, const char *file=__FILE__, unsigned int line=__LINE__ );
/// \brief Empties the list, first calling RakNet::OP_Delete on all items.
/// \details The list is not deallocated if it is small, unless \a deallocateSmallBlocks is true
void ClearPointers( bool deallocateSmallBlocks=true, const char *file=__FILE__, unsigned int line=__LINE__ );
/// \brief Empty one item from the list, first calling RakNet::OP_Delete on that item.
void ClearPointer( _KeyType key, const char *file=__FILE__, unsigned int line=__LINE__ );
/// \brief Reverses the elements in the list, and flips the sort order
/// returned by GetSortOrder() if IsSorted() returns true at the time the function is called
void ReverseList(void);
/// \brief Reallocates the list to a larger size.
/// If \a size is smaller than the value returned by GetSize(), the call does nothing.
void Reallocate(_IndexType size, const char *file=__FILE__, unsigned int line=__LINE__);
/// \brief Sorts the list unless it is an ordered list, in which it does nothing as the list is assumed to already be sorted.
/// \details However, if \a force is true, it will also resort the ordered list, useful if the comparison operator between _KeyType and _DataType would now return different results
/// Once the list is sorted, further operations to lookup by key will be log2(n) until the list is modified
void Sort(bool force);
/// \brief Sets the list to be remembered as sorted.
/// \details Optimization if the source is sorted already
void TagSorted(void);
/// \brief Defaults to ascending.
/// \details Used by Sort(), and by ML_ORDERED_LIST
void SetSortOrder(bool ascending);
/// \brief Returns true if ascending.
bool GetSortOrder(void) const;
/// \brief Returns true if the list is currently believed to be in a sorted state.
/// \details Doesn't actually check for sortedness, just if Sort()
/// was recently called, or MultilistType is ML_ORDERED_LIST
bool IsSorted(void) const;
/// Returns what type of list this is
MultilistType GetMultilistType(void) const;
/// \brief Changes what type of list this is.
/// \pre Template must be defined with ML_VARIABLE_DURING_RUNTIME for this to do anything
/// \param[in] mlType Any value of the enum MultilistType, except ML_VARIABLE_DURING_RUNTIME
void SetMultilistType(MultilistType newType);
/// \brief Returns the intersection of two lists.
/// Intersection is items common to both lists.
static void FindIntersection(
Multilist& source1,
Multilist& source2,
Multilist& intersection,
Multilist& uniqueToSource1,
Multilist& uniqueToSource2);
protected:
void ReallocateIfNeeded(const char *file, unsigned int line);
void DeallocateIfNeeded(const char *file, unsigned int line);
void ReallocToSize(_IndexType newAllocationSize, const char *file, unsigned int line);
void ReverseListInternal(void);
void InsertInOrderedList(const _DataType &d, const _KeyType &key);
_IndexType GetIndexFromKeyInSortedList(const _KeyType &key, bool *objectExists) const;
void InsertShiftArrayRight(const _DataType &d, _IndexType index);
void DeleteShiftArrayLeft(_IndexType index);
void QSortAscending(_IndexType left, _IndexType right);
void QSortDescending(_IndexType left, _IndexType right);
void CopySource( const Multilist& source );
/// An array of user values
_DataType* data;
/// Number of elements in the list
_IndexType dataSize;
/// Size of \a array
_IndexType allocationSize;
/// Array index for the head of the queue
_IndexType queueHead;
/// Array index for the tail of the queue
_IndexType queueTail;
/// How many bytes the user chose to preallocate
/// Won't automatically deallocate below this
_IndexType preallocationSize;
enum
{
ML_UNSORTED,
ML_SORTED_ASCENDING,
ML_SORTED_DESCENDING
} sortState;
bool ascendingSort;
// In case we are using the variable type multilist
MultilistType variableMultilistType;
};
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Multilist()
{
data=0;
dataSize=0;
allocationSize=0;
ascendingSort=true;
sortState=ML_UNSORTED;
queueHead=0;
queueTail=0;
preallocationSize=0;
if (_MultilistType==ML_ORDERED_LIST)
sortState=ML_SORTED_ASCENDING;
else
sortState=ML_UNSORTED;
if (_MultilistType==ML_VARIABLE_DURING_RUNTIME)
variableMultilistType=ML_UNORDERED_LIST;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::~Multilist()
{
if (data!=0)
RakNet::OP_DELETE_ARRAY(data, _FILE_AND_LINE_);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Multilist( const Multilist& source )
{
CopySource(source);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
Multilist<_MultilistType, _DataType, _KeyType, _IndexType>& Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::operator= ( const Multilist& source )
{
Clear(true);
CopySource(source);
return *this;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::CopySource( const Multilist& source )
{
dataSize=source.GetSize();
ascendingSort=source.ascendingSort;
sortState=source.sortState;
queueHead=0;
queueTail=dataSize;
preallocationSize=source.preallocationSize;
variableMultilistType=source.variableMultilistType;
if (source.data==0)
{
data=0;
allocationSize=0;
}
else
{
allocationSize=dataSize;
data = RakNet::OP_NEW_ARRAY<_DataType>(dataSize,_FILE_AND_LINE_);
_IndexType i;
for (i=0; i < dataSize; i++)
data[i]=source[i];
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_DataType& Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::operator[] ( const _IndexType position ) const
{
RakAssert(position<GetSize());
if (GetMultilistType()==ML_QUEUE)
{
if ( queueHead + position >= allocationSize )
return data[ queueHead + position - allocationSize ];
else
return data[ queueHead + position ];
}
return data[position];
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Push(const _DataType &d, const char *file, unsigned int line )
{
Push(d,d,file,line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Push(const _DataType &d, const _KeyType &key, const char *file, unsigned int line )
{
ReallocateIfNeeded(file,line);
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK)
{
data[dataSize]=d;
dataSize++;
}
else if (GetMultilistType()==ML_QUEUE)
{
data[queueTail++] = d;
if ( queueTail == allocationSize )
queueTail = 0;
dataSize++;
}
else
{
RakAssert(GetMultilistType()==ML_ORDERED_LIST);
InsertInOrderedList(d,key);
}
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK || GetMultilistType()==ML_QUEUE)
{
// Break sort if no longer sorted
if (sortState!=ML_UNSORTED && dataSize>1)
{
if (ascendingSort)
{
if ( MLKeyRef<_KeyType>(key) < operator[](dataSize-2) )
sortState=ML_UNSORTED;
}
else
{
if ( MLKeyRef<_KeyType>(key) > operator[](dataSize-2) )
sortState=ML_UNSORTED;
}
sortState=ML_UNSORTED;
}
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_DataType &Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Pop(const char *file, unsigned int line)
{
RakAssert(IsEmpty()==false);
DeallocateIfNeeded(file,line);
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK || GetMultilistType()==ML_ORDERED_LIST)
{
dataSize--;
return data[dataSize];
}
else
{
RakAssert(GetMultilistType()==ML_QUEUE);
if ( ++queueHead == allocationSize )
queueHead = 0;
if ( queueHead == 0 )
return data[ allocationSize -1 ];
dataSize--;
return data[ queueHead -1 ];
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_DataType &Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Peek(void) const
{
RakAssert(IsEmpty()==false);
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK || GetMultilistType()==ML_ORDERED_LIST)
{
return data[dataSize-1];
}
else
{
RakAssert(GetMultilistType()==ML_QUEUE);
return data[ queueHead ];
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::PushOpposite(const _DataType &d, const char *file, unsigned int line )
{
PushOpposite(d,d,file,line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::PushOpposite(const _DataType &d, const _KeyType &key, const char *file, unsigned int line )
{
ReallocateIfNeeded(file,line);
// Unordered list Push at back
if (GetMultilistType()==ML_UNORDERED_LIST)
{
data[dataSize]=d;
dataSize++;
}
else if (GetMultilistType()==ML_STACK)
{
// Stack push at front of the list, instead of back as normal
InsertAtIndex(d,0,file,line);
}
else if (GetMultilistType()==ML_QUEUE)
{
// Queue push at front of the list, instead of back as normal
InsertAtIndex(d,0,file,line);
}
else
{
RakAssert(GetMultilistType()==ML_ORDERED_LIST);
InsertInOrderedList(d,key);
}
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK || GetMultilistType()==ML_QUEUE)
{
// Break sort if no longer sorted
if (sortState!=ML_UNSORTED && dataSize>1)
{
if (ascendingSort)
{
if ( MLKeyRef<_KeyType>(key) > operator[](1) )
sortState=ML_UNSORTED;
}
else
{
if ( MLKeyRef<_KeyType>(key) < operator[](1) )
sortState=ML_UNSORTED;
}
}
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_DataType &Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::PopOpposite(const char *file, unsigned int line)
{
RakAssert(IsEmpty()==false);
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK || GetMultilistType()==ML_ORDERED_LIST)
{
// Copy leftmost to end
ReallocateIfNeeded(file,line);
data[dataSize]=data[0];
DeleteShiftArrayLeft(0);
--dataSize;
// Assuming still leaves at least one element past the end of the list allocated
DeallocateIfNeeded(file,line);
// Return end
return data[dataSize+1];
}
else
{
RakAssert(GetMultilistType()==ML_QUEUE);
// Deallocate first, since we are returning off the existing list
DeallocateIfNeeded(file,line);
dataSize--;
if (queueTail==0)
queueTail=allocationSize-1;
else
--queueTail;
return data[queueTail];
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_DataType &Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::PeekOpposite(void) const
{
RakAssert(IsEmpty()==false);
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK || GetMultilistType()==ML_ORDERED_LIST)
{
return data[0];
}
else
{
RakAssert(GetMultilistType()==ML_QUEUE);
_IndexType priorIndex;
if (queueTail==0)
priorIndex=allocationSize-1;
else
priorIndex=queueTail-1;
return data[priorIndex];
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::InsertAtIndex(const _DataType &d, _IndexType index, const char *file, unsigned int line)
{
ReallocateIfNeeded(file,line);
if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK || GetMultilistType()==ML_ORDERED_LIST)
{
if (index>=dataSize)
{
// insert at end
data[dataSize]=d;
dataSize++;
}
else
{
// insert at index
InsertShiftArrayRight(d,index);
}
}
else
{
data[queueTail++] = d;
if ( queueTail == allocationSize )
queueTail = 0;
++dataSize;
if (dataSize==1)
return;
_IndexType writeIndex, readIndex, trueWriteIndex, trueReadIndex;
writeIndex=dataSize-1;
readIndex=writeIndex-1;
while (readIndex >= index)
{
if ( queueHead + writeIndex >= allocationSize )
trueWriteIndex = queueHead + writeIndex - allocationSize;
else
trueWriteIndex = queueHead + writeIndex;
if ( queueHead + readIndex >= allocationSize )
trueReadIndex = queueHead + readIndex - allocationSize;
else
trueReadIndex = queueHead + readIndex;
data[trueWriteIndex]=data[trueReadIndex];
if (readIndex==0)
break;
writeIndex--;
readIndex--;
}
if ( queueHead + index >= allocationSize )
trueWriteIndex = queueHead + index - allocationSize;
else
trueWriteIndex = queueHead + index;
data[trueWriteIndex]=d;
}
if (_MultilistType!=ML_ORDERED_LIST)
sortState=ML_UNSORTED;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::RemoveAtIndex(_IndexType position, const char *file, unsigned int line)
{
RakAssert(position < dataSize);
RakAssert(IsEmpty()==false);
if (GetMultilistType()==ML_UNORDERED_LIST)
{
// Copy tail to current
data[position]=data[dataSize-1];
}
else if (GetMultilistType()==ML_STACK || GetMultilistType()==ML_ORDERED_LIST)
{
DeleteShiftArrayLeft(position);
}
else
{
RakAssert(GetMultilistType()==ML_QUEUE);
_IndexType index, next;
if ( queueHead + position >= allocationSize )
index = queueHead + position - allocationSize;
else
index = queueHead + position;
next = index + 1;
if ( next == allocationSize )
next = 0;
while ( next != queueTail )
{
// Overwrite the previous element
data[ index ] = data[ next ];
index = next;
//next = (next + 1) % allocationSize;
if ( ++next == allocationSize )
next = 0;
}
// Move the queueTail back
if ( queueTail == 0 )
queueTail = allocationSize - 1;
else
--queueTail;
}
dataSize--;
DeallocateIfNeeded(file,line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
bool Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::RemoveAtKey(_KeyType key, bool assertIfDoesNotExist, const char *file, unsigned int line)
{
_IndexType index = GetIndexOf(key);
if (index==(_IndexType)-1)
{
RakAssert(assertIfDoesNotExist==false && "RemoveAtKey element not found");
return false;
}
RemoveAtIndex(index,file,line);
return true;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_IndexType Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::GetIndexOf(_KeyType key) const
{
_IndexType i;
if (IsSorted())
{
bool objectExists;
i=GetIndexFromKeyInSortedList(key, &objectExists);
if (objectExists)
return i;
return (_IndexType)-1;
}
else if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK)
{
for (i=0; i < dataSize; i++)
{
if (MLKeyRef<_KeyType>(key)==data[i])
return i;
}
return (_IndexType)-1;
}
else
{
RakAssert( GetMultilistType()==ML_QUEUE );
for (i=0; i < dataSize; i++)
{
if (MLKeyRef<_KeyType>(key)==operator[](i))
return i;
}
return (_IndexType)-1;
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_IndexType Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::GetInsertionIndex(_KeyType key) const
{
_IndexType i;
if (IsSorted())
{
bool objectExists;
i=GetIndexFromKeyInSortedList(key, &objectExists);
if (objectExists)
return (_IndexType)-1;
return i;
}
else if (GetMultilistType()==ML_UNORDERED_LIST || GetMultilistType()==ML_STACK)
{
for (i=0; i < dataSize; i++)
{
if (MLKeyRef<_KeyType>(key)==data[i])
return (_IndexType)-1;
}
return dataSize;
}
else
{
RakAssert( GetMultilistType()==ML_QUEUE );
for (i=0; i < dataSize; i++)
{
if (MLKeyRef<_KeyType>(key)==operator[](i))
return (_IndexType)-1;
}
return dataSize;
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_DataType Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::GetPtr(_KeyType key) const
{
_IndexType i = GetIndexOf(key);
if (i==(_IndexType)-1)
return 0;
return data[i];
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ForEach(void (*func)(_DataType &item, const char *file, unsigned int line), const char *file, unsigned int line)
{
_IndexType i;
for (i=0; i < dataSize; i++)
func(operator[](i), file, line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ForEach(void (*func)(_DataType &item))
{
_IndexType i;
for (i=0; i < dataSize; i++)
func(operator[](i));
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
bool Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::IsEmpty(void) const
{
return dataSize==0;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_IndexType Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::GetSize(void) const
{
return dataSize;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Clear( bool deallocateSmallBlocks, const char *file, unsigned int line )
{
dataSize=0;
if (GetMultilistType()==ML_ORDERED_LIST)
if (ascendingSort)
sortState=ML_SORTED_ASCENDING;
else
sortState=ML_SORTED_DESCENDING;
else
sortState=ML_UNSORTED;
queueHead=0;
queueTail=0;
if (deallocateSmallBlocks && allocationSize < 128 && data)
{
RakNet::OP_DELETE_ARRAY(data,file,line);
data=0;
allocationSize=0;
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ClearPointers( bool deallocateSmallBlocks, const char *file, unsigned int line )
{
_IndexType i;
for (i=0; i < dataSize; i++)
RakNet::OP_DELETE(operator[](i), file, line);
Clear(deallocateSmallBlocks, file, line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ClearPointer( _KeyType key, const char *file, unsigned int line )
{
_IndexType i;
i = GetIndexOf(key);
if (i!=-1)
{
RakNet::OP_DELETE(operator[](i), file, line);
RemoveAtIndex(i);
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ReverseList(void)
{
if (IsSorted())
ascendingSort=!ascendingSort;
ReverseListInternal();
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Reallocate(_IndexType size, const char *file, unsigned int line)
{
_IndexType newAllocationSize;
if (size < dataSize)
newAllocationSize=dataSize;
else
newAllocationSize=size;
preallocationSize=size;
ReallocToSize(newAllocationSize,file,line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::Sort(bool force)
{
if (IsSorted() && force==false)
return;
if (dataSize>1)
{
if (ascendingSort)
QSortAscending(0,dataSize-1);
else
QSortDescending(0,dataSize-1);
}
TagSorted();
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::TagSorted(void)
{
if (ascendingSort)
sortState=ML_SORTED_ASCENDING;
else
sortState=ML_SORTED_DESCENDING;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::QSortAscending(_IndexType leftEdge, _IndexType rightEdge)
{
_DataType temp;
_IndexType left=leftEdge;
_IndexType right=rightEdge;
_IndexType pivotIndex=left++;
while (left<right)
{
if (data[left] <= data[pivotIndex])
{
++left;
}
else
{
temp=data[left];
data[left]=data[right];
data[right]=temp;
--right;
}
}
temp=data[pivotIndex];
// Move pivot to center
if (data[left] > data[pivotIndex])
{
--left;
data[pivotIndex]=data[left];
data[left]=temp;
}
else
{
data[pivotIndex]=data[left];
data[left]=temp;
--left;
}
if (left!=leftEdge)
QSortAscending(leftEdge, left);
if (right!=rightEdge)
QSortAscending(right, rightEdge);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::QSortDescending(_IndexType leftEdge, _IndexType rightEdge)
{
_DataType temp;
_IndexType left=leftEdge;
_IndexType right=rightEdge;
_IndexType pivotIndex=left++;
while (left<right)
{
if (data[left] >= data[pivotIndex])
{
++left;
}
else
{
temp=data[left];
data[left]=data[right];
data[right]=temp;
--right;
}
}
temp=data[pivotIndex];
// Move pivot to center
if (data[left] < data[pivotIndex])
{
--left;
data[pivotIndex]=data[left];
data[left]=temp;
}
else
{
data[pivotIndex]=data[left];
data[left]=temp;
--left;
}
if (left!=leftEdge)
QSortDescending(leftEdge, left);
if (right!=rightEdge)
QSortDescending(right, rightEdge);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::SetSortOrder(bool ascending)
{
if (ascendingSort!=ascending && IsSorted())
{
ascendingSort=ascending;
// List is sorted, and the sort order has changed. So reverse the list
ReverseListInternal();
}
else
ascendingSort=ascending;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
bool Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::GetSortOrder(void) const
{
return ascendingSort;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
bool Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::IsSorted(void) const
{
return GetMultilistType()==ML_ORDERED_LIST || sortState!=ML_UNSORTED;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
MultilistType Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::GetMultilistType(void) const
{
if (_MultilistType==ML_VARIABLE_DURING_RUNTIME)
return variableMultilistType;
return _MultilistType;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::SetMultilistType(MultilistType newType)
{
RakAssert(_MultilistType==ML_VARIABLE_DURING_RUNTIME);
switch (variableMultilistType)
{
case ML_UNORDERED_LIST:
switch (newType)
{
case ML_UNORDERED_LIST:
// No change
break;
case ML_STACK:
// Same data format
break;
case ML_QUEUE:
queueHead=0;
queueTail=dataSize;
break;
case ML_ORDERED_LIST:
Sort(false);
break;
}
break;
case ML_STACK:
switch (newType)
{
case ML_UNORDERED_LIST:
// Same data format
break;
case ML_STACK:
// No change
break;
case ML_QUEUE:
queueHead=0;
queueTail=dataSize;
break;
case ML_ORDERED_LIST:
Sort(false);
break;
}
break;
case ML_QUEUE:
switch (newType)
{
case ML_UNORDERED_LIST:
case ML_STACK:
case ML_ORDERED_LIST:
if (queueTail < queueHead)
{
// Realign data if wrapped
ReallocToSize(dataSize, _FILE_AND_LINE_);
}
else
{
// Else can just copy starting at head
_IndexType i;
for (i=0; i < dataSize; i++)
data[i]=operator[](i);
}
if (newType==ML_ORDERED_LIST)
Sort(false);
break;
case ML_QUEUE:
// No change
break;
}
break;
case ML_ORDERED_LIST:
switch (newType)
{
case ML_UNORDERED_LIST:
case ML_STACK:
case ML_QUEUE:
// Same data format
// Tag as sorted
if (ascendingSort)
sortState=ML_SORTED_ASCENDING;
else
sortState=ML_SORTED_DESCENDING;
if (newType==ML_QUEUE)
{
queueHead=0;
queueTail=dataSize;
}
break;
case ML_ORDERED_LIST:
// No change
break;
}
break;
}
variableMultilistType=newType;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::FindIntersection(
Multilist& source1,
Multilist& source2,
Multilist& intersection,
Multilist& uniqueToSource1,
Multilist& uniqueToSource2)
{
_IndexType index1=0, index2=0;
source1.SetSortOrder(true);
source2.SetSortOrder(true);
source1.Sort(false);
source2.Sort(false);
intersection.Clear(true,_FILE_AND_LINE_);
uniqueToSource1.Clear(true,_FILE_AND_LINE_);
uniqueToSource2.Clear(true,_FILE_AND_LINE_);
while (index1 < source1.GetSize() && index2 < source2.GetSize())
{
if (source1[index1]<source2[index2])
{
uniqueToSource1.Push(source1[index1],_FILE_AND_LINE_);
index1++;
}
else if (source1[index1]==source2[index2])
{
intersection.Push(source1[index1],_FILE_AND_LINE_);
index1++;
index2++;
}
else
{
uniqueToSource2.Push(source2[index2],_FILE_AND_LINE_);
index2++;
}
}
while (index1 < source1.GetSize())
{
uniqueToSource1.Push(source1[index1],_FILE_AND_LINE_);
index1++;
}
while (index2 < source2.GetSize())
{
uniqueToSource2.Push(source2[index2],_FILE_AND_LINE_);
index2++;
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ReallocateIfNeeded(const char *file, unsigned int line)
{
if (dataSize<allocationSize)
return;
_IndexType newAllocationSize;
if (allocationSize<16)
newAllocationSize=32;
else if (allocationSize>65536)
newAllocationSize=allocationSize+65536;
else
{
newAllocationSize=allocationSize<<1; // * 2
// Protect against underflow
if (newAllocationSize < allocationSize)
newAllocationSize=allocationSize+65536;
}
ReallocToSize(newAllocationSize,file,line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::DeallocateIfNeeded(const char *file, unsigned int line)
{
if (allocationSize<512)
return;
if (dataSize >= allocationSize/3 )
return;
if (dataSize <= preallocationSize )
return;
_IndexType newAllocationSize = dataSize<<1; // * 2
ReallocToSize(newAllocationSize,file,line);
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ReallocToSize(_IndexType newAllocationSize, const char *file, unsigned int line)
{
_DataType* newData = RakNet::OP_NEW_ARRAY<_DataType>(newAllocationSize,file,line);
_IndexType i;
for (i=0; i < dataSize; i++)
newData[i]=operator[](i);
if (dataSize>0)
{
RakNet::OP_DELETE_ARRAY(data,file,line);
if (GetMultilistType()==ML_QUEUE)
{
queueHead=0;
queueTail=dataSize;
}
}
data=newData;
allocationSize=newAllocationSize;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::ReverseListInternal(void)
{
_DataType temp;
_IndexType i;
for (i=0; i < dataSize/2; i++)
{
temp=operator[](i);
operator[](i)=operator[](dataSize-1-i);
operator[](dataSize-1-i)=temp;
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::InsertInOrderedList(const _DataType &d, const _KeyType &key)
{
RakAssert(GetMultilistType()==ML_ORDERED_LIST);
bool objectExists;
_IndexType index;
index = GetIndexFromKeyInSortedList(key, &objectExists);
// if (objectExists)
// {
// Ordered list only allows unique insertions
// RakAssert("Duplicate insertion into ordered list" && false);
// return;
// }
if (index>=dataSize)
{
// insert at end
data[dataSize]=d;
dataSize++;
}
else
{
// insert at index
InsertShiftArrayRight(d,index);
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
_IndexType Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::GetIndexFromKeyInSortedList(const _KeyType &key, bool *objectExists) const
{
RakAssert(IsSorted());
_IndexType index, upperBound, lowerBound;
if (dataSize==0)
{
*objectExists=false;
return 0;
}
upperBound=dataSize-1;
lowerBound=0;
index = dataSize/2;
#ifdef _MSC_VER
#pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
#endif
while (1)
{
if (MLKeyRef<_KeyType>(key) > operator[](index) )
{
if (ascendingSort)
lowerBound=index+1;
else
upperBound=index-1;
}
else if (MLKeyRef<_KeyType>(key) < operator[](index) )
{
if (ascendingSort)
upperBound=index-1;
else
lowerBound=index+1;
}
else
{
// ==
*objectExists=true;
return index;
}
index=lowerBound+(upperBound-lowerBound)/2;
if (lowerBound>upperBound || upperBound==(_IndexType)-1)
{
*objectExists=false;
return lowerBound; // No match
}
}
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::InsertShiftArrayRight(const _DataType &d, _IndexType index)
{
RakAssert(_MultilistType!=ML_QUEUE);
// Move the elements in the list to make room
_IndexType i;
for ( i = dataSize; i != index; i-- )
data[ i ] = data[ i - 1 ];
// Insert the new item at the correct spot
data[ index ] = d;
++dataSize;
}
template <const MultilistType _MultilistType, class _DataType, class _KeyType, class _IndexType>
void Multilist<_MultilistType, _DataType, _KeyType, _IndexType>::DeleteShiftArrayLeft( _IndexType index )
{
RakAssert(index < dataSize);
RakAssert(_MultilistType!=ML_QUEUE);
_IndexType i;
for ( i = index; i < dataSize-1; i++ )
data[i]=data[i+1];
}
};
/*
struct KeyAndValue
{
int key;
short value;
};
DEFINE_MULTILIST_PTR_TO_MEMBER_COMPARISONS(KeyAndValue,int,key)
void MultilistUnitTest(void)
{
DataStructures::DefaultIndexType oldSize;
DataStructures::Multilist<ML_UNORDERED_LIST, int> ml1;
ml1.Reallocate(64);
RakAssert(ml1.IsEmpty());
ml1.Push(53);
RakAssert(ml1.Peek()==53);
RakAssert(ml1.IsEmpty()==false);
RakAssert(ml1.Pop()==53);
RakAssert(ml1.IsEmpty()==true);
for (int i=0; i < 512; i++)
ml1.Push(i);
RakAssert(ml1.GetIndexOf(200)==200);
RakAssert(ml1.PeekOpposite()==0);
RakAssert(ml1.PopOpposite()==0);
RakAssert(ml1.PeekOpposite()==1);
RakAssert(ml1.Peek()==511);
ml1.ReverseList();
for (int i=0; i < 511; i++)
RakAssert(ml1[i]==511-i);
RakAssert(ml1.PeekOpposite()==511);
RakAssert(ml1.Peek()==1);
oldSize = ml1.GetSize();
ml1.RemoveAtIndex(0);
RakAssert(ml1.GetSize()==oldSize-1);
RakAssert(ml1.PeekOpposite()==1);
ml1.Clear(_FILE_AND_LINE_);
RakAssert(ml1.IsEmpty()==true);
ml1.Sort(true);
ml1.Clear(_FILE_AND_LINE_);
ml1.Push(100);
ml1.Sort(true);
ml1.Clear(_FILE_AND_LINE_);
ml1.Push(50);
ml1.Push(100);
ml1.Sort(true);
ml1.Clear(_FILE_AND_LINE_);
ml1.Push(100);
ml1.Push(50);
ml1.Sort(true);
ml1.Clear(_FILE_AND_LINE_);
ml1.Push(100);
ml1.Push(50);
ml1.Push(150);
ml1.Push(25);
ml1.Push(175);
ml1.Sort(true);
RakAssert(ml1[0]==25);
RakAssert(ml1[1]==50);
RakAssert(ml1[2]==100);
RakAssert(ml1[3]==150);
RakAssert(ml1[4]==175);
RakAssert(ml1.GetIndexOf(25)==0);
RakAssert(ml1.GetIndexOf(50)==1);
RakAssert(ml1.GetIndexOf(100)==2);
RakAssert(ml1.GetIndexOf(150)==3);
RakAssert(ml1.GetIndexOf(175)==4);
ml1.Clear(_FILE_AND_LINE_);
ml1.Push(1);
ml1.Push(2);
ml1.Push(3);
ml1.Push(4);
ml1.Push(5);
ml1.Sort(true);
RakAssert(ml1[0]==1);
RakAssert(ml1[1]==2);
RakAssert(ml1[2]==3);
RakAssert(ml1[3]==4);
RakAssert(ml1[4]==5);
RakAssert(ml1.GetIndexOf(1)==0);
RakAssert(ml1.GetIndexOf(2)==1);
RakAssert(ml1.GetIndexOf(3)==2);
RakAssert(ml1.GetIndexOf(4)==3);
RakAssert(ml1.GetIndexOf(5)==4);
ml1.Clear(_FILE_AND_LINE_);
ml1.Push(5);
ml1.Push(4);
ml1.Push(3);
ml1.Push(2);
ml1.Push(1);
ml1.Sort(true);
RakAssert(ml1[0]==1);
RakAssert(ml1[1]==2);
RakAssert(ml1[2]==3);
RakAssert(ml1[3]==4);
RakAssert(ml1[4]==5);
RakAssert(ml1.GetIndexOf(1)==0);
RakAssert(ml1.GetIndexOf(2)==1);
RakAssert(ml1.GetIndexOf(3)==2);
RakAssert(ml1.GetIndexOf(4)==3);
RakAssert(ml1.GetIndexOf(5)==4);
ml1.Sort(true);
RakAssert(ml1[0]==1);
RakAssert(ml1[1]==2);
RakAssert(ml1[2]==3);
RakAssert(ml1[3]==4);
RakAssert(ml1[4]==5);
RakAssert(ml1.GetIndexOf(1)==0);
RakAssert(ml1.GetIndexOf(2)==1);
RakAssert(ml1.GetIndexOf(3)==2);
RakAssert(ml1.GetIndexOf(4)==3);
RakAssert(ml1.GetIndexOf(5)==4);
ml1.Clear(_FILE_AND_LINE_);
DataStructures::Multilist<ML_STACK, int> ml2;
ml2.Reallocate(64);
RakAssert(ml2.IsEmpty());
ml2.Push(53);
RakAssert(ml2.Peek()==53);
RakAssert(ml2.IsEmpty()==false);
RakAssert(ml2.Pop()==53);
RakAssert(ml2.IsEmpty()==true);
for (int i=0; i < 512; i++)
ml2.Push(i);
RakAssert(ml2.GetIndexOf(200)==200);
RakAssert(ml2.PeekOpposite()==0);
RakAssert(ml2.PopOpposite()==0);
RakAssert(ml2.PeekOpposite()==1);
RakAssert(ml2.Peek()==511);
ml2.ReverseList();
for (int i=0; i < 511; i++)
RakAssert(ml2[i]==511-i);
RakAssert(ml2.PeekOpposite()==511);
RakAssert(ml2.Peek()==1);
oldSize = ml2.GetSize();
ml2.RemoveAtIndex(0);
RakAssert(ml2.GetSize()==oldSize-1);
RakAssert(ml2.Peek()==1);
RakAssert(ml2.PeekOpposite()==510);
ml2.Clear(_FILE_AND_LINE_);
RakAssert(ml2.IsEmpty()==true);
DataStructures::Multilist<ML_QUEUE, int> ml3;
RakAssert(ml3.IsEmpty());
ml3.Push(53);
RakAssert(ml3.Peek()==53);
RakAssert(ml3.IsEmpty()==false);
RakAssert(ml3.Pop()==53);
RakAssert(ml3.IsEmpty()==true);
for (int i=0; i < 512; i++)
ml3.Push(i);
RakAssert(ml3.GetIndexOf(200)==200);
RakAssert(ml3.PeekOpposite()==511);
RakAssert(ml3.PopOpposite()==511);
RakAssert(ml3.PeekOpposite()==510);
RakAssert(ml3.Peek()==0);
ml3.ReverseList();
for (int i=0; i < 511; i++)
RakAssert(ml3[i]==511-1-i);
RakAssert(ml3.PeekOpposite()==0);
RakAssert(ml3.Peek()==510);
oldSize = ml3.GetSize();
ml3.RemoveAtIndex(0);
RakAssert(ml3.GetSize()==oldSize-1);
RakAssert(ml3.Peek()==509);
RakAssert(ml3.PeekOpposite()==0);
ml3.Clear(_FILE_AND_LINE_);
RakAssert(ml3.IsEmpty()==true);
ml3.PushOpposite(100);
ml3.PushOpposite(50);
ml3.PushOpposite(150);
ml3.PushOpposite(25);
ml3.PushOpposite(175);
ml3.Sort(true);
RakAssert(ml3[0]==25);
RakAssert(ml3[1]==50);
RakAssert(ml3[2]==100);
RakAssert(ml3[3]==150);
RakAssert(ml3[4]==175);
RakAssert(ml3.GetIndexOf(25)==0);
RakAssert(ml3.GetIndexOf(50)==1);
RakAssert(ml3.GetIndexOf(100)==2);
RakAssert(ml3.GetIndexOf(150)==3);
RakAssert(ml3.GetIndexOf(175)==4);
ml3.Clear(_FILE_AND_LINE_);
ml3.PushOpposite(1);
ml3.PushOpposite(2);
ml3.PushOpposite(3);
ml3.PushOpposite(4);
ml3.PushOpposite(5);
ml3.Sort(true);
RakAssert(ml3[0]==1);
RakAssert(ml3[1]==2);
RakAssert(ml3[2]==3);
RakAssert(ml3[3]==4);
RakAssert(ml3[4]==5);
RakAssert(ml3.GetIndexOf(1)==0);
RakAssert(ml3.GetIndexOf(2)==1);
RakAssert(ml3.GetIndexOf(3)==2);
RakAssert(ml3.GetIndexOf(4)==3);
RakAssert(ml3.GetIndexOf(5)==4);
ml3.Clear(_FILE_AND_LINE_);
ml3.PushOpposite(5);
ml3.PushOpposite(4);
ml3.PushOpposite(3);
ml3.PushOpposite(2);
ml3.PushOpposite(1);
ml3.Sort(true);
RakAssert(ml3[0]==1);
RakAssert(ml3[1]==2);
RakAssert(ml3[2]==3);
RakAssert(ml3[3]==4);
RakAssert(ml3[4]==5);
RakAssert(ml3.GetIndexOf(1)==0);
RakAssert(ml3.GetIndexOf(2)==1);
RakAssert(ml3.GetIndexOf(3)==2);
RakAssert(ml3.GetIndexOf(4)==3);
RakAssert(ml3.GetIndexOf(5)==4);
ml3.Sort(true);
RakAssert(ml3[0]==1);
RakAssert(ml3[1]==2);
RakAssert(ml3[2]==3);
RakAssert(ml3[3]==4);
RakAssert(ml3[4]==5);
RakAssert(ml3.GetIndexOf(1)==0);
RakAssert(ml3.GetIndexOf(2)==1);
RakAssert(ml3.GetIndexOf(3)==2);
RakAssert(ml3.GetIndexOf(4)==3);
RakAssert(ml3.GetIndexOf(5)==4);
ml3.SetSortOrder(false);
ml3.Sort(false);
RakAssert(ml3[0]==5);
RakAssert(ml3[1]==4);
RakAssert(ml3[2]==3);
RakAssert(ml3[3]==2);
RakAssert(ml3[4]==1);
RakAssert(ml3.GetIndexOf(1)==4);
RakAssert(ml3.GetIndexOf(2)==3);
RakAssert(ml3.GetIndexOf(3)==2);
RakAssert(ml3.GetIndexOf(4)==1);
RakAssert(ml3.GetIndexOf(5)==0);
ml3.Clear(_FILE_AND_LINE_);
DataStructures::Multilist<ML_ORDERED_LIST, int> ml4;
ml4.Reallocate(64);
RakAssert(ml4.IsEmpty());
ml4.Push(53);
RakAssert(ml4.Peek()==53);
RakAssert(ml4.IsEmpty()==false);
RakAssert(ml4.Pop()==53);
RakAssert(ml4.IsEmpty()==true);
for (int i=0; i < 512; i++)
ml4.Push(i);
RakAssert(ml4.GetIndexOf(200)==200);
RakAssert(ml4.PeekOpposite()==0);
RakAssert(ml4.PopOpposite()==0);
RakAssert(ml4.PeekOpposite()==1);
RakAssert(ml4.Peek()==511);
ml4.ReverseList();
for (int i=0; i < 511; i++)
RakAssert(ml4[i]==511-i);
RakAssert(ml4.PeekOpposite()==511);
RakAssert(ml4.Peek()==1);
oldSize = ml4.GetSize();
ml4.RemoveAtIndex(0);
RakAssert(ml4.GetSize()==oldSize-1);
RakAssert(ml4.Peek()==1);
RakAssert(ml4.PeekOpposite()==510);
ml4.Clear(_FILE_AND_LINE_);
RakAssert(ml4.IsEmpty()==true);
DataStructures::Multilist<ML_ORDERED_LIST, KeyAndValue*, int> ml5;
for (int i=0; i < 16; i++)
{
KeyAndValue *kav = new KeyAndValue;
kav->key=i;
kav->value=i+100;
ml5.Push(kav,kav->key);
}
RakAssert(ml5.GetIndexOf(0)==0);
RakAssert(ml5.GetIndexOf(5)==5);
RakAssert(ml5.GetIndexOf(15)==15);
RakAssert(ml5.GetIndexOf(16)==-1);
ml5.RemoveAtKey(0,true);
RakAssert(ml5.GetIndexOf(1)==0);
KeyAndValue *iPtr = ml5.GetPtr(5);
RakAssert(iPtr);
RakAssert(iPtr->value=105);
iPtr = ml5.GetPtr(1234);
RakAssert(iPtr==0);
ml5.ForEach(DataStructures::DeletePtr<KeyAndValue*>);
DataStructures::Multilist<ML_VARIABLE_DURING_RUNTIME, int> ml6;
ml6.Push(2);
ml6.Push(1);
ml6.Push(6);
ml6.Push(3);
RakAssert(ml6.Peek()==3);
ml6.SetMultilistType(ML_STACK);
RakAssert(ml6.Peek()==3);
ml6.SetMultilistType(ML_QUEUE);
RakAssert(ml6.Peek()==2);
ml6.SetMultilistType(ML_ORDERED_LIST);
RakAssert(ml6.Peek()=6);
ml6.SetMultilistType(ML_STACK);
RakAssert(ml6.Peek()==6);
ml6.SetMultilistType(ML_QUEUE);
RakAssert(ml6.Peek()==1);
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
*/
#endif