feat(replay): add rewind buffer

This commit is contained in:
dualfroz committed 2026-08-26 15:09:58 +02:00
1 parent 7317326166
commit 855cf68993
1 file changed
+113
+113
View File
@@ -0,0 +1,113 @@
using System;
namespace Chip8.Replay;
public sealed class RewindBuffer
{
readonly TimelineSnapshot?[] ring;
int head;
int count;
long memoryBytes;
public RewindBuffer(int capacity)
{
if (capacity < 1)
{
throw new ArgumentOutOfRangeException(nameof(capacity), "rewind buffer needs at least one slot");
}
ring = new TimelineSnapshot?[capacity];
}
public int capacity => ring.Length;
public int keyframeCount => count;
public long memoryUsed => memoryBytes;
public bool isEmpty => count == 0;
public void store(int frameIndex, byte[] state)
{
var snapshot = new TimelineSnapshot(frameIndex, state);
if (count == ring.Length)
{
TimelineSnapshot evicted = ring[head]!;
memoryBytes -= evicted.stateSize;
ring[head] = snapshot;
head = (head + 1) % ring.Length;
}
else
{
int slot = (head + count) % ring.Length;
ring[slot] = snapshot;
count++;
}
memoryBytes += snapshot.stateSize;
}
public TimelineSnapshot? nearestAtOrBefore(int frameIndex)
{
TimelineSnapshot? best = null;
for (int offset = 0; offset < count; offset++)
{
TimelineSnapshot candidate = ring[(head + offset) % ring.Length]!;
if (candidate.frameIndex <= frameIndex && (best is null || candidate.frameIndex > best.frameIndex))
{
best = candidate;
}
}
return best;
}
public int oldestFrame
{
get
{
if (count == 0)
{
return -1;
}
int oldest = int.MaxValue;
for (int offset = 0; offset < count; offset++)
{
int frame = ring[(head + offset) % ring.Length]!.frameIndex;
if (frame < oldest)
{
oldest = frame;
}
}
return oldest;
}
}
public int newestFrame
{
get
{
if (count == 0)
{
return -1;
}
int newest = -1;
for (int offset = 0; offset < count; offset++)
{
int frame = ring[(head + offset) % ring.Length]!.frameIndex;
if (frame > newest)
{
newest = frame;
}
}
return newest;
}
}
public void clear()
{
Array.Clear(ring, 0, ring.Length);
head = 0;
count = 0;
memoryBytes = 0;
}
}