52 lines
1.2 KiB
TypeScript
52 lines
1.2 KiB
TypeScript
/** Мини-кэш с TTL и вытеснением по LRU (Map сохраняет порядок вставки). */
|
|
export class TtlCache<K, V> {
|
|
private readonly map = new Map<K, { value: V; expires: number }>()
|
|
|
|
constructor(
|
|
private readonly opts: {
|
|
max: number
|
|
ttlMs: number
|
|
now?: () => number
|
|
},
|
|
) {}
|
|
|
|
private now(): number {
|
|
return (this.opts.now ?? Date.now)()
|
|
}
|
|
|
|
get(key: K): V | undefined {
|
|
const hit = this.map.get(key)
|
|
if (!hit) return undefined
|
|
if (hit.expires <= this.now()) {
|
|
this.map.delete(key)
|
|
return undefined
|
|
}
|
|
// освежаем позицию для LRU
|
|
this.map.delete(key)
|
|
this.map.set(key, hit)
|
|
return hit.value
|
|
}
|
|
|
|
set(key: K, value: V): void {
|
|
this.map.delete(key)
|
|
this.map.set(key, { value, expires: this.now() + this.opts.ttlMs })
|
|
while (this.map.size > this.opts.max) {
|
|
const oldest = this.map.keys().next()
|
|
if (oldest.done) break
|
|
this.map.delete(oldest.value)
|
|
}
|
|
}
|
|
|
|
delete(key: K): void {
|
|
this.map.delete(key)
|
|
}
|
|
|
|
clear(): void {
|
|
this.map.clear()
|
|
}
|
|
|
|
get size(): number {
|
|
return this.map.size
|
|
}
|
|
}
|