//////////////////////////////////////////////////////////////////// // 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 // 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::type::size_type #define SIZE2IDX(arr) typename std::remove_const::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(); var0; ) #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); var0; ) #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(arr)); const CLIST& var(*reinterpret_cast(_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(&vec[0])); const CLIST& var(*reinterpret_cast(_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 inline cList& JoinFunctor(IDX nSize, const Functor& functor) { Reserve(_size + nSize); if (useConstruct) { for (IDX n=0; n(_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 inline TYPE& AddConstruct(Args&&... args) { if (_vectorSize <= _size) _Grow(_vectorSize + grow); return *(new(_vector + (_size++)) TYPE(std::forward(args)...)); } #else template 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 inline void Insert(T&& elem) { if (_vectorSize <= _size) _Grow(_vectorSize + grow); if (useConstruct) new(_vector+(_size++)) TYPE(std::forward(elem)); else _vector[_size++] = std::forward(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 inline void SetAt(IDX index, T&& elem) { if (_size <= index) Resize(index + 1); _vector[index] = std::forward(elem); } #else inline void SetAt(IDX index, ARG_TYPE elem) { if (_size <= index) Resize(index + 1); _vector[index] = elem; } #endif #ifdef _SUPPORT_CPP11 template inline void AddAt(IDX index, T&& elem) { if (index < _size) return InsertAt(index, std::forward(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(elem)); else _vector[index] = std::forward(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 inline void InsertAt(IDX index, T&& elem) { if (useConstruct) new(AllocateAt(index)) TYPE(std::forward(elem)); else *AllocateAt(index) = std::forward(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(_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 ::value,TYPE,REAL>::type> inline RTYPE GetMedian() { ASSERT(_size > 0); if (_size%2) return static_cast(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(*nth1) + static_cast(*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 inline ArgType GetMax(const Functor& functor) const { return *std::max_element(Begin(), End(), functor); } inline IDX GetMaxIdx() const { return static_cast(std::max_element(Begin(), End()) - Begin()); } template inline IDX GetMaxIdx(const Functor& functor) const { return static_cast(std::max_element(Begin(), End(), functor) - Begin()); } #ifdef _SUPPORT_CPP11 inline std::pair GetMinMax() const { const auto minmax(std::minmax_element(Begin(), End())); return std::pair(*minmax.first, *minmax.second); } template inline std::pair GetMinMax(const Functor& functor) const { const auto minmax(std::minmax_element(Begin(), End(), functor)); return std::pair(*minmax.first, *minmax.second); } inline std::pair GetMinMaxIdx() const { const auto minmax(std::minmax_element(Begin(), End())); return std::make_pair(static_cast(minmax.first-Begin()), static_cast(minmax.second-Begin())); } template inline std::pair GetMinMaxIdx(const Functor& functor) const { const auto minmax(std::minmax_element(Begin(), End(), functor)); return std::make_pair(static_cast(minmax.first-Begin()), static_cast(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 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 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 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 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 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 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 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 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 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 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 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 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 inline IDX RFind(const SEARCH_TYPE& searchedKey) const { IDX i(_size); while (i) if (_vector[--i] == searchedKey) return i; return NO_INDEX; } template 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 inline void ForEach(const Functor& functor) const { FOREACH(i, *this) functor(i); } template inline void ForEachPtr(const Functor& functor) const { FOREACHPTR(ptr, *this) functor(ptr); } template inline void ForEachRef(const Functor& functor) const { FOREACHPTR(ptr, *this) functor(*ptr); } // same, but in reverse order template inline void RForEach(const Functor& functor) const { RFOREACH(i, *this) functor(i); } template inline void RForEachPtr(const Functor& functor) const { RFOREACHPTR(ptr, *this) functor(ptr); } template 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(_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(_vector+index, vectorEnd+del, move); _ArrayDestruct(vectorEnd, del); } else { _ArrayMoveCopy(_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(_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(_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~TYPE(); } } else { memmove((void*)dst, (const void*)src, n*sizeof(TYPE)); } } template 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 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 VectorType; inline cList(const VectorType& rList) { CopyOf(&rList[0], rList.size()); } #ifdef _SUPPORT_CPP11 inline cList(std::initializer_list l) : _size(0), _vectorSize((size_type)l.size()), _vector(NULL) { ASSERT(l.size()_vector, elem); } #ifdef _SUPPORT_CPP11 template inline reference emplace_back(Args&&... args) { return AddConstruct(std::forward(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 void save(Archive& ar, const unsigned int /*version*/) const { ar & _size; ar & boost::serialization::make_array(_vector, _size); } template 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 inline bool ValidIDX(const IDX_TYPE& idx) { return (idx != DECLARE_NO_INDEX(IDX_TYPE)); } /*----------------------------------------------------------------*/ // some test functions template inline bool cListTest(unsigned iters) { for (unsigned i=0; i arrR; cList arr0; cList arr1; cList arr2; cList arrC; for (unsigned i=0; i= 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 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 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 void serialize(Archive& ar, const unsigned int /*version*/) { ar & _size; ar & boost::serialization::make_array(_vector, _size); } #endif }; template const typename cListFixed::IDX cListFixed::NO_INDEX(DECLARE_NO_INDEX(IDX)); /*----------------------------------------------------------------*/ } // namespace SEACAVE #endif // __SEACAVE_LIST_H__