-
Notifications
You must be signed in to change notification settings - Fork 30
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
1 parent
de0d6d1
commit c9f1125
Showing
4 changed files
with
117 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,24 @@ | ||
--- | ||
title: memoLastCall | ||
description: Creates a memoized version of a function that caches only its most recent call | ||
--- | ||
|
||
### Usage | ||
|
||
Creates a memoized version of a function that caches only its most recent call. When the function is called with the same arguments as the previous call, it returns the cached result instead of recalculating. This is useful for optimizing expensive calculations when only the latest result needs to be cached, making it more memory-efficient than traditional memoization. | ||
|
||
```ts | ||
import * as _ from 'radashi' | ||
|
||
const expensiveCalculation = (x: number, y: number): number => { | ||
console.log('Calculating...') | ||
return x + y | ||
} | ||
|
||
const memoizedCalc = _.memoLastCall(expensiveCalculation) | ||
|
||
console.log(memoizedCalc(2, 3)) | ||
console.log(memoizedCalc(2, 3)) | ||
console.log(memoizedCalc(3, 4)) | ||
console.log(memoizedCalc(2, 3)) | ||
``` |
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,46 @@ | ||
/** | ||
* Creates a memoized version of a function that caches only its most recent call. | ||
* When the function is called with the same arguments as the previous call, it returns the cached result instead of recalculating. | ||
* This is useful for optimizing expensive calculations when only the latest result needs to be cached, making it more memory-efficient than traditional memoization. | ||
* | ||
* @example | ||
* ```ts | ||
* const expensiveCalculation = (x: number, y: number): number => { | ||
* console.log('Calculating...'); | ||
* return x + y; | ||
* }; | ||
* | ||
* const memoizedCalc = memoLastCall(expensiveCalculation); | ||
* | ||
* console.log(memoizedCalc(2, 3)); // Outputs: "Calculating..." then 5 | ||
* console.log(memoizedCalc(2, 3)); // Outputs: 5 (uses cached result) | ||
* console.log(memoizedCalc(3, 4)); // Outputs: "Calculating..." then 7 | ||
* console.log(memoizedCalc(2, 3)); // Outputs: "Calculating..." then 5 (previous cache was overwritten) | ||
* ``` | ||
* | ||
* @param fn The function to memoize. | ||
* @returns A memoized version of the function. | ||
*/ | ||
export function memoLastCall<Args extends any[], Result>( | ||
fn: (...args: Args) => Result, | ||
): (...args: Args) => Result { | ||
let lastArgs: Args | null = null | ||
let lastResult: Result | null = null | ||
|
||
return (...args: Args): Result => { | ||
// Check if we have cached args and if they match current args | ||
if ( | ||
lastArgs && | ||
lastArgs.length === args.length && | ||
lastArgs.every((arg, i) => Object.is(arg, args[i])) | ||
) { | ||
return lastResult! | ||
} | ||
|
||
// If no match, calculate new result and cache it | ||
const result = fn(...args) | ||
lastArgs = args | ||
lastResult = result | ||
return result | ||
} | ||
} |
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
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,46 @@ | ||
import * as _ from 'radashi' | ||
|
||
describe('memoLastCall', () => { | ||
test('caches the last result', () => { | ||
let calculationCount = 0 | ||
const expensiveCalculation = (x: number, y: number): number => { | ||
calculationCount++ | ||
return x + y | ||
} | ||
|
||
const memoizedCalc = _.memoLastCall(expensiveCalculation) | ||
|
||
expect(memoizedCalc(2, 3)).toBe(5) | ||
expect(calculationCount).toBe(1) | ||
|
||
expect(memoizedCalc(2, 3)).toBe(5) | ||
expect(calculationCount).toBe(1) | ||
|
||
expect(memoizedCalc(3, 4)).toBe(7) | ||
expect(calculationCount).toBe(2) | ||
|
||
expect(memoizedCalc(2, 3)).toBe(5) | ||
expect(calculationCount).toBe(3) | ||
}) | ||
|
||
test('handles different argument types', () => { | ||
const memoizedFn = _.memoLastCall( | ||
(a: string, b: number, c: boolean) => `${a}-${b}-${c}`, | ||
) | ||
expect(memoizedFn('foo', 123, true)).toBe('foo-123-true') | ||
expect(memoizedFn('foo', 123, true)).toBe('foo-123-true') | ||
expect(memoizedFn('bar', 456, false)).toBe('bar-456-false') | ||
}) | ||
|
||
test('handles functions with no arguments', () => { | ||
let callCount = 0 | ||
const memoizedFn = _.memoLastCall(() => { | ||
callCount++ | ||
return 'result' | ||
}) | ||
expect(memoizedFn()).toBe('result') | ||
expect(callCount).toBe(1) | ||
expect(memoizedFn()).toBe('result') | ||
expect(callCount).toBe(1) | ||
}) | ||
}) |