JBlam.Collections.CircularBuffer 0.0.1-testing

This is a prerelease version of JBlam.Collections.CircularBuffer.
dotnet add package JBlam.Collections.CircularBuffer --version 0.0.1-testing
                    
NuGet\Install-Package JBlam.Collections.CircularBuffer -Version 0.0.1-testing
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JBlam.Collections.CircularBuffer" Version="0.0.1-testing" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="JBlam.Collections.CircularBuffer" Version="0.0.1-testing" />
                    
Directory.Packages.props
<PackageReference Include="JBlam.Collections.CircularBuffer" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add JBlam.Collections.CircularBuffer --version 0.0.1-testing
                    
#r "nuget: JBlam.Collections.CircularBuffer, 0.0.1-testing"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package JBlam.Collections.CircularBuffer@0.0.1-testing
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=JBlam.Collections.CircularBuffer&version=0.0.1-testing&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=JBlam.Collections.CircularBuffer&version=0.0.1-testing&prerelease
                    
Install as a Cake Tool

JBlam.Collections.CircularBuffer

A fixed-capacity circular buffer which can expose immutable lists.

Usage

using JBlam.Collections.Immutable;

// Create a circular buffer which retains at least 20 elements.
// The default capacity will be twice the "length" - so 40 elements in this example.
const int BufferLength = 20;
CircularBuffer<int> b = new(BufferLength);

// Items may be enqueued without explicitly managing the buffering.
for (int i = 0; i < 50; i++)
    b.Enqueue(i);

// The buffer snapshot is immutable; the lifetime does not need to be managed.
BufferList<int> snapshot = b.Current;

// Even if we cycle through the whole buffer, the snapshot is still valid.
// The underlying storage for the snapshot still exists.
for (int i = 0; i < 50; i++)
    b.Enqueue(1000 + i);
// List is indexable, sliceable, enumerable.
System.Diagnostics.Debug.Assert(snapshot[^1] == 49);
System.Diagnostics.Debug.Assert(snapshot.Count == BufferLength);
// The underlying storage is garbage collected like any other .NET object: it's eligible
// for collection when there are no more references to the snapshot.

Why?

The main motivation was to create observable fixed-size collections, with favourable memory footprint and insertion algorithmic complexity. In plain terms: make it easy to produce "latest n elements from this observable".

Why not System.Collections.Generic.Queue

The BufferList<T> snapshots are immutable; you can freely pass them around or using them in an observable. Queue<T> is mutable, so the collection contents may have changed before (or even during) observation.

Why not System.Collections.Immutable.ImmutableQueue

ImmutableQueue is two ImmutableStack instances (one forward, one backward); an ImmutableStack is a linked list, which has poor tradeoffs for memory allocation and enumeration algorithmic complexity.

BufferList snapshots are a "linked list" two buffers. The underlying storage is a plain array.

Why not a sequence of arrays

Generating each array snapshot re-allocates item storage, so the observation sequence is O(n²) in memory.

Implementation

A CircularBuffer maintains two arrays of length n; when the "head" buffer is full, the "tail" buffer is discarded, the "head" becomes the "tail", and a new "head" is allocated.

BufferList snapshots are a value-type referencing a ReadOnlyMemory<T> slice of the current "head" and "tail".

The parent CircularBuffer may continue to mutate the "unused" slice of its head buffer, outside the "read-only" slice which may have already been observed in a BufferList.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.1-testing 63 2/11/2026

0.0.1; Initial release