|
1 | 1 | import { assertGreater } from "@std/assert/greater"; |
2 | | -import { memoize } from "@std/cache/memoize"; |
| 2 | +import { MemoizationCacheResult, memoize } from "@std/cache/memoize"; |
3 | 3 | import { ArrayResult, ArrayResultError } from "../array_result.ts"; |
4 | 4 |
|
5 | 5 | type Input = Readonly<{ source: string; position: number }>; |
6 | 6 | type ParserResult<T> = ArrayResult<Readonly<{ value: T; length: number }>>; |
7 | 7 | type InnerParser<T> = (input: Input) => ParserResult<T>; |
| 8 | +type Memo<T> = Map<number, MemoizationCacheResult<ParserResult<T>>>; |
8 | 9 |
|
9 | | -let source = ""; |
10 | | -const allMemo: Set<WeakRef<SourceMemo<unknown>>> = new Set(); |
| 10 | +const allMemo: Set<WeakRef<Memo<unknown>>> = new Set(); |
11 | 11 |
|
12 | | -function clearCache(): void { |
13 | | - for (const memo of allMemo) { |
14 | | - const ref = memo.deref(); |
15 | | - if (ref == null) { |
16 | | - allMemo.delete(memo); |
17 | | - } else { |
18 | | - ref.clear(); |
19 | | - } |
20 | | - } |
21 | | -} |
22 | | -class SourceMemo<T> { |
23 | | - readonly #map: Map<number, T> = new Map(); |
24 | | - constructor() { |
25 | | - allMemo.add(new WeakRef(this)); |
26 | | - } |
27 | | - set(key: Input, value: T): void { |
28 | | - if (source !== key.source) { |
29 | | - source = key.source; |
30 | | - clearCache(); |
31 | | - } |
32 | | - this.#map.set(key.position, value); |
33 | | - } |
34 | | - get(key: Input): undefined | T { |
35 | | - if (source === key.source) { |
36 | | - return this.#map.get(key.position); |
37 | | - } else { |
38 | | - return undefined; |
39 | | - } |
40 | | - } |
41 | | - has(key: Input): boolean { |
42 | | - return source === key.source && this.#map.has(key.position); |
43 | | - } |
44 | | - delete(key: Input): void { |
45 | | - if (source === key.source) { |
46 | | - this.#map.delete(key.position); |
47 | | - } |
48 | | - } |
49 | | - clear(): void { |
50 | | - this.#map.clear(); |
51 | | - } |
52 | | -} |
53 | 12 | export class Parser<T> { |
54 | 13 | readonly rawParser: InnerParser<T>; |
55 | 14 | constructor(parser: InnerParser<T>) { |
56 | | - // Turns out @std/[email protected] is buggy |
57 | | - const cache: SourceMemo<ParserResult<T>> = new SourceMemo(); |
| 15 | + const cache: Memo<T> = new Map(); |
58 | 16 | allMemo.add(new WeakRef(cache)); |
59 | | - this.rawParser = (input) => { |
60 | | - if (cache.has(input)) { |
61 | | - return cache.get(input)!; |
62 | | - } else { |
63 | | - const result = parser(input); |
64 | | - cache.set(input, result); |
65 | | - return result; |
66 | | - } |
67 | | - }; |
| 17 | + this.rawParser = memoize<InnerParser<T>, number, Memo<T>>( |
| 18 | + parser, |
| 19 | + { getKey: ({ position }) => position, cache }, |
| 20 | + ); |
68 | 21 | } |
69 | 22 | generateParser(): (source: string) => ArrayResult<T> { |
70 | 23 | return (input) => { |
71 | | - source = input; |
72 | | - clearCache(); |
| 24 | + for (const memo of allMemo) { |
| 25 | + const ref = memo.deref(); |
| 26 | + if (ref == null) { |
| 27 | + allMemo.delete(memo); |
| 28 | + } else { |
| 29 | + ref.clear(); |
| 30 | + } |
| 31 | + } |
73 | 32 | return this.rawParser({ source: input, position: 0 }) |
74 | 33 | .map(({ value }) => value); |
75 | 34 | }; |
|
0 commit comments