Created
June 29, 2018 21:25
-
-
Save sjkillen/ccbf50c921d510032bf6f24f7b873c71 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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