#ifndef COMMON_FIXEDQUEUE_H_
#define COMMON_FIXEDQUEUE_H_
#include "common/debug.h"
#include <algorithm>
#include <array>
#include <atomic>
namespace angle
{
template <class T>
class FixedQueue final : angle::NonCopyable
{
public:
using Storage = std::vector<T>;
using value_type = typename Storage::value_type;
using size_type = typename Storage::size_type;
using reference = typename Storage::reference;
using const_reference = typename Storage::const_reference;
FixedQueue(size_t capacity);
~FixedQueue();
size_type size() const;
bool empty() const;
bool full() const;
size_type capacity() const;
void updateCapacity(size_t newCapacity);
reference front();
const_reference front() const;
void push(const value_type &value);
void push(value_type &&value);
reference back();
const_reference back() const;
void pop();
void clear();
private:
Storage mData;
size_type mFrontIndex;
size_type mEndIndex;
std::atomic<size_type> mSize;
size_type mMaxSize;
};
template <class T>
FixedQueue<T>::FixedQueue(size_t capacity)
: mFrontIndex(0), mEndIndex(0), mSize(0), mMaxSize(capacity)
{
mData.resize(mMaxSize);
}
template <class T>
FixedQueue<T>::~FixedQueue()
{
mData.clear();
}
template <class T>
ANGLE_INLINE typename FixedQueue<T>::size_type FixedQueue<T>::size() const
{
ASSERT(mSize <= mMaxSize);
return mSize;
}
template <class T>
ANGLE_INLINE bool FixedQueue<T>::empty() const
{
return size() == 0;
}
template <class T>
ANGLE_INLINE bool FixedQueue<T>::full() const
{
return size() == mMaxSize;
}
template <class T>
ANGLE_INLINE typename FixedQueue<T>::size_type FixedQueue<T>::capacity() const
{
return mMaxSize;
}
template <class T>
ANGLE_INLINE void FixedQueue<T>::updateCapacity(size_t newCapacity)
{
ASSERT(newCapacity >= size());
Storage newData(newCapacity);
for (size_type i = mFrontIndex; i < mEndIndex; i++)
{
newData[i % newCapacity] = std::move(mData[i % mMaxSize]);
}
mData.clear();
std::swap(newData, mData);
mMaxSize = newCapacity;
ASSERT(mData.size() == mMaxSize);
}
template <class T>
ANGLE_INLINE typename FixedQueue<T>::reference FixedQueue<T>::front()
{
ASSERT(!empty());
return mData[mFrontIndex % mMaxSize];
}
template <class T>
ANGLE_INLINE typename FixedQueue<T>::const_reference FixedQueue<T>::front() const
{
ASSERT(!empty());
return mData[mFrontIndex % mMaxSize];
}
template <class T>
void FixedQueue<T>::push(const value_type &value)
{
ASSERT(!full());
mData[mEndIndex % mMaxSize] = value;
mEndIndex++;
mSize++;
}
template <class T>
void FixedQueue<T>::push(value_type &&value)
{
ASSERT(!full());
mData[mEndIndex % mMaxSize] = std::move(value);
mEndIndex++;
mSize++;
}
template <class T>
ANGLE_INLINE typename FixedQueue<T>::reference FixedQueue<T>::back()
{
ASSERT(!empty());
return mData[(mEndIndex + (mMaxSize - 1)) % mMaxSize];
}
template <class T>
ANGLE_INLINE typename FixedQueue<T>::const_reference FixedQueue<T>::back() const
{
ASSERT(!empty());
return mData[(mEndIndex + (mMaxSize - 1)) % mMaxSize];
}
template <class T>
void FixedQueue<T>::pop()
{
ASSERT(!empty());
mData[mFrontIndex % mMaxSize] = value_type();
mFrontIndex++;
mSize--;
}
template <class T>
void FixedQueue<T>::clear()
{
const size_type localSize = size();
for (size_type i = 0; i < localSize; i++)
{
pop();
}
}
}
#endif