1705 lines
41 KiB
C++
1705 lines
41 KiB
C++
////////////////////////////////////////////////////////////////////
|
|
// List.h
|
|
//
|
|
// Copyright 2007 cDc@seacave
|
|
// Distributed under the Boost Software License, Version 1.0
|
|
// (See http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#ifndef __SEACAVE_LIST_H__
|
|
#define __SEACAVE_LIST_H__
|
|
|
|
|
|
// I N C L U D E S /////////////////////////////////////////////////
|
|
|
|
#include <utility>
|
|
|
|
|
|
// D E F I N E S ///////////////////////////////////////////////////
|
|
|
|
#ifndef _USE_VECTORINTERFACE
|
|
#define _USE_VECTORINTERFACE 1
|
|
#endif
|
|
|
|
// cList index type
|
|
#ifdef _SUPPORT_CPP11
|
|
#define ARR2IDX(arr) typename std::remove_reference<decltype(arr)>::type::size_type
|
|
#define SIZE2IDX(arr) typename std::remove_const<typename std::remove_reference<decltype(arr)>::type>::type
|
|
#else
|
|
#define ARR2IDX(arr) IDX
|
|
#define SIZE2IDX(arr) IDX
|
|
#endif
|
|
|
|
// cList iterator by index
|
|
#ifndef FOREACH
|
|
#define FOREACH(var, arr) for (ARR2IDX(arr) var=0, var##Size=(arr).size(); var<var##Size; ++var)
|
|
#endif
|
|
#ifndef RFOREACH
|
|
#define RFOREACH(var, arr) for (ARR2IDX(arr) var=(arr).size(); var-->0; )
|
|
#endif
|
|
// cList iterator by pointer
|
|
#ifndef FOREACHPTR
|
|
#define FOREACHPTR(var, arr) for (auto var=(arr).begin(), var##End=(arr).end(); var!=var##End; ++var)
|
|
#endif
|
|
#ifndef RFOREACHPTR
|
|
#define RFOREACHPTR(var, arr) for (auto var=(arr).end(), var##Begin=(arr).begin(); var--!=var##Begin; )
|
|
#endif
|
|
|
|
// raw data array iterator by index
|
|
#ifndef FOREACHRAW
|
|
#define FOREACHRAW(var, sz) for (SIZE2IDX(sz) var=0, var##Size=(sz); var<var##Size; ++var)
|
|
#endif
|
|
#ifndef RFOREACHRAW
|
|
#define RFOREACHRAW(var, sz) for (SIZE2IDX(sz) var=sz; var-->0; )
|
|
#endif
|
|
// raw data array iterator by pointer
|
|
#ifndef FOREACHRAWPTR
|
|
#define FOREACHRAWPTR(var, arr, sz) for (auto var=(arr), var##End=var+sz; var!=var##End; ++var)
|
|
#endif
|
|
#ifndef RFOREACHRAWPTR
|
|
#define RFOREACHRAWPTR(var, arr, sz) for (auto var##Begin=(arr), var=var##Begin+sz; var--!=var##Begin; )
|
|
#endif
|
|
|
|
// constructs a cList reference to a given raw data array
|
|
#ifndef CLISTREFRAW
|
|
#define CLISTREFRAW(CLIST, var, arr, sz) uint8_t _ArrData##var[sizeof(CLIST)]; new(_ArrData##var) CLIST(sz, const_cast<CLIST::Type*>(arr)); const CLIST& var(*reinterpret_cast<const CLIST*>(_ArrData##var))
|
|
#endif
|
|
// constructs a cList reference to a given std::_vector
|
|
#ifndef CLISTREFVECTOR
|
|
#define CLISTREFVECTOR(CLIST, var, vec) uint8_t _ArrData##var[sizeof(CLIST)]; new(_ArrData##var) CLIST(vec.size(), const_cast<CLIST::Type*>(&vec[0])); const CLIST& var(*reinterpret_cast<const CLIST*>(_ArrData##var))
|
|
#endif
|
|
|
|
#define CLISTDEF0(TYPE) SEACAVE::cList< TYPE, const TYPE&, 0 >
|
|
#define CLISTDEF2(TYPE) SEACAVE::cList< TYPE, const TYPE&, 2 >
|
|
#define CLISTDEF0IDX(TYPE,IDXTYPE) SEACAVE::cList< TYPE, const TYPE&, 0, 16, IDXTYPE >
|
|
#define CLISTDEFIDX(TYPE,IDXTYPE) SEACAVE::cList< TYPE, const TYPE&, 1, 16, IDXTYPE >
|
|
#define CLISTDEF2IDX(TYPE,IDXTYPE) SEACAVE::cList< TYPE, const TYPE&, 2, 16, IDXTYPE >
|
|
|
|
#ifndef STCALL
|
|
#define STCALL
|
|
#endif
|
|
|
|
|
|
namespace SEACAVE {
|
|
|
|
// S T R U C T S ///////////////////////////////////////////////////
|
|
|
|
typedef size_t IDX;
|
|
#define NO_IDX DECLARE_NO_INDEX(IDX)
|
|
|
|
/**************************************************************************************
|
|
* List template
|
|
* --------------
|
|
* fast array
|
|
* - set "useConstruct" to 0 for not using constructors/destructors
|
|
* when adding/removing elements to the array
|
|
* - set "useConstruct" to 1 for using memcpy/memmove when moving arrays
|
|
* instead of copy-constructors
|
|
* - set "useConstruct" to 2 for always using constructors/destructors
|
|
* - set "grow" to the number of elements to increase the allocated array
|
|
* when more space is needed
|
|
* - if using sorting, the operator < needs to be implemented (the
|
|
* operator == is also needed if argument is not ARG_TYPE)
|
|
**************************************************************************************/
|
|
|
|
template <
|
|
typename TYPE,
|
|
typename ARG_TYPE=const TYPE&,
|
|
int useConstruct=1,
|
|
int grow=16,
|
|
typename IDX_TYPE=IDX>
|
|
class cList
|
|
{
|
|
public:
|
|
typedef TYPE Type;
|
|
typedef ARG_TYPE ArgType;
|
|
typedef IDX_TYPE IDX;
|
|
typedef int (STCALL *TFncCompare)(const void* elem, const void* key); //returns 0 if equal, otherwise <0 or >0 respectively
|
|
|
|
// construct an empty list
|
|
inline cList() : _size(0), _vectorSize(0), _vector(NULL)
|
|
{
|
|
}
|
|
|
|
// construct a list containing size initialized elements
|
|
cList(IDX size) : _size(size), _vectorSize(size), _vector((TYPE*)operator new[] (size * sizeof(TYPE)))
|
|
{
|
|
ASSERT(size > 0 && size < NO_INDEX);
|
|
_ArrayConstruct(_vector, size);
|
|
}
|
|
|
|
// construct a list containing size initialized elements and allocated space for _reserved elements
|
|
cList(IDX size, IDX _reserved) : _size(size), _vectorSize(_reserved), _vector((TYPE*)operator new[] (_reserved * sizeof(TYPE)))
|
|
{
|
|
ASSERT(_reserved >= size && _reserved < NO_INDEX);
|
|
_ArrayConstruct(_vector, size);
|
|
}
|
|
|
|
// copy constructor: creates a deep-copy of the given list
|
|
cList(const cList& rList) : _size(rList._size), _vectorSize(rList._vectorSize), _vector(NULL)
|
|
{
|
|
if (_vectorSize == 0) {
|
|
ASSERT(_size == 0);
|
|
return;
|
|
}
|
|
_vector = (TYPE*)(operator new[] (_vectorSize * sizeof(TYPE)));
|
|
_ArrayCopyConstruct(_vector, rList._vector, _size);
|
|
}
|
|
#ifdef _SUPPORT_CPP11
|
|
// copy constructor: creates a move-copy of the given list
|
|
cList(cList&& rList) : _size(rList._size), _vectorSize(rList._vectorSize), _vector(rList._vector)
|
|
{
|
|
rList._Init();
|
|
}
|
|
#endif
|
|
|
|
// constructor a list from a raw data array
|
|
explicit inline cList(TYPE* pDataBegin, TYPE* pDataEnd) : _size((IDX)(pDataEnd-pDataBegin)), _vectorSize(_size)
|
|
{
|
|
if (_vectorSize == 0)
|
|
return;
|
|
_vector = (TYPE*) operator new[] (_vectorSize * sizeof(TYPE));
|
|
_ArrayCopyConstruct(_vector, pDataBegin, _size);
|
|
}
|
|
|
|
// constructor a list from a raw data array, taking ownership of the array memory
|
|
explicit inline cList(IDX nSize, TYPE* pData) : _size(nSize), _vectorSize(nSize), _vector(pData)
|
|
{
|
|
}
|
|
|
|
inline ~cList()
|
|
{
|
|
_Release();
|
|
}
|
|
|
|
// copy the content from the given list
|
|
inline cList& operator=(const cList& rList)
|
|
{
|
|
return CopyOf(rList);
|
|
}
|
|
|
|
inline cList& CopyOf(const cList& rList, bool bForceResize=false)
|
|
{
|
|
if (this == &rList)
|
|
return *this;
|
|
if (bForceResize || _vectorSize < rList._vectorSize) {
|
|
_Release();
|
|
_vectorSize = rList._vectorSize;
|
|
_vector = (TYPE*) operator new[] (_vectorSize * sizeof(TYPE));
|
|
_ArrayCopyConstruct(_vector, rList._vector, rList._size);
|
|
} else {
|
|
if (_size >= rList._size) {
|
|
_ArrayDestruct(_vector+rList._size, _size-rList._size);
|
|
_ArrayCopyRestrict(_vector, rList._vector, rList._size);
|
|
} else {
|
|
_ArrayCopyRestrict(_vector, rList._vector, _size);
|
|
_ArrayCopyConstruct(_vector+_size, rList._vector+_size, rList._size-_size);
|
|
}
|
|
}
|
|
_size = rList._size;
|
|
return *this;
|
|
}
|
|
|
|
inline cList& CopyOf(const TYPE* pData, IDX nSize, bool bForceResize=false)
|
|
{
|
|
if (_vector == pData)
|
|
return *this;
|
|
if (bForceResize || _vectorSize < nSize) {
|
|
_Release();
|
|
_vectorSize = nSize;
|
|
_vector = (TYPE*) operator new[] (_vectorSize * sizeof(TYPE));
|
|
_ArrayCopyConstruct(_vector, pData, nSize);
|
|
} else {
|
|
if (_size >= nSize) {
|
|
_ArrayDestruct(_vector+nSize, _size-nSize);
|
|
_ArrayCopyRestrict(_vector, pData, nSize);
|
|
} else {
|
|
_ArrayCopyRestrict(_vector, pData, _size);
|
|
_ArrayCopyConstruct(_vector+_size, pData+_size, nSize-_size);
|
|
}
|
|
}
|
|
_size = nSize;
|
|
return *this;
|
|
}
|
|
|
|
// release current list and swap the content with the given list
|
|
inline cList& CopyOfRemove(cList& rList)
|
|
{
|
|
if (this == &rList)
|
|
return *this;
|
|
_Release();
|
|
_size = rList._size;
|
|
_vectorSize = rList._vectorSize;
|
|
_vector = rList._vector;
|
|
rList._vector = NULL;
|
|
rList._size = rList._vectorSize = 0;
|
|
return *this;
|
|
}
|
|
|
|
inline cList& Join(const cList& rList)
|
|
{
|
|
if (this == &rList || rList._size == 0)
|
|
return *this;
|
|
const IDX newSize = _size + rList._size;
|
|
Reserve(newSize);
|
|
_ArrayCopyConstruct(_vector+_size, rList._vector, rList._size);
|
|
_size = newSize;
|
|
return *this;
|
|
}
|
|
inline cList& Join(const TYPE* pData, IDX nSize)
|
|
{
|
|
const IDX newSize = _size + nSize;
|
|
Reserve(newSize);
|
|
_ArrayCopyConstruct(_vector+_size, pData, nSize);
|
|
_size = newSize;
|
|
return *this;
|
|
}
|
|
|
|
template <typename Functor>
|
|
inline cList& JoinFunctor(IDX nSize, const Functor& functor) {
|
|
Reserve(_size + nSize);
|
|
if (useConstruct) {
|
|
for (IDX n=0; n<nSize; ++n)
|
|
new(_vector+_size++) TYPE(functor(n));
|
|
} else {
|
|
for (IDX n=0; n<nSize; ++n)
|
|
*(_vector+_size++) = functor(n);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
inline cList& JoinRemove(cList& rList)
|
|
{
|
|
if (this == &rList || rList._size == 0)
|
|
return *this;
|
|
const IDX newSize(_size + rList._size);
|
|
Reserve(newSize);
|
|
_ArrayMoveConstruct<true>(_vector+_size, rList._vector, rList._size);
|
|
_size = newSize;
|
|
rList._size = 0;
|
|
return *this;
|
|
}
|
|
|
|
// Swap the elements of the two lists.
|
|
inline cList& Swap(cList& rList)
|
|
{
|
|
if (this == &rList)
|
|
return *this;
|
|
const IDX tmpSize = _size;
|
|
_size = rList._size;
|
|
rList._size = tmpSize;
|
|
const IDX tmpVectorSize = _vectorSize;
|
|
_vectorSize = rList._vectorSize;
|
|
rList._vectorSize = tmpVectorSize;
|
|
TYPE* const tmpVector = _vector;
|
|
_vector = rList._vector;
|
|
rList._vector = tmpVector;
|
|
return *this;
|
|
}
|
|
|
|
// Swap the two elements.
|
|
inline void Swap(IDX idx1, IDX idx2)
|
|
{
|
|
ASSERT(idx1 < _size && idx2 < _size);
|
|
TYPE tmp = _vector[idx1];
|
|
_vector[idx1] = _vector[idx2];
|
|
_vector[idx2] = tmp;
|
|
}
|
|
|
|
inline bool operator==(const cList& rList) const {
|
|
if (_size != rList._size)
|
|
return false;
|
|
for (IDX i = 0; i < _size; ++i)
|
|
if (_vector[i] != rList._vector[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Set the allocated memory (normally used for types without constructor).
|
|
inline void Memset(uint8_t val)
|
|
{
|
|
memset(_vector, val, _size * sizeof(TYPE));
|
|
}
|
|
inline void MemsetValue(ARG_TYPE val)
|
|
{
|
|
std::fill_n(_vector, _size, val);
|
|
}
|
|
|
|
// Delete the old array, and create a new one of the desired size;
|
|
// the old elements are deleted and the array is filled with new empty ones.
|
|
inline void Reset(IDX newSize)
|
|
{
|
|
_Release();
|
|
_vectorSize = newSize;
|
|
_size = newSize;
|
|
if (newSize == 0) {
|
|
_vector = NULL;
|
|
return;
|
|
}
|
|
_vector = (TYPE*) operator new[] (newSize * sizeof(TYPE));
|
|
_ArrayConstruct(_vector, newSize);
|
|
}
|
|
|
|
// Pre-allocate memory for the array at the desired size;
|
|
// the old elements are kept.
|
|
inline void Reserve(IDX needVectorSize)
|
|
{
|
|
if (_vectorSize < needVectorSize)
|
|
_Grow(needVectorSize);
|
|
}
|
|
// Same as above, but only the extra needed space is passed.
|
|
inline void ReserveExtra(IDX needVectorExtraSize)
|
|
{
|
|
if (_vectorSize < _size+needVectorExtraSize)
|
|
_Grow(_vectorSize+MAXF(needVectorExtraSize,(IDX)grow));
|
|
}
|
|
|
|
// Set the size of the array at the new desired size;
|
|
// the old elements are kept, but only the ones that are below the new size.
|
|
// If increased, the array is filled with new empty elements.
|
|
inline void Resize(IDX newSize)
|
|
{
|
|
if (newSize == _size)
|
|
return;
|
|
if (newSize < _size)
|
|
return _Shrink(newSize);
|
|
Reserve(newSize);
|
|
_ArrayConstruct(_vector+_size, newSize-_size);
|
|
_size = newSize;
|
|
}
|
|
inline void ResizeExact(IDX newSize)
|
|
{
|
|
if (newSize == _size)
|
|
return;
|
|
if (newSize < _size)
|
|
return _ShrinkExact(newSize);
|
|
Reserve(newSize);
|
|
_ArrayConstruct(_vector+_size, newSize-_size);
|
|
_size = newSize;
|
|
}
|
|
|
|
// Free unused memory.
|
|
inline void ReleaseFree()
|
|
{
|
|
if (_size < _vectorSize)
|
|
_ShrinkExact(_size);
|
|
}
|
|
|
|
inline IDX GetIndex(const TYPE* pElem) const
|
|
{
|
|
ASSERT(pElem-_vector < _size);
|
|
return (IDX)(pElem-_vector);
|
|
}
|
|
|
|
inline const TYPE& operator[](IDX index) const
|
|
{
|
|
ASSERT(index < _size);
|
|
return _vector[index];
|
|
}
|
|
inline TYPE& operator[](IDX index)
|
|
{
|
|
ASSERT(index < _size);
|
|
return _vector[index];
|
|
}
|
|
|
|
inline TYPE* GetData() const
|
|
{
|
|
return _vector;
|
|
}
|
|
inline size_t GetDataSize() const
|
|
{
|
|
return sizeof(TYPE)*_size;
|
|
}
|
|
|
|
inline TYPE* Begin() const
|
|
{
|
|
return _vector;
|
|
}
|
|
|
|
inline TYPE* End() const
|
|
{
|
|
return _vector+_size;
|
|
}
|
|
|
|
inline const TYPE& First() const
|
|
{
|
|
ASSERT(_size > 0);
|
|
return _vector[0];
|
|
}
|
|
inline TYPE& First()
|
|
{
|
|
ASSERT(_size > 0);
|
|
return _vector[0];
|
|
}
|
|
|
|
inline const TYPE& Last() const
|
|
{
|
|
ASSERT(_size > 0);
|
|
return _vector[_size-1];
|
|
}
|
|
inline TYPE& Last()
|
|
{
|
|
ASSERT(_size > 0);
|
|
return _vector[_size-1];
|
|
}
|
|
|
|
// Adds a new empty element at the end of the array.
|
|
inline TYPE& AddEmpty()
|
|
{
|
|
if (_vectorSize <= _size)
|
|
_Grow(_vectorSize + grow);
|
|
if (useConstruct)
|
|
return *(new(_vector + (_size++)) TYPE);
|
|
else
|
|
return _vector[_size++];
|
|
}
|
|
inline TYPE* AddEmpty(IDX numElems)
|
|
{
|
|
const IDX newSize = _size + numElems;
|
|
if (_vectorSize < newSize)
|
|
_Grow(newSize + grow);
|
|
Type* const pData = _vector + _size;
|
|
_ArrayConstruct(pData, numElems);
|
|
_size = newSize;
|
|
return pData;
|
|
}
|
|
|
|
// Adds a new empty element at the end of the array and pass the arguments to its constructor.
|
|
#ifdef _SUPPORT_CPP11
|
|
template <typename... Args>
|
|
inline TYPE& AddConstruct(Args&&... args)
|
|
{
|
|
if (_vectorSize <= _size)
|
|
_Grow(_vectorSize + grow);
|
|
return *(new(_vector + (_size++)) TYPE(std::forward<Args>(args)...));
|
|
}
|
|
#else
|
|
template <typename... Args>
|
|
inline TYPE& AddConstruct(Args... args)
|
|
{
|
|
if (_vectorSize <= _size)
|
|
_Grow(_vectorSize + grow);
|
|
return *(new(_vector + (_size++)) TYPE(args...));
|
|
}
|
|
#endif
|
|
|
|
inline IDX InsertEmpty()
|
|
{
|
|
if (_vectorSize <= _size)
|
|
_Grow(_vectorSize + grow);
|
|
if (useConstruct)
|
|
new(_vector + _size) TYPE;
|
|
return _size++;
|
|
}
|
|
|
|
// Adds the new element at the end of the array.
|
|
#ifdef _SUPPORT_CPP11
|
|
template <typename T>
|
|
inline void Insert(T&& elem)
|
|
{
|
|
if (_vectorSize <= _size)
|
|
_Grow(_vectorSize + grow);
|
|
if (useConstruct)
|
|
new(_vector+(_size++)) TYPE(std::forward<T>(elem));
|
|
else
|
|
_vector[_size++] = std::forward<T>(elem);
|
|
}
|
|
#else
|
|
inline void Insert(ARG_TYPE elem)
|
|
{
|
|
if (_vectorSize <= _size)
|
|
_Grow(_vectorSize + grow);
|
|
if (useConstruct)
|
|
new(_vector+(_size++)) TYPE(elem);
|
|
else
|
|
_vector[_size++] = elem;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _SUPPORT_CPP11
|
|
template <typename T>
|
|
inline void SetAt(IDX index, T&& elem)
|
|
{
|
|
if (_size <= index)
|
|
Resize(index + 1);
|
|
_vector[index] = std::forward<T>(elem);
|
|
}
|
|
#else
|
|
inline void SetAt(IDX index, ARG_TYPE elem)
|
|
{
|
|
if (_size <= index)
|
|
Resize(index + 1);
|
|
_vector[index] = elem;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _SUPPORT_CPP11
|
|
template <typename T>
|
|
inline void AddAt(IDX index, T&& elem)
|
|
{
|
|
if (index < _size)
|
|
return InsertAt(index, std::forward<T>(elem));
|
|
const IDX newSize = index + 1;
|
|
if (_vectorSize <= newSize)
|
|
_Grow(newSize + grow);
|
|
_ArrayConstruct(_vector+_size, index-_size);
|
|
if (useConstruct)
|
|
new(_vector+index) TYPE(std::forward<T>(elem));
|
|
else
|
|
_vector[index] = std::forward<T>(elem);
|
|
++_size;
|
|
}
|
|
#else
|
|
inline void AddAt(IDX index, ARG_TYPE elem)
|
|
{
|
|
if (index < _size)
|
|
return InsertAt(index, elem);
|
|
const IDX newSize = index + 1;
|
|
if (_vectorSize <= newSize)
|
|
_Grow(newSize + grow);
|
|
_ArrayConstruct(_vector+_size, index-_size);
|
|
if (useConstruct)
|
|
new(_vector+index) TYPE(elem);
|
|
else
|
|
_vector[index] = elem;
|
|
++_size;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _SUPPORT_CPP11
|
|
template <typename T>
|
|
inline void InsertAt(IDX index, T&& elem)
|
|
{
|
|
if (useConstruct)
|
|
new(AllocateAt(index)) TYPE(std::forward<T>(elem));
|
|
else
|
|
*AllocateAt(index) = std::forward<T>(elem);
|
|
}
|
|
#else
|
|
inline void InsertAt(IDX index, ARG_TYPE elem)
|
|
{
|
|
if (useConstruct)
|
|
new(AllocateAt(index)) TYPE(elem);
|
|
else
|
|
*AllocateAt(index) = elem;
|
|
}
|
|
#endif
|
|
|
|
// Same as Insert, but the constructor is not called.
|
|
inline TYPE* Allocate()
|
|
{
|
|
if (_vectorSize <= _size)
|
|
_Grow(_vectorSize + grow);
|
|
return _vector+_size++;
|
|
}
|
|
inline TYPE* AllocateAt(IDX index)
|
|
{
|
|
ASSERT(index <= _size);
|
|
const IDX move(_size-index);
|
|
Allocate();
|
|
_ArrayMoveConstruct<false>(_vector+index+1, _vector+index, move);
|
|
return _vector+index;
|
|
}
|
|
|
|
inline IDX InsertSort(ARG_TYPE elem)
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE compElem(_vector[i]);
|
|
if (elem < compElem)
|
|
l2 = i;
|
|
else if (compElem < elem)
|
|
l1 = i+1;
|
|
else {
|
|
InsertAt(i, elem);
|
|
return i;
|
|
}
|
|
}
|
|
InsertAt(l1, elem);
|
|
return l1;
|
|
}
|
|
|
|
inline IDX InsertSortPtr(ARG_TYPE elem)
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE compElem(_vector[i]);
|
|
if (*elem < *compElem)
|
|
l2 = i;
|
|
else if (*compElem < *elem)
|
|
l1 = i+1;
|
|
else {
|
|
InsertAt(i, elem);
|
|
return i;
|
|
}
|
|
}
|
|
InsertAt(l1, elem);
|
|
return l1;
|
|
}
|
|
|
|
inline IDX InsertSort(ARG_TYPE elem, TFncCompare xCompare)
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
const int res(xCompare(_vector+i, &elem));
|
|
if (res == 0) {
|
|
InsertAt(i, elem);
|
|
return i;
|
|
}
|
|
if (res < 0)
|
|
l1 = i+1;
|
|
else
|
|
l2 = i;
|
|
}
|
|
InsertAt(l1, elem);
|
|
return l1;
|
|
}
|
|
|
|
inline TYPE& GetNth(IDX index)
|
|
{
|
|
ASSERT(index < _size);
|
|
TYPE* const nth(Begin()+index);
|
|
std::nth_element(Begin(), nth, End());
|
|
return *nth;
|
|
}
|
|
template <typename RTYPE = typename std::conditional<std::is_floating_point<TYPE>::value,TYPE,REAL>::type>
|
|
inline RTYPE GetMedian()
|
|
{
|
|
ASSERT(_size > 0);
|
|
if (_size%2)
|
|
return static_cast<RTYPE>(GetNth(_size >> 1));
|
|
TYPE* const nth(Begin() + (_size>>1));
|
|
std::nth_element(Begin(), nth, End());
|
|
TYPE* const nth1(nth-1);
|
|
std::nth_element(Begin(), nth1, nth);
|
|
return (static_cast<RTYPE>(*nth1) + static_cast<RTYPE>(*nth)) / RTYPE(2);
|
|
}
|
|
|
|
inline TYPE GetMean()
|
|
{
|
|
return std::accumulate(Begin(), End(), TYPE(0)) / _size;
|
|
}
|
|
|
|
inline ArgType GetMax() const {
|
|
return *std::max_element(Begin(), End());
|
|
}
|
|
template <typename Functor>
|
|
inline ArgType GetMax(const Functor& functor) const {
|
|
return *std::max_element(Begin(), End(), functor);
|
|
}
|
|
inline IDX GetMaxIdx() const {
|
|
return static_cast<IDX>(std::max_element(Begin(), End()) - Begin());
|
|
}
|
|
template <typename Functor>
|
|
inline IDX GetMaxIdx(const Functor& functor) const {
|
|
return static_cast<IDX>(std::max_element(Begin(), End(), functor) - Begin());
|
|
}
|
|
#ifdef _SUPPORT_CPP11
|
|
inline std::pair<ArgType,ArgType> GetMinMax() const {
|
|
const auto minmax(std::minmax_element(Begin(), End()));
|
|
return std::pair<ArgType,ArgType>(*minmax.first, *minmax.second);
|
|
}
|
|
template <typename Functor>
|
|
inline std::pair<ArgType,ArgType> GetMinMax(const Functor& functor) const {
|
|
const auto minmax(std::minmax_element(Begin(), End(), functor));
|
|
return std::pair<ArgType,ArgType>(*minmax.first, *minmax.second);
|
|
}
|
|
inline std::pair<IDX,IDX> GetMinMaxIdx() const {
|
|
const auto minmax(std::minmax_element(Begin(), End()));
|
|
return std::make_pair(static_cast<IDX>(minmax.first-Begin()), static_cast<IDX>(minmax.second-Begin()));
|
|
}
|
|
template <typename Functor>
|
|
inline std::pair<IDX,IDX> GetMinMaxIdx(const Functor& functor) const {
|
|
const auto minmax(std::minmax_element(Begin(), End(), functor));
|
|
return std::make_pair(static_cast<IDX>(minmax.first-Begin()), static_cast<IDX>(minmax.second-Begin()));
|
|
}
|
|
#endif
|
|
|
|
inline TYPE& PartialSort(IDX index)
|
|
{
|
|
TYPE* const nth(Begin()+index);
|
|
std::partial_sort(Begin(), nth, End());
|
|
return *nth;
|
|
}
|
|
|
|
inline void Sort()
|
|
{
|
|
std::sort(Begin(), End());
|
|
}
|
|
template <typename Functor>
|
|
inline void Sort(const Functor& functor)
|
|
{
|
|
std::sort(Begin(), End(), functor);
|
|
}
|
|
|
|
inline bool IsSorted() const
|
|
{
|
|
#ifdef _SUPPORT_CPP11
|
|
return std::is_sorted(Begin(), End());
|
|
#else
|
|
if (_size < 2)
|
|
return true;
|
|
IDX i = _size-1;
|
|
do {
|
|
ARG_TYPE elem1 = _vector[i];
|
|
ARG_TYPE elem0 = _vector[--i];
|
|
if (elem1 < elem0)
|
|
return false;
|
|
} while (i > 0);
|
|
return true;
|
|
#endif
|
|
}
|
|
template <typename Functor>
|
|
inline bool IsSorted(const Functor& functor) const
|
|
{
|
|
#ifdef _SUPPORT_CPP11
|
|
return std::is_sorted(Begin(), End(), functor);
|
|
#else
|
|
if (_size < 2)
|
|
return true;
|
|
IDX i = _size-1;
|
|
do {
|
|
ARG_TYPE elem1 = _vector[i];
|
|
ARG_TYPE elem0 = _vector[--i];
|
|
if (functor(elem1, elem0))
|
|
return false;
|
|
} while (i > 0);
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
inline std::pair<IDX,bool> InsertSortUnique(ARG_TYPE elem)
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE compElem(_vector[i]);
|
|
if (elem < compElem)
|
|
l2 = i;
|
|
else if (compElem < elem)
|
|
l1 = i+1;
|
|
else
|
|
return std::make_pair(i,true);
|
|
}
|
|
InsertAt(l1, elem);
|
|
return std::make_pair(l1, false);
|
|
}
|
|
|
|
inline std::pair<IDX,bool> InsertSortUniquePtr(ARG_TYPE elem)
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE compElem(_vector[i]);
|
|
if (*elem < *compElem)
|
|
l2 = i;
|
|
else if (*compElem < *elem)
|
|
l1 = i+1;
|
|
else
|
|
return std::make_pair(i, true);
|
|
}
|
|
InsertAt(l1, elem);
|
|
return std::make_pair(l1, false);
|
|
}
|
|
|
|
inline std::pair<IDX,bool> InsertSortUnique(ARG_TYPE elem, TFncCompare xCompare)
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
const int res(xCompare(_vector+i, &elem));
|
|
if (res == 0)
|
|
return std::make_pair(i, true);
|
|
if (res < 0)
|
|
l1 = i + 1;
|
|
else
|
|
l2 = i;
|
|
}
|
|
InsertAt(l1, elem);
|
|
return std::make_pair(l1, false);
|
|
}
|
|
|
|
// insert given element if it is in the top N
|
|
template <int N>
|
|
inline void StoreTop(ARG_TYPE elem) {
|
|
const IDX idx(FindFirstEqlGreater(elem));
|
|
if (idx < _size) {
|
|
if (_size >= N)
|
|
RemoveLast();
|
|
InsertAt(idx, elem);
|
|
} else if (_size < N) {
|
|
Insert(elem);
|
|
}
|
|
}
|
|
inline void StoreTop(ARG_TYPE elem, IDX N) {
|
|
const IDX idx(FindFirstEqlGreater(elem));
|
|
if (idx < _size) {
|
|
if (_size >= N)
|
|
RemoveLast();
|
|
InsertAt(idx, elem);
|
|
} else if (_size < N) {
|
|
Insert(elem);
|
|
}
|
|
}
|
|
|
|
inline IDX FindFirst(ARG_TYPE searchedKey) const
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (searchedKey < key)
|
|
l2 = i;
|
|
else if (key < searchedKey)
|
|
l1 = i + 1;
|
|
else
|
|
return i;
|
|
}
|
|
return NO_INDEX;
|
|
}
|
|
|
|
inline IDX FindFirstPtr(ARG_TYPE searchedKey) const
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (*searchedKey < *key)
|
|
l2 = i;
|
|
else if (*key < *searchedKey)
|
|
l1 = i + 1;
|
|
else
|
|
return i;
|
|
}
|
|
return NO_INDEX;
|
|
}
|
|
|
|
template <typename SEARCH_TYPE>
|
|
inline IDX FindFirst(const SEARCH_TYPE& searchedKey) const
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (key == searchedKey)
|
|
return i;
|
|
if (key < searchedKey)
|
|
l1 = i + 1;
|
|
else
|
|
l2 = i;
|
|
}
|
|
return NO_INDEX;
|
|
}
|
|
|
|
template <typename SEARCH_TYPE>
|
|
inline IDX FindFirstPtr(const SEARCH_TYPE& searchedKey) const
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (*key == searchedKey)
|
|
return i;
|
|
if (*key < searchedKey)
|
|
l1 = i + 1;
|
|
else
|
|
l2 = i;
|
|
}
|
|
return NO_INDEX;
|
|
}
|
|
|
|
inline IDX FindFirst(const void* searchedKey, TFncCompare xCompare) const
|
|
{
|
|
IDX l1(0), l2(_size);
|
|
while (l1 < l2) {
|
|
IDX i((l1 + l2) >> 1);
|
|
const int res(xCompare(_vector+i, searchedKey));
|
|
if (res == 0)
|
|
return i;
|
|
if (res < 0)
|
|
l1 = i + 1;
|
|
else
|
|
l2 = i;
|
|
}
|
|
return NO_INDEX;
|
|
}
|
|
|
|
inline IDX FindFirstBelow(ARG_TYPE searchedKey) const
|
|
{
|
|
if (_size == 0) return NO_INDEX;
|
|
IDX l1(0), l2(_size);
|
|
do {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (searchedKey < key)
|
|
l2 = i;
|
|
else if (key < searchedKey)
|
|
l1 = i+1;
|
|
else {
|
|
while (i-- && !(_vector[i] < searchedKey));
|
|
return i;
|
|
}
|
|
} while (l1 < l2);
|
|
return l1-1;
|
|
}
|
|
|
|
template <typename SEARCH_TYPE>
|
|
inline IDX FindFirstBelow(const SEARCH_TYPE& searchedKey) const
|
|
{
|
|
if (_size == 0) return NO_INDEX;
|
|
IDX l1(0), l2(_size);
|
|
do {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (key == searchedKey) {
|
|
while (i-- && _vector[i] == searchedKey);
|
|
return i;
|
|
}
|
|
if (key < searchedKey)
|
|
l1 = i+1;
|
|
else
|
|
l2 = i;
|
|
} while (l1 < l2);
|
|
return l1-1;
|
|
}
|
|
|
|
inline IDX FindFirstEqlGreater(ARG_TYPE searchedKey) const
|
|
{
|
|
if (_size == 0) return 0;
|
|
IDX l1(0), l2(_size);
|
|
do {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (searchedKey < key)
|
|
l2 = i;
|
|
else if (key < searchedKey)
|
|
l1 = i+1;
|
|
else {
|
|
while (i-- && !(_vector[i] < searchedKey));
|
|
return i+1;
|
|
}
|
|
} while (l1 < l2);
|
|
return l1;
|
|
}
|
|
|
|
template <typename SEARCH_TYPE>
|
|
inline IDX FindFirstEqlGreater(const SEARCH_TYPE& searchedKey) const
|
|
{
|
|
if (_size == 0) return 0;
|
|
IDX l1(0), l2(_size);
|
|
do {
|
|
IDX i((l1 + l2) >> 1);
|
|
ARG_TYPE key(_vector[i]);
|
|
if (key == searchedKey) {
|
|
while (i-- && _vector[i] == searchedKey);
|
|
return i+1;
|
|
}
|
|
if (key < searchedKey)
|
|
l1 = i+1;
|
|
else
|
|
l2 = i;
|
|
} while (l1 < l2);
|
|
return l1;
|
|
}
|
|
|
|
// find the matching "elem" by brute-force (front to back)
|
|
// returns the first element found
|
|
inline IDX Find(ARG_TYPE elem) const
|
|
{
|
|
for (IDX i = 0; i < _size; ++i)
|
|
if (_vector[i] == elem)
|
|
return i;
|
|
return NO_INDEX;
|
|
}
|
|
template <typename SEARCH_TYPE>
|
|
inline IDX Find(const SEARCH_TYPE& searchedKey) const
|
|
{
|
|
for (IDX i = 0; i < _size; ++i)
|
|
if (_vector[i] == searchedKey)
|
|
return i;
|
|
return NO_INDEX;
|
|
}
|
|
template <typename Functor>
|
|
inline IDX FindFunc(const Functor& functor) const
|
|
{
|
|
for (IDX i = 0; i < _size; ++i)
|
|
if (functor(_vector[i]))
|
|
return i;
|
|
return NO_INDEX;
|
|
}
|
|
|
|
// find the matching "elem" by brute-force (back to front)
|
|
// returns the first element found
|
|
inline IDX RFind(ARG_TYPE elem) const
|
|
{
|
|
IDX i(_size);
|
|
while (i)
|
|
if (_vector[--i] == elem)
|
|
return i;
|
|
return NO_INDEX;
|
|
}
|
|
template <typename SEARCH_TYPE>
|
|
inline IDX RFind(const SEARCH_TYPE& searchedKey) const
|
|
{
|
|
IDX i(_size);
|
|
while (i)
|
|
if (_vector[--i] == searchedKey)
|
|
return i;
|
|
return NO_INDEX;
|
|
}
|
|
template <typename Functor>
|
|
inline IDX RFindFunc(const Functor& functor) const
|
|
{
|
|
IDX i(_size);
|
|
while (i)
|
|
if (functor(_vector[--i]))
|
|
return i;
|
|
return NO_INDEX;
|
|
}
|
|
|
|
// call a function or lambda on each element
|
|
template <typename Functor>
|
|
inline void ForEach(const Functor& functor) const
|
|
{
|
|
FOREACH(i, *this)
|
|
functor(i);
|
|
}
|
|
template <typename Functor>
|
|
inline void ForEachPtr(const Functor& functor) const
|
|
{
|
|
FOREACHPTR(ptr, *this)
|
|
functor(ptr);
|
|
}
|
|
template <typename Functor>
|
|
inline void ForEachRef(const Functor& functor) const
|
|
{
|
|
FOREACHPTR(ptr, *this)
|
|
functor(*ptr);
|
|
}
|
|
// same, but in reverse order
|
|
template <typename Functor>
|
|
inline void RForEach(const Functor& functor) const
|
|
{
|
|
RFOREACH(i, *this)
|
|
functor(i);
|
|
}
|
|
template <typename Functor>
|
|
inline void RForEachPtr(const Functor& functor) const
|
|
{
|
|
RFOREACHPTR(ptr, *this)
|
|
functor(ptr);
|
|
}
|
|
template <typename Functor>
|
|
inline void RForEachRef(const Functor& functor) const
|
|
{
|
|
RFOREACHPTR(ptr, *this)
|
|
functor(*ptr);
|
|
}
|
|
|
|
// Erase each element matching "elem".
|
|
inline void Remove(ARG_TYPE elem)
|
|
{
|
|
IDX i = _size;
|
|
while (i)
|
|
if (_vector[--i] == elem)
|
|
RemoveAt(i);
|
|
}
|
|
|
|
inline ARG_TYPE RemoveTail()
|
|
{
|
|
ASSERT(_size);
|
|
ASSERT(!useConstruct);
|
|
return _vector[--_size];
|
|
}
|
|
|
|
inline void RemoveLast()
|
|
{
|
|
ASSERT(_size);
|
|
_ArrayDestruct(_vector+(--_size), 1);
|
|
}
|
|
|
|
inline void RemoveLast(IDX count)
|
|
{
|
|
ASSERT(count <= _size);
|
|
_ArrayDestruct(_vector+(_size-=count), count);
|
|
}
|
|
|
|
inline void RemoveAt(IDX index)
|
|
{
|
|
ASSERT(index < _size);
|
|
if (index+1 == _size)
|
|
RemoveLast();
|
|
else
|
|
_ArrayMoveCopy<true>(_vector+index, _vector+(--_size), 1);
|
|
}
|
|
|
|
inline void RemoveAt(IDX index, IDX count)
|
|
{
|
|
ASSERT(index+count <= _size);
|
|
if (index+count == _size) {
|
|
RemoveLast(count);
|
|
} else {
|
|
_size -= count;
|
|
const IDX move(_size-index);
|
|
TYPE* const vectorEnd(_vector+_size);
|
|
if (move < count) {
|
|
const IDX del(count-move);
|
|
_ArrayMoveCopy<true>(_vector+index, vectorEnd+del, move);
|
|
_ArrayDestruct(vectorEnd, del);
|
|
} else {
|
|
_ArrayMoveCopy<false>(_vector+index, vectorEnd, count);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void RemoveAtMove(IDX index)
|
|
{
|
|
ASSERT(index < _size);
|
|
if (index+1 == _size) {
|
|
RemoveLast();
|
|
} else {
|
|
_ArrayDestruct(_vector+index, 1);
|
|
_ArrayMoveConstructFwd(_vector+index, _vector+index+1, (--_size)-index);
|
|
}
|
|
}
|
|
|
|
inline void RemoveAtMove(IDX index, IDX count)
|
|
{
|
|
ASSERT(index+count <= _size);
|
|
if (index+count == _size) {
|
|
RemoveLast(count);
|
|
} else {
|
|
_ArrayDestruct(_vector+index, count);
|
|
_ArrayMoveConstructFwd(_vector+index, _vector+index+count, (_size-=count)-index);
|
|
}
|
|
}
|
|
|
|
inline void Empty()
|
|
{
|
|
_ArrayDestruct(_vector, _size);
|
|
_size = 0;
|
|
}
|
|
|
|
// same as Empty(), plus free all allocated memory
|
|
inline void Release()
|
|
{
|
|
_Release();
|
|
_Init();
|
|
}
|
|
|
|
// Discard all stored data and initialize it as an empty array.
|
|
// (note: call this only when you know what you are doing,
|
|
// you have to deallocate yourself all elements and _vector data)
|
|
inline void Reset()
|
|
{
|
|
_Init();
|
|
}
|
|
|
|
// Delete also the pointers (take care to use this function only if the elements are pointers).
|
|
inline void EmptyDelete()
|
|
{
|
|
while (_size)
|
|
delete _vector[--_size];
|
|
}
|
|
|
|
// same as EmptyDelete(), plus free all allocated memory
|
|
inline void ReleaseDelete()
|
|
{
|
|
EmptyDelete();
|
|
operator delete[] (_vector);
|
|
_vector = NULL;
|
|
_vectorSize = 0;
|
|
}
|
|
|
|
inline IDX GetCapacity() const
|
|
{
|
|
return _vectorSize;
|
|
}
|
|
|
|
inline IDX GetSize() const
|
|
{
|
|
return _size;
|
|
}
|
|
|
|
inline bool IsEmpty() const
|
|
{
|
|
return (_size == 0);
|
|
}
|
|
|
|
static inline unsigned GetConstructType()
|
|
{
|
|
return useConstruct;
|
|
}
|
|
static inline IDX GetGrowSize()
|
|
{
|
|
return grow;
|
|
}
|
|
|
|
protected:
|
|
// Free all memory.
|
|
inline void _Release()
|
|
{
|
|
_ArrayDestruct(_vector, _size);
|
|
operator delete[] (_vector);
|
|
}
|
|
|
|
// Initialize array.
|
|
inline void _Init()
|
|
{
|
|
_vector = NULL;
|
|
_vectorSize = _size = 0;
|
|
}
|
|
|
|
// Increase the size of the array at least to the specified amount.
|
|
inline void _Grow(IDX newVectorSize)
|
|
{
|
|
ASSERT(newVectorSize > _vectorSize);
|
|
// grow by 50% or at least to minNewVectorSize
|
|
const IDX expoVectorSize(_vectorSize + (_vectorSize>>1));
|
|
if (newVectorSize < expoVectorSize)
|
|
newVectorSize = expoVectorSize;
|
|
// allocate a larger chunk of memory, copy the data and delete the old chunk
|
|
TYPE* const tmp(_vector);
|
|
_vector = (TYPE*) operator new[] (newVectorSize * sizeof(TYPE));
|
|
_ArrayMoveConstruct<true>(_vector, tmp, _size);
|
|
_vectorSize = newVectorSize;
|
|
operator delete[] (tmp);
|
|
}
|
|
|
|
// Decrease the size of the array at the specified new size.
|
|
inline void _Shrink(IDX newSize)
|
|
{
|
|
ASSERT(newSize <= _size);
|
|
_ArrayDestruct(_vector+newSize, _size-newSize);
|
|
_size = newSize;
|
|
}
|
|
inline void _ShrinkExact(IDX newSize)
|
|
{
|
|
_Shrink(newSize);
|
|
_vectorSize = newSize;
|
|
if (newSize == 0) {
|
|
operator delete[] (_vector);
|
|
_vector = NULL;
|
|
} else {
|
|
TYPE* const tmp(_vector);
|
|
_vector = (TYPE*) operator new[] (_vectorSize * sizeof(TYPE));
|
|
_ArrayMoveConstruct<true>(_vector, tmp, _vectorSize);
|
|
operator delete[] (tmp);
|
|
}
|
|
}
|
|
|
|
// Implement construct/destruct for the array elements.
|
|
static inline void _ArrayConstruct(TYPE* RESTRICT dst, IDX n)
|
|
{
|
|
if (useConstruct) {
|
|
while (n--)
|
|
new(dst+n) TYPE;
|
|
}
|
|
}
|
|
static inline void _ArrayCopyConstruct(TYPE* RESTRICT dst, const TYPE* RESTRICT src, IDX n)
|
|
{
|
|
if (useConstruct) {
|
|
while (n--)
|
|
new(dst+n) TYPE(src[n]);
|
|
} else {
|
|
memcpy((void*)dst, (const void*)src, n*sizeof(TYPE));
|
|
}
|
|
}
|
|
static inline void _ArrayDestruct(TYPE* dst, IDX n)
|
|
{
|
|
if (useConstruct) {
|
|
while (n--)
|
|
(dst+n)->~TYPE();
|
|
}
|
|
}
|
|
// Implement copy/move for the array elements.
|
|
static inline void _ArrayCopyRestrict(TYPE* RESTRICT dst, const TYPE* RESTRICT src, IDX n)
|
|
{
|
|
if (useConstruct) {
|
|
while (n--)
|
|
dst[n] = src[n];
|
|
} else {
|
|
memcpy((void*)dst, (const void*)src, n*sizeof(TYPE));
|
|
}
|
|
}
|
|
static inline void _ArrayMoveConstructFwd(TYPE* dst, TYPE* src, IDX n)
|
|
{
|
|
ASSERT(dst != src);
|
|
if (useConstruct > 1) {
|
|
for (IDX i=0; i<n; ++i) {
|
|
new(dst+i) TYPE(src[i]);
|
|
(src+i)->~TYPE();
|
|
}
|
|
} else {
|
|
memmove((void*)dst, (const void*)src, n*sizeof(TYPE));
|
|
}
|
|
}
|
|
template <bool bRestrict>
|
|
static inline void _ArrayMoveConstruct(TYPE* dst, TYPE* src, IDX n)
|
|
{
|
|
ASSERT(dst != src);
|
|
if (useConstruct > 1) {
|
|
while (n--) {
|
|
new(dst+n) TYPE(src[n]);
|
|
(src+n)->~TYPE();
|
|
}
|
|
} else {
|
|
const size_t _size(sizeof(TYPE)*n);
|
|
if (bRestrict)
|
|
memcpy((void*)dst, (const void*)src, _size);
|
|
else
|
|
memmove((void*)dst, (const void*)src, _size);
|
|
}
|
|
}
|
|
template <bool bRestrict>
|
|
static inline void _ArrayMoveCopy(TYPE* dst, TYPE* src, IDX n)
|
|
{
|
|
ASSERT(dst != src);
|
|
if (useConstruct > 1) {
|
|
while (n--) {
|
|
dst[n] = src[n];
|
|
(src+n)->~TYPE();
|
|
}
|
|
} else {
|
|
const size_t _size(sizeof(TYPE)*n);
|
|
if (useConstruct == 1)
|
|
while (n--)
|
|
(dst+n)->~TYPE();
|
|
if (bRestrict)
|
|
memcpy((void*)dst, (const void*)src, _size);
|
|
else
|
|
memmove((void*)dst, (const void*)src, _size);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
IDX _size;
|
|
IDX _vectorSize;
|
|
TYPE* _vector;
|
|
|
|
public:
|
|
enum : IDX { NO_INDEX = DECLARE_NO_INDEX(IDX) };
|
|
|
|
#if _USE_VECTORINTERFACE != 0
|
|
public:
|
|
typedef IDX size_type;
|
|
typedef Type value_type;
|
|
typedef value_type* iterator;
|
|
typedef const value_type* const_iterator;
|
|
typedef value_type& reference;
|
|
typedef const value_type& const_reference;
|
|
typedef std::vector<Type> VectorType;
|
|
inline cList(const VectorType& rList) { CopyOf(&rList[0], rList.size()); }
|
|
#ifdef _SUPPORT_CPP11
|
|
inline cList(std::initializer_list<Type> l) : _size(0), _vectorSize((size_type)l.size()), _vector(NULL) { ASSERT(l.size()<NO_INDEX); if (_vectorSize == 0) return; _vector = (Type*) operator new[] (_vectorSize*sizeof(Type)); const Type* first(l.begin()); do new(_vector + _size++) Type(*first++); while (first!=l.end()); }
|
|
#endif
|
|
inline bool empty() const { return IsEmpty(); }
|
|
inline size_type size() const { return GetSize(); }
|
|
inline size_type capacity() const { return GetCapacity(); }
|
|
inline void clear() { Empty(); }
|
|
inline void insert(const_iterator it, const_reference elem) { InsertAt(it-this->_vector, elem); }
|
|
#ifdef _SUPPORT_CPP11
|
|
template <typename... Args>
|
|
inline reference emplace_back(Args&&... args) { return AddConstruct(std::forward<Args>(args)...); }
|
|
inline void push_back(value_type&& elem) { AddConstruct(elem); }
|
|
#endif
|
|
inline void push_back(const_reference elem) { Insert(elem); }
|
|
inline void pop_back() { RemoveLast(); }
|
|
inline void reserve(size_type newSize) { Reserve(newSize); }
|
|
inline void resize(size_type newSize) { Resize(newSize); }
|
|
inline void erase(const_iterator it) { RemoveAtMove(it-this->_vector); }
|
|
inline const_iterator cdata() const { return GetData(); }
|
|
inline const_iterator cbegin() const { return Begin(); }
|
|
inline const_iterator cend() const { return End(); }
|
|
inline iterator data() const { return GetData(); }
|
|
inline iterator begin() const { return Begin(); }
|
|
inline iterator end() const { return End(); }
|
|
inline ArgType front() const { return First(); }
|
|
inline ArgType back() const { return Last(); }
|
|
inline reference front() { return First(); }
|
|
inline reference back() { return Last(); }
|
|
inline void swap(cList& rList) { Swap(rList); }
|
|
#endif
|
|
|
|
#ifdef _USE_BOOST
|
|
protected:
|
|
// implement BOOST serialization
|
|
friend class boost::serialization::access;
|
|
template<class Archive>
|
|
void save(Archive& ar, const unsigned int /*version*/) const {
|
|
ar & _size;
|
|
ar & boost::serialization::make_array(_vector, _size);
|
|
}
|
|
template<class Archive>
|
|
void load(Archive& ar, const unsigned int /*version*/) {
|
|
IDX newSize;
|
|
ar & newSize;
|
|
Resize(newSize);
|
|
ar & boost::serialization::make_array(_vector, _size);
|
|
}
|
|
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
|
#endif
|
|
};
|
|
/*----------------------------------------------------------------*/
|
|
|
|
template <typename IDX_TYPE>
|
|
inline bool ValidIDX(const IDX_TYPE& idx) {
|
|
return (idx != DECLARE_NO_INDEX(IDX_TYPE));
|
|
}
|
|
/*----------------------------------------------------------------*/
|
|
|
|
|
|
// some test functions
|
|
template <bool dummy>
|
|
inline bool cListTest(unsigned iters) {
|
|
for (unsigned i=0; i<iters; ++i) {
|
|
const unsigned elems = 100+RAND()%1000;
|
|
std::vector<int> arrR;
|
|
cList<int, int, 0> arr0;
|
|
cList<int, int, 1> arr1;
|
|
cList<int, int, 2> arr2;
|
|
cList<int, int, 1> arrC;
|
|
for (unsigned i=0; i<elems; ++i) {
|
|
const int e = RAND();
|
|
arrR.push_back(e);
|
|
arr0.InsertSort(e);
|
|
arr1.InsertSort(e);
|
|
arr2.InsertSort(e);
|
|
arrC.Insert(e);
|
|
}
|
|
std::sort(arrR.begin(), arrR.end());
|
|
arrC.Sort([](int a, int b) { return a<b; });
|
|
for (size_t i=0; i<arrR.size(); ++i) {
|
|
const int e = arrR[i];
|
|
if (arrC[i] != e ||
|
|
arr0[i] != e ||
|
|
arr1[i] != e ||
|
|
arr2[i] != e) {
|
|
ASSERT("there is a problem" == NULL);
|
|
return false;
|
|
}
|
|
}
|
|
for (size_t i=0; i<6; ++i) {
|
|
const unsigned nDel = RAND()%arrR.size();
|
|
arrR.erase(arrR.begin()+nDel);
|
|
arr0.RemoveAtMove(nDel);
|
|
arr1.RemoveAtMove(nDel);
|
|
arr2.RemoveAtMove(nDel);
|
|
}
|
|
if (arrR.size() != arr0.GetSize() ||
|
|
arrR.size() != arr1.GetSize() ||
|
|
arrR.size() != arr2.GetSize()) {
|
|
ASSERT("there is a problem" == NULL);
|
|
return false;
|
|
}
|
|
for (size_t i=0; i<6; ++i) {
|
|
const unsigned nDel = RAND()%arrR.size();
|
|
const unsigned nCount = 1+RAND()%(arrR.size()/10+1);
|
|
if (nDel + nCount >= arrR.size())
|
|
continue;
|
|
arrR.erase(arrR.begin()+nDel, arrR.begin()+nDel+nCount);
|
|
arr0.RemoveAtMove(nDel, nCount);
|
|
arr1.RemoveAtMove(nDel, nCount);
|
|
arr2.RemoveAtMove(nDel, nCount);
|
|
}
|
|
if (arrR.size() != arr0.GetSize() ||
|
|
arrR.size() != arr1.GetSize() ||
|
|
arrR.size() != arr2.GetSize()) {
|
|
ASSERT("there is a problem" == NULL);
|
|
return false;
|
|
}
|
|
for (size_t i=0; i<arrR.size(); ++i) {
|
|
const int e = arrR[i];
|
|
if (arr0[i] != e ||
|
|
arr1[i] != e ||
|
|
arr2[i] != e) {
|
|
ASSERT("there is a problem" == NULL);
|
|
return false;
|
|
}
|
|
}
|
|
cList<int, int, 1> arrS(1+RAND()%(2*elems));
|
|
for (size_t i=0; i<6; ++i) {
|
|
arrS.Insert(RAND());
|
|
}
|
|
arrS.RemoveLast(RAND()%arrS.GetSize());
|
|
arrS.CopyOf(&arrR[0], arrR.size());
|
|
for (size_t i=0; i<6; ++i) {
|
|
arrS.Insert(RAND());
|
|
}
|
|
arrS.RemoveLast(6);
|
|
for (size_t i=0; i<arrR.size(); ++i) {
|
|
const int e = arrR[i];
|
|
if (arrS[i] != e) {
|
|
ASSERT("there is a problem" == NULL);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
/*----------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/**************************************************************************************
|
|
* Fixed size list template
|
|
**************************************************************************************/
|
|
|
|
template <typename TYPE, int N>
|
|
class cListFixed {
|
|
public:
|
|
typedef TYPE Type;
|
|
typedef const TYPE& ArgType;
|
|
typedef unsigned IDX;
|
|
enum {MAX_SIZE = N};
|
|
|
|
inline cListFixed() : _size(0) {}
|
|
inline void CopyOf(const TYPE* pData, IDX nSize) {
|
|
memcpy(_vector, pData, nSize);
|
|
_size = nSize;
|
|
}
|
|
inline bool IsEmpty() const {
|
|
return (_size == 0);
|
|
}
|
|
inline IDX GetSize() const {
|
|
return _size;
|
|
}
|
|
inline const TYPE* Begin() const {
|
|
return _vector;
|
|
}
|
|
inline TYPE* Begin() {
|
|
return _vector;
|
|
}
|
|
inline const TYPE* End() const {
|
|
return _vector+_size;
|
|
}
|
|
inline TYPE* End() {
|
|
return _vector+_size;
|
|
}
|
|
inline const TYPE& First() const {
|
|
ASSERT(_size > 0);
|
|
return _vector[0];
|
|
}
|
|
inline TYPE& First() {
|
|
ASSERT(_size > 0);
|
|
return _vector[0];
|
|
}
|
|
inline const TYPE& Last() const {
|
|
ASSERT(_size > 0);
|
|
return _vector[_size-1];
|
|
}
|
|
inline TYPE& Last() {
|
|
ASSERT(_size > 0);
|
|
return _vector[_size-1];
|
|
}
|
|
inline const TYPE& operator[](IDX index) const {
|
|
ASSERT(index < _size);
|
|
return _vector[index];
|
|
}
|
|
inline TYPE& operator[](IDX index) {
|
|
ASSERT(index < _size);
|
|
return _vector[index];
|
|
}
|
|
inline bool operator==(const cListFixed& rList) const {
|
|
if (_size != rList._size)
|
|
return false;
|
|
for (IDX i = 0; i < _size; ++i)
|
|
if (_vector[i] != rList._vector[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
inline TYPE& AddEmpty() {
|
|
ASSERT(_size < N);
|
|
return _vector[_size++];
|
|
}
|
|
inline void InsertAt(IDX index, ArgType elem) {
|
|
ASSERT(_size < N);
|
|
memmove(_vector+index+1, _vector+index, sizeof(TYPE)*(_size++ - index));
|
|
_vector[index] = elem;
|
|
}
|
|
inline void Insert(ArgType elem) {
|
|
ASSERT(_size < N);
|
|
_vector[_size++] = elem;
|
|
}
|
|
inline void RemoveLast() {
|
|
ASSERT(_size);
|
|
--_size;
|
|
}
|
|
inline void RemoveAt(IDX index) {
|
|
ASSERT(index < _size);
|
|
if (index+1 == _size)
|
|
RemoveLast();
|
|
else
|
|
memcpy(_vector+index, _vector+(--_size), sizeof(TYPE));
|
|
}
|
|
inline void Empty() {
|
|
_ArrayDestruct(_vector, _size);
|
|
_size = 0;
|
|
}
|
|
inline void Sort() {
|
|
std::sort(Begin(), End());
|
|
}
|
|
inline IDX Find(ArgType elem) const
|
|
{
|
|
IDX i = _size;
|
|
while (i)
|
|
if (_vector[--i] == elem)
|
|
return i;
|
|
return NO_INDEX;
|
|
}
|
|
inline IDX FindFirstEqlGreater(ArgType searchedKey) const {
|
|
if (_size == 0) return 0;
|
|
IDX l1 = 0, l2 = _size;
|
|
do {
|
|
IDX i = (l1 + l2) >> 1;
|
|
const TYPE& key = _vector[i];
|
|
if (key == searchedKey) {
|
|
while (i-- && _vector[i] == searchedKey);
|
|
return i+1;
|
|
}
|
|
if (key < searchedKey)
|
|
l1 = i+1;
|
|
else
|
|
l2 = i;
|
|
} while (l1 < l2);
|
|
return l1;
|
|
}
|
|
inline void StoreTop(ArgType elem) {
|
|
const IDX idx(FindFirstEqlGreater(elem));
|
|
if (idx < GetSize()) {
|
|
if (GetSize() >= N)
|
|
RemoveLast();
|
|
InsertAt(idx, elem);
|
|
} else if (GetSize() < N) {
|
|
Insert(elem);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
TYPE _vector[N];
|
|
IDX _size;
|
|
|
|
public:
|
|
static const IDX NO_INDEX;
|
|
|
|
#ifdef _USE_BOOST
|
|
protected:
|
|
// implement BOOST serialization
|
|
friend class boost::serialization::access;
|
|
template<class Archive>
|
|
void serialize(Archive& ar, const unsigned int /*version*/) {
|
|
ar & _size;
|
|
ar & boost::serialization::make_array(_vector, _size);
|
|
}
|
|
#endif
|
|
};
|
|
template <typename TYPE, int N>
|
|
const typename cListFixed<TYPE,N>::IDX cListFixed<TYPE,N>::NO_INDEX(DECLARE_NO_INDEX(IDX));
|
|
/*----------------------------------------------------------------*/
|
|
|
|
} // namespace SEACAVE
|
|
|
|
#endif // __SEACAVE_LIST_H__
|