export class BoundedMap<K, V> implements ReadonlyMap<K, V> {
readonly #entries = new Map<K, V>();
constructor(readonly capacity: number) {
if (!Number.isSafeInteger(capacity) || capacity <= 0) {
throw new InvalidBoundedMapCapacity({ capacity });
}
}
get size(): number {
return this.#entries.size;
}
get(key: K): V | undefined {
return this.#entries.get(key);
}
has(key: K): boolean {
return this.#entries.has(key);
}
delete(key: K): boolean {
return this.#entries.delete(key);
}
clear(): void {
this.#entries.clear();
}
set(key: K, value: V): readonly [K, V] | undefined {
if (this.#entries.has(key)) {
this.#entries.delete(key);
}
this.#entries.set(key, value);
if (this.#entries.size <= this.capacity) {
return undefined;
}
const oldest = this.#entries.entries().next();
if (oldest.done) {
return undefined;
}
this.#entries.delete(oldest.value[0]);
return oldest.value;
}
entries(): MapIterator<[K, V]> {
return this.#entries.entries();
}
keys(): MapIterator<K> {
return this.#entries.keys();
}
values(): MapIterator<V> {
return this.#entries.values();
}
forEach(
callbackfn: (value: V, key: K, map: ReadonlyMap<K, V>) => void,
thisArg?: unknown,
): void {
this.#entries.forEach((value, key) => {
callbackfn.call(thisArg, value, key, this);
});
}
[Symbol.iterator](): MapIterator<[K, V]> {
return this.entries();
}
}