-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43868 from kacper-mikolajczak/feat/memoization-to…
…ol-poc2 General purpose memoization tool
- Loading branch information
Showing
20 changed files
with
629 additions
and
66 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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
10 changes: 8 additions & 2 deletions
10
src/libs/NumberFormatUtils.ts → src/libs/NumberFormatUtils/index.ts
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 |
---|---|---|
@@ -1,12 +1,18 @@ | ||
import type {ValueOf} from 'type-fest'; | ||
import memoize from '@libs/memoize'; | ||
import type CONST from '@src/CONST'; | ||
import initPolyfill from './intlPolyfill'; | ||
|
||
initPolyfill(); | ||
|
||
const MemoizedNumberFormat = memoize(Intl.NumberFormat, {maxSize: 10}); | ||
|
||
function format(locale: ValueOf<typeof CONST.LOCALES>, number: number, options?: Intl.NumberFormatOptions): string { | ||
return new Intl.NumberFormat(locale, options).format(number); | ||
return new MemoizedNumberFormat(locale, options).format(number); | ||
} | ||
|
||
function formatToParts(locale: ValueOf<typeof CONST.LOCALES>, number: number, options?: Intl.NumberFormatOptions): Intl.NumberFormatPart[] { | ||
return new Intl.NumberFormat(locale, options).formatToParts(number); | ||
return new MemoizedNumberFormat(locale, options).formatToParts(number); | ||
} | ||
|
||
export {format, formatToParts}; |
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,10 @@ | ||
import intlPolyfill from '@libs/IntlPolyfill'; | ||
|
||
// On iOS, polyfills from `additionalSetup` are applied after memoization, which results in incorrect cache entry of `Intl.NumberFormat` (e.g. lacking `formatToParts` method). | ||
// To fix this, we need to apply the polyfill manually before memoization. | ||
// For further information, see: https://github.com/Expensify/App/pull/43868#issuecomment-2217637217 | ||
const initPolyfill = () => { | ||
intlPolyfill(); | ||
}; | ||
|
||
export default initPolyfill; |
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,2 @@ | ||
const initPolyfill = () => {}; | ||
export default initPolyfill; |
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
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,85 @@ | ||
import type {Cache, CacheConfig} from './types'; | ||
|
||
/** | ||
* Builder of the cache using `Array` primitive under the hood. It is an LRU cache, where the most recently accessed elements are at the end of the array, and the least recently accessed elements are at the front. | ||
* @param config - Cache configuration, check `CacheConfig` type for more details. | ||
* @returns | ||
*/ | ||
function ArrayCache<K, V>(config: CacheConfig<K>): Cache<K, V> { | ||
const cache: Array<[K, V]> = []; | ||
|
||
const {maxSize, keyComparator} = config; | ||
|
||
/** | ||
* Returns the index of the key in the cache array. | ||
* We search the array backwards because the most recently added entries are at the end, and our heuristic follows the principles of an LRU cache - that the most recently added entries are most likely to be used again. | ||
*/ | ||
function getKeyIndex(key: K): number { | ||
for (let i = cache.length - 1; i >= 0; i--) { | ||
if (keyComparator(cache[i][0], key)) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
|
||
return { | ||
get(key) { | ||
const index = getKeyIndex(key); | ||
|
||
if (index === -1) { | ||
return undefined; | ||
} | ||
|
||
const [entry] = cache.splice(index, 1); | ||
cache.push(entry); | ||
return {value: entry[1]}; | ||
}, | ||
|
||
set(key, value) { | ||
const index = getKeyIndex(key); | ||
|
||
if (index !== -1) { | ||
cache.splice(index, 1); | ||
} | ||
|
||
cache.push([key, value]); | ||
|
||
if (cache.length > maxSize) { | ||
cache.shift(); | ||
} | ||
}, | ||
|
||
getSet(key, valueProducer) { | ||
const index = getKeyIndex(key); | ||
|
||
if (index !== -1) { | ||
const [entry] = cache.splice(index, 1); | ||
cache.push(entry); | ||
return {value: entry[1]}; | ||
} | ||
|
||
const value = valueProducer(); | ||
|
||
cache.push([key, value]); | ||
|
||
if (cache.length > maxSize) { | ||
cache.shift(); | ||
} | ||
|
||
return {value}; | ||
}, | ||
|
||
snapshot: { | ||
keys: () => cache.map((entry) => entry[0]), | ||
values: () => cache.map((entry) => entry[1]), | ||
entries: () => [...cache], | ||
}, | ||
|
||
get size() { | ||
return cache.length; | ||
}, | ||
}; | ||
} | ||
|
||
export default ArrayCache; |
Oops, something went wrong.