Minimal implementation of a circular buffer based on std::array, where elements can only be pushed and iterated. I'm interested on potential failures and very trivial optimizations, as I'd like to keep it as simple as possible.
#ifndef CIRCULAR_BUFFER_H
#define CIRCULAR_BUFFER_H
#include <array>
// Array-based push-only circular buffer.
// Sample usage:
//
// CircularBuffer<int, 3> buff;
// buff.push( 1 ); // 1
// buff.push( 2 ); // 1 2
// buff.push( 3 ); // 1 2 3
// buff.push( 4 ); // 2 3 4
// buff.push( 5 ); // 3 4 5
//for( int i : buff )
// std::cout << i << std::endl;
template <class T, std::size_t SIZE>
class CircularBuffer
{
public:
static_assert( SIZE > 0 );
void push( const T & value )
{
if( ( ++mCurrentIndex ) == mCapacity )
mCurrentIndex = 0;
mBuffer[ mCurrentIndex ] = value;
if( mSize != mCapacity )
++mSize;
}
void push( T && value )
{
if( ( ++mCurrentIndex ) == mCapacity )
mCurrentIndex = 0;
mBuffer[ mCurrentIndex ] = std::move( value );
if( mSize != mCapacity )
++mSize;
}
void reset()
{
mCurrentIndex = -1;
mSize = 0;
}
class iterator
{
public:
using iterator_category = std::output_iterator_tag;
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T&;
explicit iterator( pointer bufferPtr, unsigned int index, unsigned int visited ) :
mBufferPtr( bufferPtr ),
mIndex( index ),
mVisited( visited )
{}
iterator& operator++()
{
if( ++mIndex == mCapacity )
mIndex = 0;
++mVisited;
return *this;
}
iterator operator++( int )
{
iterator retval = *this;
++( *this );
return retval;
}
bool operator==( iterator other ) const
{
return ( ( mBufferPtr + mIndex ) == ( other.mBufferPtr + other.mIndex ) ) &&
( mVisited == other.mVisited );
}
bool operator!=( iterator other ) const
{
return !( *this == other );
}
reference operator*() const
{
if( mIndex == -1 )
throw std::runtime_error( "Circular buffer is empty" );
return mBufferPtr[ mIndex ];
}
private:
pointer mBufferPtr;
unsigned int mIndex;
unsigned int mVisited;
};
iterator begin()
{
const unsigned int beginIndex = ( mSize < mCapacity ) ? 0 : ( mCurrentIndex + 1 ) % mCapacity;
return iterator( mBuffer.data(), beginIndex, 1 );
}
iterator end()
{
const unsigned int endIndex = ( mSize < mCapacity ) ? ( mCurrentIndex + 1 ) : ( mCurrentIndex + 1 ) % mCapacity;
return iterator( mBuffer.data(), endIndex, mSize + 1 );
}
private:
enum { mCapacity = SIZE };
std::array<T, mCapacity> mBuffer;
unsigned int mCurrentIndex = -1;
unsigned int mSize = 0;
};
#endif // CIRCULAR_BUFFER_H