memo
Memoization tools, TC39 proposal-function-memo implementation.
Table of Contents
Install
deno:
deno add @miyauci/memo
node:
npx jsr add @miyauci/memo
Usage
Returns the proxy function whose call is monitored. It calls at most once for each given arguments.
import { memo } from "@miyauci/memo";
function f(x: number): number {
console.log(x);
return x * 2;
}
const fMemo = memo(f);
fMemo(3); // Prints 3 and returns 6.
fMemo(3); // Does not print anything. Returns 6.
fMemo(2); // Prints 2 and returns 4.
fMemo(2); // Does not print anything. Returns 4.
fMemo(3); // Does not print anything. Returns 6.
Either version would work with recursive functions:
import { memo } from "@miyauci/memo";
const fib = memo((num: number): number => {
if (num < 2) return num;
return fib(num - 1) + fib(num - 2);
});
fib(1000);
Custom cache
To control the cache, specify cache
.
The cache must implement the following interfaces:
interface MapLike<K, V> {
get(key: K): V | undefined;
has(key: K): boolean;
set(key: K, value: V): void;
}
By default, an unlimited cache is used by WeakMap
.
import { type MapLike, memo } from "@miyauci/memo";
declare const lruCache: MapLike<object, unknown>;
declare const fn: () => unknown;
const $fn = memo(fn, lruCache);
See TC39 proposal-policy-map-set and its implementation.
Keying
Cache keys are represented by composite keys.
The composite keys are passed several elements for the key, called components.
The default components are as follows:
- this arg(
this
) - args
Also, composite key employs the same-value-zero algorithm to verify the equivalence of each component.
You can modify the component through the keying
callback.
import { type MapLike, memo } from "@miyauci/memo";
declare const respond: (request: Request) => Response;
const $respond = memo(
respond,
undefined,
(thisArg, [request]) => [request.method, request.url.toString()],
);
Construction caching
Caching of construction is also supported. Calls to constructor functions with
the new
operator are cacheable based on their arguments.
import { memo } from "@miyauci/memo";
import { assert } from "@std/assert";
declare const url: string;
assert(new URL(url) !== new URL(url));
const $URL = memo(URL);
assert(new $URL(url) === new $URL(url));
Keying for construction
Unlike in the case of functions, the following components are used as keys by default in the construction:
- args
- newTarget(
new.target
)
You can specify keying
as in the function.
import { type MapLike, memo } from "@miyauci/memo";
const $URL = memo(
URL,
undefined,
(
thisArg,
[url, base],
newTarget,
) => [url.toString(), base?.toString(), newTarget],
);
Polyfill
Polyfill affects the global object. You must be very careful when using it.
import "@miyauci/memo/polyfill";
const fib = ((num: number): number => {
if (num < 2) return num;
return fib(num - 1) + fib(num - 2);
}).memo();
fib(1000);
API
See jsr doc for all APIs.
Contributing
See CONTRIBUTING.md
License
MIT © 2023 Tomoki Miyauchi