64 lines
1.5 KiB
C#
64 lines
1.5 KiB
C#
using System.Threading.Channels;
|
|
|
|
namespace Manager.App.Services;
|
|
|
|
public class CircularBuffer <T>
|
|
{
|
|
private readonly T[] _buffer;
|
|
private readonly Channel<T> _channel;
|
|
private readonly object _lock = new();
|
|
|
|
public int Capacity { get; }
|
|
public int Head { get; private set; }
|
|
public int Count { get; private set; }
|
|
|
|
|
|
public CircularBuffer(int capacity)
|
|
{
|
|
if (capacity <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(capacity));
|
|
}
|
|
|
|
Capacity = capacity;
|
|
_buffer = new T[Capacity];
|
|
_channel = Channel.CreateBounded<T>(new BoundedChannelOptions(Capacity)
|
|
{
|
|
SingleReader = false,
|
|
SingleWriter = false,
|
|
FullMode = BoundedChannelFullMode.DropOldest
|
|
});
|
|
}
|
|
|
|
public void Add(T item)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_buffer[Head] = item;
|
|
Head = (Head + 1) % _buffer.Length;
|
|
|
|
if (Count < _buffer.Length)
|
|
{
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
_channel.Writer.TryWrite(item);
|
|
}
|
|
|
|
public IEnumerable<T> Items
|
|
{
|
|
get
|
|
{
|
|
for (var i = 0; i < Count; i++)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
yield return _buffer[(Head - Count + i + _buffer.Length) % _buffer.Length];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public IAsyncEnumerable<T> GetStreamAsync() => _channel.Reader.ReadAllAsync();
|
|
} |