/** * Fixed-capacity circular buffer. When full, new items overwrite the oldest. */ export class RingBuffer { private buffer: Array; private head = 0; // next write position private count = 0; private readonly capacity: number; constructor(capacity: number) { this.capacity = capacity; this.buffer = new Array(capacity); } push(item: T): void { this.buffer[this.head] = item; this.head = (this.head + 1) % this.capacity; if (this.count < this.capacity) { this.count++; } } get size(): number { return this.count; } /** Returns entries oldest-first */ toArray(): T[] { if (this.count === 0) return []; const result: T[] = []; const start = this.count < this.capacity ? 0 : this.head; for (let i = 0; i < this.count; i++) { const idx = (start + i) % this.capacity; result.push(this.buffer[idx] as T); } return result; } clear(): void { this.buffer = new Array(this.capacity); this.head = 0; this.count = 0; } }