Skip to content

Instantly share code, notes, and snippets.

@sjkillen
Created June 29, 2018 21:25
Show Gist options
  • Save sjkillen/ccbf50c921d510032bf6f24f7b873c71 to your computer and use it in GitHub Desktop.
Save sjkillen/ccbf50c921d510032bf6f24f7b873c71 to your computer and use it in GitHub Desktop.
const pure = Symbol("pure function");
const scanDone = Symbol();
function scanParam(func) {
if (func.length !== 1) {
throw "Only works with unary functions";
}
const shape = {};
try {
func(getScanner(shape));
} catch (e) {
if (e !== scanDone) throw e;
}
return shape;
}
function cullShape(shape) {
const entries = Object.entries(shape);
if (entries.length === 0) {
return null;
}
for (const [key, obj] of Object.entries(shape)) {
shape[key] = cullShape(obj);
}
return shape;
}
function getScanner(shape) {
return new Proxy({}, {
get(t, prop) {
if (prop === pure) throw scanDone;
shape[prop] = {};
return getScanner(shape[prop]);
}
});
}
function shapesDiffer(shape, a, b) {
for (const [key, extension] of Object.entries(shape)) {
if (extension !== null) {
if (shapesDiffer(shape[key], a[key], b[key])) {
return true;
}
} else if (a[key] !== b[key]) {
return true;
}
}
return false;
}
function smartMemoize(func) {
const shape = cullShape(scanParam(func));
let lastCall = null;
let lastResult = null;
return function (arg) {
if (lastCall && !shapesDiffer(shape, lastCall, arg)) {
console.log(`Used Cached Result ${lastResult}`);
return lastResult;
}
lastCall = arg;
lastResult = func.call(this, arg);
};
}
function testFunc({ a, b: { c, d }, [pure]: _ }) {
console.log("Cache Miss");
return 42;
}
const testMe = smartMemoize(testFunc);
const arg1 = { a: 0, b: { c: 1, d: 2 }, z: 4200 };
const arg2 = { a: 0, b: { c: 1, d: 2 }, z: 42 };
const arg3 = { a: 1, b: { c: 1, d: 2 }, z: 99 };
testMe(arg1);// First call
testMe(arg2);// No Changes, cache hit
testMe(arg3);// a changed to 1, rerun function
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment