|
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