Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 66 additions & 1 deletion packages/memoize/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

Fastest memoize library available.

## Table of contents

- [@OSW/Memoize](#oswmemoize)
- [Table of contents](#table-of-contents)
- [Features:](#features)
- [Usage](#usage)
- [API](#api)
- [Options](#options)
- [Example](#example)
- [Building](#building)
- [Running unit tests](#running-unit-tests)
- [Roadmap](#roadmap)
- [Nice to have](#nice-to-have)
- [Limitations](#limitations)

## Features:

- Simple and fully typed API
Expand All @@ -14,7 +29,57 @@ Fastest memoize library available.
- 1 KB gzipped and minified with bundled dependencies
- Compatible with all module systems available - ESM, CJS, AMD, System, UMD, etc.

## API
## Usage

### API

Memoizing a usual non recursive function:

```ts
const memoizedFunction = memoize(yourFunction);
memoizedFunction(param1,param2,...);
```
If the function you're trying to memoize proves to be more of a headache than anticipated there are more direct methods of accomplishing this task, and options that will be explained.

For recursive functions:

```ts
const memoizedFunction = memoize(yourFunction);
memoizedFunction(param1,param2,...);
```

### Options

| Option | Description | Usage |
|-----------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| async : bool | Sets the type of function (sync/async) | |
| recursive : bool | Sets the type of function (recursive/non-recursive) | |
| thisArg : any | Sets the "this" argument of the function. Must be used for methods, inside the class. | memoizedMethod = memoize(this.yourMethod, { thisArg: this }); |
| stringify | No clue how this works | |
| store : IMemoizeStoreOptions | Custom store that can be used externally. Defaults to: Map | const yourStore = new Map();<br> memoizedFunction = memoize(yourFunction, { store: yourStore }); |
| size : IMemoizeStoreSize * | Size options - Defaults to: undefined - infinite size | memoizedFunction = memoize(yourFunction, { size: { max: 2, removeStrategy: 'clear' }); |
| time : IMemoizeStoreTime ** | Storage time options. Defaults to: undefined - infinite time span | const store = new MemoizeStore( time: { max: 3,period: 1, unit: 's' } );<br> memoizedFunction = memoize(yourFunction, store); |

*For size there is:

| Field | Description | Usage |
|-----------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------|
| size.max : number | Maximum number of entries allowed in the store | const store = new MemoizeStore( size: { max: 2 }); |
| size.removeStrategy : IMemoizeStoreRemoveStrategy | Remove strategy if the storage is full. Defaults to: 'oldest' which enforces a LRU caching strategy. Available options 'clear' \| 'oldest' | const store = new MemoizeStore( size: { removeStrategy: 'clear' }); |

**For time there is:

| Field | Description | Usage |
|--------------------------------------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------|
| time.max : number | Maximum time allowed. Defaults to: 'NaN' | const store = new MemoizeStore( time: { max: 3 } ); |
| time.period : number | Periodically clear the expired entries. Uses the same time unit as `max` - Defaults to undefined | const store = new MemoizeStore( time: { period: 1} ); |
| time.unit : IMemoizeStoreTimeUnits | Time unit - Defaults to: 'ms'. Available options 'ms', 's', 'm', 'h', 'd' | const store = new MemoizeStore( time: { unit: 's' } ); |

## Example

```ts

```

## Building

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ export interface IMemoizeStore<T = unknown> {
/** Clears the entire store */
clear: () => void;
}

export interface IMemoizeStoreMetadata {
/** Stores start date in unix time?? */
addedOn: number;
}

/** User defined storage container */
export interface IMemoizeStoreOptions<T = unknown> {
/** Custom store that can be used externally. Defaults to: Map */
store?: IMemoizeStore<T>;
Expand All @@ -22,13 +23,15 @@ export interface IMemoizeStoreOptions<T = unknown> {
time?: IMemoizeStoreTime;
}

/** User defined storage capacity */
export interface IMemoizeStoreSize {
/** Maximum number of entries allowed in the store. Defaults to: 'NaN' */
max: number;
/** Remove strategy if the storage is full. Defaults to: 'oldest' which enforces a LRU caching strategy. Available options 'clear' | 'oldest' */
removeStrategy?: IMemoizeStoreRemoveStrategy;
}

/** User defined storage lifespan */
export interface IMemoizeStoreTime {
/** Maximum time allowed. Defaults to: 'NaN' */
max: number;
Expand Down
40 changes: 40 additions & 0 deletions packages/memoize/src/lib/memoize.api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,4 +295,44 @@ describe('Memoize - all default APIs should work as expected', () => {
expect(memoizedTime).toBeGreaterThan(memoizedAsyncRecursiveTime);
}
});
it('Example Test', () => {
let actualCalls = 0;
function testFunction(a: number, b: number) {
actualCalls++;
return a + b;
}
const a = 10;
console.log('Theoretical no. of function calls with no memoization: ' + a * a * a);
const memoizedTestFunction = memoize(testFunction);
for (let k = 0; k < a; k++) {
for (let i = 0; i < a; i++) {
for (let j = 0; j < a; j++) {
memoizedTestFunction(i, j);
}
}
}

console.log('No. of function calls with memoization: ' + actualCalls);
});

it('Example Test 2', () => {
let actualCalls = 0;
const fib = memoize(async (num: number): Promise<number> => {
actualCalls++;
if (num < 2) {
return Promise.resolve(num);
} else {
return (await fib(num - 1)) + (await fib(num - 2));
}
});
const a = 10;

for (let k = 0; k < a; k++) {
for (let j = 0; j < a; j++) {
fib(j);
}
}

console.log('No. of function calls with memoization: ' + actualCalls);
});
});
2 changes: 2 additions & 0 deletions packages/memoize/src/lib/memoize.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export function memoizeLast<T extends MemoizeCallback | MemoizeAsyncCallback>(
) {
return memoize(callback, { ...options, size: { max: 1 } });
}

/** All in one memoization function, selects the correct function for the options given */
export function memoize<
T extends MemoizeCallback | MemoizeAsyncCallback,
R extends MemoizedFunction<T> | MemoizedAsyncFunction<T> = T extends MemoizeCallback
Expand Down
2 changes: 2 additions & 0 deletions packages/memoize/src/lib/memoize.interface.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { IMemoizeStoreOptions } from './memoize-store/memoize-store.interface.ap
import { MemoizeStringify } from './memoize/memoize.interface';

export interface MemoizeBaseOptions<T = unknown> extends IMemoizeStoreOptions<T> {
/** Sets the "this" argument of the function. Must be used for methods, inside the class. */
thisArg?: any;
stringify?: MemoizeStringify;
}

/** Type of the function to be memoized */
export interface MemoizeOptions<T = unknown> extends MemoizeBaseOptions<T> {
async?: boolean;
recursive?: boolean;
Expand Down
6 changes: 6 additions & 0 deletions packages/memoize/src/lib/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,9 @@ export function isAsyncFunction<T extends MemoizeCallback | MemoizeAsyncCallback
// }.constructor;
// return fn instanceof generatorFunction;
// }



let a: boolean;

a = true;