1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
x12
 
 
 
 
 
 
 
 
 
 
 
 
 
x12
 
 
 
 
 
 
x12
x21
x21
x21
 
x12
 
x350
x350
x350
 
x12
x133
x138
x138
x133
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
x12
x229
 
x229
x335
x335
 
x229
x229
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
x12
x125
x236
x236
x236
x236
 
x238
x125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
x12
x133
x133
 
x133
x133
x12 |
|
// Copyright 2018-2025 the Deno authors. MIT license.
// This module is browser compatible.
import type { MemoizationCache } from "./memoize.ts";
export type { MemoizationCache };
/**
* Least-recently-used cache.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @see {@link https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU | Least-recently-used cache}
*
* Automatically removes entries above the max size based on when they were
* last accessed with `get`, `set`, or `has`.
*
* @typeParam K The type of the cache keys.
* @typeParam V The type of the cache values.
*
* @example Basic usage
* ```ts
* import { LruCache } from "@std/cache";
* import { assert, assertEquals } from "@std/assert";
*
* const MAX_SIZE = 3;
* const cache = new LruCache<string, number>(MAX_SIZE);
*
* cache.set("a", 1);
* cache.set("b", 2);
* cache.set("c", 3);
* cache.set("d", 4);
*
* // most recent values are stored up to `MAX_SIZE`
* assertEquals(cache.get("b"), 2);
* assertEquals(cache.get("c"), 3);
* assertEquals(cache.get("d"), 4);
*
* // less recent values are removed
* assert(!cache.has("a"));
* ```
*/
export class LruCache<K, V> extends Map<K, V>
implements MemoizationCache<K, V> {
/**
* The maximum number of entries to store in the cache.
*
* @example Max size
* ```ts no-assert
* import { LruCache } from "@std/cache";
* import { assertEquals } from "@std/assert";
*
* const cache = new LruCache<string, number>(100);
* assertEquals(cache.maxSize, 100);
* ```
*/
maxSize: number;
/**
* Constructs a new `LruCache`.
*
* @param maxSize The maximum number of entries to store in the cache.
*/
constructor(maxSize: number) {
super();
this.maxSize = maxSize;
}
#setMostRecentlyUsed(key: K, value: V): void {
// delete then re-add to ensure most recently accessed elements are last
super.delete(key);
super.set(key, value);
}
#pruneToMaxSize(): void {
if (this.size > this.maxSize) {
this.delete(this.keys().next().value!);
}
}
/**
* Checks whether an element with the specified key exists or not.
*
* @param key The key to check.
* @returns `true` if the cache contains the specified key, otherwise `false`.
*
* @example Checking for the existence of a key
* ```ts
* import { LruCache } from "@std/cache";
* import { assert } from "@std/assert";
*
* const cache = new LruCache<string, number>(100);
*
* cache.set("a", 1);
* assert(cache.has("a"));
* ```
*/
override has(key: K): boolean {
const exists = super.has(key);
if (exists) {
this.#setMostRecentlyUsed(key, super.get(key)!);
}
return exists;
}
/**
* Gets the element with the specified key.
*
* @param key The key to get the value for.
* @returns The value associated with the specified key, or `undefined` if the key is not present in the cache.
*
* @example Getting a value from the cache
* ```ts
* import { LruCache } from "@std/cache";
* import { assertEquals } from "@std/assert";
*
* const cache = new LruCache<string, number>(100);
*
* cache.set("a", 1);
* assertEquals(cache.get("a"), 1);
* ```
*/
override get(key: K): V | undefined {
if (super.has(key)) {
const value = super.get(key)!;
this.#setMostRecentlyUsed(key, value);
return value;
}
return undefined;
}
/**
* Sets the specified key to the specified value.
*
* @param key The key to set the value for.
* @param value The value to set.
* @returns `this` for chaining.
*
* @example Setting a value in the cache
* ```ts no-assert
* import { LruCache } from "@std/cache";
*
* const cache = new LruCache<string, number>(100);
* cache.set("a", 1);
* ```
*/
override set(key: K, value: V): this {
this.#setMostRecentlyUsed(key, value);
this.#pruneToMaxSize();
return this;
}
}
|