mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 03:28:20 +02:00
1100 lines
21 KiB
C++
1100 lines
21 KiB
C++
#pragma once
|
|
|
|
#include "../Common.h"
|
|
#include "Array.h"
|
|
|
|
NS_BF_BEGIN;
|
|
|
|
#define DEQUE_IDX(i) (this->mVals[((i) + this->mOffset) % this->mAllocSize])
|
|
#define DEQUE_IDX_ON(arr, i) ((arr).mVals[((i) + (arr).mOffset) % (arr).mAllocSize])
|
|
|
|
template <typename T, typename TAlloc = AllocatorCLib >
|
|
class DequeBase : public TAlloc
|
|
{
|
|
public:
|
|
typedef T value_type;
|
|
|
|
T* mVals;
|
|
intptr mSize;
|
|
intptr mAllocSize;
|
|
intptr mOffset;
|
|
|
|
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:
|
|
DequeBase* mDeque;
|
|
intptr mIdx;
|
|
|
|
public:
|
|
iterator()
|
|
{
|
|
mIdx = -1;
|
|
}
|
|
|
|
iterator(DequeBase* deque, intptr idx)
|
|
{
|
|
mDeque = deque;
|
|
mIdx = idx;
|
|
}
|
|
|
|
iterator& operator++()
|
|
{
|
|
mIdx++;
|
|
return *this;
|
|
}
|
|
|
|
iterator operator++(int)
|
|
{
|
|
auto prevVal = *this;
|
|
mIdx++;
|
|
return prevVal;
|
|
}
|
|
|
|
iterator& operator--()
|
|
{
|
|
mIdx--;
|
|
return *this;
|
|
}
|
|
|
|
iterator operator--(int)
|
|
{
|
|
auto prevVal = *this;
|
|
mIdx--;
|
|
return prevVal;
|
|
}
|
|
|
|
iterator& operator+=(intptr offset)
|
|
{
|
|
mIdx += offset;
|
|
return *this;
|
|
}
|
|
|
|
bool operator!=(const iterator& itr) const
|
|
{
|
|
return itr.mIdx != mIdx;
|
|
}
|
|
|
|
bool operator==(const iterator& itr) const
|
|
{
|
|
return itr.mIdx == mIdx;
|
|
}
|
|
|
|
intptr operator-(const iterator& itr) const
|
|
{
|
|
return mIdx - itr.mIdx;
|
|
}
|
|
|
|
iterator operator+(intptr offset) const
|
|
{
|
|
iterator itr(mIdx + offset);
|
|
return itr;
|
|
}
|
|
|
|
iterator operator-(intptr offset) const
|
|
{
|
|
iterator itr(mIdx - offset);
|
|
return itr;
|
|
}
|
|
|
|
T& operator*() const
|
|
{
|
|
return DEQUE_IDX_ON(*mDeque, mIdx);
|
|
}
|
|
|
|
T* operator->() const
|
|
{
|
|
return &DEQUE_IDX_ON(*mDeque, mIdx);
|
|
}
|
|
|
|
bool operator<(const iterator& val2) const
|
|
{
|
|
return mIdx < val2.mIdx;
|
|
}
|
|
};
|
|
|
|
// 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*() const
|
|
// {
|
|
// return *mPtr;
|
|
// }
|
|
//
|
|
// const T* operator->() const
|
|
// {
|
|
// return mPtr;
|
|
// }
|
|
//
|
|
// bool operator<(const const_iterator& val2) const
|
|
// {
|
|
// return mPtr < val2.mPtr;
|
|
// }
|
|
// };
|
|
|
|
private:
|
|
|
|
|
|
public:
|
|
DequeBase()
|
|
{
|
|
mVals = NULL;
|
|
mSize = 0;
|
|
mAllocSize = 0;
|
|
mOffset = 0;
|
|
}
|
|
|
|
DequeBase(DequeBase<T, TAlloc>&& val)
|
|
{
|
|
mVals = val.mVals;
|
|
mSize = val.mSize;
|
|
mAllocSize = val.mAllocSize;
|
|
mOffset = val.mOffset;
|
|
|
|
val.mVals = NULL;
|
|
val.mSize = 0;
|
|
val.mAllocSize = 0;
|
|
val.mOffset = 0;
|
|
}
|
|
|
|
T& operator[](intptr idx)
|
|
{
|
|
BF_ASSERT((uintptr)idx < (uintptr)mSize);
|
|
return DEQUE_IDX(idx);
|
|
}
|
|
|
|
const T& operator[](intptr idx) const
|
|
{
|
|
BF_ASSERT((uintptr)idx < (uintptr)mSize);
|
|
return DEQUE_IDX(idx);
|
|
}
|
|
|
|
bool operator==(const DequeBase& arrB) const
|
|
{
|
|
if (mSize != arrB.mSize)
|
|
return false;
|
|
for (int i = 0; i < mSize; i++)
|
|
if (DEQUE_IDX(i) != DEQUE_IDX_ON(arrB, i))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool operator!=(const DequeBase& arrB) const
|
|
{
|
|
if (mSize != arrB.mSize)
|
|
return true;
|
|
for (int i = 0; i < mSize; i++)
|
|
if (DEQUE_IDX(i) != DEQUE_IDX_ON(arrB, i))
|
|
return true;
|
|
return true;
|
|
}
|
|
|
|
// const_iterator begin() const
|
|
// {
|
|
// return mVals;
|
|
// }
|
|
//
|
|
// const_iterator end() const
|
|
// {
|
|
// return mVals + mSize;
|
|
// }
|
|
|
|
iterator begin()
|
|
{
|
|
return iterator(this, 0);
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
return iterator(this, mSize);
|
|
}
|
|
|
|
T& front() const
|
|
{
|
|
return DEQUE_IDX(0);
|
|
}
|
|
|
|
T& back() const
|
|
{
|
|
return DEQUE_IDX(mSize - 1);
|
|
}
|
|
|
|
intptr size() const
|
|
{
|
|
return mSize;
|
|
}
|
|
|
|
bool empty() const
|
|
{
|
|
return mSize == 0;
|
|
}
|
|
|
|
bool IsEmpty() const
|
|
{
|
|
return mSize == 0;
|
|
}
|
|
|
|
/*void Free()
|
|
{
|
|
if (mVals != NULL)
|
|
{
|
|
deallocate(mVals);
|
|
}
|
|
mVals = NULL;
|
|
mAllocSize = 0;
|
|
mSize = 0;
|
|
}*/
|
|
|
|
T GetSafe(intptr idx)
|
|
{
|
|
if ((idx < 0) || (idx >= mSize))
|
|
return T();
|
|
return DEQUE_IDX(idx);
|
|
}
|
|
|
|
T GetLastSafe()
|
|
{
|
|
if (mSize == 0)
|
|
return T();
|
|
return DEQUE_IDX(mSize - 1);
|
|
}
|
|
|
|
T GetFirstSafe()
|
|
{
|
|
if (mSize == 0)
|
|
return T();
|
|
return DEQUE_IDX(0);
|
|
}
|
|
|
|
bool Contains(T val)
|
|
{
|
|
for (int i = 0; i < mSize; i++)
|
|
if (DEQUE_IDX(i) == val)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
intptr IndexOf(T val)
|
|
{
|
|
for (int i = 0; i < mSize; i++)
|
|
if (DEQUE_IDX(i) == val)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
intptr IndexOf(T val, int startIdx)
|
|
{
|
|
for (int i = startIdx; i < mSize; i++)
|
|
if (DEQUE_IDX(i) == val)
|
|
return i;
|
|
return -1;
|
|
}
|
|
};
|
|
|
|
// NON-POD
|
|
template <typename T, typename TAlloc, bool TIsPod>
|
|
class DequeImpl : public DequeBase<T, TAlloc>
|
|
{
|
|
protected:
|
|
void MoveDeque(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<T>(newSize);
|
|
if (this->mVals != NULL)
|
|
{
|
|
if (this->mSize > 0)
|
|
{
|
|
for (int i = 0; i < this->mSize; i++)
|
|
new (&newVals[i]) T(std::move(DEQUE_IDX(i)));
|
|
}
|
|
TAlloc::deallocate(this->mVals);
|
|
}
|
|
this->mVals = newVals;
|
|
this->mAllocSize = newSize;
|
|
this->mOffset = 0;
|
|
}
|
|
|
|
void EnsureFree(intptr freeCount)
|
|
{
|
|
if (this->mSize + freeCount > this->mAllocSize)
|
|
Grow(std::max(this->mAllocSize + this->mAllocSize / 2 + 1, this->mSize + freeCount));
|
|
}
|
|
|
|
public:
|
|
using DequeBase<T, TAlloc>::DequeBase;
|
|
|
|
DequeImpl() : DequeBase<T, TAlloc>()
|
|
{
|
|
|
|
}
|
|
|
|
DequeImpl(const DequeImpl& val)
|
|
{
|
|
this->mVals = NULL;
|
|
this->mSize = 0;
|
|
this->mAllocSize = 0;
|
|
this->mOffset = 0;
|
|
|
|
*this = val;
|
|
}
|
|
|
|
DequeImpl(DequeImpl&& val) : DequeBase<T, TAlloc>(std::move(val))
|
|
{
|
|
|
|
}
|
|
|
|
~DequeImpl()
|
|
{
|
|
for (int i = 0; i < this->mSize; i++)
|
|
this->mVals[i].~T(); //-V595
|
|
if (this->mVals != NULL)
|
|
{
|
|
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 (&DEQUE_IDX(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 Clear()
|
|
{
|
|
for (int i = 0; i < this->mSize; i++)
|
|
this->mVals[i].~T();
|
|
this->mSize = 0;
|
|
this->mOffset = 0;
|
|
}
|
|
|
|
DequeImpl& operator=(const DequeImpl& 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;
|
|
}
|
|
|
|
DequeImpl& operator=(DequeImpl&& val)
|
|
{
|
|
if (this->mVals != NULL)
|
|
{
|
|
for (int i = 0; i < this->mSize; i++)
|
|
this->mVals[i].~T();
|
|
TAlloc::deallocate(this->mVals);
|
|
}
|
|
|
|
this->mVals = val.mVals;
|
|
this->mSize = val.mSize;
|
|
this->mAllocSize = val.mAllocSize;
|
|
this->mOffset = val.mOffset;
|
|
|
|
val.mVals = NULL;
|
|
|
|
return *this;
|
|
}
|
|
|
|
void RemoveAt(intptr idx)
|
|
{
|
|
BF_ASSERT((uintptr)idx < (uintptr)this->mSize);
|
|
|
|
DEQUE_IDX(idx).~T();
|
|
|
|
if (idx == 0)
|
|
{
|
|
this->mOffset = (this->mOffset + 1) % this->mAllocSize;
|
|
}
|
|
else
|
|
{
|
|
// If we're removing the last element then we don't have to move anything
|
|
if (idx != this->mSize - 1)
|
|
{
|
|
for (intptr i = idx; i < this->mSize - 1; i++)
|
|
new (&DEQUE_IDX(i)) T(std::move(DEQUE_IDX(i + 1)));
|
|
}
|
|
}
|
|
this->mSize--;
|
|
}
|
|
|
|
// 'Fast' because it's allowed to change item order
|
|
void RemoveAtFast(intptr idx)
|
|
{
|
|
BF_ASSERT((uintptr)idx < (uintptr)this->mSize);
|
|
|
|
DEQUE_IDX(idx).~T();
|
|
|
|
if (idx == 0)
|
|
{
|
|
this->mOffset = (this->mOffset + 1) % this->mAllocSize;
|
|
}
|
|
else
|
|
{
|
|
// If we're removing the last element then we don't have to move anything
|
|
if (idx != this->mSize - 1)
|
|
{
|
|
new (&DEQUE_IDX(idx)) T(std::move(DEQUE_IDX(this->mSize - 1)));
|
|
}
|
|
}
|
|
this->mSize--;
|
|
}
|
|
|
|
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++)
|
|
DEQUE_IDX(i).~T();
|
|
|
|
// If we're removing the last element then we don't have to move anything
|
|
if (idx != this->mSize - length)
|
|
{
|
|
for (intptr i = idx; i < this->mSize - length; i++)
|
|
new (&DEQUE_IDX(i)) T(std::move(DEQUE_IDX(i + 1)));
|
|
}
|
|
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
|
|
// MoveDeque(newVals, this->mVals, idx);
|
|
// if (idx < this->mSize) // Copy right of idx
|
|
// MoveDeque(newVals + idx + 1, this->mVals + idx, this->mSize - idx);
|
|
// TAlloc::deallocate(this->mVals);
|
|
// }
|
|
// this->mVals = newVals;
|
|
// this->mAllocSize = newSize;
|
|
// }
|
|
// else if (idx != this->mSize)
|
|
// {
|
|
// intptr moveCount = this->mSize - idx;
|
|
// MoveDeque(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
|
|
// MoveDeque(newVals, this->mVals, idx);
|
|
// if (idx < this->mSize) // Copy right of idx
|
|
// MoveDeque(newVals + idx + size, this->mVals + idx, this->mSize - idx);
|
|
// TAlloc::deallocate(this->mVals);
|
|
// }
|
|
// this->mVals = newVals;
|
|
// this->mAllocSize = newSize;
|
|
// }
|
|
// else if (idx != this->mSize)
|
|
// {
|
|
// intptr moveCount = this->mSize - idx;
|
|
// MoveDeque(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;
|
|
// }
|
|
//
|
|
// void Insert(intptr idx, T val, intptr count)
|
|
// {
|
|
// BF_ASSERT((uintptr)idx <= (uintptr)this->mSize);
|
|
// if (this->mSize + count > this->mAllocSize)
|
|
// {
|
|
// intptr newSize = BF_MAX(this->mSize + count, this->mAllocSize + this->mAllocSize / 2 + 1);
|
|
//
|
|
// T* newVals = TAlloc::allocate(newSize);
|
|
// if (this->mVals != NULL)
|
|
// {
|
|
// if (idx > 0) // Copy left of idx
|
|
// MoveDeque(this->newVals, this->mVals, idx);
|
|
// if (idx < this->mSize) // Copy right of idx
|
|
// MoveDeque(newVals + idx + count, this->mVals + idx, this->mSize - idx);
|
|
// TAlloc::deallocate(this->mVals);
|
|
// }
|
|
// this->mVals = newVals;
|
|
// this->mAllocSize = newSize;
|
|
// }
|
|
// else if (idx != this->mSize)
|
|
// {
|
|
// intptr moveCount = this->mSize - idx;
|
|
// MoveDeque(this->mVals + idx + count, this->mVals + idx, moveCount);
|
|
// }
|
|
// for (int i = 0; i < count; i++)
|
|
// new (&this->mVals[idx + i]) T(val);
|
|
// this->mSize += count;
|
|
// }
|
|
|
|
bool Remove(T val)
|
|
{
|
|
for (intptr i = 0; i < this->mSize; i++)
|
|
{
|
|
if (this->mVals[i] == val)
|
|
{
|
|
RemoveAt(i);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// typename DequeBase<T, TAlloc>::iterator erase(typename DequeBase<T, TAlloc>::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 (&DEQUE_IDX(this->mSize++)) T(val);
|
|
}
|
|
|
|
void pop_back()
|
|
{
|
|
BF_ASSERT(this->mSize > 0);
|
|
DEQUE_IDX(this->mSize - 1).~T();
|
|
--this->mSize;
|
|
}
|
|
|
|
T PopBack()
|
|
{
|
|
BF_ASSERT(this->mSize > 0);
|
|
T value = DEQUE_IDX(this->mSize - 1);
|
|
DEQUE_IDX(this->mSize - 1).~T();
|
|
--this->mSize;
|
|
return value;
|
|
}
|
|
|
|
T RemoveBack()
|
|
{
|
|
BF_ASSERT(this->mSize > 0);
|
|
DEQUE_IDX(this->mSize - 1).~T();
|
|
--this->mSize;
|
|
}
|
|
|
|
void Add(T val)
|
|
{
|
|
if (this->mSize >= this->mAllocSize)
|
|
Grow(this->mAllocSize + this->mAllocSize / 2 + 1);
|
|
new (&DEQUE_IDX(this->mSize++)) T(val);
|
|
}
|
|
};
|
|
|
|
// POD
|
|
template <typename T, typename TAlloc>
|
|
class DequeImpl<T, TAlloc, true> : public DequeBase<T, TAlloc>
|
|
{
|
|
protected:
|
|
void Grow(intptr newSize)
|
|
{
|
|
T* newVals = TAlloc::allocate<T>(newSize);
|
|
if (this->mVals != NULL)
|
|
{
|
|
if (this->mSize > 0)
|
|
{
|
|
intptr endSegSize = this->mAllocSize - this->mOffset;
|
|
if (endSegSize < this->mSize)
|
|
{
|
|
memcpy(newVals, this->mVals + this->mOffset, endSegSize * sizeof(T));
|
|
memcpy(newVals + endSegSize, this->mVals, (this->mSize - endSegSize) * sizeof(T));
|
|
}
|
|
else
|
|
{
|
|
memcpy(newVals, this->mVals + this->mOffset, this->mSize * sizeof(T));
|
|
}
|
|
}
|
|
this->mOffset = 0;
|
|
TAlloc::deallocate(this->mVals);
|
|
}
|
|
this->mVals = newVals;
|
|
this->mAllocSize = newSize;
|
|
BF_ASSERT(this->mOffset < this->mAllocSize);
|
|
}
|
|
|
|
void EnsureFree(intptr freeCount)
|
|
{
|
|
if (this->mSize + freeCount > this->mAllocSize)
|
|
Grow(std::max(this->mAllocSize + this->mAllocSize / 2 + 1, this->mSize + freeCount));
|
|
}
|
|
|
|
public:
|
|
using DequeBase<T, TAlloc>::DequeBase;
|
|
|
|
DequeImpl() : DequeBase<T, TAlloc>::DequeBase()
|
|
{
|
|
|
|
}
|
|
|
|
DequeImpl(const DequeImpl& val)
|
|
{
|
|
this->mVals = NULL;
|
|
this->mSize = 0;
|
|
this->mAllocSize = 0;
|
|
this->mOffset = 0;
|
|
|
|
*this = val;
|
|
}
|
|
|
|
DequeImpl(DequeImpl&& val) : DequeBase<T, TAlloc>(std::move(val))
|
|
{
|
|
|
|
}
|
|
|
|
~DequeImpl()
|
|
{
|
|
if (this->mVals != NULL)
|
|
{
|
|
TAlloc::deallocate(this->mVals);
|
|
}
|
|
}
|
|
|
|
DequeImpl& operator=(const DequeImpl& 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)
|
|
{
|
|
if (size < this->mSize)
|
|
this->mSize = size;
|
|
else if (size > this->mSize)
|
|
{
|
|
Reserve(size);
|
|
while (size > this->mSize)
|
|
{
|
|
int idx = this->mSize;
|
|
DEQUE_IDX(idx) = T();
|
|
this->mSize = idx;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResizeRaw(intptr size)
|
|
{
|
|
if (size < this->mSize)
|
|
this->mSize = size;
|
|
else if (size > this->mSize)
|
|
{
|
|
Reserve(size);
|
|
this->mSize = size;
|
|
}
|
|
}
|
|
|
|
void Reserve(intptr size)
|
|
{
|
|
if (size > this->mAllocSize)
|
|
Grow(size);
|
|
}
|
|
|
|
void SetSize(intptr size)
|
|
{
|
|
if (size > this->mAllocSize)
|
|
Grow(size);
|
|
|
|
this->mSize = size;
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
this->mSize = 0;
|
|
this->mOffset = 0;
|
|
}
|
|
|
|
void RemoveAt(intptr idx)
|
|
{
|
|
BF_ASSERT((uintptr)idx < (uintptr)this->mSize);
|
|
|
|
if (idx == 0)
|
|
{
|
|
this->mOffset = (this->mOffset + 1) % this->mAllocSize;
|
|
}
|
|
else
|
|
{
|
|
// 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));
|
|
for (intptr i = idx; i < this->mSize - 1; i++)
|
|
DEQUE_IDX(i) = DEQUE_IDX(i + 1);
|
|
}
|
|
}
|
|
this->mSize--;
|
|
}
|
|
|
|
// 'Fast' because it's allowed to change item order
|
|
void RemoveAtFast(intptr idx)
|
|
{
|
|
BF_ASSERT((uintptr)idx < (uintptr)this->mSize);
|
|
|
|
if (idx == 0)
|
|
{
|
|
this->mOffset = (this->mOffset + 1) % this->mAllocSize;
|
|
}
|
|
else
|
|
{
|
|
// If we're removing the last element then we don't have to move anything
|
|
if (idx != this->mSize - 1)
|
|
{
|
|
DEQUE_IDX(idx) = DEQUE_IDX(this->mSize - 1);
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
for (intptr i = idx; i < this->mSize - length; i++)
|
|
DEQUE_IDX(i) = DEQUE_IDX(i + length);
|
|
}
|
|
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)
|
|
{
|
|
for (intptr i = 0; i < idx; i++) // Copy left of idx
|
|
newVals[i] = DEQUE_IDX(i);
|
|
for (intptr i = idx; i < this->mSize; i++) // Copy right of idx
|
|
newVals[i + 1] = DEQUE_IDX(i);
|
|
TAlloc::deallocate(this->mVals);
|
|
}
|
|
this->mVals = newVals;
|
|
this->mAllocSize = newSize;
|
|
this->mOffset = 0;
|
|
}
|
|
else if (idx != this->mSize)
|
|
{
|
|
for (intptr i = this->mSize; i > idx; i--)
|
|
DEQUE_IDX(i) = DEQUE_IDX(i - 1);
|
|
}
|
|
DEQUE_IDX(idx) = 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
|
|
// 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));
|
|
// 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++)
|
|
// DEQUE_IDX(idx + i) = vals[i];
|
|
// this->mSize += size;
|
|
// }
|
|
//
|
|
// void Insert(intptr idx, T val, 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));
|
|
// 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++)
|
|
// DEQUE_IDX(idx + i) = val;
|
|
// this->mSize += size;
|
|
// }
|
|
|
|
bool Remove(T val)
|
|
{
|
|
for (intptr i = 0; i < this->mSize; i++)
|
|
{
|
|
if (DEQUE_IDX(i) == val)
|
|
{
|
|
RemoveAt(i);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool RemoveAll(T val)
|
|
{
|
|
bool found = false;
|
|
|
|
for (intptr i = 0; i < this->mSize; i++)
|
|
{
|
|
if (DEQUE_IDX(i) == val)
|
|
{
|
|
found = true;
|
|
RemoveAt(i);
|
|
i--;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
typename DequeBase<T, TAlloc>::iterator erase(typename DequeBase<T, TAlloc>::iterator itr)
|
|
{
|
|
RemoveAt(itr.mIdx);
|
|
return itr;
|
|
}
|
|
|
|
void push_back(T val)
|
|
{
|
|
if (this->mSize >= this->mAllocSize)
|
|
Grow(this->mAllocSize + this->mAllocSize / 2 + 1);
|
|
DEQUE_IDX(this->mSize++) = val;
|
|
}
|
|
|
|
void pop_back()
|
|
{
|
|
BF_ASSERT(this->mSize > 0);
|
|
--this->mSize;
|
|
}
|
|
|
|
void RemoveBack()
|
|
{
|
|
BF_ASSERT(this->mSize > 0);
|
|
--this->mSize;
|
|
}
|
|
|
|
T PopBack()
|
|
{
|
|
BF_ASSERT(this->mSize > 0);
|
|
--this->mSize;
|
|
return this->mVals[this->mSize];
|
|
}
|
|
|
|
void Add(T val)
|
|
{
|
|
if (this->mSize >= this->mAllocSize)
|
|
Grow(this->mAllocSize + this->mAllocSize / 2 + 1);
|
|
DEQUE_IDX(this->mSize++) = val;
|
|
}
|
|
};
|
|
|
|
template <typename T, typename TAlloc = AllocatorCLib >
|
|
class Deque : public DequeImpl<T, TAlloc, std::is_pod<T>::value>
|
|
{
|
|
public:
|
|
typedef DequeImpl<T, TAlloc, std::is_pod<T>::value> _DequeImpl;
|
|
|
|
using DequeImpl<T, TAlloc, std::is_pod<T>::value>::DequeImpl;
|
|
using _DequeImpl::operator=;
|
|
using _DequeImpl::operator==;
|
|
using _DequeImpl::operator!=;
|
|
|
|
Deque() : _DequeImpl()
|
|
{
|
|
|
|
}
|
|
|
|
Deque(const Deque& val)
|
|
{
|
|
this->mVals = NULL;
|
|
this->mSize = 0;
|
|
this->mAllocSize = 0;
|
|
this->mOffset = 0;
|
|
|
|
*this = val;
|
|
}
|
|
|
|
Deque(Deque&& val) : _DequeImpl(std::move(val))
|
|
{
|
|
|
|
}
|
|
|
|
_DequeImpl& operator=(const Deque& val)
|
|
{
|
|
return _DequeImpl::operator=(val);
|
|
}
|
|
|
|
_DequeImpl& operator=(Deque&& val)
|
|
{
|
|
return _DequeImpl::operator=(val);
|
|
}
|
|
};
|
|
|
|
NS_BF_END;
|
|
|
|
namespace std
|
|
{
|
|
template<typename T>
|
|
struct hash<Beefy::Deque<T> >
|
|
{
|
|
size_t operator()(const Beefy::Deque<T>& val) const
|
|
{
|
|
return HashBytes((const uint8*)val.mVals, sizeof(T) * val.mSize);
|
|
}
|
|
};
|
|
}
|