Class ScyllaRingBuffer<T>
High-performance fixed-capacity ring buffer backed by a circular array. Stores items in FIFO order (oldest-to-newest) and supports O(1) write, read, and peek operations.
Inherited Members
Namespace: Scylla.Core.Structures
Assembly: ScyllaCore.dll
Syntax
public sealed class ScyllaRingBuffer<T> : IScyllaCollection<T>, IScyllaCollection
Type Parameters
| Name | Description |
|---|---|
| T | The element type. Can be any managed type including reference types, value types, and nullable types. For Burst/DOTS-compatible unmanaged types, use ScyllaRingBufferDOTS<T> instead. |
Remarks
The buffer uses two integer indices - _head (oldest element) and _tail (next write
position) - that wrap around a fixed-length backing array. This design avoids any internal allocations
after construction and keeps all core operations at O(1).
Overwrite behavior: When overwriteOnFull is true and the buffer is full, a new
write discards the oldest element by advancing both head and tail simultaneously. When
overwriteOnFull is false, the write operation returns false without modifying
the buffer.
Thread-safety: This class is unsynchronized by default. All public state-mutating operations (TryWrite(T), TryRead(out T), RemoveWhere(Predicate<T>), Clear()) are not safe to call concurrently. Use AsSynchronized(object) or Synchronized(object) to obtain a fully lock-synchronized wrapper for multi-threaded scenarios.
Reference-type safety: When the element type is a reference type, removed or cleared slots are
explicitly set to default to release GC references.
// Direct construction
var buffer = new ScyllaRingBuffer<int>(capacity: 64, overwriteOnFull: true);
// Using fluent builder for complex configuration
var buffer = ScyllaRingBuffer<string>.CreateBuilder()
.WithCapacity(128)
.OverwriteOnFull()
.Synchronized()
.Build();
Constructors
ScyllaRingBuffer(int, bool)
Creates a new ring buffer with the specified fixed capacity.
Declaration
public ScyllaRingBuffer(int capacity, bool overwriteOnFull = false)
Parameters
| Type | Name | Description |
|---|---|---|
| int | capacity | The maximum number of elements the ring buffer can hold. Values less than 1 are clamped to 1. |
| bool | overwriteOnFull | If |
Properties
Capabilities
Gets the capability flags supported by this ring buffer instance.
Declaration
public ScyllaCollectionCapabilities Capabilities { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaCollectionCapabilities | A combination of ScyllaCollectionCapabilities flags. This ring buffer always advertises
|
Capacity
Gets the fixed maximum number of elements this ring buffer can hold.
Declaration
public int Capacity { get; }
Property Value
| Type | Description |
|---|---|
| int | The length of the backing array, set at construction time and never changed. |
Count
Gets the current number of elements stored in the ring buffer.
Declaration
public int Count { get; }
Property Value
| Type | Description |
|---|---|
| int | A value in the range |
FreeCount
Gets the number of additional elements that can be written before the buffer is full.
Declaration
public int FreeCount { get; }
Property Value
| Type | Description |
|---|---|
| int | Equivalent to |
IsEmpty
Gets whether the ring buffer contains no elements.
Declaration
public bool IsEmpty { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
IsFull
Gets whether the ring buffer is currently at full capacity.
Declaration
public bool IsFull { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
OverwriteOnFull
Gets whether writing to a full buffer automatically overwrites the oldest element.
Declaration
public bool OverwriteOnFull { get; }
Property Value
| Type | Description |
|---|---|
| bool |
|
SyncRoot
Gets the synchronization root for externally coordinating operations on this collection.
Declaration
public object SyncRoot { get; }
Property Value
| Type | Description |
|---|---|
| object | Always |
ThreadSafety
Gets the thread-safety level of this ring buffer instance.
Declaration
public ScyllaCollectionThreadSafety ThreadSafety { get; }
Property Value
| Type | Description |
|---|---|
| ScyllaCollectionThreadSafety | Always Unsynchronized for this concrete class. Obtain a synchronized wrapper via AsSynchronized(object) if thread safety is required. |
Methods
AsReversed()
Returns a lightweight wrapper struct that exposes GetEnumerator(), enabling foreach
syntax for iterating the buffer contents from newest to oldest.
Declaration
public ScyllaRingBuffer<T>.ReverseEnumerable AsReversed()
Returns
| Type | Description |
|---|---|
| ScyllaRingBuffer<T>.ReverseEnumerable | A ScyllaRingBuffer<T>.ReverseEnumerable struct that wraps this ring buffer for reverse iteration. |
Remarks
Usage: foreach (var item in buffer.AsReversed()) { ... }
AsSynchronized(object)
Creates and returns a thread-safe synchronized wrapper around this ring buffer.
Declaration
public ScyllaRingBuffer<T>.SynchronizedScyllaRingBuffer AsSynchronized(object syncRoot = null)
Parameters
| Type | Name | Description |
|---|---|---|
| object | syncRoot | Optional external lock object to use for synchronization. If |
Returns
| Type | Description |
|---|---|
| ScyllaRingBuffer<T>.SynchronizedScyllaRingBuffer | A ScyllaRingBuffer<T>.SynchronizedScyllaRingBuffer that wraps this ring buffer instance. |
Remarks
The returned ScyllaRingBuffer<T>.SynchronizedScyllaRingBuffer wraps this instance and acquires the supplied (or privately created) lock on every operation. This instance and the wrapper share the same backing state; mutations via one are immediately visible through the other. It is the caller's responsibility to avoid concurrent access through the unsynchronized instance once a synchronized wrapper has been issued.
Clear()
Removes all elements from the ring buffer and resets it to an empty state.
Declaration
public void Clear()
Remarks
For reference types, the occupied range of the backing array is cleared via
Clear(Array, int, int) to release GC references. For value types,
no array clearing is performed. After this method returns, _head, _tail, and
_count are all reset to 0. Returns immediately if the buffer is already empty.
Contains(T, IEqualityComparer<T>)
Determines whether the ring buffer contains at least one element equal to the specified item. Performs a linear scan from head to tail in O(n) time.
Declaration
public bool Contains(T item, IEqualityComparer<T> comparer = null)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | The item to locate in the buffer. |
| IEqualityComparer<T> | comparer | Optional equality comparer used for element comparisons. If |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
The scan starts at the physical position of the oldest element (_head) and follows the
circular order for Count steps, wrapping around the backing array as needed.
CopyTo(Span<T>)
Copies elements from the ring buffer into the provided span in oldest-to-newest (FIFO) order.
Declaration
public int CopyTo(Span<T> destination)
Parameters
| Type | Name | Description |
|---|---|---|
| Span<T> | destination | The span to copy elements into. Copying stops when either all elements have been copied or the
destination is full, whichever comes first. An empty span returns |
Returns
| Type | Description |
|---|---|
| int | The number of elements copied. |
Remarks
The copy is implemented as at most two contiguous Span<T> block copies to handle
the case where the occupied region wraps around the end of the backing array. The first block
runs from _head to the end of the array (or to the limit), and the second block, if needed,
continues from index 0. This avoids per-element iteration.
CopyTo(T[], int)
Copies elements from the ring buffer into the provided array starting at the specified index, in oldest-to-newest (FIFO) order.
Declaration
public int CopyTo(T[] destination, int destinationIndex)
Parameters
| Type | Name | Description |
|---|---|---|
| T[] | destination | The array to copy elements into. Must not be |
| int | destinationIndex | The zero-based index in |
Returns
| Type | Description |
|---|---|
| int | The number of elements copied. |
Remarks
Uses at most two Copy(Array, int, Array, int, int) calls to handle the case where the occupied region wraps around the end of the backing array, matching the two-segment copy strategy of the CopyTo(Span<T>) overload.
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
| ArgumentOutOfRangeException | Thrown when |
CreateBuilder()
Creates a new fluent builder for configuring and constructing a ScyllaRingBuffer<T> instance. The builder provides a discoverable API for setting capacity, overwrite-on-full mode, and synchronized wrappers.
Declaration
public static ScyllaRingBuffer<T>.Builder CreateBuilder()
Returns
| Type | Description |
|---|---|
| ScyllaRingBuffer<T>.Builder | A new ScyllaRingBuffer<T>.Builder instance with default configuration (capacity 4, no overwrite, unsynchronized). |
Remarks
var buffer = ScyllaRingBuffer<int>.CreateBuilder()
.WithCapacity(64)
.OverwriteOnFull()
.Build();
GetEnumerator()
Returns a forward enumerator that iterates through all elements in oldest-to-newest (FIFO) order.
Declaration
public ScyllaRingBuffer<T>.Enumerator GetEnumerator()
Returns
| Type | Description |
|---|---|
| ScyllaRingBuffer<T>.Enumerator | A ScyllaRingBuffer<T>.Enumerator positioned before the first (oldest) element. |
Remarks
The returned ScyllaRingBuffer<T>.Enumerator is a value type, so this method causes no heap allocation
when called on the concrete type. Use a foreach loop directly on ScyllaRingBuffer<T>
to take advantage of the struct enumerator pattern.
GetReverseEnumerator()
Returns a reverse enumerator that iterates through all elements in newest-to-oldest order.
Declaration
public ScyllaRingBuffer<T>.ReverseEnumerator GetReverseEnumerator()
Returns
| Type | Description |
|---|---|
| ScyllaRingBuffer<T>.ReverseEnumerator | A ScyllaRingBuffer<T>.ReverseEnumerator positioned before the first (newest) element. |
Remarks
The returned ScyllaRingBuffer<T>.ReverseEnumerator is a value type, so this method causes no heap
allocation when called on the concrete type. For foreach loop support, prefer
AsReversed().
PeekAt(int)
Returns the item at the specified logical index without removing it.
Declaration
public T PeekAt(int index)
Parameters
| Type | Name | Description |
|---|---|---|
| int | index | The zero-based logical index into the buffer. Must be in the range |
Returns
| Type | Description |
|---|---|
| T | The item stored at logical position |
Remarks
Logical index 0 maps to the oldest element (at physical index _head), and logical
index Count - 1 maps to the newest element. The physical index is computed via
LogicalToPhysical(int), which handles circular wraparound.
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | Thrown when |
RemoveWhere(Predicate<T>)
Removes all items that satisfy the specified predicate, preserving the FIFO order of the remaining items. Performs a single O(n) in-place compaction pass.
Declaration
public int RemoveWhere(Predicate<T> match)
Parameters
| Type | Name | Description |
|---|---|---|
| Predicate<T> | match | A predicate that returns |
Returns
| Type | Description |
|---|---|
| int | The number of elements removed. Returns |
Remarks
The algorithm reads each live element in logical (oldest-to-newest) order. Elements for which
match returns false are written back to the backing array at a
compacted position beginning from _head. Elements for which match
returns true are skipped (removed).
After the pass, _tail is updated to point one past the last retained element, and
_count is decremented by the number of removed items. If all elements are removed,
_head and _tail are both reset to 0 to avoid unnecessary wraparound on
the next write.
For reference types, vacated backing-array slots are explicitly set to default to
release GC references.
Exceptions
| Type | Condition |
|---|---|
| ArgumentNullException | Thrown when |
TryAdd(T)
Attempts to add an item to the ring buffer. Delegates to TryWrite(T). Implements TryAdd(T) for polymorphic usage.
Declaration
public bool TryAdd(T item)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | The item to add. |
Returns
| Type | Description |
|---|---|
| bool |
|
TryPeek(out T)
Attempts to peek at the oldest item without removing it. Delegates to TryPeekOldest(out T). Implements TryPeek(out T) for polymorphic usage.
Declaration
public bool TryPeek(out T item)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | When this method returns, contains the oldest element if the buffer is non-empty, or |
Returns
| Type | Description |
|---|---|
| bool |
|
TryPeekAt(int, out T)
Attempts to return the item at the specified logical index without removing it.
Declaration
public bool TryPeekAt(int index, out T item)
Parameters
| Type | Name | Description |
|---|---|---|
| int | index | The zero-based logical index into the buffer. Values outside |
| T | item | When this method returns, contains the element at |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
Unlike PeekAt(int), this method returns false and sets item
to default when the index is out of range, rather than throwing an exception.
TryPeekNewest(out T)
Attempts to inspect the most recently written item at the tail of the ring buffer without removing it.
Declaration
public bool TryPeekNewest(out T item)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | When this method returns, contains the newest element if the buffer is non-empty, or |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
The newest element's physical index is (_tail - 1 + Capacity) % Capacity, computed with
explicit wraparound to handle the case where _tail is currently at index 0.
TryPeekOldest(out T)
Attempts to inspect the oldest item at the head of the ring buffer without removing it.
Declaration
public bool TryPeekOldest(out T item)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | When this method returns, contains the oldest element if the buffer is non-empty, or |
Returns
| Type | Description |
|---|---|
| bool |
|
TryRead(out T)
Attempts to read (dequeue) the oldest item from the head of the ring buffer, removing it.
Declaration
public bool TryRead(out T item)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | When this method returns, contains the oldest element if the operation succeeded, or |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
On success the element at _head is returned, the backing-array slot is cleared to
default (releasing GC references for reference types), _head is advanced with
wraparound, and _count is decremented.
TryRemove(out T)
Attempts to remove the oldest item from the ring buffer. Delegates to TryRead(out T). Implements TryRemove(out T) for polymorphic usage.
Declaration
public bool TryRemove(out T item)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | When this method returns, contains the oldest element if the operation succeeded, or
|
Returns
| Type | Description |
|---|---|
| bool |
|
TryWrite(T)
Attempts to write (enqueue) an item at the tail of the ring buffer.
Declaration
public bool TryWrite(T item)
Parameters
| Type | Name | Description |
|---|---|---|
| T | item | The item to write. |
Returns
| Type | Description |
|---|---|
| bool |
|
Remarks
When the buffer is not full, the item is placed at _tail, _tail is advanced
with wraparound, and _count is incremented.
When the buffer is full and OverwriteOnFull is true, the item overwrites
the slot at _tail (which equals the oldest element's slot at _head in the full state),
and both _head and _tail advance by one. The count remains at capacity, and the
oldest element is silently discarded.