list-toolkit 2.2.5 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README.md +40 -36
  2. package/llms-full.txt +743 -0
  3. package/llms.txt +100 -0
  4. package/package.json +40 -32
  5. package/src/cache/cache-fifo.d.ts +6 -0
  6. package/src/cache/cache-fifo.js +7 -4
  7. package/src/cache/cache-lfu.d.ts +18 -0
  8. package/src/cache/cache-lfu.js +18 -6
  9. package/src/cache/cache-lru.d.ts +74 -0
  10. package/src/cache/cache-lru.js +60 -5
  11. package/src/cache/cache-random.d.ts +20 -0
  12. package/src/cache/cache-random.js +17 -6
  13. package/src/cache/decorator.d.ts +46 -0
  14. package/src/cache/decorator.js +26 -2
  15. package/src/cache.d.ts +13 -0
  16. package/src/cache.js +7 -2
  17. package/src/ext-list.d.ts +3 -0
  18. package/src/ext-list.js +0 -2
  19. package/src/ext-slist.d.ts +3 -0
  20. package/src/ext-slist.js +0 -2
  21. package/src/ext-value-list.d.ts +3 -0
  22. package/src/ext-value-list.js +0 -2
  23. package/src/ext-value-slist.d.ts +3 -0
  24. package/src/ext-value-slist.js +0 -2
  25. package/src/heap/basics.d.ts +89 -0
  26. package/src/heap/basics.js +42 -5
  27. package/src/heap/leftist-heap.d.ts +107 -0
  28. package/src/heap/leftist-heap.js +54 -2
  29. package/src/heap/min-heap.d.ts +270 -0
  30. package/src/heap/min-heap.js +186 -2
  31. package/src/heap/skew-heap.d.ts +105 -0
  32. package/src/heap/skew-heap.js +54 -2
  33. package/src/heap.d.ts +3 -0
  34. package/src/heap.js +0 -2
  35. package/src/list/basics.d.ts +43 -0
  36. package/src/list/basics.js +26 -8
  37. package/src/list/core.d.ts +271 -0
  38. package/src/list/core.js +162 -7
  39. package/src/list/ext-value.d.ts +253 -0
  40. package/src/list/ext-value.js +40 -6
  41. package/src/list/ext.d.ts +242 -0
  42. package/src/list/ext.js +148 -10
  43. package/src/list/nodes.d.ts +336 -0
  44. package/src/list/nodes.js +141 -3
  45. package/src/list/ptr.d.ts +72 -0
  46. package/src/list/ptr.js +44 -2
  47. package/src/list/value.d.ts +292 -0
  48. package/src/list/value.js +47 -6
  49. package/src/list-helpers.d.ts +44 -0
  50. package/src/list-helpers.js +36 -3
  51. package/src/list-utils.d.ts +141 -0
  52. package/src/list-utils.js +89 -3
  53. package/src/list.d.ts +3 -0
  54. package/src/list.js +0 -2
  55. package/src/meta-utils.d.ts +212 -0
  56. package/src/meta-utils.js +152 -1
  57. package/src/nt-utils.d.ts +91 -0
  58. package/src/nt-utils.js +65 -4
  59. package/src/queue.d.ts +74 -0
  60. package/src/queue.js +28 -2
  61. package/src/slist/basics.d.ts +47 -0
  62. package/src/slist/basics.js +23 -8
  63. package/src/slist/core.d.ts +251 -0
  64. package/src/slist/core.js +151 -6
  65. package/src/slist/ext-value.d.ts +188 -0
  66. package/src/slist/ext-value.js +35 -6
  67. package/src/slist/ext.d.ts +182 -0
  68. package/src/slist/ext.js +114 -12
  69. package/src/slist/nodes.d.ts +361 -0
  70. package/src/slist/nodes.js +156 -3
  71. package/src/slist/ptr.d.ts +73 -0
  72. package/src/slist/ptr.js +45 -2
  73. package/src/slist/value.d.ts +246 -0
  74. package/src/slist/value.js +38 -6
  75. package/src/slist.d.ts +3 -0
  76. package/src/slist.js +0 -2
  77. package/src/stack.d.ts +59 -0
  78. package/src/stack.js +29 -3
  79. package/src/tree/splay-tree.d.ts +151 -0
  80. package/src/tree/splay-tree.js +94 -3
  81. package/src/value-list.d.ts +3 -0
  82. package/src/value-list.js +0 -2
  83. package/src/value-slist.d.ts +3 -0
  84. package/src/value-slist.js +0 -2
  85. package/cjs/cache/cache-fifo.js +0 -37
  86. package/cjs/cache/cache-lfu.js +0 -76
  87. package/cjs/cache/cache-lru.js +0 -100
  88. package/cjs/cache/cache-random.js +0 -77
  89. package/cjs/cache/decorator.js +0 -47
  90. package/cjs/cache.js +0 -27
  91. package/cjs/ext-list.js +0 -21
  92. package/cjs/ext-slist.js +0 -21
  93. package/cjs/ext-value-list.js +0 -21
  94. package/cjs/ext-value-slist.js +0 -21
  95. package/cjs/heap/basics.js +0 -63
  96. package/cjs/heap/leftist-heap.js +0 -124
  97. package/cjs/heap/min-heap.js +0 -294
  98. package/cjs/heap/skew-heap.js +0 -114
  99. package/cjs/heap.js +0 -21
  100. package/cjs/list/basics.js +0 -88
  101. package/cjs/list/core.js +0 -305
  102. package/cjs/list/ext-value.js +0 -88
  103. package/cjs/list/ext.js +0 -356
  104. package/cjs/list/nodes.js +0 -240
  105. package/cjs/list/ptr.js +0 -61
  106. package/cjs/list/value.js +0 -99
  107. package/cjs/list-helpers.js +0 -91
  108. package/cjs/list-utils.js +0 -141
  109. package/cjs/list.js +0 -21
  110. package/cjs/meta-utils.js +0 -171
  111. package/cjs/nt-utils.js +0 -132
  112. package/cjs/package.json +0 -1
  113. package/cjs/queue.js +0 -58
  114. package/cjs/slist/basics.js +0 -71
  115. package/cjs/slist/core.js +0 -362
  116. package/cjs/slist/ext-value.js +0 -82
  117. package/cjs/slist/ext.js +0 -336
  118. package/cjs/slist/nodes.js +0 -276
  119. package/cjs/slist/ptr.js +0 -87
  120. package/cjs/slist/value.js +0 -90
  121. package/cjs/slist.js +0 -21
  122. package/cjs/stack.js +0 -55
  123. package/cjs/tree/splay-tree.js +0 -362
  124. package/cjs/value-list.js +0 -21
  125. package/cjs/value-slist.js +0 -21
