Skip to content

Commit

Permalink
feat(cache/unstable): add memoize() and LruCache (#4725)
Browse files Browse the repository at this point in the history
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
  • Loading branch information
3 people authored Aug 8, 2024
1 parent 4ec7dd4 commit 0c64f32
Show file tree
Hide file tree
Showing 12 changed files with 1,229 additions and 33 deletions.
72 changes: 39 additions & 33 deletions .github/dependency_graph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions _tools/check_circular_package_dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Mod =
| "assert"
| "async"
| "bytes"
| "cache"
| "cli"
| "collections"
| "crypto"
Expand Down Expand Up @@ -80,6 +81,7 @@ const ENTRYPOINTS: Record<Mod, string[]> = {
assert: ["mod.ts"],
async: ["mod.ts"],
bytes: ["mod.ts"],
cache: ["mod.ts"],
cli: ["mod.ts"],
collections: ["mod.ts"],
crypto: ["mod.ts"],
Expand Down
1 change: 1 addition & 0 deletions _tools/check_docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const ENTRY_POINTS = [
"../assert/mod.ts",
"../async/mod.ts",
"../bytes/mod.ts",
"../cache/mod.ts",
"../cli/mod.ts",
"../crypto/mod.ts",
"../collections/mod.ts",
Expand Down
87 changes: 87 additions & 0 deletions cache/_serialize_arg_list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import type { MemoizationCache } from "./memoize.ts";

/**
* Default serialization of arguments list for use as cache keys. Equivalence
* follows [`SameValueZero`](https://tc39.es/ecma262/multipage/abstract-operations.html#sec-samevaluezero)
* reference equality, such that `getKey(x, y) === getKey(x, y)` for all values
* of `x` and `y`, but `getKey({}) !== getKey({})`.
*
* @param cache The cache for which the keys will be used.
* @returns `getKey`, the function for getting cache keys.
*/

export function _serializeArgList<Return>(
cache: MemoizationCache<unknown, Return>,
): (this: unknown, ...args: unknown[]) => string {
const weakKeyToKeySegmentCache = new WeakMap<WeakKey, string>();
const weakKeySegmentToKeyCache = new Map<string, string[]>();
let i = 0;

const registry = new FinalizationRegistry<string>((keySegment) => {
for (const key of weakKeySegmentToKeyCache.get(keySegment) ?? []) {
cache.delete(key);
}
weakKeySegmentToKeyCache.delete(keySegment);
});

return function getKey(...args) {
const weakKeySegments: string[] = [];
const keySegments = [this, ...args].map((arg) => {
if (typeof arg === "undefined") return "undefined";
if (typeof arg === "bigint") return `${arg}n`;

if (typeof arg === "number") {
return String(arg);
}

if (
arg === null ||
typeof arg === "string" ||
typeof arg === "boolean"
) {
// This branch will need to be updated if further types are added to
// the language that support value equality,
// e.g. https://github.com/tc39/proposal-record-tuple
return JSON.stringify(arg);
}

try {
assertWeakKey(arg);
} catch {
if (typeof arg === "symbol") {
return `Symbol.for(${JSON.stringify(arg.description)})`;
}
// Non-weak keys other than `Symbol.for(...)` are handled by the branches above.
throw new Error(
"Should be unreachable. Please open an issue at https://github.com/denoland/std/issues/new",
);
}

if (!weakKeyToKeySegmentCache.has(arg)) {
const keySegment = `{${i++}}`;
weakKeySegments.push(keySegment);
registry.register(arg, keySegment);
weakKeyToKeySegmentCache.set(arg, keySegment);
}

const keySegment = weakKeyToKeySegmentCache.get(arg)!;
weakKeySegments.push(keySegment);
return keySegment;
});

const key = keySegments.join(",");

for (const keySegment of weakKeySegments) {
const keys = weakKeySegmentToKeyCache.get(keySegment) ?? [];
keys.push(key);
weakKeySegmentToKeyCache.set(keySegment, keys);
}

return key;
};
}

function assertWeakKey(arg: unknown): asserts arg is WeakKey {
new WeakRef(arg as WeakKey);
}
Loading

0 comments on commit 0c64f32

Please sign in to comment.