Last active
May 20, 2022 18:17
-
-
Save drabaioli/c2842fee2a70a7cfefd33d10336dada0 to your computer and use it in GitHub Desktop.
Circular buffer on top of std::array (push only)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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