Core.Buffers
1.0.36
dotnet add package Core.Buffers --version 1.0.36
NuGet\Install-Package Core.Buffers -Version 1.0.36
<PackageReference Include="Core.Buffers" Version="1.0.36" />
<PackageVersion Include="Core.Buffers" Version="1.0.36" />
<PackageReference Include="Core.Buffers" />
paket add Core.Buffers --version 1.0.36
#r "nuget: Core.Buffers, 1.0.36"
#:package Core.Buffers@1.0.36
#addin nuget:?package=Core.Buffers&version=1.0.36
#tool nuget:?package=Core.Buffers&version=1.0.36
Core.Buffers
A .NET library for efficient buffer management that provides thread-safe, modern, and fast buffer functionality currently missing in vanilla .NET.
Installation
dotnet add package Core.Buffers
Features
- DoubleBuffer<TEntity>: A thread-safe double-buffering mechanism for unmanaged types, allowing for concurrent read and write operations.
- DoubleBufferQueue<TEntity>: A thread-safe queue implementation built on top of a double buffer, allowing for concurrent enqueue operations while maintaining the ability to swap buffers atomically.
- CircularBuffer<T>: A thread-safe fixed-size circular buffer implementation, where the oldest item is overwritten when the buffer is full.
- RunningSumCircularBuffer<T>: A thread-safe specialized circular buffer that maintains a running sum of its elements for fast average calculations.
Usage
DoubleBuffer<TEntity>
The DoubleBuffer<TEntity>
class provides a thread-safe double-buffering mechanism that allows for concurrent read and write operations. This is particularly useful in scenarios where you need to write to a buffer while reading from another buffer.
using Core.Buffers;
using System.Buffers;
// Create a double buffer with a size of 1024 elements * 2 ( double buffer )
using var buffer = new DoubleBuffer<int>(MemoryPool<int>.Shared, 1024);
// Write to the active buffer
for (int i = 0; i < buffer.Size; i++)
{
buffer.Active.Span[i] = i;
}
// Swap buffers atomically and get the previous buffer as ReadOnlyMemory
ReadOnlyMemory<int> previousBuffer = buffer.Swap();
// Now you can read from the previous buffer while writing to the new active buffer
// The previousBuffer can be used directly for reading
// Write to the (next) active buffer
for (int i = 0; i < buffer.Size; i++)
{
buffer.Active.Span[i] = i;
}
// You can also access the shadow (inactive) buffer
Console.WriteLine($"Active buffer offset: {buffer.ActiveOffset}");
Console.WriteLine($"Shadow buffer offset: {buffer.ShadowOffset}");
// Read from the shadow buffer (read-only)
for (int i = 0; i < buffer.Size; i++)
{
Console.WriteLine(buffer.Shadow.Span[i]);
}
DoubleBufferQueue<TEntity>
The DoubleBufferQueue<TEntity>
class extends the DoubleBuffer<TEntity>
class to provide a thread-safe queue implementation that allows for concurrent enqueue operations while maintaining the ability to swap buffers atomically.
using Core.Buffers;
using System.Buffers;
// Create a double buffer queue with a size of 1024 elements * 2 ( double buffer )
using var queue = new DoubleBufferQueue<int>(MemoryPool<int>.Shared, 1024);
// Enqueue items to the active buffer
for (int i = 0; i < 100; i++)
{
queue.Enqueue(i);
// or
if (!queue.TryEnqueue(i)) break;
}
// Check if the queue is full
if (queue.Exhausted)
{
Console.WriteLine("Queue is full!");
}
// Get the count of items in the active buffer
Console.WriteLine($"Items in queue: {queue.Count}");
// Swap buffers atomically and get the previous buffer as ReadOnlyMemory, with the length of the committed items
ReadOnlyMemory<int> previousBuffer = queue.Swap();
// Now you can process the items in the previous buffer
// while new items are being enqueued to the new active buffer
// The previousBuffer contains only the valid items (sliced to the count)
CircularBuffer<T>
The CircularBuffer<T>
class provides a thread-safe fixed-size circular buffer implementation. When the buffer is full, adding new items overwrites the oldest items. The buffer uses MemoryPool for efficient memory management.
using Core.Buffers;
using System;
using System.Buffers;
using System.Threading.Tasks;
// Method 1: Create a circular buffer with a capacity of 5, using the shared MemoryPool
using var buffer1 = new CircularBuffer<int>(5, useMemoryPool: true);
// Method 2: Create a circular buffer with a capacity of 5, using a custom MemoryPool
using var customPool = MemoryPool<int>.Create();
using var buffer2 = new CircularBuffer<int>(customPool, 5);
// Method 3: Create a circular buffer with a capacity of 5, allocated on the heap (no pooling)
using var buffer3 = new CircularBuffer<int>(null, 5);
// or
using var buffer4 = new CircularBuffer<int>(5, useMemoryPool: false);
// Add items to the buffer
for (int i = 0; i < 10; i++)
{
var overwritten = buffer1.Push(i);
if (overwritten.HasValue)
{
Console.WriteLine($"Overwritten value: {overwritten.Value}"); // Will print values 0-4 as they get overwritten
}
}
// Check buffer state
Console.WriteLine($"Buffer count: {buffer1.Count}"); // 5
Console.WriteLine($"Buffer capacity: {buffer1.Capacity}"); // 5
Console.WriteLine($"Buffer is empty: {buffer1.IsEmpty}"); // False
// Access items by index
for (int i = 0; i < buffer1.Count; i++)
{
Console.WriteLine($"Item at index {i}: {buffer1[i]}");
}
// Iterate through the buffer
foreach (int item in buffer1)
{
Console.WriteLine(item);
}
// Convert to array
int[] array = buffer1.ToArray();
// Clear the buffer
buffer1.Clear();
Console.WriteLine($"Buffer is empty: {buffer1.IsEmpty}"); // True
// Thread-safe usage example
Parallel.For(0, 1000, i =>
{
buffer1.Push(i);
});
Console.WriteLine($"After parallel push, count: {buffer1.Count}"); // Will be 5 (or capacity)
RunningSumCircularBuffer<T>
The RunningSumCircularBuffer<T>
class extends the CircularBuffer<T>
class to maintain a running sum of its elements, allowing for efficient average calculations. This is useful for scenarios like calculating moving averages or other statistical operations on a sliding window of data.
using Core.Buffers;
using System;
using System.Buffers;
using System.Threading.Tasks;
// Method 1: Create a running sum circular buffer with a capacity of 5, using the shared MemoryPool
using var buffer1 = new RunningSumCircularBuffer<double>(5);
// Method 2: Create a running sum circular buffer with a capacity of 5, using a custom MemoryPool
using var customPool = MemoryPool<double>.Create();
using var buffer2 = new RunningSumCircularBuffer<double>(customPool, 5);
// Method 3: Create a running sum circular buffer with a capacity of 5, allocated on the heap (no pooling)
using var buffer3 = new RunningSumCircularBuffer<double>(null, 5);
// Add items to the buffer
buffer1.Push(10.0);
buffer1.Push(20.0);
buffer1.Push(30.0);
// Get the running sum and average
Console.WriteLine($"Running sum: {buffer1.RunningSum}"); // 60.0
Console.WriteLine($"Average: {buffer1.Average}"); // 20.0
// Add more items (will start overwriting oldest items)
buffer1.Push(40.0);
buffer1.Push(50.0);
buffer1.Push(60.0); // This will overwrite 10.0
// The running sum and average are automatically updated
Console.WriteLine($"Running sum: {buffer1.RunningSum}"); // 200.0 (20+30+40+50+60)
Console.WriteLine($"Average: {buffer1.Average}"); // 40.0
// Clear the buffer
buffer1.Clear();
Console.WriteLine($"Running sum after clear: {buffer1.RunningSum}"); // 0.0
Console.WriteLine($"Average after clear: {buffer1.Average}"); // 0.0
// Thread-safe usage example
Parallel.For(0, 1000, i =>
{
buffer1.Push(i);
});
Console.WriteLine($"After parallel push, running sum: {buffer1.RunningSum}");
Console.WriteLine($"After parallel push, average: {buffer1.Average}");
Requirements
- .NET 7.0, .NET 8.0, or .NET 9.0
License
This project is licensed under the MIT License - see the LICENSE file for details.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 is compatible. 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. |
-
net7.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.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.