UNPKG

@tanstack/router-core

Version:

Modern and scalable routing for React applications

1 lines 3.11 kB
{"version":3,"file":"sieve-cache.cjs","names":[],"sources":["../../src/sieve-cache.ts"],"sourcesContent":["export type SieveCache<TKey, TValue> = {\n get: (key: TKey) => TValue | undefined\n set: (key: TKey, value: TValue) => void\n clear: () => void\n}\n\n/**\n * A fixed-capacity cache using the SIEVE eviction algorithm\n * (https://cachemon.github.io/SIEVE-website/).\n *\n * Entries live in the Map's FIFO insertion order; a hit only flips a `visited`\n * bit instead of relinking the entry, which makes `get` (by far the hottest\n * operation here) one `Map.get` plus a boolean store. Eviction sweeps a `hand`\n * from the oldest entry towards the newest, clearing `visited` bits until it\n * finds an unvisited entry to drop, so entries touched since the last sweep\n * survive one more round. This keeps LRU-like hit ratios while being\n * scan-resistant.\n */\nexport function createSieveCache<TKey, TValue>(\n max: number,\n): SieveCache<TKey, TValue> {\n type Node = {\n key: TKey\n value: TValue\n visited: boolean\n }\n const cache = new Map<TKey, Node>()\n let hand: IterableIterator<Node> | undefined\n let newest: Node | undefined\n\n return {\n get(key) {\n const entry = cache.get(key)\n if (!entry) {\n return undefined\n }\n entry.visited = true\n return entry.value\n },\n set(key, value) {\n const existing = cache.get(key)\n if (existing) {\n existing.value = value\n return\n }\n if (cache.size >= max) {\n // sweep from `hand` towards `newest` (wrapping around to `oldest`),\n // clearing `visited` bits, and evict the first unvisited entry\n let node = hand?.next().value\n while (!node || node.visited) {\n if (node) {\n node.visited = false\n } else {\n hand = cache.values()\n }\n node = hand!.next().value\n }\n // Live Map iterators see later insertions. Reset at the boundary so the\n // next sweep wraps to the oldest entry instead of visiting a replacement.\n if (node === newest) {\n hand = undefined\n }\n cache.delete(node.key)\n }\n const entry: Node = { key, value, visited: false }\n newest = entry\n cache.set(key, entry)\n },\n clear() {\n cache.clear()\n hand = undefined\n newest = undefined\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAkBA,SAAgB,iBACd,KAC0B;CAM1B,MAAM,wBAAQ,IAAI,IAAgB;CAClC,IAAI;CACJ,IAAI;CAEJ,OAAO;EACL,IAAI,KAAK;GACP,MAAM,QAAQ,MAAM,IAAI,GAAG;GAC3B,IAAI,CAAC,OACH;GAEF,MAAM,UAAU;GAChB,OAAO,MAAM;EACf;EACA,IAAI,KAAK,OAAO;GACd,MAAM,WAAW,MAAM,IAAI,GAAG;GAC9B,IAAI,UAAU;IACZ,SAAS,QAAQ;IACjB;GACF;GACA,IAAI,MAAM,QAAQ,KAAK;IAGrB,IAAI,OAAO,MAAM,KAAK,EAAE;IACxB,OAAO,CAAC,QAAQ,KAAK,SAAS;KAC5B,IAAI,MACF,KAAK,UAAU;UAEf,OAAO,MAAM,OAAO;KAEtB,OAAO,KAAM,KAAK,EAAE;IACtB;IAGA,IAAI,SAAS,QACX,OAAO,KAAA;IAET,MAAM,OAAO,KAAK,GAAG;GACvB;GACA,MAAM,QAAc;IAAE;IAAK;IAAO,SAAS;GAAM;GACjD,SAAS;GACT,MAAM,IAAI,KAAK,KAAK;EACtB;EACA,QAAQ;GACN,MAAM,MAAM;GACZ,OAAO,KAAA;GACP,SAAS,KAAA;EACX;CACF;AACF"}