Comparing version 0.1.1 to 0.1.2
import { createSelector as rCS, createSelectorCreator, createStructuredSelector } from 'reselect'; | ||
export declare const strongMemoize: <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: import("./types").WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare const createSelector: typeof rCS; | ||
export { createStructuredSelector, createSelectorCreator }; |
import { createSelectorCreator, createStructuredSelector } from 'reselect'; | ||
import { strongMemoize } from "./weak"; | ||
import { weakMemoizeCreator } from './weak'; | ||
import { createStrongStorage } from './strongStorage'; | ||
export var strongMemoize = weakMemoizeCreator(createStrongStorage); | ||
export var createSelector = createSelectorCreator(strongMemoize); | ||
export { createStructuredSelector, createSelectorCreator }; |
import { WeakStorage } from "./types"; | ||
declare type WeakStorageCreator = () => WeakStorage; | ||
export declare function weakMemoizeCreator(cacheCreator?: WeakStorageCreator): <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare const kashe: <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare const strongMemoize: <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare function swap<T, K, R>(fn: (t: T, k: K) => R): (k: K, T: T) => R; | ||
@@ -5,0 +6,0 @@ declare type BoxedCall<T extends any[], K> = (state: object, ...rest: T) => K; |
import functionDouble from "function-double"; | ||
import { createStrongStorage, createWeakStorage } from "./weakStorage"; | ||
import { createWeakStorage } from "./weakStorage"; | ||
var cacheStack = []; | ||
@@ -16,3 +16,3 @@ var cacheOverride; | ||
var addKashePrefix = function (name) { return "kashe-" + name; }; | ||
function weakMemoizeCreator(cacheCreator) { | ||
export function weakMemoizeCreator(cacheCreator) { | ||
if (cacheCreator === void 0) { cacheCreator = createWeakStorage; } | ||
@@ -35,2 +35,3 @@ return function kasheCreator(func, cache) { | ||
} | ||
export var kashe = weakMemoizeCreator(createWeakStorage); | ||
function weakKasheFactory(func, indexId) { | ||
@@ -50,7 +51,5 @@ if (indexId === void 0) { indexId = 0; } | ||
} | ||
return localCache.set(cacheArg, func.apply(void 0, args)); | ||
return localCache.set(cacheArg, func.apply.apply(func, args)); | ||
}; | ||
} | ||
export var kashe = weakMemoizeCreator(createWeakStorage); | ||
export var strongMemoize = weakMemoizeCreator(createStrongStorage); | ||
export function swap(fn) { | ||
@@ -57,0 +56,0 @@ return function (k, t) { return fn(t, k); }; |
import { WeakMappable, WeakStorage } from "./types"; | ||
export declare const createWeakStorage: (indexId?: number, storage?: WeakMappable) => WeakStorage; | ||
export declare const createStrongStorage: (startIndex?: number, endIndex?: number, storage?: WeakMappable) => WeakStorage; |
@@ -1,2 +0,2 @@ | ||
var weakable = function (value) { return (value && (typeof value === 'object')); }; | ||
import { isWeakable } from "./utils"; | ||
export var createWeakStorage = function (indexId, storage) { | ||
@@ -7,3 +7,3 @@ if (indexId === void 0) { indexId = 0; } | ||
get: function (args) { | ||
if (!weakable(args[indexId])) { | ||
if (!isWeakable(args[indexId])) { | ||
console.log('arguments given', args); | ||
@@ -14,8 +14,12 @@ throw new Error("Argument #" + indexId + " expected to be weak-mappable object, " + typeof args[indexId] + " given"); | ||
if (test) { | ||
if (test.arguments.every(function (v, index) { return v === args[index]; })) { | ||
return { | ||
value: test.storedValue, | ||
index: indexId, | ||
}; | ||
var a = test.arguments; | ||
for (var i = 0; i < a.length; ++i) { | ||
if (a[i] !== args[i]) { | ||
return undefined; | ||
} | ||
} | ||
return { | ||
value: test.storedValue, | ||
index: indexId, | ||
}; | ||
} | ||
@@ -33,43 +37,1 @@ return undefined; | ||
}; | ||
export var createStrongStorage = function (startIndex, endIndex, storage) { | ||
if (startIndex === void 0) { startIndex = 0; } | ||
if (endIndex === void 0) { endIndex = Infinity; } | ||
if (storage === void 0) { storage = new WeakMap(); } | ||
return ({ | ||
get: function (args) { | ||
var max = Math.min(endIndex, args.length); | ||
var reads = 0; | ||
for (var i = startIndex; i < max; ++i) { | ||
if (weakable(args[i])) { | ||
reads++; | ||
var test_1 = storage.get(args[i]); | ||
if (test_1) { | ||
if (test_1.arguments.every(function (v, index) { return v === args[index]; })) { | ||
return { | ||
value: test_1.storedValue, | ||
index: i, | ||
}; | ||
} | ||
} | ||
} | ||
} | ||
if (!reads) { | ||
console.log('arguments given', args); | ||
throw new Error('No weak-mappable object found to read a result from'); | ||
} | ||
return undefined; | ||
}, | ||
set: function (args, value) { | ||
var max = Math.min(endIndex, args.length); | ||
for (var i = startIndex; i < max; ++i) { | ||
if (weakable(args[i])) { | ||
storage.set(args[i], { | ||
storedValue: value, | ||
arguments: args, | ||
}); | ||
} | ||
} | ||
return value; | ||
} | ||
}); | ||
}; |
import { createSelector as rCS, createSelectorCreator, createStructuredSelector } from 'reselect'; | ||
export declare const strongMemoize: <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: import("./types").WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare const createSelector: typeof rCS; | ||
export { createStructuredSelector, createSelectorCreator }; |
@@ -7,2 +7,4 @@ "use strict"; | ||
var weak_1 = require("./weak"); | ||
exports.createSelector = reselect_1.createSelectorCreator(weak_1.strongMemoize); | ||
var strongStorage_1 = require("./strongStorage"); | ||
exports.strongMemoize = weak_1.weakMemoizeCreator(strongStorage_1.createStrongStorage); | ||
exports.createSelector = reselect_1.createSelectorCreator(exports.strongMemoize); |
import { WeakStorage } from "./types"; | ||
declare type WeakStorageCreator = () => WeakStorage; | ||
export declare function weakMemoizeCreator(cacheCreator?: WeakStorageCreator): <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare const kashe: <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare const strongMemoize: <Arg extends object, T extends any[], Return>(func: (x: Arg, ...rest: T) => Return, cache?: WeakStorage) => (x: Arg, ...rest: T) => Return; | ||
export declare function swap<T, K, R>(fn: (t: T, k: K) => R): (k: K, T: T) => R; | ||
@@ -5,0 +6,0 @@ declare type BoxedCall<T extends any[], K> = (state: object, ...rest: T) => K; |
@@ -36,2 +36,4 @@ "use strict"; | ||
} | ||
exports.weakMemoizeCreator = weakMemoizeCreator; | ||
exports.kashe = weakMemoizeCreator(weakStorage_1.createWeakStorage); | ||
function weakKasheFactory(func, indexId) { | ||
@@ -51,7 +53,5 @@ if (indexId === void 0) { indexId = 0; } | ||
} | ||
return localCache.set(cacheArg, func.apply(void 0, args)); | ||
return localCache.set(cacheArg, func.apply.apply(func, args)); | ||
}; | ||
} | ||
exports.kashe = weakMemoizeCreator(weakStorage_1.createWeakStorage); | ||
exports.strongMemoize = weakMemoizeCreator(weakStorage_1.createStrongStorage); | ||
function swap(fn) { | ||
@@ -58,0 +58,0 @@ return function (k, t) { return fn(t, k); }; |
import { WeakMappable, WeakStorage } from "./types"; | ||
export declare const createWeakStorage: (indexId?: number, storage?: WeakMappable) => WeakStorage; | ||
export declare const createStrongStorage: (startIndex?: number, endIndex?: number, storage?: WeakMappable) => WeakStorage; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var weakable = function (value) { return (value && (typeof value === 'object')); }; | ||
var utils_1 = require("./utils"); | ||
exports.createWeakStorage = function (indexId, storage) { | ||
@@ -9,3 +9,3 @@ if (indexId === void 0) { indexId = 0; } | ||
get: function (args) { | ||
if (!weakable(args[indexId])) { | ||
if (!utils_1.isWeakable(args[indexId])) { | ||
console.log('arguments given', args); | ||
@@ -16,8 +16,12 @@ throw new Error("Argument #" + indexId + " expected to be weak-mappable object, " + typeof args[indexId] + " given"); | ||
if (test) { | ||
if (test.arguments.every(function (v, index) { return v === args[index]; })) { | ||
return { | ||
value: test.storedValue, | ||
index: indexId, | ||
}; | ||
var a = test.arguments; | ||
for (var i = 0; i < a.length; ++i) { | ||
if (a[i] !== args[i]) { | ||
return undefined; | ||
} | ||
} | ||
return { | ||
value: test.storedValue, | ||
index: indexId, | ||
}; | ||
} | ||
@@ -35,43 +39,1 @@ return undefined; | ||
}; | ||
exports.createStrongStorage = function (startIndex, endIndex, storage) { | ||
if (startIndex === void 0) { startIndex = 0; } | ||
if (endIndex === void 0) { endIndex = Infinity; } | ||
if (storage === void 0) { storage = new WeakMap(); } | ||
return ({ | ||
get: function (args) { | ||
var max = Math.min(endIndex, args.length); | ||
var reads = 0; | ||
for (var i = startIndex; i < max; ++i) { | ||
if (weakable(args[i])) { | ||
reads++; | ||
var test_1 = storage.get(args[i]); | ||
if (test_1) { | ||
if (test_1.arguments.every(function (v, index) { return v === args[index]; })) { | ||
return { | ||
value: test_1.storedValue, | ||
index: i, | ||
}; | ||
} | ||
} | ||
} | ||
} | ||
if (!reads) { | ||
console.log('arguments given', args); | ||
throw new Error('No weak-mappable object found to read a result from'); | ||
} | ||
return undefined; | ||
}, | ||
set: function (args, value) { | ||
var max = Math.min(endIndex, args.length); | ||
for (var i = startIndex; i < max; ++i) { | ||
if (weakable(args[i])) { | ||
storage.set(args[i], { | ||
storedValue: value, | ||
arguments: args, | ||
}); | ||
} | ||
} | ||
return value; | ||
} | ||
}); | ||
}; |
{ | ||
"name": "kashe", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "Stateless memoization replacement for reselect and memoize-one", | ||
@@ -15,2 +15,3 @@ "main": "dist/es5/index.js", | ||
"static": "ts-react-toolbox publish", | ||
"prepublish": "yarn build", | ||
"format": "ts-react-toolbox format", | ||
@@ -17,0 +18,0 @@ "analyze": "ts-react-toolbox analyze" |
@@ -29,7 +29,9 @@ <div align="center"> | ||
- __Is it server-side friendly?__ Nope, server handles many requests from many clients, and memoized value is constantly got wiped. | ||
- __Is it saver-side _safe_?__ Oh no! Cross request memoization could be a killer! What if memoized value not got rejected?? | ||
- __Is it server-side _safe_?__ Oh no! Cross request memoization could be a killer! What if memoized value not got rejected?? | ||
- __Is it test friendly?__ Nope, tests should always work the same, while memoization will make it... less predictable. | ||
So - it's time to fix all the problems above. | ||
So - it's time to fix all the problems above. Wanna know more - [read the article](https://dev.to/thekashey/memoization-forget-me-bomb-34kh) | ||
> In short - to better REMEMBER something, you have to better FORGET it | ||
# API | ||
@@ -103,2 +105,36 @@ - kashe - memoization | ||
#### The difference between inboxed and boxed | ||
- `boxed` could __increase__ probability to cache a value | ||
- `inboxed` could __decrease__ probability to cache a value | ||
`inboxed` is scoping all the _nested_ caches _behind_ a first argument. It if changes - cache changes. | ||
> Yet again - first argument is WHERE cache is stored. | ||
`boxed` is just storing result in a first argument. If cache is not found it is still possible to discover | ||
it in a nested cache. | ||
```js | ||
const memoizedSelector = kashe(selector); | ||
const inboxedSelector = inboxed(memoizedSelector); | ||
const boxedSelector = boxed(memoizedSelector); | ||
// state1 !== state2. selectors would use different caches, memoizedSelector included | ||
inboxedSelector(state1, data) !== inboxedSelector(state2, data) | ||
// state1 !== state2. memoization would fail, but memoizedSelector would return the same values | ||
boxedSelector(state1, data) === boxedSelector(state2, data) | ||
``` | ||
`inboxedSelector` is more memory safe, but CPU intensive. It guratines all selectors would be _clean_ for a session(first argument). | ||
`boxedSelector` is useful as long as everything here is still holds only ONE result. It may be wiped from nested selector, but still exists in a boxed | ||
```js | ||
memoizedSelector(data1); | ||
boxedSelector(state, data1); // they are the same | ||
boxedSelector(state, data2); // updating cache for both selectors | ||
memoizedSelector(data2); // they are the same | ||
memoizedSelector(data1); // cache is updated | ||
boxedSelector(state, data2); // !!!! result is still stored in `state` | ||
``` | ||
### fork | ||
@@ -118,3 +154,3 @@ - `fork(function: T):T` - create a copy of a selector, with overiden internal cache. | ||
#### Size | ||
1.14 kb | ||
1.01 kb | ||
@@ -261,2 +297,18 @@ # Cook-book | ||
# Speed | ||
```html | ||
// a simple one argument function | ||
memoize-one one argument x 58,277,071 ops/sec ±1.60% (87 runs sampled) | ||
kashe one argument x 19,724,367 ops/sec ±0.76% (91 runs sampled) | ||
// a simple two arguments function | ||
memoize-one two arguments x 42,526,871 ops/sec ±0.77% (90 runs sampled) | ||
kashe two arguments x 16,929,449 ops/sec ±0.84% (89 runs sampled) | ||
// using more than one object to call - memoize-one is failing, while kashe still works | ||
// PS: multiply results by 2 | ||
memoize-one two states x 308,917 ops/sec ±0.56% (92 runs sampled) | ||
kashe two states x 8,992,170 ops/sec ±0.96% (83 runs sampled) | ||
``` | ||
# Kashe-y? | ||
@@ -263,0 +315,0 @@ When I first time I heard my nickname - `kashey` pronounces as `cache` - I decides to create a caching library one day. Here we go. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
35774
35
558
316