Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

memize

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

memize - npm Package Compare versions

Comparing version
1.1.0
to
2.0.0
+77
dist/index.d.ts
/**
* 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.
*/
export default function memize<F extends (...args: any[]) => any>(fn: F, options?: MemizeOptions | undefined): ((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction;
/**
* Memize options object.
*/
export type MemizeOptions = {
/**
* Maximum size of the cache.
*/
maxSize?: number | undefined;
};
/**
* Internal cache entry.
*/
export type MemizeCacheNode = {
/**
* Previous node.
*/
prev?: (MemizeCacheNode | undefined) | null;
/**
* Next node.
*/
next?: (MemizeCacheNode | undefined) | null;
/**
* Function arguments for cache
* entry.
*/
args: Array<any>;
/**
* Function result.
*/
val: any;
};
/**
* Properties of the enhanced function for controlling cache.
*/
export type MemizeMemoizedFunction = {
/**
* Clear the cache.
*/
clear: () => void;
};
/**
* 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;
}
export { memize as default };
+56
-67
{
"name": "memize",
"version": "1.1.0",
"description": "Unabashedly-barebones memoization library with an aim toward speed",
"main": "index.js",
"scripts": {
"build": "npm run build:bundle && npm run build:types",
"build:bundle": "NODE_ENV=production rollup -c rollup.config.js",
"postbuild:bundle": "npm run minify",
"build:types": "tsc -p tsconfig.decl.json",
"minify": "uglifyjs dist/memize.js -c -m --mangle-props domprops --mangle-props regex=\"/^next|prev|val|args|maxSize$/\" > dist/memize.min.js",
"test:unit": "NODE_ENV=test mocha",
"test:lint": "eslint .",
"test:types": "tsc",
"test": "npm run test:unit && npm run test:lint && npm run test:types",
"benchmark": "node benchmark",
"prepublishOnly": "npm test && npm run build"
},
"files": [
"dist",
"index.js",
"index.d.ts"
],
"keywords": [
"memoize",
"memoization",
"memoisation",
"cache"
],
"repository": {
"type": "git",
"url": "https://github.com/aduth/memize.git"
},
"bugs": {
"url": "https://github.com/aduth/memize/issues"
},
"author": {
"name": "Andrew Duthie",
"email": "andrew@andrewduthie.com",
"url": "https://andrewduthie.com"
},
"license": "MIT",
"devDependencies": {
"@aduth/eslint-config": "^3.0.0",
"@types/node": "^13.9.0",
"benchmark": "^2.1.4",
"chai": "^4.2.0",
"cli-table2": "^0.2.0",
"eslint": "^6.8.0",
"eslint-plugin-jsdoc": "^22.0.0",
"fast-memoize": "^2.5.2",
"lodash": "^4.17.15",
"lru-memoize": "^1.1.0",
"memoizee": "^0.4.14",
"memoizejs": "^0.1.1",
"memoizerific": "^1.11.3",
"mocha": "^7.1.0",
"moize": "^5.4.5",
"ora": "^4.0.3",
"ramda": "^0.27.0",
"rollup": "^2.0.2",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-replace": "^2.2.0",
"sinon": "^9.0.0",
"typescript": "^3.8.3",
"uglify-js": "^3.8.0",
"underscore": "^1.9.2"
}
"name": "memize",
"version": "2.0.0",
"description": "Unabashedly-barebones memoization library with an aim toward speed",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "npm run build:bundle && npm run build:types",
"build:bundle": "rollup -c rollup.config.js",
"build:types": "tsc -b tsconfig.decl.json",
"test:unit": "NODE_ENV=test mocha",
"test:lint": "eslint .",
"test:types": "tsc -b",
"test": "npm run test:unit && npm run test:lint && npm run test:types",
"prebenchmark": "npm install --no-save benchmark memoizee moize ramda underscore lodash fast-memoize lru-memoize memoizejs memoizerific cli-table2 ora",
"benchmark": "node benchmark",
"prepublishOnly": "npm test && npm run build"
},
"files": [
"dist"
],
"keywords": [
"memoize",
"memoization",
"memoisation",
"cache"
],
"repository": {
"type": "git",
"url": "https://github.com/aduth/memize.git"
},
"bugs": {
"url": "https://github.com/aduth/memize/issues"
},
"author": {
"name": "Andrew Duthie",
"email": "andrew@andrewduthie.com",
"url": "https://andrewduthie.com"
},
"license": "MIT",
"devDependencies": {
"@aduth/eslint-config": "^4.4.1",
"@rollup/plugin-replace": "^5.0.2",
"@types/chai": "^4.3.4",
"@types/mocha": "^10.0.1",
"@types/node": "^18.16.1",
"chai": "^4.3.7",
"eslint": "^8.39.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"mocha": "^10.2.0",
"prettier": "^2.8.8",
"rollup": "^3.21.0",
"sinon": "^15.0.4",
"typescript": "^5.0.4"
}
}

@@ -35,6 +35,2 @@ Memize

Otherwise, download a pre-built copy from unpkg:
[https://unpkg.com/memize/dist/memize.min.js](https://unpkg.com/memize/dist/memize.min.js)
## Usage

@@ -41,0 +37,0 @@

#### v1.1.0 (2020-03-07)
- New Feature: Add TypeScript type definition.
#### v1.0.5 (2018-01-25)
- Fix: Correctly skips incorrect cached value return on mismatched argument length
#### v1.0.4 (2017-09-06)
- Fix: Resolve infinite loop which can occur due to lingering references in recalling from previous cache
- Internal: Include more thorough test cases for expected cache list progression
#### v1.0.3 (2017-08-30)
- Fix: Resolve error which can occur in certain conditions with `maxSize`
#### v1.0.2 (2017-08-24)
- Fix: Resolve infinite loop which can occur due to lingering references in recalling from previous cache
#### v1.0.1 (2017-08-09)
- Internal: Include repository details in `package.json`
#### v1.0.0 (2017-08-08)
- Initial release
var memize = (function () {
'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 {Function} F
*
* @param {F} fn Function to memoize.
* @param {MemizeOptions} [options] Options object.
*
* @return {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;
}
var memize_1 = memize;
return memize_1;
}());
var memize=function(){"use strict";return function(e,f){var i,l,o=0;function n(){var n,r,u=i,t=arguments.length;n:for(;u;){if(u.n.length===arguments.length){for(r=0;r<t;r++)if(u.n[r]!==arguments[r]){u=u.r;continue n}return u!==i&&(u===l&&(l=u.u),u.u.r=u.r,u.r&&(u.r.u=u.u),u.r=i,u.u=null,i.u=u,i=u),u.t}u=u.r}for(n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];return u={n:n,t:e.apply(null,n)},i?(i.u=u).r=i:l=u,o===f.e?(l=l.u).r=null:o++,(i=u).t}return f=f||{},n.clear=function(){l=i=null,o=0},n}}();
export = memize;
/**
* 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 {Function} F
*
* @param {F} fn Function to memoize.
* @param {MemizeOptions} [options] Options object.
*
* @return {F & MemizeMemoizedFunction} Memoized function.
*/
declare function memize<F extends Function>(fn: F, options?: MemizeOptions | undefined): F & MemizeMemoizedFunction;
declare namespace memize {
export { MemizeOptions, MemizeCacheNode, MemizeMemoizedFunction };
}
/**
* Memize options object.
*/
type MemizeOptions = {
/**
* Maximum size of the cache.
*/
maxSize?: number;
};
/**
* Properties of the enhanced function for controlling cache.
*/
type MemizeMemoizedFunction = {
/**
* Clear the cache.
*/
clear: () => void;
};
/**
* Internal cache entry.
*/
type MemizeCacheNode = {
/**
* Previous node.
*/
prev?: MemizeCacheNode | null | undefined;
/**
* Next node.
*/
next?: MemizeCacheNode | null | undefined;
/**
* Function arguments for cache
* entry.
*/
args: any[];
/**
* Function result.
*/
val: any;
};
/**
* 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 {Function} F
*
* @param {F} fn Function to memoize.
* @param {MemizeOptions} [options] Options object.
*
* @return {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;
};
if ( process.env.NODE_ENV === 'test' ) {
// Cache is not exposed in the public API, but used in tests to ensure
// expected list progression
memoized.getCache = function() {
return [ head, tail, size ];
};
}
// 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;