85 lines
1.8 KiB
TypeScript
85 lines
1.8 KiB
TypeScript
/**
|
|
* A fixed-size circular buffer that automatically evicts the oldest items
|
|
* when the buffer is full. Useful for maintaining a rolling window of data.
|
|
*/
|
|
export class CircularBuffer<T> {
|
|
private buffer: T[]
|
|
private head = 0
|
|
private size = 0
|
|
|
|
constructor(private capacity: number) {
|
|
this.buffer = new Array(capacity)
|
|
}
|
|
|
|
/**
|
|
* Add an item to the buffer. If the buffer is full,
|
|
* the oldest item will be evicted.
|
|
*/
|
|
add(item: T): void {
|
|
this.buffer[this.head] = item
|
|
this.head = (this.head + 1) % this.capacity
|
|
if (this.size < this.capacity) {
|
|
this.size++
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add multiple items to the buffer at once.
|
|
*/
|
|
addAll(items: T[]): void {
|
|
for (const item of items) {
|
|
this.add(item)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the most recent N items from the buffer.
|
|
* Returns fewer items if the buffer contains less than N items.
|
|
*/
|
|
getRecent(count: number): T[] {
|
|
const result: T[] = []
|
|
const start = this.size < this.capacity ? 0 : this.head
|
|
const available = Math.min(count, this.size)
|
|
|
|
for (let i = 0; i < available; i++) {
|
|
const index = (start + this.size - available + i) % this.capacity
|
|
result.push(this.buffer[index]!)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* Get all items currently in the buffer, in order from oldest to newest.
|
|
*/
|
|
toArray(): T[] {
|
|
if (this.size === 0) return []
|
|
|
|
const result: T[] = []
|
|
const start = this.size < this.capacity ? 0 : this.head
|
|
|
|
for (let i = 0; i < this.size; i++) {
|
|
const index = (start + i) % this.capacity
|
|
result.push(this.buffer[index]!)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* Clear all items from the buffer.
|
|
*/
|
|
clear(): void {
|
|
this.buffer.length = 0
|
|
this.head = 0
|
|
this.size = 0
|
|
}
|
|
|
|
/**
|
|
* Get the current number of items in the buffer.
|
|
*/
|
|
length(): number {
|
|
return this.size
|
|
}
|
|
}
|