107 lines
2.7 KiB
C#
107 lines
2.7 KiB
C#
|
using System;
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
using System.Threading;
|
|||
|
|
|||
|
namespace KcpSharp
|
|||
|
{
|
|||
|
internal sealed class KcpAcknowledgeList
|
|||
|
{
|
|||
|
private readonly KcpSendQueue _sendQueue;
|
|||
|
private (uint SerialNumber, uint Timestamp)[] _array;
|
|||
|
private int _count;
|
|||
|
private SpinLock _lock;
|
|||
|
|
|||
|
public KcpAcknowledgeList(KcpSendQueue sendQueue, int windowSize)
|
|||
|
{
|
|||
|
_array = new (uint SerialNumber, uint Timestamp)[windowSize];
|
|||
|
_count = 0;
|
|||
|
_lock = new SpinLock();
|
|||
|
_sendQueue = sendQueue;
|
|||
|
}
|
|||
|
|
|||
|
public bool TryGetAt(int index, out uint serialNumber, out uint timestamp)
|
|||
|
{
|
|||
|
bool lockTaken = false;
|
|||
|
try
|
|||
|
{
|
|||
|
_lock.Enter(ref lockTaken);
|
|||
|
|
|||
|
if ((uint)index >= (uint)_count)
|
|||
|
{
|
|||
|
serialNumber = default;
|
|||
|
timestamp = default;
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
(serialNumber, timestamp) = _array[index];
|
|||
|
return true;
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
if (lockTaken)
|
|||
|
{
|
|||
|
_lock.Exit();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Clear()
|
|||
|
{
|
|||
|
bool lockTaken = false;
|
|||
|
try
|
|||
|
{
|
|||
|
_lock.Enter(ref lockTaken);
|
|||
|
|
|||
|
_count = 0;
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
if (lockTaken)
|
|||
|
{
|
|||
|
_lock.Exit();
|
|||
|
}
|
|||
|
}
|
|||
|
_sendQueue.NotifyAckListChanged(false);
|
|||
|
}
|
|||
|
|
|||
|
public void Add(uint serialNumber, uint timestamp)
|
|||
|
{
|
|||
|
bool lockTaken = false;
|
|||
|
try
|
|||
|
{
|
|||
|
_lock.Enter(ref lockTaken);
|
|||
|
|
|||
|
EnsureCapacity();
|
|||
|
_array[_count++] = (serialNumber, timestamp);
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
if (lockTaken)
|
|||
|
{
|
|||
|
_lock.Exit();
|
|||
|
}
|
|||
|
}
|
|||
|
_sendQueue.NotifyAckListChanged(true);
|
|||
|
}
|
|||
|
|
|||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|||
|
private void EnsureCapacity()
|
|||
|
{
|
|||
|
if (_count == _array.Length)
|
|||
|
{
|
|||
|
Expand();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
|||
|
private void Expand()
|
|||
|
{
|
|||
|
int capacity = _count + 1;
|
|||
|
capacity = Math.Max(capacity + capacity / 2, 16);
|
|||
|
var newArray = new (uint SerialNumber, uint Timestamp)[capacity];
|
|||
|
_array.AsSpan(0, _count).CopyTo(newArray);
|
|||
|
_array = newArray;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|