You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1704 lines
41 KiB

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