/** * Oeffnungszeiten live: kleiner LRU-Speicher mit Ablaufzeit (rein, ohne eigene Uhr: die Zeit kommt als Millisekunden-Parameter). * * - hoechstens max Eintraege; ist er voll, faellt der am laengsten nicht benutzte (hole oder setze) heraus; * - jeder Eintrag verfaellt ttlMs nach dem Setzen (genau nach ttlMs ist er weg); ein Treffer erneuert nur seinen Platz in * der Reihe, nie die Ablaufzeit, damit auch ein oft abgefragter Eintrag spaetestens nach ttlMs neu gebaut wird; * - hole liefert bei Fehlschlag oder Ablauf undefined; gespeichert werden darf jeder Wert (auch null, 0, ''). * Umsetzung: eine Map; ihre Einfuegereihenfolge ist die Nutzungsreihenfolge (aeltester zuerst), ein Treffer haengt den Eintrag neu an. */ const pruefeZeit = (nowMs, wer) => { if (typeof nowMs !== 'number' || !Number.isFinite(nowMs)) throw new TypeError(`${wer}: nowMs muss eine Zahl (Millisekunden) sein`) } /** * @param {{ max: number, ttlMs: number }} optionen max = ganze Zahl >= 1, ttlMs = Zahl > 0 (endlich) * @returns {{ hole(key: string, nowMs: number): *, setze(key: string, wert: *, nowMs: number): void, vergiss(key: string): void, leere(): void, groesse(): number }} */ export function neuerLru({ max, ttlMs } = {}) { if (!Number.isInteger(max) || max < 1) throw new TypeError('neuerLru: max muss eine ganze Zahl ab 1 sein') if (typeof ttlMs !== 'number' || !Number.isFinite(ttlMs) || ttlMs <= 0) throw new TypeError('neuerLru: ttlMs muss eine Zahl groesser 0 sein') /** @type {Map} */ const eintraege = new Map() return { hole(key, nowMs) { pruefeZeit(nowMs, 'hole') const eintrag = eintraege.get(key) if (!eintrag) return undefined eintraege.delete(key) if (eintrag.bis <= nowMs) return undefined eintraege.set(key, eintrag) return eintrag.wert }, setze(key, wert, nowMs) { pruefeZeit(nowMs, 'setze') eintraege.delete(key) eintraege.set(key, { bis: nowMs + ttlMs, wert }) while (eintraege.size > max) eintraege.delete(eintraege.keys().next().value) }, vergiss(key) { eintraege.delete(key) }, leere() { eintraege.clear() }, groesse() { return eintraege.size }, } }