diff --git a/src/cache.ts b/src/cache.ts new file mode 100644 index 0000000..8f6a758 --- /dev/null +++ b/src/cache.ts @@ -0,0 +1,39 @@ +type Function_ = (...x: never[]) => unknown; + +type Memoize = { + (...x: Parameters): ReturnType; + clearCache: () => void; +}; + +const memoizedFunctions: Memoize[] = []; + +export const memoize = ( + fn: F, +) => { + const cache = new Map(); + + const memoizedFunction = ((...x: never[]) => { + const hash = JSON.stringify(x); + if (cache.has(hash)) { + return cache.get(hash); + } else { + return fn(...x); + } + }) as F; + + const memoizedCallableObject = Object.assign(memoizedFunction, { + clearCache: () => { + cache.clear(); + } + }); + + memoizedFunctions.push(memoizedCallableObject); + + return memoizedCallableObject; +}; + +export const clearCache = () => { + memoizedFunctions.forEach(memoizedFunction => { + memoizedFunction.clearCache(); + }); +} diff --git a/src/parser.ts b/src/parser.ts index 285bcfc..c9c6636 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,5 +1,6 @@ import { encoder } from './unicode'; import { InputType, InputTypes, isTypedArray } from './inputTypes'; +import { clearCache, memoize } from './cache'; // createParserState :: x -> s -> ParserState e a s const createParserState = (target: InputType, data: D | null = null): ParserState => { @@ -90,13 +91,15 @@ export class Parser { p: StateTransformerFunction; constructor(p: StateTransformerFunction) { - this.p = p; + this.p = memoize(p); } // run :: Parser e a s ~> x -> Either e a run(target: InputType): ResultType { const state = createParserState(target); + clearCache(); + const resultState = this.p(state); if (resultState.isError) { @@ -123,6 +126,8 @@ export class Parser { const state = createParserState(target); const newState = this.p(state); + clearCache(); + if (newState.isError) { return errorFn(newState.error, newState); }