|
1 | 1 | import { assert } from "@std/assert/assert";
|
2 |
| -import { LruCache } from "@std/cache/lru-cache"; |
3 | 2 | import { MemoizationCacheResult, memoize } from "@std/cache/memoize";
|
4 | 3 | import { ArrayResult, ArrayResultError } from "../array_result.ts";
|
5 | 4 |
|
6 |
| -const CACHE_SIZE = 10; |
7 |
| - |
8 | 5 | type Source = Readonly<{ source: string; position: number }>;
|
9 | 6 | type ParserResult<T> = ArrayResult<Readonly<{ value: T; size: number }>>;
|
10 | 7 | type InnerParser<T> = (input: Source) => ParserResult<T>;
|
11 | 8 |
|
12 | 9 | class SourceMemo<T> {
|
13 |
| - #map: LruCache<string, Map<number, T>> = new LruCache(CACHE_SIZE); |
| 10 | + #source = ""; |
| 11 | + #map: Map<number, T> = new Map(); |
14 | 12 | set(key: Source, value: T): void {
|
15 |
| - let map = this.#map.get(key.source); |
16 |
| - if (map == null) { |
17 |
| - const newMap: Map<number, T> = new Map(); |
18 |
| - this.#map.set(key.source, newMap); |
19 |
| - map = newMap; |
| 13 | + if (this.#source !== key.source) { |
| 14 | + this.#source = key.source; |
| 15 | + this.#map = new Map(); |
20 | 16 | }
|
21 |
| - map.set(key.position, value); |
| 17 | + this.#map.set(key.position, value); |
22 | 18 | }
|
23 | 19 | get(key: Source): undefined | T {
|
24 |
| - return this.#map.get(key.source)?.get(key.position); |
| 20 | + if (this.#source === key.source) { |
| 21 | + return this.#map.get(key.position); |
| 22 | + } else { |
| 23 | + return undefined; |
| 24 | + } |
25 | 25 | }
|
26 | 26 | has(key: Source): boolean {
|
27 |
| - return this.#map.get(key.source)?.has(key.position) ?? false; |
| 27 | + return this.#source === key.source && this.#map.has(key.position); |
28 | 28 | }
|
29 | 29 | delete(key: Source): void {
|
30 |
| - this.#map.get(key.source)?.delete(key.position); |
| 30 | + if (this.#source === key.source) { |
| 31 | + this.#map.delete(key.position); |
| 32 | + } |
| 33 | + } |
| 34 | + clear(): void { |
| 35 | + this.#map.clear(); |
| 36 | + } |
| 37 | +} |
| 38 | +type SourceMemoResult<T> = SourceMemo<MemoizationCacheResult<ParserResult<T>>>; |
| 39 | + |
| 40 | +const caches: Set<WeakRef<SourceMemo<unknown>>> = new Set(); |
| 41 | + |
| 42 | +export function clearCache(): void { |
| 43 | + for (const memo of caches) { |
| 44 | + const ref = memo.deref(); |
| 45 | + if (ref == null) { |
| 46 | + caches.delete(memo); |
| 47 | + } else { |
| 48 | + ref.clear(); |
| 49 | + } |
31 | 50 | }
|
32 | 51 | }
|
33 | 52 | export class Parser<T> {
|
34 | 53 | readonly rawParser: InnerParser<T>;
|
35 | 54 | constructor(parser: InnerParser<T>) {
|
36 |
| - this.rawParser = memoize< |
37 |
| - InnerParser<T>, |
38 |
| - Source, |
39 |
| - SourceMemo<MemoizationCacheResult<ParserResult<T>>> |
40 |
| - >(parser, { cache: new SourceMemo() }); |
| 55 | + const cache: SourceMemoResult<T> = new SourceMemo(); |
| 56 | + caches.add(new WeakRef(cache)); |
| 57 | + this.rawParser = memoize<InnerParser<T>, Source, SourceMemoResult<T>>( |
| 58 | + parser, |
| 59 | + { cache }, |
| 60 | + ); |
41 | 61 | }
|
42 | 62 | generateParser(): (source: string) => ArrayResult<T> {
|
43 | 63 | return (source) =>
|
|
0 commit comments