forked from memoize-immutable/memoize-immutable
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ff907e4
Showing
7 changed files
with
336 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
root = true | ||
|
||
[*] | ||
indent_style = space | ||
indent_size = 2 | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
[*.md] | ||
trim_trailing_whitespace = false |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"extends": "eslint:recommended", | ||
"env": { | ||
"browser": true, | ||
"node": true, | ||
"amd": true, | ||
"mocha": true, | ||
"es6": true | ||
}, | ||
"plugins": [ | ||
"mocha" | ||
], | ||
"rules": { | ||
"quotes": [ 2, "single" ], | ||
"no-unused-vars": 2, | ||
"mocha/no-exclusive-tests": 2, | ||
"comma-dangle": 0 | ||
}, | ||
"globals": { | ||
"expect": false | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Logs | ||
logs | ||
*.log | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Dist files | ||
dist/ | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directory | ||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git | ||
node_modules | ||
|
||
# Bower | ||
bower_components/ |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Memoize Immutable | ||
|
||
An efficient function memoizer that uses strict-equality for argument comparison. Ideal with Redux and other immutable environments. | ||
|
||
## How is it different from other memoizers? | ||
|
||
This memoizer compares arguments by strict-equality, | ||
which means non-primitive arguments (such as objects) are compared by reference. | ||
Most memoizers out-there compare arguments by deep-equality, which requires serializing all arguments, | ||
and is very inefficient when working with Redux and other immutable environments. | ||
|
||
## Install | ||
|
||
npm install --save memoize-immutable | ||
|
||
## Usage | ||
|
||
```javascript | ||
var memoize = require('memoize-immutable'); | ||
|
||
var nbExecs = 0; | ||
var arraySum = function(arr) { | ||
nbExecs++; | ||
return arr.reduce(function(acc, curr) { | ||
return acc + curr; | ||
}, 0); | ||
}; | ||
var arraySumMemoized = memoize(arraySum); | ||
|
||
|
||
var arr1 = [ 1, 2, 3, 4, 5, 6 ]; | ||
var copy = arr1; | ||
|
||
expect(arraySumMemoized(arr1)).to.equal(21); | ||
expect(nbExecs).to.equal(1); | ||
|
||
expect(arraySumMemoized(copy)).to.equal(21); | ||
expect(nbExecs).to.equal(1); | ||
|
||
// Of course, you shouldn't mutate the arguments, or else... | ||
arr1.push(7); | ||
expect(arraySumMemoized(arr1)).to.equal(21); | ||
expect(nbExecs).to.equal(1); | ||
|
||
var clone = arr1.concat(); | ||
expect(arraySumMemoized(clone)).to.equal(28); | ||
expect(nbExecs).to.equal(2); | ||
``` | ||
|
||
## license | ||
|
||
MIT | ||
|
||
## Authors | ||
|
||
Original problem by [@louis_remi](https://twitter.com/louis_remi), | ||
original solution by [@LasseFister](https://twitter.com/lassefister), | ||
original implementation by [@louis_remi](https://twitter.com/louis_remi). |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* A function memoizer for immutable arguments | ||
* (compares non-primitive arguments by reference to retrieve result from cache) | ||
*/ | ||
|
||
if (typeof exports === 'object' && typeof exports.nodeName !== 'string' && typeof define !== 'function') { | ||
var define = function (factory) { | ||
factory(require, exports, module); | ||
}; | ||
} | ||
|
||
define(function (require, exports, module) { | ||
|
||
if ( typeof WeakMap === 'undefined' || typeof Map === 'undefined' ) { | ||
throw new Error('This lib requires an implementation of WeakMap and Map'); | ||
} | ||
|
||
var _idMap = new WeakMap(); | ||
var _id = { id: 0 }; | ||
// the last three arguments help with testing | ||
module.exports = function memoize(fn, cache, idMap, id) { | ||
if ( !cache ) { | ||
cache = new Map(); | ||
} | ||
if ( !idMap ) { | ||
idMap = _idMap; | ||
} | ||
if ( !id ) { | ||
id = _id; | ||
} | ||
|
||
return function() { | ||
var aKey = []; | ||
for ( var i = 0; i < arguments.length; i++ ) { | ||
var argType = typeof arguments[i]; | ||
|
||
// if the argument is not a primitive, get a unique (memoized?) id for it | ||
if ( | ||
// typeof null is "object", although we'll consider it as a primitive | ||
arguments[i] !== null && | ||
( argType === 'object' || argType === 'function' || argType === 'symbol' ) | ||
) { | ||
if ( !idMap.has(arguments[i]) ) { | ||
idMap.set(arguments[i], id.id++); | ||
} | ||
aKey.push( idMap.get(arguments[i]) ); | ||
|
||
// otherwise, add the argument and its type to the aKey | ||
} else { | ||
aKey.push( arguments[i] == null ? | ||
'' + arguments[i] : | ||
argType + '_:::_' + arguments[i] | ||
); | ||
} | ||
} | ||
|
||
var sKey = aKey.join('_///_'); | ||
|
||
if ( !cache.has(sKey) ) { | ||
cache.set( sKey, fn.apply(this, arguments) ); | ||
} | ||
|
||
return cache.get( sKey ); | ||
}; | ||
}; | ||
}); |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "memoize-immutable", | ||
"version": "1.0.0", | ||
"description": "A function memoizer that compares arguments by reference. Ideal with Redux and other immutable environments.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha test.js" | ||
}, | ||
"keywords": [ | ||
"immutable", | ||
"memoize", | ||
"redux" | ||
], | ||
"author": "@louis_remi", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"chai": "^3.5.0", | ||
"eslint": "^2.9.0", | ||
"eslint-plugin-mocha": "^2.2.0", | ||
"mocha": "^2.4.5", | ||
"mocha-phantomjs": "^4.0.2" | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
var expect = require('chai').expect; | ||
|
||
var memoize = require('./index'); | ||
|
||
describe('memoize', function() { | ||
var cache; | ||
var idMap; | ||
var id; | ||
|
||
beforeEach(function() { | ||
cache = new Map(); | ||
idMap = new Map(); | ||
id = { id: 0 }; | ||
}); | ||
|
||
it('should memoize a result when called with 0 args', function(done) { | ||
var nbExecs = 0; | ||
var fn = function() { | ||
return ++nbExecs; | ||
}; | ||
var memoizedFn = memoize(fn, cache, idMap, id); | ||
|
||
// first execution with empty cache | ||
expect(memoizedFn()).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('')).to.equal(1); | ||
expect(idMap.size).to.equal(0); | ||
|
||
// second execution | ||
expect(memoizedFn()).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('')).to.equal(1); | ||
expect(idMap.size).to.equal(0); | ||
|
||
done(); | ||
}); | ||
|
||
it('should memoize a result when called with 1 primitive arg', function(done) { | ||
var nbExecs = 0; | ||
var fn = function() { | ||
return ++nbExecs; | ||
}; | ||
var memoizedFn = memoize(fn, cache, idMap, id); | ||
var arg1 = 12; | ||
|
||
// first execution with empty cache | ||
expect(memoizedFn(arg1)).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('number_:::_12')).to.equal(1); | ||
expect(idMap.size).to.equal(0); | ||
|
||
// second execution | ||
expect(memoizedFn(arg1)).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('number_:::_12')).to.equal(1); | ||
expect(idMap.size).to.equal(0); | ||
|
||
done(); | ||
}); | ||
|
||
it('should memoize a result when called with 1 non-primitive arg', function(done) { | ||
var nbExecs = 0; | ||
var fn = function() { | ||
return ++nbExecs; | ||
}; | ||
var memoizedFn = memoize(fn, cache, idMap, id); | ||
var arg1 = {}; | ||
|
||
// first execution with empty cache | ||
expect(memoizedFn(arg1)).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('0')).to.equal(1) | ||
expect(idMap.size).to.equal(1); | ||
|
||
// second execution | ||
expect(memoizedFn(arg1)).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('0')).to.equal(1) | ||
expect(idMap.size).to.equal(1); | ||
|
||
done(); | ||
}); | ||
|
||
it('should memoize a result when called with mixed primitive and non-primitive args', function(done) { | ||
var nbExecs = 0; | ||
var fn = function() { | ||
return ++nbExecs; | ||
}; | ||
var memoizedFn = memoize(fn, cache, idMap, id); | ||
var arg1 = {a:'b'}; | ||
var arg2 = 'string'; | ||
var arg3 = [1,2]; | ||
var arg4 = function() {}; | ||
var arg5 = 12; | ||
var arg6 = null; | ||
var arg7 = false; | ||
var arg8 = undefined; | ||
|
||
// first execution with empty cache | ||
expect(memoizedFn(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('0_///_string_:::_string_///_1_///_2_///_number_:::_12_///_null_///_boolean_:::_false_///_undefined')) | ||
.to.equal(1); | ||
expect(idMap.size).to.equal(3); | ||
|
||
// second execution | ||
expect(memoizedFn(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)).to.equal(1); | ||
expect(nbExecs).to.equal(1); | ||
expect(cache.size).to.equal(1); | ||
expect(cache.get('0_///_string_:::_string_///_1_///_2_///_number_:::_12_///_null_///_boolean_:::_false_///_undefined')) | ||
.to.equal(1); | ||
expect(idMap.size).to.equal(3); | ||
|
||
done(); | ||
}); | ||
}); |