quick-lru
Advanced tools
Comparing version 6.1.2 to 7.0.0
@@ -1,2 +0,2 @@ | ||
export interface Options<KeyType, ValueType> { | ||
export type Options<KeyType, ValueType> = { | ||
/** | ||
@@ -25,11 +25,7 @@ The maximum number of milliseconds an item should remain in the cache. | ||
onEviction?: (key: KeyType, value: ValueType) => void; | ||
} | ||
}; | ||
export default class QuickLRU<KeyType, ValueType> extends Map implements Iterable<[KeyType, ValueType]> { | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
export default class QuickLRU<KeyType, ValueType> extends Map<KeyType, ValueType> implements Iterable<[KeyType, ValueType]> { | ||
/** | ||
The stored item count. | ||
*/ | ||
readonly size: number; | ||
/** | ||
Simple ["Least Recently Used" (LRU) cache](https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29). | ||
@@ -106,2 +102,12 @@ | ||
/** | ||
The stored item count. | ||
*/ | ||
get size(): number; | ||
/** | ||
The set max size. | ||
*/ | ||
get maxSize(): number; | ||
/** | ||
Iterable for all the keys. | ||
@@ -108,0 +114,0 @@ */ |
196
index.js
export default class QuickLRU extends Map { | ||
#size = 0; | ||
#cache = new Map(); | ||
#oldCache = new Map(); | ||
#maxSize; | ||
#maxAge; | ||
#onEviction; | ||
constructor(options = {}) { | ||
@@ -13,14 +20,14 @@ super(); | ||
// TODO: Use private class fields when ESLint supports them. | ||
this.maxSize = options.maxSize; | ||
this.maxAge = options.maxAge || Number.POSITIVE_INFINITY; | ||
this.onEviction = options.onEviction; | ||
this.cache = new Map(); | ||
this.oldCache = new Map(); | ||
this._size = 0; | ||
this.#maxSize = options.maxSize; | ||
this.#maxAge = options.maxAge || Number.POSITIVE_INFINITY; | ||
this.#onEviction = options.onEviction; | ||
} | ||
// TODO: Use private class methods when targeting Node.js 16. | ||
_emitEvictions(cache) { | ||
if (typeof this.onEviction !== 'function') { | ||
// For tests. | ||
get __oldCache() { | ||
return this.#oldCache; | ||
} | ||
#emitEvictions(cache) { | ||
if (typeof this.#onEviction !== 'function') { | ||
return; | ||
@@ -30,10 +37,10 @@ } | ||
for (const [key, item] of cache) { | ||
this.onEviction(key, item.value); | ||
this.#onEviction(key, item.value); | ||
} | ||
} | ||
_deleteIfExpired(key, item) { | ||
#deleteIfExpired(key, item) { | ||
if (typeof item.expiry === 'number' && item.expiry <= Date.now()) { | ||
if (typeof this.onEviction === 'function') { | ||
this.onEviction(key, item.value); | ||
if (typeof this.#onEviction === 'function') { | ||
this.#onEviction(key, item.value); | ||
} | ||
@@ -47,4 +54,4 @@ | ||
_getOrDeleteIfExpired(key, item) { | ||
const deleted = this._deleteIfExpired(key, item); | ||
#getOrDeleteIfExpired(key, item) { | ||
const deleted = this.#deleteIfExpired(key, item); | ||
if (deleted === false) { | ||
@@ -55,34 +62,34 @@ return item.value; | ||
_getItemValue(key, item) { | ||
return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value; | ||
#getItemValue(key, item) { | ||
return item.expiry ? this.#getOrDeleteIfExpired(key, item) : item.value; | ||
} | ||
_peek(key, cache) { | ||
#peek(key, cache) { | ||
const item = cache.get(key); | ||
return this._getItemValue(key, item); | ||
return this.#getItemValue(key, item); | ||
} | ||
_set(key, value) { | ||
this.cache.set(key, value); | ||
this._size++; | ||
#set(key, value) { | ||
this.#cache.set(key, value); | ||
this.#size++; | ||
if (this._size >= this.maxSize) { | ||
this._size = 0; | ||
this._emitEvictions(this.oldCache); | ||
this.oldCache = this.cache; | ||
this.cache = new Map(); | ||
if (this.#size >= this.#maxSize) { | ||
this.#size = 0; | ||
this.#emitEvictions(this.#oldCache); | ||
this.#oldCache = this.#cache; | ||
this.#cache = new Map(); | ||
} | ||
} | ||
_moveToRecent(key, item) { | ||
this.oldCache.delete(key); | ||
this._set(key, item); | ||
#moveToRecent(key, item) { | ||
this.#oldCache.delete(key); | ||
this.#set(key, item); | ||
} | ||
* _entriesAscending() { | ||
for (const item of this.oldCache) { | ||
* #entriesAscending() { | ||
for (const item of this.#oldCache) { | ||
const [key, value] = item; | ||
if (!this.cache.has(key)) { | ||
const deleted = this._deleteIfExpired(key, value); | ||
if (!this.#cache.has(key)) { | ||
const deleted = this.#deleteIfExpired(key, value); | ||
if (deleted === false) { | ||
@@ -94,5 +101,5 @@ yield item; | ||
for (const item of this.cache) { | ||
for (const item of this.#cache) { | ||
const [key, value] = item; | ||
const deleted = this._deleteIfExpired(key, value); | ||
const deleted = this.#deleteIfExpired(key, value); | ||
if (deleted === false) { | ||
@@ -105,12 +112,11 @@ yield item; | ||
get(key) { | ||
if (this.cache.has(key)) { | ||
const item = this.cache.get(key); | ||
return this._getItemValue(key, item); | ||
if (this.#cache.has(key)) { | ||
const item = this.#cache.get(key); | ||
return this.#getItemValue(key, item); | ||
} | ||
if (this.oldCache.has(key)) { | ||
const item = this.oldCache.get(key); | ||
if (this._deleteIfExpired(key, item) === false) { | ||
this._moveToRecent(key, item); | ||
if (this.#oldCache.has(key)) { | ||
const item = this.#oldCache.get(key); | ||
if (this.#deleteIfExpired(key, item) === false) { | ||
this.#moveToRecent(key, item); | ||
return item.value; | ||
@@ -121,14 +127,14 @@ } | ||
set(key, value, {maxAge = this.maxAge} = {}) { | ||
const expiry = | ||
typeof maxAge === 'number' && maxAge !== Number.POSITIVE_INFINITY ? | ||
Date.now() + maxAge : | ||
undefined; | ||
if (this.cache.has(key)) { | ||
this.cache.set(key, { | ||
set(key, value, {maxAge = this.#maxAge} = {}) { | ||
const expiry = typeof maxAge === 'number' && maxAge !== Number.POSITIVE_INFINITY | ||
? (Date.now() + maxAge) | ||
: undefined; | ||
if (this.#cache.has(key)) { | ||
this.#cache.set(key, { | ||
value, | ||
expiry | ||
expiry, | ||
}); | ||
} else { | ||
this._set(key, {value, expiry}); | ||
this.#set(key, {value, expiry}); | ||
} | ||
@@ -140,8 +146,8 @@ | ||
has(key) { | ||
if (this.cache.has(key)) { | ||
return !this._deleteIfExpired(key, this.cache.get(key)); | ||
if (this.#cache.has(key)) { | ||
return !this.#deleteIfExpired(key, this.#cache.get(key)); | ||
} | ||
if (this.oldCache.has(key)) { | ||
return !this._deleteIfExpired(key, this.oldCache.get(key)); | ||
if (this.#oldCache.has(key)) { | ||
return !this.#deleteIfExpired(key, this.#oldCache.get(key)); | ||
} | ||
@@ -153,8 +159,8 @@ | ||
peek(key) { | ||
if (this.cache.has(key)) { | ||
return this._peek(key, this.cache); | ||
if (this.#cache.has(key)) { | ||
return this.#peek(key, this.#cache); | ||
} | ||
if (this.oldCache.has(key)) { | ||
return this._peek(key, this.oldCache); | ||
if (this.#oldCache.has(key)) { | ||
return this.#peek(key, this.#oldCache); | ||
} | ||
@@ -164,14 +170,14 @@ } | ||
delete(key) { | ||
const deleted = this.cache.delete(key); | ||
const deleted = this.#cache.delete(key); | ||
if (deleted) { | ||
this._size--; | ||
this.#size--; | ||
} | ||
return this.oldCache.delete(key) || deleted; | ||
return this.#oldCache.delete(key) || deleted; | ||
} | ||
clear() { | ||
this.cache.clear(); | ||
this.oldCache.clear(); | ||
this._size = 0; | ||
this.#cache.clear(); | ||
this.#oldCache.clear(); | ||
this.#size = 0; | ||
} | ||
@@ -184,19 +190,19 @@ | ||
const items = [...this._entriesAscending()]; | ||
const items = [...this.#entriesAscending()]; | ||
const removeCount = items.length - newSize; | ||
if (removeCount < 0) { | ||
this.cache = new Map(items); | ||
this.oldCache = new Map(); | ||
this._size = items.length; | ||
this.#cache = new Map(items); | ||
this.#oldCache = new Map(); | ||
this.#size = items.length; | ||
} else { | ||
if (removeCount > 0) { | ||
this._emitEvictions(items.slice(0, removeCount)); | ||
this.#emitEvictions(items.slice(0, removeCount)); | ||
} | ||
this.oldCache = new Map(items.slice(removeCount)); | ||
this.cache = new Map(); | ||
this._size = 0; | ||
this.#oldCache = new Map(items.slice(removeCount)); | ||
this.#cache = new Map(); | ||
this.#size = 0; | ||
} | ||
this.maxSize = newSize; | ||
this.#maxSize = newSize; | ||
} | ||
@@ -217,5 +223,5 @@ | ||
* [Symbol.iterator]() { | ||
for (const item of this.cache) { | ||
for (const item of this.#cache) { | ||
const [key, value] = item; | ||
const deleted = this._deleteIfExpired(key, value); | ||
const deleted = this.#deleteIfExpired(key, value); | ||
if (deleted === false) { | ||
@@ -226,6 +232,6 @@ yield [key, value.value]; | ||
for (const item of this.oldCache) { | ||
for (const item of this.#oldCache) { | ||
const [key, value] = item; | ||
if (!this.cache.has(key)) { | ||
const deleted = this._deleteIfExpired(key, value); | ||
if (!this.#cache.has(key)) { | ||
const deleted = this.#deleteIfExpired(key, value); | ||
if (deleted === false) { | ||
@@ -239,7 +245,7 @@ yield [key, value.value]; | ||
* entriesDescending() { | ||
let items = [...this.cache]; | ||
let items = [...this.#cache]; | ||
for (let i = items.length - 1; i >= 0; --i) { | ||
const item = items[i]; | ||
const [key, value] = item; | ||
const deleted = this._deleteIfExpired(key, value); | ||
const deleted = this.#deleteIfExpired(key, value); | ||
if (deleted === false) { | ||
@@ -250,8 +256,8 @@ yield [key, value.value]; | ||
items = [...this.oldCache]; | ||
items = [...this.#oldCache]; | ||
for (let i = items.length - 1; i >= 0; --i) { | ||
const item = items[i]; | ||
const [key, value] = item; | ||
if (!this.cache.has(key)) { | ||
const deleted = this._deleteIfExpired(key, value); | ||
if (!this.#cache.has(key)) { | ||
const deleted = this.#deleteIfExpired(key, value); | ||
if (deleted === false) { | ||
@@ -265,3 +271,3 @@ yield [key, value.value]; | ||
* entriesAscending() { | ||
for (const [key, value] of this._entriesAscending()) { | ||
for (const [key, value] of this.#entriesAscending()) { | ||
yield [key, value.value]; | ||
@@ -272,9 +278,9 @@ } | ||
get size() { | ||
if (!this._size) { | ||
return this.oldCache.size; | ||
if (!this.#size) { | ||
return this.#oldCache.size; | ||
} | ||
let oldCacheSize = 0; | ||
for (const key of this.oldCache.keys()) { | ||
if (!this.cache.has(key)) { | ||
for (const key of this.#oldCache.keys()) { | ||
if (!this.#cache.has(key)) { | ||
oldCacheSize++; | ||
@@ -284,5 +290,9 @@ } | ||
return Math.min(this._size + oldCacheSize, this.maxSize); | ||
return Math.min(this.#size + oldCacheSize, this.#maxSize); | ||
} | ||
get maxSize() { | ||
return this.#maxSize; | ||
} | ||
entries() { | ||
@@ -289,0 +299,0 @@ return this.entriesAscending(); |
{ | ||
"name": "quick-lru", | ||
"version": "6.1.2", | ||
"version": "7.0.0", | ||
"description": "Simple “Least Recently Used” (LRU) cache", | ||
@@ -14,9 +14,11 @@ "license": "MIT", | ||
"type": "module", | ||
"exports": "./index.js", | ||
"exports": { | ||
"types": "./index.d.ts", | ||
"default": "./index.js" | ||
}, | ||
"engines": { | ||
"node": ">=12" | ||
"node": ">=18" | ||
}, | ||
"scripts": { | ||
"//test": "xo && nyc ava && tsd", | ||
"test": "xo && ava" | ||
"test": "xo && nyc ava && tsd" | ||
}, | ||
@@ -41,6 +43,6 @@ "files": [ | ||
"devDependencies": { | ||
"ava": "^3.15.0", | ||
"ava": "^5.3.1", | ||
"nyc": "^15.1.0", | ||
"tsd": "^0.14.0", | ||
"xo": "^0.37.1" | ||
"tsd": "^0.29.0", | ||
"xo": "^0.56.0" | ||
}, | ||
@@ -47,0 +49,0 @@ "nyc": { |
@@ -11,5 +11,5 @@ # quick-lru [![Coverage Status](https://codecov.io/gh/sindresorhus/quick-lru/branch/main/graph/badge.svg)](https://codecov.io/gh/sindresorhus/quick-lru/branch/main) | ||
```sh | ||
npm install quick-lru | ||
``` | ||
$ npm install quick-lru | ||
``` | ||
@@ -140,20 +140,12 @@ ## Usage | ||
#### .size | ||
#### .size *(getter)* | ||
The stored item count. | ||
#### .maxSize *(getter)* | ||
The set max size. | ||
## Related | ||
- [yocto-queue](https://github.com/sindresorhus/yocto-queue) - Tiny queue data structure | ||
--- | ||
<div align="center"> | ||
<b> | ||
<a href="https://tidelift.com/subscription/pkg/npm-quick-lru?utm_source=npm-quick-lru&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a> | ||
</b> | ||
<br> | ||
<sub> | ||
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies. | ||
</sub> | ||
</div> |
339
15059
150