Skip to content

Instantly share code, notes, and snippets.

@drabaioli
Last active May 20, 2022 18:17
Show Gist options
  • Save drabaioli/c2842fee2a70a7cfefd33d10336dada0 to your computer and use it in GitHub Desktop.
Save drabaioli/c2842fee2a70a7cfefd33d10336dada0 to your computer and use it in GitHub Desktop.
Circular buffer on top of std::array (push only)
#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, std::size_t index, std::size_t 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
{
return mBufferPtr[ mIndex ];
}
private:
pointer mBufferPtr;
std::size_t mIndex;
std::size_t mVisited;
};
class const_iterator
{
public:
using iterator_category = std::output_iterator_tag;
using value_type = const T;
using difference_type = std::ptrdiff_t;
using pointer = const T*;
using const_reference = const T &;
explicit const_iterator( pointer bufferPtr, std::size_t index, std::size_t visited ) :
mBufferPtr( bufferPtr ),
mIndex( index ),
mVisited( visited )
{}
const_iterator& operator++()
{
if( ++mIndex == mCapacity )
mIndex = 0;
++mVisited;
return *this;
}
const_iterator operator++( int )
{
iterator retval = *this;
++( *this );
return retval;
}
bool operator==( const_iterator other ) const
{
return ( ( mBufferPtr + mIndex ) == ( other.mBufferPtr + other.mIndex ) ) &&
( mVisited == other.mVisited );
}
bool operator!=( const_iterator other ) const
{
return !( *this == other );
}
const_reference operator*() const
{
return mBufferPtr[ mIndex ];
}
private:
pointer mBufferPtr;
std::size_t mIndex;
std::size_t mVisited;
};
iterator begin()
{
const std::size_t beginIndex = ( mSize < mCapacity ) ? 0 : ( mCurrentIndex + 1 ) % mCapacity;
return iterator( mBuffer.data(), beginIndex, 1 );
}
iterator end()
{
const std::size_t endIndex = ( mSize < mCapacity ) ? ( mCurrentIndex + 1 ) : ( mCurrentIndex + 1 ) % mCapacity;
return iterator( mBuffer.data(), endIndex, mSize + 1 );
}
const_iterator begin() const
{
const std::size_t beginIndex = ( mSize < mCapacity ) ? 0 : ( mCurrentIndex + 1 ) % mCapacity;
return const_iterator( mBuffer.data(), beginIndex, 1 );
}
const_iterator end() const
{
const std::size_t endIndex = ( mSize < mCapacity ) ? ( mCurrentIndex + 1 ) : ( mCurrentIndex + 1 ) % mCapacity;
return const_iterator( mBuffer.data(), endIndex, mSize + 1 );
}
private:
enum { mCapacity = SIZE };
std::array<T, mCapacity> mBuffer;
std::size_t mCurrentIndex = -1;
std::size_t mSize = 0;
};
#endif // CIRCULAR_BUFFER_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment