#pragma once #pragma once #include "Array.h" NS_BF_BEGIN; template > class SizedArrayBase : protected TAlloc { public: typedef T value_type; T* mVals; intptr mSize; intptr mAllocSize; struct iterator { public: typedef std::random_access_iterator_tag iterator_category; typedef T value_type; typedef intptr difference_type; typedef T* pointer; typedef T& reference; public: T* mPtr; public: iterator() { mPtr = NULL; } iterator(T* ptr) { mPtr = ptr; } iterator& operator++() { mPtr++; return *this; } iterator operator++(int) { auto prevVal = *this; mPtr++; return prevVal; } iterator& operator--() { mPtr--; return *this; } iterator operator--(int) { auto prevVal = *this; mPtr--; return prevVal; } iterator& operator+=(intptr offset) { mPtr += offset; return *this; } bool operator!=(const iterator& itr) const { return itr.mPtr != mPtr; } bool operator==(const iterator& itr) const { return itr.mPtr == mPtr; } intptr operator-(const iterator& itr) const { return mPtr - itr.mPtr; } iterator operator+(intptr offset) const { iterator itr(mPtr + offset); return itr; } iterator operator-(intptr offset) const { iterator itr(mPtr - offset); return itr; } T& operator*() const { return *mPtr; } T* operator->() const { return mPtr; } bool operator<(const iterator& val2) { return mPtr < val2.mPtr; } bool operator>(const iterator& val2) { return mPtr > val2.mPtr; } bool operator>=(const iterator& val2) { return mPtr >= val2.mPtr; } }; struct const_iterator { public: typedef std::random_access_iterator_tag iterator_category; typedef T value_type; typedef intptr difference_type; typedef const T* pointer; typedef const T& reference; public: const T* mPtr; public: const_iterator(const T* ptr) { mPtr = ptr; } const_iterator& operator++() { mPtr++; return *this; } const_iterator operator++(int) { auto prevVal = *this; mPtr++; return prevVal; } bool operator!=(const const_iterator& itr) const { return itr.mPtr != mPtr; } bool operator==(const const_iterator& itr) const { return itr.mPtr == mPtr; } intptr operator-(const iterator& itr) const { return mPtr - itr.mPtr; } const_iterator operator+(intptr offset) const { const_iterator itr(mPtr + offset); return itr; } const T& operator*() { return *mPtr; } const T* operator->() { return mPtr; } bool operator<(const const_iterator& val2) { return mPtr < val2.mPtr; } }; private: public: SizedArrayBase() { this->mVals = NULL; this->mSize = 0; this->mAllocSize = 0; } SizedArrayBase(SizedArrayBase&& val) { this->mVals = val.mVals; this->mSize = val.mSize; this->mAllocSize = val.mAllocSize; val.mVals = NULL; val.mSize = 0; val.mAllocSize = 0; } T& operator[](intptr idx) { BF_ASSERT((uintptr)idx < (uintptr)this->mSize); return this->mVals[idx]; } const T& operator[](intptr idx) const { BF_ASSERT((uintptr)idx < (uintptr)this->mSize); return this->mVals[idx]; } bool operator==(const SizedArrayBase& arrB) const { if (this->mSize != arrB.mSize) return false; for (int i = 0; i < this->mSize; i++) if (this->mVals[i] != arrB.mVals[i]) return false; return true; } bool operator!=(const SizedArrayBase& arrB) const { if (this->mSize != arrB.mSize) return true; for (int i = 0; i < this->mSize; i++) if (this->mVals[i] != arrB.mVals[i]) return true; return false; } const_iterator begin() const { return this->mVals; } const_iterator end() const { return this->mVals + this->mSize; } iterator begin() { return this->mVals; } iterator end() { return this->mVals + this->mSize; } T& front() const { return this->mVals[0]; } T& back() const { return this->mVals[this->mSize - 1]; } intptr size() const { return this->mSize; } bool empty() const { return this->mSize == 0; } bool IsEmpty() const { return this->mSize == 0; } void clear() { this->mSize = 0; } void Clear() { this->mSize = 0; } /*void Free() { if (this->mVals != NULL) { deallocate(this->mVals); } this->mVals = NULL; this->mAllocSize = 0; this->mSize = 0; }*/ T GetSafe(intptr idx) { if ((idx < 0) || (idx >= this->mSize)) return T(); return this->mVals[idx]; } T GetLastSafe() { if (this->mSize == 0) return T(); return this->mVals[this->mSize - 1]; } T GetFirstSafe() { if (this->mSize == 0) return T(); return this->mVals[0]; } bool Contains(T val) const { for (int i = 0; i < this->mSize; i++) if (this->mVals[i] == val) return true; return false; } intptr IndexOf(T val) const { for (int i = 0; i < this->mSize; i++) if (this->mVals[i] == val) return i; return -1; } }; // NON-POD template class SizedArrayBaseT : public SizedArrayBase { public: typedef typename std::aligned_storage::type TStorage; TStorage mFirstVal; protected: void MoveArray(T* to, T* from, intptr count) { if (to < from) { // Prefer in-order moves for (intptr i = 0; i < count; i++) new (&to[i]) T(std::move(from[i])); } else { for (intptr i = count - 1; i >= 0; i--) new (&to[i]) T(std::move(from[i])); } } void Grow(intptr newSize) { T* newVals = TAlloc::allocate(newSize); if (this->mVals != NULL) { if (this->mSize > 0) MoveArray(newVals, this->mVals, this->mSize); if (this->mVals != (T*)&mFirstVal) TAlloc::deallocate(this->mVals); } this->mVals = newVals; this->mAllocSize = newSize; } void EnsureFree(intptr freeCount) { if (this->mSize + freeCount > this->mAllocSize) Grow(std::max(this->mAllocSize + this->mAllocSize / 2 + 1, this->mSize + freeCount)); } public: using SizedArrayBase::SizedArrayBase; SizedArrayBaseT() : SizedArrayBase() { } SizedArrayBaseT(const SizedArrayBaseT& val) { this->mVals = NULL; this->mSize = 0; this->mAllocSize = 0; *this = val; } SizedArrayBaseT(SizedArrayBaseT&& val) : SizedArrayBase(val) { } ~SizedArrayBaseT() { for (int i = 0; i < this->mSize; i++) this->mVals[i].~T(); if (this->mVals != (T*)&mFirstVal) { TAlloc::deallocate(this->mVals); } } void resize(intptr size) { while (size < this->mSize) pop_back(); if (size > this->mSize) { reserve(size); while (size > this->mSize) new (&this->mVals[this->mSize++]) T(); } } void reserve(intptr size) { if (size > this->mAllocSize) Grow(size); } void SetSize(intptr size) { if (size > this->mAllocSize) Grow(size); this->mSize = size; } SizedArrayBaseT& operator=(const SizedArrayBaseT& val) { if (&val == this) return *this; for (int i = 0; i < this->mSize; i++) this->mVals[i].~T(); this->mSize = 0; if (val.mSize > this->mAllocSize) Grow(val.mSize); resize(val.mSize); for (int i = 0; i < val.mSize; i++) new (&this->mVals[i]) T(val.mVals[i]); this->mSize = val.mSize; return *this; } void RemoveAt(intptr idx) { BF_ASSERT((uintptr)idx < (uintptr)this->mSize); this->mVals[idx].~T(); // If we're removing the last element then we don't have to move anything if (idx != this->mSize - 1) { intptr moveCount = this->mSize - idx - 1; MoveArray(this->mVals + idx, this->mVals + idx + 1, moveCount); } this->mSize--; } void RemoveAll(const std::function& func) { int outIdx = 0; for (int i = 0; i < this->mSize; i++) { if (func(this->mVals[i])) { this->mVals[i].~T(); } else { if (i != outIdx) { new (&this->mVals[outIdx]) T(this->mVals[i]); } outIdx++; } } this->mSize = outIdx; } void RemoveRange(intptr idx, intptr length) { BF_ASSERT( ((uintptr)idx < (uintptr)this->mSize) && ((uintptr)length > 0) && ((uintptr)(idx + length) <= (uintptr)this->mSize)); for (intptr i = idx; i < idx + length; i++) this->mVals[i].~T(); // If we're removing the last element then we don't have to move anything if (idx != this->mSize - length) { intptr moveCount = this->mSize - idx - length; MoveArray(this->mVals + idx, this->mVals + idx + length, moveCount); } this->mSize -= length; } void Insert(intptr idx, T val) { BF_ASSERT((uintptr)idx <= (uintptr)this->mSize); if (this->mSize >= this->mAllocSize) { intptr newSize = this->mAllocSize + this->mAllocSize / 2 + 1; T* newVals = TAlloc::allocate(newSize); if (this->mVals != NULL) { if (idx > 0) // Copy left of idx MoveArray(newVals, this->mVals, idx); if (idx < this->mSize) // Copy right of idx MoveArray(newVals + idx + 1, this->mVals + idx, this->mSize - idx); if (this->mVals != (T*)&mFirstVal) TAlloc::deallocate(this->mVals); } this->mVals = newVals; this->mAllocSize = newSize; } else if (idx != this->mSize) { intptr moveCount = this->mSize - idx; MoveArray(this->mVals + idx + 1, this->mVals + idx, moveCount); } new (&this->mVals[idx]) T(val); this->mSize++; } void Insert(intptr idx, T* vals, intptr size) { BF_ASSERT((uintptr)idx <= (uintptr)this->mSize); if (this->mSize + size > this->mAllocSize) { intptr newSize = BF_MAX(this->mSize + size, this->mAllocSize + this->mAllocSize / 2 + 1); T* newVals = TAlloc::allocate(newSize); if (this->mVals != NULL) { if (idx > 0) // Copy left of idx MoveArray(newVals, this->mVals, idx); if (idx < this->mSize) // Copy right of idx MoveArray(newVals + idx + size, this->mVals + idx, this->mSize - idx); if (this->mVals != (T*)&mFirstVal) TAlloc::deallocate(this->mVals); } this->mVals = newVals; this->mAllocSize = newSize; } else if (idx != this->mSize) { intptr moveCount = this->mSize - idx; MoveArray(this->mVals + idx + size, this->mVals + idx, moveCount); } for (int i = 0; i < size; i++) new (&this->mVals[idx + i]) T(vals[i]); this->mSize += size; } bool Remove(T val) { for (intptr i = 0; i < this->mSize; i++) { if (this->mVals[i] == val) { RemoveAt(i); return true; } } return false; } typename SizedArrayBase::iterator erase(typename SizedArrayBase::iterator itr) { RemoveAt(itr.mPtr - this->mVals); return itr; } void push_back(T val) { if (this->mSize >= this->mAllocSize) Grow(this->mAllocSize + this->mAllocSize / 2 + 1); new (&this->mVals[this->mSize++]) T(val); } void pop_back() { BF_ASSERT(this->mSize > 0); this->mVals[this->mSize - 1].~T(); --this->mSize; } void Add(T val) { if (this->mSize >= this->mAllocSize) Grow(this->mAllocSize + this->mAllocSize / 2 + 1); new (&this->mVals[this->mSize++]) T(val); } }; // POD template class SizedArrayBaseT : public SizedArrayBase { public: typedef T TStorage; T mFirstVal; protected: void Grow(intptr newSize) { T* newVals = TAlloc::allocate(newSize); if (this->mVals != NULL) { if (this->mSize > 0) memcpy(newVals, this->mVals, this->mSize * sizeof(T)); if (this->mVals != &mFirstVal) TAlloc::deallocate(this->mVals); } this->mVals = newVals; this->mAllocSize = newSize; } void EnsureFree(intptr freeCount) { if (this->mSize + freeCount > this->mAllocSize) Grow(std::max(this->mAllocSize + this->mAllocSize / 2 + 1, this->mSize + freeCount)); } public: using SizedArrayBase::SizedArrayBase; SizedArrayBaseT() : SizedArrayBase() { } SizedArrayBaseT(const SizedArrayBaseT& val) { this->mVals = NULL; this->mSize = 0; this->mAllocSize = 0; *this = val; } SizedArrayBaseT(SizedArrayBaseT&& val) : SizedArrayBase(val) { } ~SizedArrayBaseT() { if (this->mVals != &mFirstVal) { TAlloc::deallocate(this->mVals); } } SizedArrayBaseT& operator=(const SizedArrayBaseT& val) { if (&val == this) return *this; this->mSize = 0; if (val.mSize > this->mAllocSize) Grow(val.mSize); memcpy(this->mVals, val.mVals, val.mSize * sizeof(T)); this->mSize = val.mSize; return *this; } void resize(intptr size) { while (size < this->mSize) pop_back(); if (size > this->mSize) { reserve(size); while (size > this->mSize) new (&this->mVals[this->mSize++]) T(); } } void reserve(intptr size) { if (size > this->mAllocSize) Grow(size); } void SetSize(intptr size) { if (size > this->mAllocSize) Grow(size); this->mSize = size; } void RemoveAt(intptr idx) { BF_ASSERT((uintptr)idx < (uintptr)this->mSize); // If we're removing the last element then we don't have to move anything if (idx != this->mSize - 1) { intptr moveCount = this->mSize - idx - 1; memmove(this->mVals + idx, this->mVals + idx + 1, moveCount * sizeof(T)); } this->mSize--; } void RemoveRange(intptr idx, intptr length) { BF_ASSERT( ((uintptr)idx < (uintptr)this->mSize) && ((uintptr)length > 0) && ((uintptr)(idx + length) <= (uintptr)this->mSize)); // If we're removing the last element then we don't have to move anything if (idx != this->mSize - length) { intptr moveCount = this->mSize - idx - length; memmove(this->mVals + idx, this->mVals + idx + length, moveCount * sizeof(T)); } this->mSize -= length; } void Insert(intptr idx, T val) { BF_ASSERT((uintptr)idx <= (uintptr)this->mSize); if (this->mSize >= this->mAllocSize) { intptr newSize = this->mAllocSize + this->mAllocSize / 2 + 1; T* newVals = TAlloc::allocate(newSize); if (this->mVals != NULL) { if (idx > 0) // Copy left of idx memmove(newVals, this->mVals, idx * sizeof(T)); if (idx < this->mSize) // Copy right of idx memmove(newVals + idx + 1, this->mVals + idx, (this->mSize - idx) * sizeof(T)); if (this->mVals != &mFirstVal) TAlloc::deallocate(this->mVals); } this->mVals = newVals; this->mAllocSize = newSize; } else if (idx != this->mSize) { intptr moveCount = this->mSize - idx; memmove(this->mVals + idx + 1, this->mVals + idx, moveCount * sizeof(T)); } this->mVals[idx] = val; this->mSize++; } void Insert(intptr idx, const T* vals, intptr size) { BF_ASSERT((uintptr)idx <= (uintptr)this->mSize); if (this->mSize + size > this->mAllocSize) { intptr newSize = BF_MAX(this->mSize + size, this->mAllocSize + this->mAllocSize / 2 + 1); T* newVals = TAlloc::allocate(newSize); if (this->mVals != NULL) { if (idx > 0) // Copy left of idx memmove(newVals, this->mVals, idx * sizeof(T)); if (idx < this->mSize) // Copy right of idx memmove(newVals + idx + size, this->mVals + idx, (this->mSize - idx) * sizeof(T)); if (this->mVals != &mFirstVal) TAlloc::deallocate(this->mVals); } this->mVals = newVals; this->mAllocSize = newSize; } else if (idx != this->mSize) { intptr moveCount = this->mSize - idx; memmove(this->mVals + idx + size, this->mVals + idx, moveCount * sizeof(T)); } for (int i = 0; i < size; i++) this->mVals[idx + i] = vals[i]; this->mSize += size; } bool Remove(T val) { for (intptr i = 0; i < this->mSize; i++) { if (this->mVals[i] == val) { RemoveAt(i); return true; } } return false; } typename SizedArrayBase::iterator erase(typename SizedArrayBase::iterator itr) { RemoveAt(itr.mPtr - this->mVals); return itr; } void push_back(T val) { if (this->mSize >= this->mAllocSize) Grow(this->mAllocSize + this->mAllocSize / 2 + 1); this->mVals[this->mSize++] = val; } void pop_back() { BF_ASSERT(this->mSize > 0); --this->mSize; } void Add(T val) { if (this->mSize >= this->mAllocSize) Grow(this->mAllocSize + this->mAllocSize / 2 + 1); this->mVals[this->mSize++] = val; } }; template > class SizedArrayImpl : public SizedArrayBaseT::value> { public: typedef SizedArrayBaseT::value> _Base; }; template > class SizedArray : public SizedArrayImpl { public: typedef SizedArrayImpl _Base; typedef typename _Base::_Base _BaseBase; typename _Base::TStorage mInternalBuffer[TInternalSize - 1]; public: using SizedArrayImpl::SizedArrayImpl; using _Base::operator=; using _Base::operator==; using _Base::operator!=; SizedArray() { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = TInternalSize; } SizedArray(const Array& arr) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = TInternalSize; for (auto& val : arr) this->Add(val); } SizedArray(const SizedArray& val) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = TInternalSize; _BaseBase::operator=(val); } SizedArray(const typename _Base::_Base& val) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = TInternalSize; _BaseBase::operator=(val); } SizedArray(SizedArray&& val) { if (val.mVals == (T*)&val.mFirstVal) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = TInternalSize; _BaseBase::operator=(val); } else { this->mVals = val.mVals; this->mSize = val.mSize; this->mAllocSize = val.mAllocSize; val.mVals = (T*)&val.mFirstVal; val.mSize = 0; val.mAllocSize = TInternalSize; } } SizedArray(std::initializer_list il) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = TInternalSize; for (auto& val : il) this->push_back(val); } _BaseBase& operator=(const SizedArray& val) { if (&val == this) return *this; return _BaseBase::operator=(val); } _BaseBase& operator=(std::initializer_list il) { this->mSize = 0; for (auto& val : il) this->push_back(val); return *this; } }; template class SizedArray : public SizedArrayImpl { public: typedef SizedArrayImpl _Base; typedef typename _Base::_Base _BaseBase; using _Base::SizedArrayImpl; using _Base::operator=; using _Base::operator==; using _Base::operator!=; SizedArray() { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = 1; } SizedArray(const SizedArray& val) { this->mVals = NULL; this->mSize = 0; this->mAllocSize = 0; _BaseBase::operator=(val); } SizedArray(const _BaseBase& val) { this->mVals = NULL; this->mSize = 0; this->mAllocSize = 0; _BaseBase::operator=(val); } SizedArray(SizedArray&& val) { if (val.mVals == (T*)&val.mFirstVal) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = 1; _BaseBase::operator=(val); } else { this->mVals = val.mVals; this->mSize = val.mSize; this->mAllocSize = val.mAllocSize; val.mVals = NULL; val.mSize = 0; val.mAllocSize = 0; } } SizedArray(std::initializer_list il) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = 1; for (auto& val : il) this->push_back(val); } _BaseBase& operator=(const SizedArray& val) { if (&val == this) return *this; return _BaseBase::operator=(val); } }; template class SizedArray : public SizedArrayImpl { public: typedef SizedArrayImpl _Base; typedef typename _Base::_Base _BaseBase; using _Base::SizedArrayImpl; using _Base::operator=; using _Base::operator==; using _Base::operator!=; SizedArray() { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = 1; } SizedArray(const SizedArray& val) { this->mVals = NULL; this->mSize = 0; this->mAllocSize = 0; _BaseBase::operator=(val); } SizedArray(const _BaseBase& val) { this->mVals = NULL; this->mSize = 0; this->mAllocSize = 0; _BaseBase::operator=(val); } SizedArray(SizedArray&& val) { if (val.mVals == val.mInternalBuffer) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = 1; _BaseBase::operator=(val); } else { this->mVals = val.mVals; this->mSize = val.mSize; this->mAllocSize = val.mAllocSize; val.mVals = &val.mInternalBuffer; val.mSize = 0; val.mAllocSize = 1; } } SizedArray(std::initializer_list il) { this->mVals = (T*)&this->mFirstVal; this->mSize = 0; this->mAllocSize = 1; for (auto& val : il) this->push_back(val); } _BaseBase& operator=(const SizedArray& val) { return _BaseBase::operator=(val); } }; template static bool operator==(const ArrayBase& arrA, const SizedArrayBase& arrB) { if (arrA.mSize != arrB.mSize) return false; for (intptr i = 0; i < arrA.mSize; i++) if (arrA.mVals[i] != arrB.mVals[i]) return false; return true; } NS_BF_END; namespace std { template struct hash > { size_t operator()(const Beefy::SizedArrayImpl& val) const { return HashBytes((const uint8*)val.mVals, sizeof(T) * val.mSize); } }; }