27#ifndef sigproc_circularBuffer
28#define sigproc_circularBuffer
78template <
typename _derivedT,
typename _storedT,
typename _indexT>
87 static_assert( std::is_signed_v<_indexT> ==
true,
"circularBuffer indexT must be signed" );
190 return *
static_cast<derivedT *
>( this );
195 return *
static_cast<const derivedT *
>( this );
199template <
class derivedT,
typename storedT,
typename indexT>
204template <
class derivedT,
typename storedT,
typename indexT>
210template <
class derivedT,
typename storedT,
typename indexT>
220 derived().setMaxEntries( maxEnt );
225template <
class derivedT,
typename storedT,
typename indexT>
231template <
class derivedT,
typename storedT,
typename indexT>
237template <
class derivedT,
typename storedT,
typename indexT>
260template <
class derivedT,
typename storedT,
typename indexT>
282template <
class derivedT,
typename storedT,
typename indexT>
288template <
class derivedT,
typename storedT,
typename indexT>
294template <
class derivedT,
typename storedT,
typename indexT>
295uint64_t circularBufferBase<derivedT, storedT, indexT>::mono()
300template <
class derivedT,
typename storedT,
typename indexT>
306template <
class derivedT,
typename storedT,
typename indexT>
312template <
class derivedT,
typename storedT,
typename indexT>
315 return derived().at( refEntry, idx );
318template <
class derivedT,
typename storedT,
typename indexT>
321 return derived().at( refEntry, idx );
328template <
typename _storedT,
typename _indexT>
366 indexT _idx = refEntry + idx;
371 else if( _idx > this->
m_buffer.size() - 1 )
392 indexT _idx = refEntry + idx;
397 else if( _idx > this->
m_buffer.size() - 1 )
412template <
typename _storedT,
typename _indexT>
471template <
typename _storedT,
typename _indexT,
bool fixed_size = false>
474template <
typename _storedT,
typename _indexT>
476 :
public circularBufferBase<circularBufferIndex<_storedT, _indexT, false>, _storedT, _indexT>
479 typedef _storedT storedT;
480 typedef _indexT indexT;
483 std::vector<size_t> m_indices;
503 void setMaxEntries( indexT maxEnt )
505 m_indices.resize( 3 * this->m_maxEntries );
506 for(
size_t i = 0; i < this->m_maxEntries; ++i )
509 m_indices[this->m_maxEntries + i] = i;
510 m_indices[2 * this->m_maxEntries + i] = i;
519 storedT &at( indexT refEntry,
523 return this->m_buffer[m_indices[this->m_maxEntries + refEntry + idx]];
533 const storedT &at( indexT refEntry,
537 return this->m_buffer[this->m_maxEntries + m_indices[refEntry + idx]];
545template <
typename _storedT,
typename _indexT>
552 static_assert( std::is_signed_v<_indexT> ==
true,
"circularBuffer indexT must be signed" );
553 static_assert( std::is_trivially_copyable_v<_storedT> ==
true,
554 "fixed_size circularBufferIndex requires trivially copyable storedT" );
601 for(
size_t i = 0; i < static_cast<size_t>(
m_maxEntries ); ++i )
610 m_latest.store( 0, std::memory_order_release );
612 m_mono.store( 0, std::memory_order_release );
654 m_nextEntry.store( next, std::memory_order_relaxed );
655 m_mono.fetch_add( 1, std::memory_order_release );
674 return m_latest.load( std::memory_order_acquire );
680 return m_mono.load( std::memory_order_acquire );
709 sn.
mono =
m_mono.load( std::memory_order_acquire );
733 if( count <= 0 || refEntry < 0 || count > sn.
validEntries )
743 for(
indexT n = 0; n < count; ++n )
762 if( dest ==
nullptr )
767 for(
int retry = 0; retry < maxRetries; ++retry )
776 for(
indexT n = 0; n < count; ++n )
781 if(
m_mono.load( std::memory_order_acquire ) == sn.
mono )
802 for(
indexT n = 0; n < count; ++n )
807 return m_mono.load( std::memory_order_acquire ) == sn.
mono;
817 for(
int retry = 0; retry < maxRetries; ++retry )
827 if( sn.
latest >= count - 1 )
829 refEntry = sn.
latest - ( count - 1 );
841 for(
indexT n = 0; n < count; ++n )
846 if(
m_mono.load( std::memory_order_acquire ) == sn.
mono )
CRTP base class for all circular buffers, providing the underlying memory management and accessors.
storedT & at(indexT refEntry, indexT idx)
Get the entry at a given index relative a fixed reference entry.
storedT & operator[](indexT idx)
Get the entry at a given index.
indexT maxEntries()
Get the maximum size of the buffer.
circularBufferBase()
Default c'tor.
std::vector< storedT > m_buffer
The circular buffer storage.
void maxEntries(indexT maxEnt)
Set the maximum size of the buffer.
indexT size() const
Get the number of entries.
indexT earliest()
Returns the index of the earliest entry.
indexT latest()
Returns the index of the latest entry.
indexT m_maxEntries
The maximum number of entries to allow in the buffer before wrapping.
_derivedT derivedT
The child class.
_storedT storedT
The type stored in the circular buffer.
_indexT indexT
The index type, also used for sizes.
void nextEntry()
Move to the next entry in the circular buffer.
indexT m_latest
Index into m_buff of the latest entry. This is the newest entry in the buffer.
indexT m_nextEntry
Index into m_buffer of the next entry. This is the oldest entry in the buffer.
void nextEntry(const storedT &newEnt)
Add the next entry to the circular buffer.
_storedT storedT
The maximum number of entries to allow in the buffer before wrapping.
void setMaxEntries(indexT maxEnt)
Interface implementation for maxEntries.
const storedT & at(indexT refEntry, indexT idx) const
Interface implementation for entry access, const version.
circularBufferBranch()
Default c'tor.
storedT & at(indexT refEntry, indexT idx)
Interface implementation for entry access.
circularBufferBranch(indexT maxEnt)
Sizing constructor.
_indexT indexT
The index type, also used for sizes.
circularBufferIndex()=default
Default c'tor.
indexT size() const
Get the number of valid entries.
storedT operator[](indexT idx) const
Get the entry at a given index.
uint64_t mono() const
Returns the publication counter.
bool loadSequence(indexT refEntry, indexT count, storedT *dest, snapshotT &sn, int maxRetries=3) const
Copy a logical sequence into caller-owned storage, retrying if the producer advances.
indexT m_maxEntries
Fixed capacity of the buffer.
_indexT indexT
The index type, also used for sizes.
indexT maxEntries()
Get the fixed capacity of the buffer.
std::atomic< uint64_t > m_mono
A monotonic publication counter.
circularBufferIndex(indexT maxEnt)
Sizing constructor.
bool loadSequence(const snapshotT &sn, indexT refEntry, indexT count, storedT *dest) const
Copy a logical sequence from a caller-supplied snapshot, validating that the producer has not advance...
indexT latest() const
Returns the index of the latest entry.
std::vector< size_t > m_indices
Vector of indices for fast indexing into m_buffer.
std::atomic< indexT > m_latest
The latest slot published by the producer.
_storedT storedT
The maximum number of entries to allow in the buffer before wrapping.
indexT earliest() const
Returns the index of the earliest entry.
bool loadLatestSequence(indexT count, storedT *dest, snapshotT &sn, int maxRetries=3) const
Copy the latest logical sequence into caller-owned storage, retrying if the producer advances.
std::atomic< indexT > m_nextEntry
The slot that will be written next by the producer.
bool windowReadable(const snapshotT &sn, indexT refEntry, indexT count) const
Determine whether a logical window is readable from the provided snapshot.
snapshotT snapshot() const
Return a snapshot of the current readable region.
std::atomic< indexT > m_validEntries
The number of valid published entries.
void nextEntry(const storedT &newEnt)
Add the next entry to the circular buffer.
storedT at(indexT refEntry, indexT idx) const
Get the entry at a given index relative a fixed reference entry.
indexT physicalIndex(indexT refEntry, indexT idx) const
Convert a logical index into a physical slot index.
void nextEntry()
Move to the next entry using a default constructed value.
void maxEntries(indexT maxEnt)
Set the maximum size of the buffer.
std::vector< storedT > m_buffer
The circular buffer storage.
Circular buffer which wraps with a pre-populated indices array [generally fastest].
_storedT storedT
The maximum number of entries to allow in the buffer before wrapping.
_indexT indexT
The index type, also used for sizes.
const storedT & at(indexT refEntry, indexT idx) const
Interface implementation for entry access, const version.
circularBufferMod()
Default c'tor.
circularBufferMod(indexT maxEnt)
Sizing constructor.
storedT & at(indexT refEntry, indexT idx)
Interface implementation for entry access.
void setMaxEntries(indexT maxEnt)
Interface implementation for maxEntries.
Snapshot of the readable state of the buffer.
indexT validEntries
Number of currently valid entries.
indexT earliest
Earliest readable slot in the current snapshot.
indexT maxEntries
Fixed capacity.
bool full
Whether the buffer has reached fixed capacity.
uint64_t mono
Publication generation for retry validation.
indexT latest
Latest published slot in the current snapshot.