81 lines
2.3 KiB
C#
81 lines
2.3 KiB
C#
namespace Qrakhen.Qamp.Memory;
|
|
|
|
// add to qrakhen.memory package for clout
|
|
public abstract class TailBuffer<T>
|
|
{
|
|
private T[] _data;
|
|
public T[] Data {
|
|
get => _data;
|
|
}
|
|
|
|
public int Capacity => _data.Length;
|
|
public int Tail { get; private set; }
|
|
|
|
public TailBuffer(int size = 0x80)
|
|
{
|
|
_data = new T[size];
|
|
}
|
|
|
|
public TailBuffer(T[] data)
|
|
{
|
|
_data = new T[data.Length * 2];
|
|
Array.Copy(data, 0, _data, 0, data.Length);
|
|
SetTail(data.Length);
|
|
}
|
|
|
|
public void Insert(int cursor, T[] data)
|
|
{
|
|
cursor = SeekTail(cursor);
|
|
Prepare(cursor, data.Length);
|
|
int length = data.Length;
|
|
if (cursor == Tail) {
|
|
// Just append here.
|
|
Array.Copy(data, 0, _data, cursor, length);
|
|
SetTail(cursor + length);
|
|
} else {
|
|
// Shift everything to the right of insertion
|
|
Array.Copy(_data, cursor, _data, cursor + length, Tail - cursor);
|
|
Array.Copy(data, 0, _data, cursor, length);
|
|
SetTail(Tail + length);
|
|
}
|
|
}
|
|
|
|
public void Delete(Range range)
|
|
=> Delete(range.From, range.To - range.From);
|
|
|
|
public void Delete(int cursor, int count)
|
|
{
|
|
if (cursor + count >= Tail)
|
|
SetTail(cursor); // Directly terminate at cursor, nothing is behind tail.
|
|
else {
|
|
// Move everything from end of deletion until tail to start of deletion.
|
|
Array.Copy(_data, cursor + count, _data, cursor, Tail - (cursor + count));
|
|
SetTail(Tail - count);
|
|
}
|
|
}
|
|
|
|
// never write beyond tail (there might be invalid data)
|
|
private int SeekTail(int cursor) => cursor > Tail ? Tail : cursor;
|
|
|
|
private void Prepare(int index, int count)
|
|
{
|
|
ArgumentOutOfRangeException.ThrowIfNegative(index);
|
|
if (index + count <= _data.Length)
|
|
return;
|
|
while (index + count > _data.Length) {
|
|
T[] grow = new T[_data.Length * 2];
|
|
Array.Copy(_data, grow, _data.Length);
|
|
_data = grow;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the tail, or, if omitted, seeks the tail by finding the first null terminator.
|
|
/// </summary>
|
|
/// <param name="tail"></param>
|
|
protected virtual void SetTail(int tail = -1)
|
|
{
|
|
Tail = tail;
|
|
}
|
|
}
|