package/llms.txt ADDED
@@ -0,0 +1,100 @@
1
+ # list-toolkit
2
+
3
+ > Zero-dependency JavaScript library providing efficient list-based data structures: linked lists, caches, heaps, queues, stacks, and splay trees.
4
+
5
+ - NPM: https://npmjs.org/package/list-toolkit
6
+ - GitHub: https://github.com/uhop/list-toolkit
7
+ - Wiki: https://github.com/uhop/list-toolkit/wiki
8
+ - License: BSD-3-Clause
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install list-toolkit
14
+ ```
15
+
16
+ ## Quick start
17
+
18
+ ```js
19
+ import ValueList from 'list-toolkit/value-list.js';
20
+
21
+ const list = ValueList.from([1, 2, 3]);
22
+ for (const value of list) console.log(value); // 1, 2, 3
23
+
24
+ list.pushBack(4);
25
+ list.pushFront(0);
26
+ console.log(list.popFront()); // 0
27
+ ```
28
+
29
+ ```js
30
+ import List from 'list-toolkit/list.js';
31
+
32
+ // Node-based list: link properties are added directly to your objects
33
+ const a = {name: 'Alice'}, b = {name: 'Bob'};
34
+ const people = List.from([a, b]);
35
+ for (const node of people) console.log(node.name); // Alice, Bob
36
+ ```
37
+
38
+ ## Modules
39
+
40
+ ### Linked lists (doubly linked, circular)
41
+
42
+ - **List** (`list-toolkit/list.js`) — hosted node-based DLL. Link properties (`next`/`prev`) are added to user objects. Customizable link names.
43
+ - **ValueList** (`list-toolkit/value-list.js`) — hosted value-based DLL. Wraps values in `ValueNode` containers.
44
+ - **ExtList** (`list-toolkit/ext-list.js`) — external (headless) node-based DLL. Points into an existing circular list.
45
+ - **ExtValueList** (`list-toolkit/ext-value-list.js`) — external (headless) value-based DLL.
46
+
47
+ ### Linked lists (singly linked, circular)
48
+
49
+ - **SList** (`list-toolkit/slist.js`) — hosted node-based SLL.
50
+ - **ValueSList** (`list-toolkit/value-slist.js`) — hosted value-based SLL.
51
+ - **ExtSList** (`list-toolkit/ext-slist.js`) — external (headless) node-based SLL.
52
+ - **ExtValueSList** (`list-toolkit/ext-value-slist.js`) — external (headless) value-based SLL.
53
+
54
+ ### Caches
55
+
56
+ - **CacheLRU** (`list-toolkit/cache.js`) — least recently used eviction. Default export.
57
+ - **CacheFIFO** (`list-toolkit/cache/cache-fifo.js`) — first in first out eviction.
58
+ - **CacheLFU** (`list-toolkit/cache/cache-lfu.js`) — least frequently used eviction.
59
+ - **CacheRandom** (`list-toolkit/cache/cache-random.js`) — random eviction.
60
+ - **cacheDecorator** (`list-toolkit/cache.js`) — decorator to cache function/method results.
61
+
62
+ All caches share the same API: `has(key)`, `find(key)`/`get(key)`, `register(key, value)`/`set(key, value)`, `remove(key)`/`delete(key)`, `clear()`.
63
+
64
+ ### Heaps (priority queues)
65
+
66
+ - **MinHeap** (`list-toolkit/heap.js`) — array-based binary min-heap. Default export.
67
+ - **LeftistHeap** (`list-toolkit/heap/leftist-heap.js`) — merge-based leftist heap.
68
+ - **SkewHeap** (`list-toolkit/heap/skew-heap.js`) — merge-based skew heap.
69
+
70
+ All heaps support `less` or `compare` for ordering. Common API: `push(value)`, `pop()`, `top`/`peek()`, `merge()`, `has(value)`, `remove(value)`.
71
+
72
+ ### Adapters
73
+
74
+ - **Queue** (`list-toolkit/queue.js`) — FIFO queue adapter. Methods: `add`/`push`/`enqueue`, `remove`/`pop`/`dequeue`, `peek`, `top`, `clear`.
75
+ - **Stack** (`list-toolkit/stack.js`) — LIFO stack adapter. Methods: `push`, `pop`, `peek`, `top`, `clear`.
76
+
77
+ ### Trees
78
+
79
+ - **SplayTree** (`list-toolkit/tree/splay-tree.js`) — self-adjusting BST. Methods: `insert`, `find`, `remove`, `promote`, `split` (via `splitMaxTree`), `join`.
80
+
81
+ ### Utilities
82
+
83
+ - **list-utils** (`list-toolkit/list-utils.js`) — push/append values, find/remove nodes by condition, validation.
84
+ - **nt-utils** (`list-toolkit/nt-utils.js`) — convert between null-terminated and circular lists.
85
+ - **meta-utils** (`list-toolkit/meta-utils.js`) — `addAlias`, `addAliases`, iterator helpers, `copyOptions`.
86
+
87
+ ## Key concepts
88
+
89
+ - All lists are **circular** — the last node links back to the head.
90
+ - **Hosted lists** use a `HeadNode` sentinel. **External lists** are headless.
91
+ - **Value lists** wrap values in `ValueNode`. **Node lists** use link properties directly on user objects.
92
+ - Link names (`nextName`/`prevName`) are customizable, allowing objects to be in multiple lists.
93
+ - **Pointers** (`Ptr`) provide safe iteration with insert/remove during traversal.
94
+ - **TypeScript** declarations (`.d.ts`) are included for all modules.
95
+
96
+ ## Links
97
+
98
+ - Docs: https://github.com/uhop/list-toolkit/wiki
99
+ - npm: https://www.npmjs.com/package/list-toolkit
100
+ - Full LLM reference: https://github.com/uhop/list-toolkit/blob/master/llms-full.txt
package/package.json CHANGED
@@ -1,25 +1,28 @@
1
1
  {
2
2
  "name": "list-toolkit",
3
- "version": "2.2.5",
4
- "description": "List-based data structures to organize your objects.",
3
+ "version": "2.3.0",
4
+ "description": "Zero-dependency list-based data structures: linked lists (doubly/singly linked, circular), caches (LRU, LFU, FIFO), heaps, queues, stacks, splay trees.",
5
5
  "type": "module",
6
6
  "exports": {
7
- "./*": {
8
- "require": "./cjs/*",
9
- "default": "./src/*"
10
- }
7
+ "./*": "./src/*"
11
8
  },
12
9
  "scripts": {
13
- "prepare-dist": "node scripts/prepare-dist.js",
14
- "build": "babel src --out-dir cjs",
15
- "prepublishOnly": "npm run prepare-dist && npm run build",
10
+ "lint": "prettier --check .",
11
+ "lint:fix": "prettier --write .",
12
+ "ts-check": "tsc --noEmit",
13
+ "ts-test": "tape6 --flags FO '/ts-tests/test-*.*ts'",
14
+ "ts-test:bun": "tape6-bun --flags FO '/ts-tests/test-*.*ts'",
15
+ "ts-test:deno": "tape6-deno --flags FO '/ts-tests/test-*.*ts'",
16
+ "start": "tape6-server --trace",
16
17
  "test": "tape6 --flags FO",
17
18
  "test:bun": "tape6-bun --flags FO",
18
19
  "test:deno": "tape6-deno --flags FO",
19
20
  "test:proc": "tape6-proc --flags FO",
20
- "test:proc:bun": "bun run `npx tape6-proc --self` --flags FO",
21
- "test:proc:deno": "deno run -A `npx tape6-proc --self` --flags FO -r -A",
22
- "start": "tape6-server --trace"
21
+ "test:proc:bun": "bun run `tape6-proc --self` --flags FO",
22
+ "test:proc:deno": "deno run -A `tape6-proc --self` --flags FO -r -A",
23
+ "test:seq": "tape6-seq --flags FO",
24
+ "test:seq:bun": "bun run `tape6-seq --self` --flags FO",
25
+ "test:seq:deno": "deno run -A `tape6-seq --self` --flags FO"
23
26
  },
24
27
  "repository": {
25
28
  "type": "git",
@@ -28,9 +31,23 @@
28
31
  "keywords": [
29
32
  "list",
30
33
  "lists",
34
+ "linked-list",
35
+ "doubly-linked-list",
36
+ "singly-linked-list",
37
+ "circular-list",
31
38
  "cache",
39
+ "lru-cache",
40
+ "lfu-cache",
41
+ "fifo-cache",
32
42
  "heap",
33
- "data structures"
43
+ "min-heap",
44
+ "priority-queue",
45
+ "queue",
46
+ "stack",
47
+ "splay-tree",
48
+ "data-structures",
49
+ "esm",
50
+ "zero-dependency"
34
51
  ],
35
52
  "author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (http://www.lazutkin.com/)",
36
53
  "funding": "https://github.com/sponsors/uhop",
@@ -38,31 +55,22 @@
38
55
  "bugs": {
39
56
  "url": "https://github.com/uhop/list-toolkit/issues"
40
57
  },
58
+ "github": "http://github.com/uhop/list-toolkit",
41
59
  "homepage": "https://github.com/uhop/list-toolkit#readme",
60
+ "llms": "https://raw.githubusercontent.com/uhop/list-toolkit/master/llms.txt",
61
+ "llmsFull": "https://raw.githubusercontent.com/uhop/list-toolkit/master/llms-full.txt",
42
62
  "devDependencies": {
43
- "@babel/cli": "^7.28.6",
44
- "@babel/core": "^7.28.6",
45
- "@babel/preset-env": "^7.28.6",
46
- "nano-benchmark": "^1.0.7",
47
- "tape-six": "^1.4.5",
48
- "tape-six-proc": "^1.1.6"
63
+ "nano-benchmark": "^1.0.10",
64
+ "prettier": "^3.8.1",
65
+ "tape-six": "^1.7.2",
66
+ "tape-six-proc": "^1.2.3",
67
+ "typescript": "^5.9.3"
49
68
  },
50
69
  "files": [
51
70
  "/src",
52
- "/cjs"
71
+ "llms.txt",
72
+ "llms-full.txt"
53
73
  ],
54
- "babel": {
55
- "presets": [
56
- [
57
- "@babel/preset-env",
58
- {
59
- "targets": {
60
- "node": "current"
61
- }
62
- }
63
- ]
64
- ]
65
- },
66
74
  "tape6": {
67
75
  "tests": [
68
76
  "/tests/test-*.*js"
@@ -0,0 +1,6 @@
1
+ import {CacheLRU} from './cache-lru.js';
2
+
3
+ /** FIFO (First In First Out) cache. Evicts the oldest entry. */
4
+ export class CacheFIFO<K = unknown, V = unknown> extends CacheLRU<K, V> {}
5
+
6
+ export default CacheFIFO;
@@ -1,19 +1,22 @@
1
- 'use strict';
2
-
3
1
  import CacheLRU from './cache-lru.js';
4
2
 
5
- // Evicts on the first-in-first-out basis.
6
-
3
+ /**
4
+ * FIFO (First In First Out) cache. Evicts the oldest entry.
5
+ * Extends {@link CacheLRU} with FIFO eviction policy.
6
+ */
7
7
  export class CacheFIFO extends CacheLRU {
8
+ /** @override */
8
9
  use(key) {
9
10
  return this.dict.get(key);
10
11
  }
12
+ /** @override */
11
13
  addNew(key, value) {
12
14
  this.list.pushBack({key, value});
13
15
  const node = this.list.back;
14
16
  this.dict.set(key, node);
15
17
  return node;
16
18
  }
19
+ /** @override */
17
20
  evictAndReplace(key, value) {
18
21
  const node = this.list.front;
19
22
  this.list.moveToBack(node);
@@ -0,0 +1,18 @@
1
+ import {CacheLRU} from './cache-lru.js';
2
+
3
+ /** LFU (Least Frequently Used) cache. Evicts the least frequently accessed entry. */
4
+ export class CacheLFU<K = unknown, V = unknown> extends CacheLRU<K, V> {
5
+ /**
6
+ * @param capacity - Maximum number of entries (default 10).
7
+ */
8
+ constructor(capacity?: number);
9
+
10
+ /**
11
+ * Reset all frequency counters to a given value.
12
+ * @param initialValue - Counter value to set (default 1).
13
+ * @returns `this` for chaining.
14
+ */
15
+ resetCounters(initialValue?: number): this;
16
+ }
17
+
18
+ export default CacheLFU;
@@ -1,26 +1,30 @@
1
- 'use strict';
2
-
3
1
  import {addAlias} from '../meta-utils.js';
4
2
  import MinHeap from '../heap/min-heap.js';
5
3
  import CacheLRU from './cache-lru.js';
6
4
 
7
- // Evicts the least frequently used items.
8
-
5
+ /**
6
+ * LFU (Least Frequently Used) cache. Evicts the least frequently accessed entry.
7
+ * Extends {@link CacheLRU} with a min-heap for frequency tracking.
8
+ */
9
9
  export class CacheLFU extends CacheLRU {
10
+ /** @param {number} [capacity=10] - Maximum number of entries. */
10
11
  constructor(capacity = 10) {
11
12
  super(capacity);
12
13
  this.heap = new MinHeap({less: (a, b) => a.value.counter < b.value.counter});
13
14
  }
15
+ /** @override */
14
16
  use(key) {
15
17
  const node = this.dict.get(key);
16
18
  if (node) ++node.value.counter;
17
19
  return node;
18
20
  }
21
+ /** @override */
19
22
  update(node, value) {
20
23
  node.value.counter = 1;
21
24
  node.value.value = value;
22
25
  return this;
23
26
  }
27
+ /** @override */
24
28
  addNew(key, value) {
25
29
  this.list.pushFront({key, value, counter: 1});
26
30
  const node = this.list.front;
@@ -28,6 +32,7 @@ export class CacheLFU extends CacheLRU {
28
32
  this.heap.push(node);
29
33
  return node;
30
34
  }
35
+ /** @override */
31
36
  evictAndReplace(key, value) {
32
37
  const node = this.heap.top;
33
38
  this.dict.delete(node.value.key);
@@ -36,6 +41,7 @@ export class CacheLFU extends CacheLRU {
36
41
  this.heap.updateTop();
37
42
  return node;
38
43
  }
44
+ /** @override */
39
45
  remove(key) {
40
46
  const node = this.dict.get(key);
41
47
  if (node) {
@@ -45,14 +51,20 @@ export class CacheLFU extends CacheLRU {
45
51
  }
46
52
  return this;
47
53
  }
54
+ /** @override */
48
55
  clear() {
49
56
  super.clear();
50
57
  this.heap.clear();
51
58
  return this;
52
59
  }
60
+ /**
61
+ * Reset all frequency counters.
62
+ * @param {number} [initialValue=1] - Value to set all counters to.
63
+ * @returns {CacheLFU} `this` for chaining.
64
+ */
53
65
  resetCounters(initialValue = 1) {
54
- for (const item of this.heap) {
55
- item.counter = initialValue;
66
+ for (const item of this.heap.array) {
67
+ item.value.counter = initialValue;
56
68
  }
57
69
  return this;
58
70
  }
@@ -0,0 +1,74 @@
1
+ /** LRU (Least Recently Used) cache backed by a doubly linked value list and a Map. */
2
+ export class CacheLRU<K = unknown, V = unknown> {
3
+ /** Maximum number of entries. */
4
+ capacity: number;
5
+
6
+ /**
7
+ * @param capacity - Maximum number of entries (default 10).
8
+ */
9
+ constructor(capacity?: number);
10
+
11
+ /** Whether the cache has no entries. */
12
+ get isEmpty(): boolean;
13
+
14
+ /** Number of entries currently stored. */
15
+ get size(): number;
16
+
17
+ /**
18
+ * Check whether a key exists in the cache.
19
+ * @param key - Key to look up.
20
+ * @returns `true` if the key is present.
21
+ */
22
+ has(key: K): boolean;
23
+
24
+ /**
25
+ * Look up a value by key, promoting it as most recently used.
26
+ * @param key - Key to look up.
27
+ * @returns The value, or `undefined` if not found.
28
+ */
29
+ find(key: K): V | undefined;
30
+
31
+ /** Alias for {@link find}. */
32
+ get(key: K): V | undefined;
33
+
34
+ /**
35
+ * Remove an entry by key.
36
+ * @param key - Key to remove.
37
+ * @returns `this` for chaining.
38
+ */
39
+ remove(key: K): this;
40
+
41
+ /** Alias for {@link remove}. */
42
+ delete(key: K): this;
43
+
44
+ /**
45
+ * Add or update an entry. Evicts the least recently used entry if at capacity.
46
+ * @param key - Key to register.
47
+ * @param value - Value to associate.
48
+ * @returns `this` for chaining.
49
+ */
50
+ register(key: K, value: V): this;
51
+
52
+ /** Alias for {@link register}. */
53
+ add(key: K, value: V): this;
54
+
55
+ /** Alias for {@link register}. */
56
+ set(key: K, value: V): this;
57
+
58
+ /**
59
+ * Remove all entries.
60
+ * @returns `this` for chaining.
61
+ */
62
+ clear(): this;
63
+
64
+ /** Iterate over `{key, value}` entry objects from most to least recently used. */
65
+ [Symbol.iterator](): IterableIterator<{key: K; value: V}>;
66
+
67
+ /**
68
+ * Iterate over `{key, value}` entry objects from least to most recently used.
69
+ * @returns An iterable iterator.
70
+ */
71
+ getReverseIterator(): IterableIterator<{key: K; value: V}>;
72
+ }
73
+
74
+ export default CacheLRU;
@@ -1,30 +1,47 @@
1
- 'use strict';
2
-
3
1
  import ValueList from '../value-list.js';
4
2
  import {addAliases} from '../meta-utils.js';
5
3
 
6
- // The base cache class. Evicts the least recently used items.
7
- // Based on doubly linked value lists.
8
-
4
+ /**
5
+ * LRU (Least Recently Used) cache backed by a doubly linked value list.
6
+ * Evicts the least recently used item when capacity is exceeded.
7
+ */
9
8
  export class CacheLRU {
9
+ /** @param {number} [capacity=10] - Maximum number of entries. */
10
10
  constructor(capacity = 10) {
11
11
  this.capacity = capacity;
12
12
  this.list = new ValueList();
13
13
  this.dict = new Map();
14
14
  }
15
+ /** Whether the cache has no entries. */
15
16
  get isEmpty() {
16
17
  return !this.dict.size;
17
18
  }
19
+ /** The number of entries in the cache. */
18
20
  get size() {
19
21
  return this.dict.size;
20
22
  }
23
+ /**
24
+ * Check whether a key exists.
25
+ * @param {*} key - Key to look up.
26
+ * @returns {boolean} `true` if the key exists.
27
+ */
21
28
  has(key) {
22
29
  return this.dict.has(key);
23
30
  }
31
+ /**
32
+ * Retrieve the value for a key, marking it as recently used.
33
+ * @param {*} key - Key to look up.
34
+ * @returns {*} The value, or `undefined` if not found.
35
+ */
24
36
  find(key) {
25
37
  const node = this.use(key);
26
38
  return node ? node.value.value : undefined;
27
39
  }
40
+ /**
41
+ * Remove an entry by key.
42
+ * @param {*} key - Key to remove.
43
+ * @returns {CacheLRU} `this` for chaining.
44
+ */
28
45
  remove(key) {
29
46
  const node = this.dict.get(key);
30
47
  if (node) {
@@ -33,6 +50,12 @@ export class CacheLRU {
33
50
  }
34
51
  return this;
35
52
  }
53
+ /**
54
+ * Add or update an entry. Evicts the LRU item if at capacity.
55
+ * @param {*} key - Key to register.
56
+ * @param {*} value - Value to store.
57
+ * @returns {CacheLRU} `this` for chaining.
58
+ */
36
59
  register(key, value) {
37
60
  const node = this.use(key);
38
61
  if (node) {
@@ -46,21 +69,44 @@ export class CacheLRU {
46
69
  this.addNew(key, value);
47
70
  return this;
48
71
  }
72
+ /**
73
+ * Mark a key as recently used and return its node.
74
+ * @param {*} key - Key to look up.
75
+ * @returns {object|undefined} The internal node, or `undefined`.
76
+ */
49
77
  use(key) {
50
78
  const node = this.dict.get(key);
51
79
  if (node) this.list.moveToFront(node);
52
80
  return node;
53
81
  }
82
+ /**
83
+ * Update the value of an existing node.
84
+ * @param {object} node - Internal node to update.
85
+ * @param {*} value - New value.
86
+ * @returns {CacheLRU} `this` for chaining.
87
+ */
54
88
  update(node, value) {
55
89
  node.value.value = value;
56
90
  return this;
57
91
  }
92
+ /**
93
+ * Add a new entry to the cache.
94
+ * @param {*} key - Key.
95
+ * @param {*} value - Value.
96
+ * @returns {object} The newly created node.
97
+ */
58
98
  addNew(key, value) {
59
99
  this.list.pushFront({key, value});
60
100
  const node = this.list.front;
61
101
  this.dict.set(key, node);
62
102
  return node;
63
103
  }
104
+ /**
105
+ * Evict the LRU entry and replace it with a new key/value.
106
+ * @param {*} key - New key.
107
+ * @param {*} value - New value.
108
+ * @returns {object} The reused node.
109
+ */
64
110
  evictAndReplace(key, value) {
65
111
  const node = this.list.back;
66
112
  this.list.moveToFront(node);
@@ -69,14 +115,23 @@ export class CacheLRU {
69
115
  node.value = {key, value};
70
116
  return node;
71
117
  }
118
+ /**
119
+ * Remove all entries.
120
+ * @returns {CacheLRU} `this` for chaining.
121
+ */
72
122
  clear() {
73
123
  this.dict.clear();
74
124
  this.list.clear();
75
125
  return this;
76
126
  }
127
+ /** Iterate over `{key, value}` entries from most to least recently used. */
77
128
  [Symbol.iterator]() {
78
129
  return this.list[Symbol.iterator]();
79
130
  }
131
+ /**
132
+ * Get an iterable over entries in reverse (LRU-first) order.
133
+ * @returns {Iterable} An iterable iterator of `{key, value}` objects.
134
+ */
80
135
  getReverseIterator() {
81
136
  return this.list.getReverseIterator();
82
137
  }
@@ -0,0 +1,20 @@
1
+ import {CacheLRU} from './cache-lru.js';
2
+
3
+ /** Random eviction cache. Evicts a randomly selected entry. */
4
+ export class CacheRandom<K = unknown, V = unknown> extends CacheLRU<K, V> {
5
+ /** Next ID counter for random ordering. */
6
+ nextId: number;
7
+
8
+ /**
9
+ * @param capacity - Maximum number of entries (default 10).
10
+ */
11
+ constructor(capacity?: number);
12
+
13
+ /**
14
+ * Reset all IDs and rebuild the internal heap.
15
+ * @returns `this` for chaining.
16
+ */
17
+ resetIds(): this;
18
+ }
19
+
20
+ export default CacheRandom;
@@ -1,24 +1,28 @@
1
- 'use strict';
2
-
3
1
  import {addAlias} from '../meta-utils.js';
4
2
  import MinHeap from '../heap/min-heap.js';
5
3
  import CacheLRU from './cache-lru.js';
6
4
 
7
- // Evicts items randomly.
8
-
5
+ /**
6
+ * Random eviction cache. Evicts a randomly chosen entry.
7
+ * Extends {@link CacheLRU} with random eviction via a min-heap.
8
+ */
9
9
  export class CacheRandom extends CacheLRU {
10
+ /** @param {number} [capacity=10] - Maximum number of entries. */
10
11
  constructor(capacity = 10) {
11
12
  super(capacity);
12
13
  this.heap = new MinHeap({less: (a, b) => a.value.id > b.value.id});
13
14
  this.nextId = 0;
14
15
  }
16
+ /** @override */
15
17
  use(key) {
16
18
  return this.dict.get(key);
17
19
  }
20
+ /** @override */
18
21
  update(node, value) {
19
22
  node.value.value = value;
20
23
  return this;
21
24
  }
25
+ /** @override */
22
26
  addNew(key, value) {
23
27
  this.list.pushFront({key, value, id: this.nextId++});
24
28
  const node = this.list.front;
@@ -26,6 +30,7 @@ export class CacheRandom extends CacheLRU {
26
30
  this.heap.push(node);
27
31
  return node;
28
32
  }
33
+ /** @override */
29
34
  evictAndReplace(key, value) {
30
35
  const index = Math.floor(this.heap.length * Math.random());
31
36
 
@@ -42,6 +47,7 @@ export class CacheRandom extends CacheLRU {
42
47
 
43
48
  return node;
44
49
  }
50
+ /** @override */
45
51
  remove(key) {
46
52
  const node = this.dict.get(key);
47
53
  if (node) {
@@ -51,16 +57,21 @@ export class CacheRandom extends CacheLRU {
51
57
  }
52
58
  return this;
53
59
  }
60
+ /** @override */
54
61
  clear() {
55
62
  super.clear();
56
63
  this.heap.clear();
57
64
  this.nextId = 0;
58
65
  return this;
59
66
  }
67
+ /**
68
+ * Reset all internal IDs and rebuild the heap.
69
+ * @returns {CacheRandom} `this` for chaining.
70
+ */
60
71
  resetIds() {
61
72
  this.nextId = 0;
62
- for (const item of this.heap) {
63
- item.id = this.nextId++;
73
+ for (const item of this.heap.array) {
74
+ item.value.id = this.nextId++;
64
75
  }
65
76
  const array = this.heap.array;
66
77
  this.heap.clear().merge(array);
@@ -0,0 +1,46 @@
1
+ import {CacheLRU} from './cache-lru.js';
2
+
3
+ /** A wrapped function with attached cache and original function reference. */
4
+ export interface WrappedFn<F extends (...args: any[]) => any, K = unknown, V = unknown> {
5
+ (...args: Parameters<F>): ReturnType<F>;
6
+ /** The original unwrapped function. */
7
+ fn: F;
8
+ /** The cache backing this wrapper. */
9
+ cache: CacheLRU<K, V>;
10
+ }
11
+
12
+ /**
13
+ * Wrap a function with caching. The first argument is used as the cache key.
14
+ * @param fn - Function to wrap.
15
+ * @param cache - Cache instance to use.
16
+ * @returns A wrapped function with `.fn` and `.cache` properties.
17
+ */
18
+ export function decorateFn<F extends (...args: any[]) => any>(fn: F, cache: CacheLRU): WrappedFn<F>;
19
+
20
+ /**
21
+ * Decorate an own property descriptor's `value` with caching.
22
+ * @param object - Object owning the property.
23
+ * @param key - Property name.
24
+ * @param cache - Cache instance to use.
25
+ * @returns The wrapped function.
26
+ */
27
+ export function decorate(object: object, key: PropertyKey, cache: CacheLRU): WrappedFn<any>;
28
+
29
+ /**
30
+ * Decorate a method on an object with caching (direct assignment).
31
+ * @param object - Object owning the method.
32
+ * @param key - Method name.
33
+ * @param cache - Cache instance to use.
34
+ * @returns The wrapped function.
35
+ */
36
+ export function decorateMethod(object: object, key: PropertyKey, cache: CacheLRU): WrappedFn<any>;
37
+
38
+ /**
39
+ * Retrieve the cache from a previously decorated property.
40
+ * @param object - Object owning the property.
41
+ * @param key - Property name.
42
+ * @returns The cache instance.
43
+ */
44
+ export function getCache(object: object, key: PropertyKey): CacheLRU;
45
+
46
+ export default decorate;