wabbajack/Wabbajack.Common.CSP/RingBuffer.cs

116 lines
2.8 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace Wabbajack.Common.CSP
{
public class RingBuffer<T> : IEnumerable<T>
{
private int _size;
private int _length;
private int _tail;
private int _head;
private T[] _arr;
public RingBuffer(int size = 8)
{
_size = size;
_arr = new T[size];
_tail = 0;
_length = 0;
_head = 0;
}
public T Pop()
{
if (_length == 0)
throw new InvalidDataException("Pop on empty buffer");
var val = _arr[_tail];
_arr[_tail] = default;
_tail = (_tail + 1) % _size;
_length -= 1;
return val;
}
public T Peek()
{
return _length == 0 ? default : _arr[_tail];
}
public void Unshift(T x)
{
_arr[_head] = x;
_head = (_head + 1) % _size;
_length += 1;
}
public void UnboundedUnshift(T x)
{
if (_length + 1 == _size)
Resize();
Unshift(x);
}
public bool IsEmpty => _length == 0;
public int Length => _length;
private void Resize()
{
var new_arr_size = _size * 2;
var new_arr = new T[new_arr_size];
if (_tail < _head)
{
Array.Copy(_arr, _tail, new_arr, 0, _length);
_tail = 0;
_head = _length;
_arr = new_arr;
_size = new_arr_size;
}
else if (_tail > _head)
{
Array.Copy(_arr, _tail, new_arr, 0, _size - _tail);
Array.Copy(_arr, 0, new_arr, (_size - _tail), _head);
_tail = 0;
_head = _length;
_arr = new_arr;
_size = new_arr_size;
}
else
{
_tail = 0;
_head = 0;
_arr = new_arr;
_size = new_arr_size;
}
}
/// <summary>
/// Filers out all items where should_keep(itm) returns false
/// </summary>
/// <param name="should_keep"></param>
public void Cleanup(Func<T, bool> should_keep)
{
for (var idx = 0; idx < _length; idx++)
{
var v = Pop();
if (should_keep(v))
{
Unshift(v);
}
}
}
public IEnumerator<T> GetEnumerator()
{
while (!IsEmpty)
yield return Pop();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}