+162
| 'use strict'; | ||
| /** | ||
| * Memize options object. | ||
| * | ||
| * @typedef MemizeOptions | ||
| * | ||
| * @property {number} [maxSize] Maximum size of the cache. | ||
| */ | ||
| /** | ||
| * Internal cache entry. | ||
| * | ||
| * @typedef MemizeCacheNode | ||
| * | ||
| * @property {?MemizeCacheNode|undefined} [prev] Previous node. | ||
| * @property {?MemizeCacheNode|undefined} [next] Next node. | ||
| * @property {Array<*>} args Function arguments for cache | ||
| * entry. | ||
| * @property {*} val Function result. | ||
| */ | ||
| /** | ||
| * Properties of the enhanced function for controlling cache. | ||
| * | ||
| * @typedef MemizeMemoizedFunction | ||
| * | ||
| * @property {()=>void} clear Clear the cache. | ||
| */ | ||
| /** | ||
| * Accepts a function to be memoized, and returns a new memoized function, with | ||
| * optional options. | ||
| * | ||
| * @template {(...args: any[]) => any} F | ||
| * | ||
| * @param {F} fn Function to memoize. | ||
| * @param {MemizeOptions} [options] Options object. | ||
| * | ||
| * @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function. | ||
| */ | ||
| function memize(fn, options) { | ||
| var size = 0; | ||
| /** @type {?MemizeCacheNode|undefined} */ | ||
| var head; | ||
| /** @type {?MemizeCacheNode|undefined} */ | ||
| var tail; | ||
| options = options || {}; | ||
| function memoized(/* ...args */) { | ||
| var node = head, | ||
| len = arguments.length, | ||
| args, | ||
| i; | ||
| searchCache: while (node) { | ||
| // Perform a shallow equality test to confirm that whether the node | ||
| // under test is a candidate for the arguments passed. Two arrays | ||
| // are shallowly equal if their length matches and each entry is | ||
| // strictly equal between the two sets. Avoid abstracting to a | ||
| // function which could incur an arguments leaking deoptimization. | ||
| // Check whether node arguments match arguments length | ||
| if (node.args.length !== arguments.length) { | ||
| node = node.next; | ||
| continue; | ||
| } | ||
| // Check whether node arguments match arguments values | ||
| for (i = 0; i < len; i++) { | ||
| if (node.args[i] !== arguments[i]) { | ||
| node = node.next; | ||
| continue searchCache; | ||
| } | ||
| } | ||
| // At this point we can assume we've found a match | ||
| // Surface matched node to head if not already | ||
| if (node !== head) { | ||
| // As tail, shift to previous. Must only shift if not also | ||
| // head, since if both head and tail, there is no previous. | ||
| if (node === tail) { | ||
| tail = node.prev; | ||
| } | ||
| // Adjust siblings to point to each other. If node was tail, | ||
| // this also handles new tail's empty `next` assignment. | ||
| /** @type {MemizeCacheNode} */ (node.prev).next = node.next; | ||
| if (node.next) { | ||
| node.next.prev = node.prev; | ||
| } | ||
| node.next = head; | ||
| node.prev = null; | ||
| /** @type {MemizeCacheNode} */ (head).prev = node; | ||
| head = node; | ||
| } | ||
| // Return immediately | ||
| return node.val; | ||
| } | ||
| // No cached value found. Continue to insertion phase: | ||
| // Create a copy of arguments (avoid leaking deoptimization) | ||
| args = new Array(len); | ||
| for (i = 0; i < len; i++) { | ||
| args[i] = arguments[i]; | ||
| } | ||
| node = { | ||
| args: args, | ||
| // Generate the result from original function | ||
| val: fn.apply(null, args), | ||
| }; | ||
| // Don't need to check whether node is already head, since it would | ||
| // have been returned above already if it was | ||
| // Shift existing head down list | ||
| if (head) { | ||
| head.prev = node; | ||
| node.next = head; | ||
| } else { | ||
| // If no head, follows that there's no tail (at initial or reset) | ||
| tail = node; | ||
| } | ||
| // Trim tail if we're reached max size and are pending cache insertion | ||
| if (size === /** @type {MemizeOptions} */ (options).maxSize) { | ||
| tail = /** @type {MemizeCacheNode} */ (tail).prev; | ||
| /** @type {MemizeCacheNode} */ (tail).next = null; | ||
| } else { | ||
| size++; | ||
| } | ||
| head = node; | ||
| return node.val; | ||
| } | ||
| memoized.clear = function () { | ||
| head = null; | ||
| tail = null; | ||
| size = 0; | ||
| }; | ||
| // Ignore reason: There's not a clear solution to create an intersection of | ||
| // the function with additional properties, where the goal is to retain the | ||
| // function signature of the incoming argument and add control properties | ||
| // on the return value. | ||
| // @ts-ignore | ||
| return memoized; | ||
| } | ||
| module.exports = memize; |
+9
-5
| { | ||
| "name": "memize", | ||
| "version": "2.0.0", | ||
| "version": "2.1.0", | ||
| "description": "Unabashedly-barebones memoization library with an aim toward speed", | ||
| "type": "module", | ||
| "main": "dist/index.js", | ||
| "exports": { | ||
| "import": "./dist/index.js", | ||
| "require": "./dist/index.cjs" | ||
| }, | ||
| "types": "dist/index.d.ts", | ||
@@ -45,7 +49,7 @@ "scripts": { | ||
| "@rollup/plugin-replace": "^5.0.2", | ||
| "@types/chai": "^4.3.4", | ||
| "@types/chai": "^4.3.5", | ||
| "@types/mocha": "^10.0.1", | ||
| "@types/node": "^18.16.1", | ||
| "@types/node": "^20.1.3", | ||
| "chai": "^4.3.7", | ||
| "eslint": "^8.39.0", | ||
| "eslint": "^8.40.0", | ||
| "eslint-config-prettier": "^8.8.0", | ||
@@ -55,3 +59,3 @@ "eslint-plugin-prettier": "^4.2.1", | ||
| "prettier": "^2.8.8", | ||
| "rollup": "^3.21.0", | ||
| "rollup": "^3.21.6", | ||
| "sinon": "^15.0.4", | ||
@@ -58,0 +62,0 @@ "typescript": "^5.0.4" |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
19945
26.76%6
20%342
63.64%0
-100%