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