ts-cachecraft 1.0.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,2322 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ARCCache: () => ARCCache,
24
+ BaseCache: () => BaseCache,
25
+ ClockCache: () => ClockCache,
26
+ FIFOCache: () => FIFOCache,
27
+ LFUCache: () => LFUCache,
28
+ LIFOCache: () => LIFOCache,
29
+ LRUCache: () => LRUCache,
30
+ LRUKCache: () => LRUKCache,
31
+ MRUCache: () => MRUCache,
32
+ RRCache: () => RRCache,
33
+ SLRUCache: () => SLRUCache,
34
+ SieveCache: () => SieveCache,
35
+ TTLCache: () => TTLCache,
36
+ TwoTierCache: () => TwoTierCache,
37
+ WTinyLFUCache: () => WTinyLFUCache
38
+ });
39
+ module.exports = __toCommonJS(index_exports);
40
+
41
+ // src/base-cache.ts
42
+ var BaseCache = class {
43
+ _capacity;
44
+ _hits = 0;
45
+ _misses = 0;
46
+ _evictions = 0;
47
+ onEvict;
48
+ listeners = /* @__PURE__ */ new Map();
49
+ constructor(options) {
50
+ const capacity = typeof options === "number" ? options : options.capacity;
51
+ if (capacity < 1) throw new RangeError("Cache capacity must be at least 1");
52
+ this._capacity = capacity;
53
+ if (typeof options === "object") {
54
+ this.onEvict = options.onEvict;
55
+ }
56
+ }
57
+ get capacity() {
58
+ return this._capacity;
59
+ }
60
+ stats() {
61
+ const total = this._hits + this._misses;
62
+ return {
63
+ hits: this._hits,
64
+ misses: this._misses,
65
+ evictions: this._evictions,
66
+ size: this.size,
67
+ capacity: this._capacity,
68
+ hitRate: total === 0 ? 0 : this._hits / total
69
+ };
70
+ }
71
+ snapshot() {
72
+ return {
73
+ entries: this.collectEntries(),
74
+ stats: this.stats(),
75
+ strategy: this.strategy
76
+ };
77
+ }
78
+ on(event, listener) {
79
+ if (!this.listeners.has(event)) {
80
+ this.listeners.set(event, /* @__PURE__ */ new Set());
81
+ }
82
+ this.listeners.get(event).add(listener);
83
+ }
84
+ off(event, listener) {
85
+ this.listeners.get(event)?.delete(listener);
86
+ }
87
+ emit(detail) {
88
+ const set = this.listeners.get(detail.event);
89
+ if (set) {
90
+ for (const listener of set) {
91
+ listener(detail);
92
+ }
93
+ }
94
+ }
95
+ now() {
96
+ return Date.now();
97
+ }
98
+ };
99
+
100
+ // src/structures/doubly-linked-list.ts
101
+ function createNode(key, value) {
102
+ return { key, value, prev: null, next: null, accessCount: 0 };
103
+ }
104
+ var DoublyLinkedList = class {
105
+ head;
106
+ tail;
107
+ _size = 0;
108
+ constructor() {
109
+ this.head = createNode("__head__", void 0);
110
+ this.tail = createNode("__tail__", void 0);
111
+ this.head.next = this.tail;
112
+ this.tail.prev = this.head;
113
+ }
114
+ get size() {
115
+ return this._size;
116
+ }
117
+ addToFront(node) {
118
+ node.next = this.head.next;
119
+ node.prev = this.head;
120
+ this.head.next.prev = node;
121
+ this.head.next = node;
122
+ this._size++;
123
+ }
124
+ addToBack(node) {
125
+ node.prev = this.tail.prev;
126
+ node.next = this.tail;
127
+ this.tail.prev.next = node;
128
+ this.tail.prev = node;
129
+ this._size++;
130
+ }
131
+ remove(node) {
132
+ if (!node.prev || !node.next) return;
133
+ node.prev.next = node.next;
134
+ node.next.prev = node.prev;
135
+ node.prev = null;
136
+ node.next = null;
137
+ this._size--;
138
+ }
139
+ moveToFront(node) {
140
+ this.remove(node);
141
+ this.addToFront(node);
142
+ }
143
+ moveToBack(node) {
144
+ this.remove(node);
145
+ this.addToBack(node);
146
+ }
147
+ removeLast() {
148
+ if (this._size === 0) return null;
149
+ const node = this.tail.prev;
150
+ this.remove(node);
151
+ return node;
152
+ }
153
+ removeFirst() {
154
+ if (this._size === 0) return null;
155
+ const node = this.head.next;
156
+ this.remove(node);
157
+ return node;
158
+ }
159
+ peekFirst() {
160
+ return this._size === 0 ? null : this.head.next;
161
+ }
162
+ peekLast() {
163
+ return this._size === 0 ? null : this.tail.prev;
164
+ }
165
+ clear() {
166
+ this.head.next = this.tail;
167
+ this.tail.prev = this.head;
168
+ this._size = 0;
169
+ }
170
+ *[Symbol.iterator]() {
171
+ let current = this.head.next;
172
+ while (current && current !== this.tail) {
173
+ yield current;
174
+ current = current.next;
175
+ }
176
+ }
177
+ toArray() {
178
+ const result = [];
179
+ for (const node of this) {
180
+ result.push(node);
181
+ }
182
+ return result;
183
+ }
184
+ };
185
+
186
+ // src/caches/dll-cache.ts
187
+ var DLLCache = class extends BaseCache {
188
+ list = new DoublyLinkedList();
189
+ map = /* @__PURE__ */ new Map();
190
+ defaultTTL;
191
+ config;
192
+ constructor(options, config) {
193
+ super(options);
194
+ this.defaultTTL = options.ttl;
195
+ this.config = config;
196
+ }
197
+ get(key) {
198
+ const node = this.map.get(key);
199
+ if (!node) {
200
+ this._misses++;
201
+ this.emit({ event: "get", key, timestamp: this.now() });
202
+ return void 0;
203
+ }
204
+ if (node.expiry && node.expiry <= this.now()) {
205
+ this.deleteNode(key, node);
206
+ this._misses++;
207
+ this.emit({ event: "expire", key, value: node.value, timestamp: this.now() });
208
+ this.emit({ event: "get", key, timestamp: this.now() });
209
+ return void 0;
210
+ }
211
+ node.lastAccessed = this.now();
212
+ node.accessCount = (node.accessCount ?? 0) + 1;
213
+ if (this.config.reorderOnGet) {
214
+ this.list.moveToFront(node);
215
+ }
216
+ this._hits++;
217
+ this.emit({ event: "get", key, value: node.value, timestamp: this.now() });
218
+ return node.value;
219
+ }
220
+ set(key, value, ttl) {
221
+ const now = this.now();
222
+ const effectiveTTL = ttl ?? this.defaultTTL;
223
+ const expiry = effectiveTTL ? now + effectiveTTL : void 0;
224
+ const existing = this.map.get(key);
225
+ if (existing) {
226
+ existing.value = value;
227
+ existing.lastAccessed = now;
228
+ existing.expiry = expiry;
229
+ existing.metadata = { ...existing.metadata, createdAt: existing.metadata?.createdAt ?? now };
230
+ if (this.config.reorderOnUpdate) {
231
+ this.list.moveToFront(existing);
232
+ }
233
+ this.emit({ event: "set", key, value, timestamp: now });
234
+ return;
235
+ }
236
+ if (this.map.size >= this._capacity) {
237
+ const evicted = this.config.evictPosition === "back" ? this.list.removeLast() : this.list.removeFirst();
238
+ if (evicted) {
239
+ this.map.delete(evicted.key);
240
+ this._evictions++;
241
+ this.onEvict?.(evicted.key, evicted.value);
242
+ this.emit({ event: "evict", key, value, evictedKey: evicted.key, evictedValue: evicted.value, timestamp: now });
243
+ }
244
+ }
245
+ const node = createNode(key, value);
246
+ node.metadata = { createdAt: now };
247
+ node.lastAccessed = now;
248
+ node.accessCount = 0;
249
+ node.expiry = expiry;
250
+ if (this.config.addPosition === "front") {
251
+ this.list.addToFront(node);
252
+ } else {
253
+ this.list.addToBack(node);
254
+ }
255
+ this.map.set(key, node);
256
+ this.emit({ event: "set", key, value, timestamp: now });
257
+ }
258
+ delete(key) {
259
+ const node = this.map.get(key);
260
+ if (!node) return false;
261
+ this.deleteNode(key, node);
262
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
263
+ return true;
264
+ }
265
+ has(key) {
266
+ const node = this.map.get(key);
267
+ if (!node) return false;
268
+ if (node.expiry && node.expiry <= this.now()) {
269
+ return false;
270
+ }
271
+ return true;
272
+ }
273
+ clear() {
274
+ this.list.clear();
275
+ this.map.clear();
276
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
277
+ }
278
+ get size() {
279
+ return this.map.size;
280
+ }
281
+ *keys() {
282
+ for (const node of this.list) {
283
+ yield node.key;
284
+ }
285
+ }
286
+ *values() {
287
+ for (const node of this.list) {
288
+ yield node.value;
289
+ }
290
+ }
291
+ *entries() {
292
+ for (const node of this.list) {
293
+ yield [node.key, node.value];
294
+ }
295
+ }
296
+ collectEntries() {
297
+ const result = [];
298
+ for (const node of this.list) {
299
+ result.push({
300
+ key: node.key,
301
+ value: node.value,
302
+ createdAt: node.metadata?.createdAt ?? 0,
303
+ lastAccessed: node.lastAccessed ?? 0,
304
+ accessCount: node.accessCount ?? 0
305
+ });
306
+ }
307
+ return result;
308
+ }
309
+ deleteNode(key, node) {
310
+ this.list.remove(node);
311
+ this.map.delete(key);
312
+ }
313
+ };
314
+
315
+ // src/caches/lru.ts
316
+ var LRUCache = class extends DLLCache {
317
+ constructor(options) {
318
+ super(options, {
319
+ reorderOnGet: true,
320
+ reorderOnUpdate: true,
321
+ addPosition: "front",
322
+ evictPosition: "back"
323
+ });
324
+ }
325
+ get strategy() {
326
+ return "LRU";
327
+ }
328
+ };
329
+
330
+ // src/caches/mru.ts
331
+ var MRUCache = class extends DLLCache {
332
+ constructor(options) {
333
+ super(options, {
334
+ reorderOnGet: true,
335
+ reorderOnUpdate: true,
336
+ addPosition: "front",
337
+ evictPosition: "front"
338
+ });
339
+ }
340
+ get strategy() {
341
+ return "MRU";
342
+ }
343
+ };
344
+
345
+ // src/caches/lfu.ts
346
+ var LFUCache = class extends BaseCache {
347
+ store = /* @__PURE__ */ new Map();
348
+ freqBuckets = /* @__PURE__ */ new Map();
349
+ minFrequency = 0;
350
+ constructor(options) {
351
+ super(options);
352
+ }
353
+ getOrCreateBucket(freq) {
354
+ let bucket = this.freqBuckets.get(freq);
355
+ if (!bucket) {
356
+ bucket = new DoublyLinkedList();
357
+ this.freqBuckets.set(freq, bucket);
358
+ }
359
+ return bucket;
360
+ }
361
+ incrementFrequency(meta) {
362
+ const oldFreq = meta.frequency;
363
+ const oldBucket = this.freqBuckets.get(oldFreq);
364
+ oldBucket.remove(meta.node);
365
+ if (oldBucket.size === 0 && this.minFrequency === oldFreq) {
366
+ this.minFrequency = oldFreq + 1;
367
+ }
368
+ meta.frequency = oldFreq + 1;
369
+ const newBucket = this.getOrCreateBucket(meta.frequency);
370
+ newBucket.addToFront(meta.node);
371
+ }
372
+ get(key) {
373
+ const meta = this.store.get(key);
374
+ if (!meta) {
375
+ this._misses++;
376
+ this.emit({ event: "get", key, timestamp: this.now() });
377
+ return void 0;
378
+ }
379
+ this._hits++;
380
+ meta.accessCount++;
381
+ meta.lastAccessed = this.now();
382
+ this.incrementFrequency(meta);
383
+ this.emit({ event: "get", key, value: meta.node.value, timestamp: this.now() });
384
+ return meta.node.value;
385
+ }
386
+ set(key, value, _ttl) {
387
+ const existing = this.store.get(key);
388
+ if (existing) {
389
+ existing.node.value = value;
390
+ existing.lastAccessed = this.now();
391
+ existing.accessCount++;
392
+ this.incrementFrequency(existing);
393
+ this.emit({ event: "set", key, value, timestamp: this.now() });
394
+ return;
395
+ }
396
+ if (this.store.size >= this._capacity) {
397
+ this.evict();
398
+ }
399
+ const node = createNode(key, value);
400
+ const now = this.now();
401
+ const meta = {
402
+ createdAt: now,
403
+ lastAccessed: now,
404
+ accessCount: 1,
405
+ frequency: 1,
406
+ node
407
+ };
408
+ this.store.set(key, meta);
409
+ const bucket = this.getOrCreateBucket(1);
410
+ bucket.addToFront(node);
411
+ this.minFrequency = 1;
412
+ this.emit({ event: "set", key, value, timestamp: this.now() });
413
+ }
414
+ evict() {
415
+ const bucket = this.freqBuckets.get(this.minFrequency);
416
+ if (!bucket || bucket.size === 0) return;
417
+ const evicted = bucket.removeLast();
418
+ if (!evicted) return;
419
+ this.store.delete(evicted.key);
420
+ this._evictions++;
421
+ this.onEvict?.(evicted.key, evicted.value);
422
+ this.emit({
423
+ event: "evict",
424
+ key: evicted.key,
425
+ evictedKey: evicted.key,
426
+ evictedValue: evicted.value,
427
+ timestamp: this.now()
428
+ });
429
+ }
430
+ delete(key) {
431
+ const meta = this.store.get(key);
432
+ if (!meta) return false;
433
+ const bucket = this.freqBuckets.get(meta.frequency);
434
+ if (bucket) {
435
+ bucket.remove(meta.node);
436
+ }
437
+ this.store.delete(key);
438
+ this.emit({ event: "delete", key, value: meta.node.value, timestamp: this.now() });
439
+ return true;
440
+ }
441
+ has(key) {
442
+ return this.store.has(key);
443
+ }
444
+ clear() {
445
+ this.store.clear();
446
+ this.freqBuckets.clear();
447
+ this.minFrequency = 0;
448
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
449
+ }
450
+ get size() {
451
+ return this.store.size;
452
+ }
453
+ *keys() {
454
+ for (const key of this.store.keys()) {
455
+ yield key;
456
+ }
457
+ }
458
+ *values() {
459
+ for (const meta of this.store.values()) {
460
+ yield meta.node.value;
461
+ }
462
+ }
463
+ *entries() {
464
+ for (const [key, meta] of this.store.entries()) {
465
+ yield [key, meta.node.value];
466
+ }
467
+ }
468
+ get strategy() {
469
+ return "LFU";
470
+ }
471
+ collectEntries() {
472
+ const result = [];
473
+ for (const [key, meta] of this.store.entries()) {
474
+ result.push({
475
+ key,
476
+ value: meta.node.value,
477
+ createdAt: meta.createdAt,
478
+ lastAccessed: meta.lastAccessed,
479
+ accessCount: meta.accessCount
480
+ });
481
+ }
482
+ return result;
483
+ }
484
+ };
485
+
486
+ // src/caches/ttl.ts
487
+ var TTLCache = class extends BaseCache {
488
+ store = /* @__PURE__ */ new Map();
489
+ defaultTTL;
490
+ cleanupTimer = null;
491
+ constructor(options) {
492
+ super(options);
493
+ this.defaultTTL = options.ttl ?? 0;
494
+ if (this.defaultTTL > 0) {
495
+ this.cleanupTimer = setInterval(() => this.cleanup(), this.defaultTTL);
496
+ }
497
+ }
498
+ isExpired(entry) {
499
+ return entry.expiry > 0 && this.now() >= entry.expiry;
500
+ }
501
+ cleanup() {
502
+ for (const [key, entry] of this.store.entries()) {
503
+ if (this.isExpired(entry)) {
504
+ this.store.delete(key);
505
+ this.emit({
506
+ event: "expire",
507
+ key,
508
+ value: entry.value,
509
+ timestamp: this.now()
510
+ });
511
+ }
512
+ }
513
+ }
514
+ get(key) {
515
+ const entry = this.store.get(key);
516
+ if (!entry) {
517
+ this._misses++;
518
+ this.emit({ event: "get", key, timestamp: this.now() });
519
+ return void 0;
520
+ }
521
+ if (this.isExpired(entry)) {
522
+ this.store.delete(key);
523
+ this.emit({ event: "expire", key, value: entry.value, timestamp: this.now() });
524
+ this._misses++;
525
+ this.emit({ event: "get", key, timestamp: this.now() });
526
+ return void 0;
527
+ }
528
+ this._hits++;
529
+ entry.accessCount++;
530
+ entry.lastAccessed = this.now();
531
+ this.emit({ event: "get", key, value: entry.value, timestamp: this.now() });
532
+ return entry.value;
533
+ }
534
+ set(key, value, ttl) {
535
+ const existing = this.store.get(key);
536
+ const now = this.now();
537
+ const effectiveTTL = ttl ?? this.defaultTTL;
538
+ const expiry = effectiveTTL > 0 ? now + effectiveTTL : 0;
539
+ if (existing && !this.isExpired(existing)) {
540
+ existing.value = value;
541
+ existing.lastAccessed = now;
542
+ existing.accessCount++;
543
+ existing.expiry = expiry;
544
+ existing.ttl = effectiveTTL;
545
+ this.emit({ event: "set", key, value, timestamp: now });
546
+ return;
547
+ }
548
+ if (existing) {
549
+ this.store.delete(key);
550
+ }
551
+ if (this.store.size >= this._capacity) {
552
+ this.evict();
553
+ }
554
+ this.store.set(key, {
555
+ value,
556
+ createdAt: now,
557
+ lastAccessed: now,
558
+ accessCount: 1,
559
+ expiry,
560
+ ttl: effectiveTTL
561
+ });
562
+ this.emit({ event: "set", key, value, timestamp: now });
563
+ }
564
+ evict() {
565
+ let oldestKey = null;
566
+ let oldestTime = Infinity;
567
+ for (const [key, entry] of this.store.entries()) {
568
+ if (this.isExpired(entry)) {
569
+ this.store.delete(key);
570
+ this._evictions++;
571
+ this.onEvict?.(key, entry.value);
572
+ this.emit({
573
+ event: "evict",
574
+ key,
575
+ evictedKey: key,
576
+ evictedValue: entry.value,
577
+ timestamp: this.now()
578
+ });
579
+ return;
580
+ }
581
+ if (entry.createdAt < oldestTime) {
582
+ oldestTime = entry.createdAt;
583
+ oldestKey = key;
584
+ }
585
+ }
586
+ if (oldestKey !== null) {
587
+ const entry = this.store.get(oldestKey);
588
+ this.store.delete(oldestKey);
589
+ this._evictions++;
590
+ this.onEvict?.(oldestKey, entry.value);
591
+ this.emit({
592
+ event: "evict",
593
+ key: oldestKey,
594
+ evictedKey: oldestKey,
595
+ evictedValue: entry.value,
596
+ timestamp: this.now()
597
+ });
598
+ }
599
+ }
600
+ delete(key) {
601
+ const entry = this.store.get(key);
602
+ if (!entry) return false;
603
+ this.store.delete(key);
604
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
605
+ return true;
606
+ }
607
+ has(key) {
608
+ const entry = this.store.get(key);
609
+ if (!entry) return false;
610
+ return !this.isExpired(entry);
611
+ }
612
+ clear() {
613
+ this.store.clear();
614
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
615
+ }
616
+ get size() {
617
+ let count = 0;
618
+ for (const entry of this.store.values()) {
619
+ if (!this.isExpired(entry)) {
620
+ count++;
621
+ }
622
+ }
623
+ return count;
624
+ }
625
+ *keys() {
626
+ for (const [key, entry] of this.store.entries()) {
627
+ if (!this.isExpired(entry)) {
628
+ yield key;
629
+ }
630
+ }
631
+ }
632
+ *values() {
633
+ for (const [, entry] of this.store.entries()) {
634
+ if (!this.isExpired(entry)) {
635
+ yield entry.value;
636
+ }
637
+ }
638
+ }
639
+ *entries() {
640
+ for (const [key, entry] of this.store.entries()) {
641
+ if (!this.isExpired(entry)) {
642
+ yield [key, entry.value];
643
+ }
644
+ }
645
+ }
646
+ get strategy() {
647
+ return "TTL";
648
+ }
649
+ collectEntries() {
650
+ const result = [];
651
+ for (const [key, entry] of this.store.entries()) {
652
+ if (!this.isExpired(entry)) {
653
+ result.push({
654
+ key,
655
+ value: entry.value,
656
+ createdAt: entry.createdAt,
657
+ lastAccessed: entry.lastAccessed,
658
+ accessCount: entry.accessCount,
659
+ ttl: entry.ttl
660
+ });
661
+ }
662
+ }
663
+ return result;
664
+ }
665
+ destroy() {
666
+ if (this.cleanupTimer !== null) {
667
+ clearInterval(this.cleanupTimer);
668
+ this.cleanupTimer = null;
669
+ }
670
+ this.clear();
671
+ }
672
+ };
673
+
674
+ // src/caches/fifo.ts
675
+ var FIFOCache = class extends DLLCache {
676
+ constructor(options) {
677
+ super(options, {
678
+ reorderOnGet: false,
679
+ reorderOnUpdate: false,
680
+ addPosition: "back",
681
+ evictPosition: "front"
682
+ });
683
+ }
684
+ get strategy() {
685
+ return "FIFO";
686
+ }
687
+ };
688
+
689
+ // src/caches/lifo.ts
690
+ var LIFOCache = class extends DLLCache {
691
+ constructor(options) {
692
+ super(options, {
693
+ reorderOnGet: false,
694
+ reorderOnUpdate: true,
695
+ addPosition: "front",
696
+ evictPosition: "front"
697
+ });
698
+ }
699
+ get strategy() {
700
+ return "LIFO";
701
+ }
702
+ };
703
+
704
+ // src/caches/rr.ts
705
+ var RRCache = class extends BaseCache {
706
+ store = /* @__PURE__ */ new Map();
707
+ keyList = [];
708
+ constructor(options) {
709
+ super(options);
710
+ }
711
+ get(key) {
712
+ const entry = this.store.get(key);
713
+ if (!entry) {
714
+ this._misses++;
715
+ this.emit({ event: "get", key, timestamp: this.now() });
716
+ return void 0;
717
+ }
718
+ this._hits++;
719
+ entry.accessCount++;
720
+ entry.lastAccessed = this.now();
721
+ this.emit({ event: "get", key, value: entry.value, timestamp: this.now() });
722
+ return entry.value;
723
+ }
724
+ set(key, value, _ttl) {
725
+ const existing = this.store.get(key);
726
+ if (existing) {
727
+ existing.value = value;
728
+ existing.lastAccessed = this.now();
729
+ existing.accessCount++;
730
+ this.emit({ event: "set", key, value, timestamp: this.now() });
731
+ return;
732
+ }
733
+ if (this.store.size >= this._capacity) {
734
+ this.evict();
735
+ }
736
+ const now = this.now();
737
+ const keyIndex = this.keyList.length;
738
+ this.keyList.push(key);
739
+ this.store.set(key, {
740
+ value,
741
+ createdAt: now,
742
+ lastAccessed: now,
743
+ accessCount: 1,
744
+ keyIndex
745
+ });
746
+ this.emit({ event: "set", key, value, timestamp: now });
747
+ }
748
+ evict() {
749
+ if (this.keyList.length === 0) return;
750
+ const randomIndex = Math.floor(Math.random() * this.keyList.length);
751
+ const evictedKey = this.keyList[randomIndex];
752
+ const entry = this.store.get(evictedKey);
753
+ this.removeKeyAtIndex(randomIndex);
754
+ this.store.delete(evictedKey);
755
+ this._evictions++;
756
+ this.onEvict?.(evictedKey, entry.value);
757
+ this.emit({
758
+ event: "evict",
759
+ key: evictedKey,
760
+ evictedKey,
761
+ evictedValue: entry.value,
762
+ timestamp: this.now()
763
+ });
764
+ }
765
+ removeKeyAtIndex(index) {
766
+ const lastIndex = this.keyList.length - 1;
767
+ if (index !== lastIndex) {
768
+ const lastKey = this.keyList[lastIndex];
769
+ this.keyList[index] = lastKey;
770
+ const lastEntry = this.store.get(lastKey);
771
+ if (lastEntry) {
772
+ lastEntry.keyIndex = index;
773
+ }
774
+ }
775
+ this.keyList.pop();
776
+ }
777
+ delete(key) {
778
+ const entry = this.store.get(key);
779
+ if (!entry) return false;
780
+ this.removeKeyAtIndex(entry.keyIndex);
781
+ this.store.delete(key);
782
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
783
+ return true;
784
+ }
785
+ has(key) {
786
+ return this.store.has(key);
787
+ }
788
+ clear() {
789
+ this.store.clear();
790
+ this.keyList.length = 0;
791
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
792
+ }
793
+ get size() {
794
+ return this.store.size;
795
+ }
796
+ *keys() {
797
+ for (const key of this.store.keys()) {
798
+ yield key;
799
+ }
800
+ }
801
+ *values() {
802
+ for (const entry of this.store.values()) {
803
+ yield entry.value;
804
+ }
805
+ }
806
+ *entries() {
807
+ for (const [key, entry] of this.store.entries()) {
808
+ yield [key, entry.value];
809
+ }
810
+ }
811
+ get strategy() {
812
+ return "RR";
813
+ }
814
+ collectEntries() {
815
+ const result = [];
816
+ for (const [key, entry] of this.store.entries()) {
817
+ result.push({
818
+ key,
819
+ value: entry.value,
820
+ createdAt: entry.createdAt,
821
+ lastAccessed: entry.lastAccessed,
822
+ accessCount: entry.accessCount
823
+ });
824
+ }
825
+ return result;
826
+ }
827
+ };
828
+
829
+ // src/caches/arc.ts
830
+ var ARCCache = class extends BaseCache {
831
+ /** Adaptation parameter: target size of T1. */
832
+ p = 0;
833
+ /** T1: recent cache entries (seen once recently). */
834
+ t1 = new DoublyLinkedList();
835
+ /** T2: frequent cache entries (seen at least twice recently). */
836
+ t2 = new DoublyLinkedList();
837
+ /** B1: ghost list for recently evicted from T1 (keys only). */
838
+ b1 = new DoublyLinkedList();
839
+ /** B2: ghost list for recently evicted from T2 (keys only). */
840
+ b2 = new DoublyLinkedList();
841
+ t1Map = /* @__PURE__ */ new Map();
842
+ t2Map = /* @__PURE__ */ new Map();
843
+ b1Map = /* @__PURE__ */ new Map();
844
+ b2Map = /* @__PURE__ */ new Map();
845
+ metaMap = /* @__PURE__ */ new Map();
846
+ constructor(options) {
847
+ super(options);
848
+ }
849
+ get strategy() {
850
+ return "ARC";
851
+ }
852
+ get size() {
853
+ return this.t1.size + this.t2.size;
854
+ }
855
+ get(key) {
856
+ const now = this.now();
857
+ if (this.t1Map.has(key)) {
858
+ const node = this.t1Map.get(key);
859
+ this.t1.remove(node);
860
+ this.t1Map.delete(key);
861
+ this.t2.addToFront(node);
862
+ this.t2Map.set(key, node);
863
+ const meta = this.metaMap.get(key);
864
+ meta.lastAccessed = now;
865
+ meta.accessCount++;
866
+ this._hits++;
867
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
868
+ return node.value;
869
+ }
870
+ if (this.t2Map.has(key)) {
871
+ const node = this.t2Map.get(key);
872
+ this.t2.moveToFront(node);
873
+ const meta = this.metaMap.get(key);
874
+ meta.lastAccessed = now;
875
+ meta.accessCount++;
876
+ this._hits++;
877
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
878
+ return node.value;
879
+ }
880
+ this._misses++;
881
+ this.emit({ event: "get", key, value: void 0, timestamp: now });
882
+ return void 0;
883
+ }
884
+ set(key, value, _ttl) {
885
+ const now = this.now();
886
+ const c = this._capacity;
887
+ if (this.t1Map.has(key)) {
888
+ const node2 = this.t1Map.get(key);
889
+ node2.value = value;
890
+ this.t1.remove(node2);
891
+ this.t1Map.delete(key);
892
+ this.t2.addToFront(node2);
893
+ this.t2Map.set(key, node2);
894
+ const meta = this.metaMap.get(key);
895
+ meta.lastAccessed = now;
896
+ meta.accessCount++;
897
+ this.emit({ event: "set", key, value, timestamp: now });
898
+ return;
899
+ }
900
+ if (this.t2Map.has(key)) {
901
+ const node2 = this.t2Map.get(key);
902
+ node2.value = value;
903
+ this.t2.moveToFront(node2);
904
+ const meta = this.metaMap.get(key);
905
+ meta.lastAccessed = now;
906
+ meta.accessCount++;
907
+ this.emit({ event: "set", key, value, timestamp: now });
908
+ return;
909
+ }
910
+ if (this.b1Map.has(key)) {
911
+ const delta = this.b2.size >= this.b1.size ? 1 : Math.ceil(this.b2.size / (this.b1.size || 1));
912
+ this.p = Math.min(this.p + delta, c);
913
+ this.replace(key);
914
+ const ghostNode = this.b1Map.get(key);
915
+ this.b1.remove(ghostNode);
916
+ this.b1Map.delete(key);
917
+ const node2 = createNode(key, value);
918
+ this.t2.addToFront(node2);
919
+ this.t2Map.set(key, node2);
920
+ this.metaMap.set(key, { createdAt: now, lastAccessed: now, accessCount: 1 });
921
+ this.emit({ event: "set", key, value, timestamp: now });
922
+ return;
923
+ }
924
+ if (this.b2Map.has(key)) {
925
+ const delta = this.b1.size >= this.b2.size ? 1 : Math.ceil(this.b1.size / (this.b2.size || 1));
926
+ this.p = Math.max(this.p - delta, 0);
927
+ this.replace(key);
928
+ const ghostNode = this.b2Map.get(key);
929
+ this.b2.remove(ghostNode);
930
+ this.b2Map.delete(key);
931
+ const node2 = createNode(key, value);
932
+ this.t2.addToFront(node2);
933
+ this.t2Map.set(key, node2);
934
+ this.metaMap.set(key, { createdAt: now, lastAccessed: now, accessCount: 1 });
935
+ this.emit({ event: "set", key, value, timestamp: now });
936
+ return;
937
+ }
938
+ const l1 = this.t1.size + this.b1.size;
939
+ const l2 = this.t2.size + this.b2.size;
940
+ if (l1 === c) {
941
+ if (this.t1.size < c) {
942
+ const ghost = this.b1.removeLast();
943
+ if (ghost) {
944
+ this.b1Map.delete(ghost.key);
945
+ }
946
+ this.replace(key);
947
+ } else {
948
+ const evicted = this.t1.removeLast();
949
+ if (evicted) {
950
+ this.t1Map.delete(evicted.key);
951
+ this.metaMap.delete(evicted.key);
952
+ this._evictions++;
953
+ this.onEvict?.(evicted.key, evicted.value);
954
+ this.emit({
955
+ event: "evict",
956
+ key,
957
+ evictedKey: evicted.key,
958
+ evictedValue: evicted.value,
959
+ timestamp: now
960
+ });
961
+ }
962
+ }
963
+ } else if (l1 < c && l1 + l2 >= c) {
964
+ if (l1 + l2 >= 2 * c) {
965
+ const ghost = this.b2.removeLast();
966
+ if (ghost) {
967
+ this.b2Map.delete(ghost.key);
968
+ }
969
+ }
970
+ this.replace(key);
971
+ }
972
+ const node = createNode(key, value);
973
+ this.t1.addToFront(node);
974
+ this.t1Map.set(key, node);
975
+ this.metaMap.set(key, { createdAt: now, lastAccessed: now, accessCount: 1 });
976
+ this.emit({ event: "set", key, value, timestamp: now });
977
+ }
978
+ delete(key) {
979
+ const now = this.now();
980
+ if (this.t1Map.has(key)) {
981
+ const node = this.t1Map.get(key);
982
+ this.t1.remove(node);
983
+ this.t1Map.delete(key);
984
+ this.metaMap.delete(key);
985
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
986
+ return true;
987
+ }
988
+ if (this.t2Map.has(key)) {
989
+ const node = this.t2Map.get(key);
990
+ this.t2.remove(node);
991
+ this.t2Map.delete(key);
992
+ this.metaMap.delete(key);
993
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
994
+ return true;
995
+ }
996
+ return false;
997
+ }
998
+ has(key) {
999
+ return this.t1Map.has(key) || this.t2Map.has(key);
1000
+ }
1001
+ clear() {
1002
+ this.t1.clear();
1003
+ this.t2.clear();
1004
+ this.b1.clear();
1005
+ this.b2.clear();
1006
+ this.t1Map.clear();
1007
+ this.t2Map.clear();
1008
+ this.b1Map.clear();
1009
+ this.b2Map.clear();
1010
+ this.metaMap.clear();
1011
+ this.p = 0;
1012
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1013
+ }
1014
+ *keys() {
1015
+ for (const node of this.t1) {
1016
+ yield node.key;
1017
+ }
1018
+ for (const node of this.t2) {
1019
+ yield node.key;
1020
+ }
1021
+ }
1022
+ *values() {
1023
+ for (const node of this.t1) {
1024
+ yield node.value;
1025
+ }
1026
+ for (const node of this.t2) {
1027
+ yield node.value;
1028
+ }
1029
+ }
1030
+ *entries() {
1031
+ for (const node of this.t1) {
1032
+ yield [node.key, node.value];
1033
+ }
1034
+ for (const node of this.t2) {
1035
+ yield [node.key, node.value];
1036
+ }
1037
+ }
1038
+ collectEntries() {
1039
+ const result = [];
1040
+ for (const node of this.t1) {
1041
+ const meta = this.metaMap.get(node.key);
1042
+ result.push({
1043
+ key: node.key,
1044
+ value: node.value,
1045
+ createdAt: meta?.createdAt ?? 0,
1046
+ lastAccessed: meta?.lastAccessed ?? 0,
1047
+ accessCount: meta?.accessCount ?? 0
1048
+ });
1049
+ }
1050
+ for (const node of this.t2) {
1051
+ const meta = this.metaMap.get(node.key);
1052
+ result.push({
1053
+ key: node.key,
1054
+ value: node.value,
1055
+ createdAt: meta?.createdAt ?? 0,
1056
+ lastAccessed: meta?.lastAccessed ?? 0,
1057
+ accessCount: meta?.accessCount ?? 0
1058
+ });
1059
+ }
1060
+ return result;
1061
+ }
1062
+ /**
1063
+ * Replace: evict an entry from either T1 or T2 to make room.
1064
+ * The evicted entry's key is moved to the corresponding ghost list.
1065
+ */
1066
+ replace(incomingKey) {
1067
+ const now = this.now();
1068
+ if (this.t1.size > 0 && (this.t1.size > this.p || this.t1.size === this.p && this.b2Map.has(incomingKey))) {
1069
+ const evicted = this.t1.removeLast();
1070
+ this.t1Map.delete(evicted.key);
1071
+ this.metaMap.delete(evicted.key);
1072
+ const ghost = createNode(evicted.key, void 0);
1073
+ this.b1.addToFront(ghost);
1074
+ this.b1Map.set(evicted.key, ghost);
1075
+ this.trimGhostList(this.b1, this.b1Map);
1076
+ this._evictions++;
1077
+ this.onEvict?.(evicted.key, evicted.value);
1078
+ this.emit({
1079
+ event: "evict",
1080
+ key: incomingKey,
1081
+ evictedKey: evicted.key,
1082
+ evictedValue: evicted.value,
1083
+ timestamp: now
1084
+ });
1085
+ } else if (this.t2.size > 0) {
1086
+ const evicted = this.t2.removeLast();
1087
+ this.t2Map.delete(evicted.key);
1088
+ this.metaMap.delete(evicted.key);
1089
+ const ghost = createNode(evicted.key, void 0);
1090
+ this.b2.addToFront(ghost);
1091
+ this.b2Map.set(evicted.key, ghost);
1092
+ this.trimGhostList(this.b2, this.b2Map);
1093
+ this._evictions++;
1094
+ this.onEvict?.(evicted.key, evicted.value);
1095
+ this.emit({
1096
+ event: "evict",
1097
+ key: incomingKey,
1098
+ evictedKey: evicted.key,
1099
+ evictedValue: evicted.value,
1100
+ timestamp: now
1101
+ });
1102
+ }
1103
+ }
1104
+ /** Cap a ghost list at capacity to prevent unbounded memory growth. */
1105
+ trimGhostList(list, map) {
1106
+ while (list.size > this._capacity) {
1107
+ const removed = list.removeLast();
1108
+ if (removed) {
1109
+ map.delete(removed.key);
1110
+ }
1111
+ }
1112
+ }
1113
+ };
1114
+
1115
+ // src/caches/two-tier.ts
1116
+ var TwoTierCache = class extends BaseCache {
1117
+ hotList = new DoublyLinkedList();
1118
+ coldList = new DoublyLinkedList();
1119
+ hotMap = /* @__PURE__ */ new Map();
1120
+ coldMap = /* @__PURE__ */ new Map();
1121
+ metaMap = /* @__PURE__ */ new Map();
1122
+ hotCapacity;
1123
+ coldCapacity;
1124
+ promoteThreshold;
1125
+ constructor(options) {
1126
+ super({ capacity: options.hotCapacity + options.coldCapacity, onEvict: options.onEvict });
1127
+ this.hotCapacity = options.hotCapacity;
1128
+ this.coldCapacity = options.coldCapacity;
1129
+ this.promoteThreshold = options.promoteThreshold ?? 2;
1130
+ }
1131
+ get strategy() {
1132
+ return "TWO-TIER";
1133
+ }
1134
+ get size() {
1135
+ return this.hotMap.size + this.coldMap.size;
1136
+ }
1137
+ get(key) {
1138
+ const now = this.now();
1139
+ if (this.hotMap.has(key)) {
1140
+ const node = this.hotMap.get(key);
1141
+ this.hotList.moveToFront(node);
1142
+ const meta = this.metaMap.get(key);
1143
+ meta.lastAccessed = now;
1144
+ meta.accessCount++;
1145
+ this._hits++;
1146
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1147
+ return node.value;
1148
+ }
1149
+ if (this.coldMap.has(key)) {
1150
+ const node = this.coldMap.get(key);
1151
+ const meta = this.metaMap.get(key);
1152
+ meta.lastAccessed = now;
1153
+ meta.accessCount++;
1154
+ if (meta.accessCount >= this.promoteThreshold) {
1155
+ this.coldList.remove(node);
1156
+ this.coldMap.delete(key);
1157
+ this.ensureHotCapacity(now, key);
1158
+ this.hotList.addToFront(node);
1159
+ this.hotMap.set(key, node);
1160
+ meta.tier = "hot";
1161
+ } else {
1162
+ this.coldList.moveToFront(node);
1163
+ }
1164
+ this._hits++;
1165
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1166
+ return node.value;
1167
+ }
1168
+ this._misses++;
1169
+ this.emit({ event: "get", key, value: void 0, timestamp: now });
1170
+ return void 0;
1171
+ }
1172
+ set(key, value, _ttl) {
1173
+ const now = this.now();
1174
+ if (this.hotMap.has(key)) {
1175
+ const node2 = this.hotMap.get(key);
1176
+ node2.value = value;
1177
+ this.hotList.moveToFront(node2);
1178
+ const meta = this.metaMap.get(key);
1179
+ meta.lastAccessed = now;
1180
+ meta.accessCount++;
1181
+ this.emit({ event: "set", key, value, timestamp: now });
1182
+ return;
1183
+ }
1184
+ if (this.coldMap.has(key)) {
1185
+ const node2 = this.coldMap.get(key);
1186
+ node2.value = value;
1187
+ this.coldList.moveToFront(node2);
1188
+ const meta = this.metaMap.get(key);
1189
+ meta.lastAccessed = now;
1190
+ meta.accessCount++;
1191
+ this.emit({ event: "set", key, value, timestamp: now });
1192
+ return;
1193
+ }
1194
+ this.ensureColdCapacity(now, key);
1195
+ const node = createNode(key, value);
1196
+ this.coldList.addToFront(node);
1197
+ this.coldMap.set(key, node);
1198
+ this.metaMap.set(key, {
1199
+ createdAt: now,
1200
+ lastAccessed: now,
1201
+ accessCount: 1,
1202
+ tier: "cold"
1203
+ });
1204
+ this.emit({ event: "set", key, value, timestamp: now });
1205
+ }
1206
+ delete(key) {
1207
+ const now = this.now();
1208
+ if (this.hotMap.has(key)) {
1209
+ const node = this.hotMap.get(key);
1210
+ this.hotList.remove(node);
1211
+ this.hotMap.delete(key);
1212
+ this.metaMap.delete(key);
1213
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1214
+ return true;
1215
+ }
1216
+ if (this.coldMap.has(key)) {
1217
+ const node = this.coldMap.get(key);
1218
+ this.coldList.remove(node);
1219
+ this.coldMap.delete(key);
1220
+ this.metaMap.delete(key);
1221
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1222
+ return true;
1223
+ }
1224
+ return false;
1225
+ }
1226
+ has(key) {
1227
+ return this.hotMap.has(key) || this.coldMap.has(key);
1228
+ }
1229
+ clear() {
1230
+ this.hotList.clear();
1231
+ this.coldList.clear();
1232
+ this.hotMap.clear();
1233
+ this.coldMap.clear();
1234
+ this.metaMap.clear();
1235
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1236
+ }
1237
+ *keys() {
1238
+ for (const node of this.hotList) {
1239
+ yield node.key;
1240
+ }
1241
+ for (const node of this.coldList) {
1242
+ yield node.key;
1243
+ }
1244
+ }
1245
+ *values() {
1246
+ for (const node of this.hotList) {
1247
+ yield node.value;
1248
+ }
1249
+ for (const node of this.coldList) {
1250
+ yield node.value;
1251
+ }
1252
+ }
1253
+ *entries() {
1254
+ for (const node of this.hotList) {
1255
+ yield [node.key, node.value];
1256
+ }
1257
+ for (const node of this.coldList) {
1258
+ yield [node.key, node.value];
1259
+ }
1260
+ }
1261
+ collectEntries() {
1262
+ const result = [];
1263
+ for (const node of this.hotList) {
1264
+ const meta = this.metaMap.get(node.key);
1265
+ result.push({
1266
+ key: node.key,
1267
+ value: node.value,
1268
+ createdAt: meta?.createdAt ?? 0,
1269
+ lastAccessed: meta?.lastAccessed ?? 0,
1270
+ accessCount: meta?.accessCount ?? 0,
1271
+ tier: "hot"
1272
+ });
1273
+ }
1274
+ for (const node of this.coldList) {
1275
+ const meta = this.metaMap.get(node.key);
1276
+ result.push({
1277
+ key: node.key,
1278
+ value: node.value,
1279
+ createdAt: meta?.createdAt ?? 0,
1280
+ lastAccessed: meta?.lastAccessed ?? 0,
1281
+ accessCount: meta?.accessCount ?? 0,
1282
+ tier: "cold"
1283
+ });
1284
+ }
1285
+ return result;
1286
+ }
1287
+ /** Evict from hot tier if full, demoting LRU to cold tier. */
1288
+ ensureHotCapacity(now, triggerKey) {
1289
+ if (this.hotList.size >= this.hotCapacity) {
1290
+ const evicted = this.hotList.removeLast();
1291
+ if (evicted) {
1292
+ this.hotMap.delete(evicted.key);
1293
+ this.ensureColdCapacity(now, triggerKey);
1294
+ this.coldList.addToBack(evicted);
1295
+ this.coldMap.set(evicted.key, evicted);
1296
+ const meta = this.metaMap.get(evicted.key);
1297
+ if (meta) meta.tier = "cold";
1298
+ }
1299
+ }
1300
+ }
1301
+ /** Evict LRU from cold tier if full (permanent eviction). */
1302
+ ensureColdCapacity(now, triggerKey) {
1303
+ if (this.coldList.size >= this.coldCapacity) {
1304
+ const evicted = this.coldList.removeLast();
1305
+ if (evicted) {
1306
+ this.coldMap.delete(evicted.key);
1307
+ this.metaMap.delete(evicted.key);
1308
+ this._evictions++;
1309
+ this.onEvict?.(evicted.key, evicted.value);
1310
+ this.emit({
1311
+ event: "evict",
1312
+ key: triggerKey ?? evicted.key,
1313
+ evictedKey: evicted.key,
1314
+ evictedValue: evicted.value,
1315
+ timestamp: now
1316
+ });
1317
+ }
1318
+ }
1319
+ }
1320
+ };
1321
+
1322
+ // src/caches/slru.ts
1323
+ var SLRUCache = class extends BaseCache {
1324
+ probationList = new DoublyLinkedList();
1325
+ protectedList = new DoublyLinkedList();
1326
+ probationMap = /* @__PURE__ */ new Map();
1327
+ protectedMap = /* @__PURE__ */ new Map();
1328
+ metaMap = /* @__PURE__ */ new Map();
1329
+ protectedCapacity;
1330
+ probationCapacity;
1331
+ constructor(options) {
1332
+ super(options);
1333
+ const ratio = options.protectedRatio ?? 0.8;
1334
+ this.protectedCapacity = Math.max(1, Math.floor(options.capacity * ratio));
1335
+ this.probationCapacity = Math.max(1, options.capacity - this.protectedCapacity);
1336
+ }
1337
+ get strategy() {
1338
+ return "SLRU";
1339
+ }
1340
+ get size() {
1341
+ return this.probationMap.size + this.protectedMap.size;
1342
+ }
1343
+ get(key) {
1344
+ const now = this.now();
1345
+ if (this.protectedMap.has(key)) {
1346
+ const node = this.protectedMap.get(key);
1347
+ this.protectedList.moveToFront(node);
1348
+ const meta = this.metaMap.get(key);
1349
+ meta.lastAccessed = now;
1350
+ meta.accessCount++;
1351
+ this._hits++;
1352
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1353
+ return node.value;
1354
+ }
1355
+ if (this.probationMap.has(key)) {
1356
+ const node = this.probationMap.get(key);
1357
+ const meta = this.metaMap.get(key);
1358
+ meta.lastAccessed = now;
1359
+ meta.accessCount++;
1360
+ this.probationList.remove(node);
1361
+ this.probationMap.delete(key);
1362
+ this.ensureProtectedCapacity(now, key);
1363
+ this.protectedList.addToFront(node);
1364
+ this.protectedMap.set(key, node);
1365
+ meta.segment = "protected";
1366
+ this._hits++;
1367
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1368
+ return node.value;
1369
+ }
1370
+ this._misses++;
1371
+ this.emit({ event: "get", key, value: void 0, timestamp: now });
1372
+ return void 0;
1373
+ }
1374
+ set(key, value, _ttl) {
1375
+ const now = this.now();
1376
+ if (this.protectedMap.has(key)) {
1377
+ const node2 = this.protectedMap.get(key);
1378
+ node2.value = value;
1379
+ this.protectedList.moveToFront(node2);
1380
+ const meta = this.metaMap.get(key);
1381
+ meta.lastAccessed = now;
1382
+ meta.accessCount++;
1383
+ this.emit({ event: "set", key, value, timestamp: now });
1384
+ return;
1385
+ }
1386
+ if (this.probationMap.has(key)) {
1387
+ const node2 = this.probationMap.get(key);
1388
+ node2.value = value;
1389
+ this.probationList.moveToFront(node2);
1390
+ const meta = this.metaMap.get(key);
1391
+ meta.lastAccessed = now;
1392
+ meta.accessCount++;
1393
+ this.emit({ event: "set", key, value, timestamp: now });
1394
+ return;
1395
+ }
1396
+ this.ensureProbationCapacity(now, key);
1397
+ const node = createNode(key, value);
1398
+ this.probationList.addToFront(node);
1399
+ this.probationMap.set(key, node);
1400
+ this.metaMap.set(key, {
1401
+ createdAt: now,
1402
+ lastAccessed: now,
1403
+ accessCount: 1,
1404
+ segment: "probation"
1405
+ });
1406
+ this.emit({ event: "set", key, value, timestamp: now });
1407
+ }
1408
+ delete(key) {
1409
+ const now = this.now();
1410
+ if (this.protectedMap.has(key)) {
1411
+ const node = this.protectedMap.get(key);
1412
+ this.protectedList.remove(node);
1413
+ this.protectedMap.delete(key);
1414
+ this.metaMap.delete(key);
1415
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1416
+ return true;
1417
+ }
1418
+ if (this.probationMap.has(key)) {
1419
+ const node = this.probationMap.get(key);
1420
+ this.probationList.remove(node);
1421
+ this.probationMap.delete(key);
1422
+ this.metaMap.delete(key);
1423
+ this.emit({ event: "delete", key, value: node.value, timestamp: now });
1424
+ return true;
1425
+ }
1426
+ return false;
1427
+ }
1428
+ has(key) {
1429
+ return this.protectedMap.has(key) || this.probationMap.has(key);
1430
+ }
1431
+ clear() {
1432
+ this.probationList.clear();
1433
+ this.protectedList.clear();
1434
+ this.probationMap.clear();
1435
+ this.protectedMap.clear();
1436
+ this.metaMap.clear();
1437
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1438
+ }
1439
+ *keys() {
1440
+ for (const node of this.protectedList) {
1441
+ yield node.key;
1442
+ }
1443
+ for (const node of this.probationList) {
1444
+ yield node.key;
1445
+ }
1446
+ }
1447
+ *values() {
1448
+ for (const node of this.protectedList) {
1449
+ yield node.value;
1450
+ }
1451
+ for (const node of this.probationList) {
1452
+ yield node.value;
1453
+ }
1454
+ }
1455
+ *entries() {
1456
+ for (const node of this.protectedList) {
1457
+ yield [node.key, node.value];
1458
+ }
1459
+ for (const node of this.probationList) {
1460
+ yield [node.key, node.value];
1461
+ }
1462
+ }
1463
+ collectEntries() {
1464
+ const result = [];
1465
+ for (const node of this.protectedList) {
1466
+ const meta = this.metaMap.get(node.key);
1467
+ result.push({
1468
+ key: node.key,
1469
+ value: node.value,
1470
+ createdAt: meta?.createdAt ?? 0,
1471
+ lastAccessed: meta?.lastAccessed ?? 0,
1472
+ accessCount: meta?.accessCount ?? 0,
1473
+ metadata: { segment: "protected" }
1474
+ });
1475
+ }
1476
+ for (const node of this.probationList) {
1477
+ const meta = this.metaMap.get(node.key);
1478
+ result.push({
1479
+ key: node.key,
1480
+ value: node.value,
1481
+ createdAt: meta?.createdAt ?? 0,
1482
+ lastAccessed: meta?.lastAccessed ?? 0,
1483
+ accessCount: meta?.accessCount ?? 0,
1484
+ metadata: { segment: "probation" }
1485
+ });
1486
+ }
1487
+ return result;
1488
+ }
1489
+ /** If protected is full, demote LRU from protected to probation. */
1490
+ ensureProtectedCapacity(now, triggerKey) {
1491
+ if (this.protectedList.size >= this.protectedCapacity) {
1492
+ const demoted = this.protectedList.removeLast();
1493
+ if (demoted) {
1494
+ this.protectedMap.delete(demoted.key);
1495
+ this.ensureProbationCapacity(now, triggerKey);
1496
+ this.probationList.addToBack(demoted);
1497
+ this.probationMap.set(demoted.key, demoted);
1498
+ const meta = this.metaMap.get(demoted.key);
1499
+ if (meta) meta.segment = "probation";
1500
+ }
1501
+ }
1502
+ }
1503
+ /** Evict LRU from probation if full. */
1504
+ ensureProbationCapacity(now, triggerKey) {
1505
+ if (this.probationList.size >= this.probationCapacity) {
1506
+ const evicted = this.probationList.removeLast();
1507
+ if (evicted) {
1508
+ this.probationMap.delete(evicted.key);
1509
+ this.metaMap.delete(evicted.key);
1510
+ this._evictions++;
1511
+ this.onEvict?.(evicted.key, evicted.value);
1512
+ this.emit({
1513
+ event: "evict",
1514
+ key: triggerKey ?? evicted.key,
1515
+ evictedKey: evicted.key,
1516
+ evictedValue: evicted.value,
1517
+ timestamp: now
1518
+ });
1519
+ }
1520
+ }
1521
+ }
1522
+ };
1523
+
1524
+ // src/caches/clock.ts
1525
+ var ClockCache = class extends BaseCache {
1526
+ buffer;
1527
+ map = /* @__PURE__ */ new Map();
1528
+ // key -> index in buffer
1529
+ hand = 0;
1530
+ constructor(options) {
1531
+ super(options);
1532
+ this.buffer = Array.from({ length: this._capacity }).fill(null);
1533
+ }
1534
+ get(key) {
1535
+ const idx = this.map.get(key);
1536
+ if (idx === void 0) {
1537
+ this._misses++;
1538
+ this.emit({ event: "get", key, timestamp: this.now() });
1539
+ return void 0;
1540
+ }
1541
+ const entry = this.buffer[idx];
1542
+ entry.refBit = true;
1543
+ entry.lastAccessed = this.now();
1544
+ entry.accessCount++;
1545
+ this._hits++;
1546
+ this.emit({ event: "get", key, value: entry.value, timestamp: this.now() });
1547
+ return entry.value;
1548
+ }
1549
+ set(key, value, _ttl) {
1550
+ const now = this.now();
1551
+ const existingIdx = this.map.get(key);
1552
+ if (existingIdx !== void 0) {
1553
+ const entry = this.buffer[existingIdx];
1554
+ entry.value = value;
1555
+ entry.refBit = true;
1556
+ entry.lastAccessed = now;
1557
+ this.emit({ event: "set", key, value, timestamp: now });
1558
+ return;
1559
+ }
1560
+ if (this.map.size >= this._capacity) {
1561
+ this.evict(key, value, now);
1562
+ }
1563
+ let idx = this.findEmptySlot();
1564
+ if (idx === -1) {
1565
+ idx = this.hand;
1566
+ }
1567
+ this.buffer[idx] = {
1568
+ key,
1569
+ value,
1570
+ refBit: false,
1571
+ createdAt: now,
1572
+ lastAccessed: now,
1573
+ accessCount: 0
1574
+ };
1575
+ this.map.set(key, idx);
1576
+ this.emit({ event: "set", key, value, timestamp: now });
1577
+ }
1578
+ findEmptySlot() {
1579
+ for (let i = 0; i < this._capacity; i++) {
1580
+ if (this.buffer[i] === null) return i;
1581
+ }
1582
+ return -1;
1583
+ }
1584
+ evict(newKey, newValue, now) {
1585
+ while (true) {
1586
+ const entry = this.buffer[this.hand];
1587
+ if (entry) {
1588
+ if (entry.refBit) {
1589
+ entry.refBit = false;
1590
+ this.hand = (this.hand + 1) % this._capacity;
1591
+ } else {
1592
+ this.map.delete(entry.key);
1593
+ this._evictions++;
1594
+ this.onEvict?.(entry.key, entry.value);
1595
+ this.emit({
1596
+ event: "evict",
1597
+ key: newKey,
1598
+ value: newValue,
1599
+ evictedKey: entry.key,
1600
+ evictedValue: entry.value,
1601
+ timestamp: now
1602
+ });
1603
+ this.buffer[this.hand] = null;
1604
+ this.hand = (this.hand + 1) % this._capacity;
1605
+ return;
1606
+ }
1607
+ } else {
1608
+ this.hand = (this.hand + 1) % this._capacity;
1609
+ return;
1610
+ }
1611
+ }
1612
+ }
1613
+ delete(key) {
1614
+ const idx = this.map.get(key);
1615
+ if (idx === void 0) return false;
1616
+ const entry = this.buffer[idx];
1617
+ this.buffer[idx] = null;
1618
+ this.map.delete(key);
1619
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
1620
+ return true;
1621
+ }
1622
+ has(key) {
1623
+ return this.map.has(key);
1624
+ }
1625
+ clear() {
1626
+ this.buffer.fill(null);
1627
+ this.map.clear();
1628
+ this.hand = 0;
1629
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1630
+ }
1631
+ get size() {
1632
+ return this.map.size;
1633
+ }
1634
+ *keys() {
1635
+ for (const entry of this.buffer) {
1636
+ if (entry) yield entry.key;
1637
+ }
1638
+ }
1639
+ *values() {
1640
+ for (const entry of this.buffer) {
1641
+ if (entry) yield entry.value;
1642
+ }
1643
+ }
1644
+ *entries() {
1645
+ for (const entry of this.buffer) {
1646
+ if (entry) yield [entry.key, entry.value];
1647
+ }
1648
+ }
1649
+ get strategy() {
1650
+ return "CLOCK";
1651
+ }
1652
+ collectEntries() {
1653
+ const result = [];
1654
+ for (const entry of this.buffer) {
1655
+ if (entry) {
1656
+ result.push({
1657
+ key: entry.key,
1658
+ value: entry.value,
1659
+ createdAt: entry.createdAt,
1660
+ lastAccessed: entry.lastAccessed,
1661
+ accessCount: entry.accessCount
1662
+ });
1663
+ }
1664
+ }
1665
+ return result;
1666
+ }
1667
+ };
1668
+
1669
+ // src/structures/count-min-sketch.ts
1670
+ var CountMinSketch = class {
1671
+ table;
1672
+ width;
1673
+ depth;
1674
+ seeds;
1675
+ _totalCount = 0;
1676
+ maxCount;
1677
+ constructor(width = 1024, depth = 4) {
1678
+ this.width = width;
1679
+ this.depth = depth;
1680
+ this.maxCount = width * 10;
1681
+ this.table = Array.from({ length: depth }, () => new Uint32Array(width));
1682
+ this.seeds = Array.from({ length: depth }, (_, i) => i * 2654435769 + 1779033703);
1683
+ }
1684
+ hash(key, seed) {
1685
+ let h = seed;
1686
+ for (let i = 0; i < key.length; i++) {
1687
+ h = Math.imul(h ^ key.charCodeAt(i), 1540483477);
1688
+ h ^= h >>> 13;
1689
+ h = Math.imul(h, 1540483477);
1690
+ h ^= h >>> 15;
1691
+ }
1692
+ return (h >>> 0) % this.width;
1693
+ }
1694
+ increment(key) {
1695
+ for (let i = 0; i < this.depth; i++) {
1696
+ const idx = this.hash(key, this.seeds[i]);
1697
+ this.table[i][idx]++;
1698
+ }
1699
+ this._totalCount++;
1700
+ if (this._totalCount >= this.maxCount) {
1701
+ this.halve();
1702
+ }
1703
+ }
1704
+ estimate(key) {
1705
+ let min = Infinity;
1706
+ for (let i = 0; i < this.depth; i++) {
1707
+ const idx = this.hash(key, this.seeds[i]);
1708
+ min = Math.min(min, this.table[i][idx]);
1709
+ }
1710
+ return min;
1711
+ }
1712
+ halve() {
1713
+ for (let i = 0; i < this.depth; i++) {
1714
+ for (let j = 0; j < this.width; j++) {
1715
+ this.table[i][j] = this.table[i][j] >>> 1;
1716
+ }
1717
+ }
1718
+ this._totalCount = Math.floor(this._totalCount / 2);
1719
+ }
1720
+ reset() {
1721
+ for (let i = 0; i < this.depth; i++) {
1722
+ this.table[i].fill(0);
1723
+ }
1724
+ this._totalCount = 0;
1725
+ }
1726
+ get totalCount() {
1727
+ return this._totalCount;
1728
+ }
1729
+ };
1730
+
1731
+ // src/caches/w-tiny-lfu.ts
1732
+ var WTinyLFUCache = class extends BaseCache {
1733
+ sketch;
1734
+ // Window LRU
1735
+ windowList = new DoublyLinkedList();
1736
+ windowMap = /* @__PURE__ */ new Map();
1737
+ windowCapacity;
1738
+ // Main cache: probation (cold) + protected (hot) segments
1739
+ probationList = new DoublyLinkedList();
1740
+ probationMap = /* @__PURE__ */ new Map();
1741
+ protectedList = new DoublyLinkedList();
1742
+ protectedMap = /* @__PURE__ */ new Map();
1743
+ protectedCapacity;
1744
+ mainCapacity;
1745
+ constructor(options) {
1746
+ super(options);
1747
+ const windowRatio = options.windowRatio ?? 0.01;
1748
+ this.windowCapacity = Math.max(1, Math.floor(this._capacity * windowRatio));
1749
+ this.mainCapacity = this._capacity - this.windowCapacity;
1750
+ this.protectedCapacity = Math.max(1, Math.floor(this.mainCapacity * 0.8));
1751
+ this.sketch = new CountMinSketch(Math.max(256, this._capacity * 10), 4);
1752
+ }
1753
+ get(key) {
1754
+ const now = this.now();
1755
+ let node = this.windowMap.get(key);
1756
+ if (node) {
1757
+ node.lastAccessed = now;
1758
+ node.accessCount = (node.accessCount ?? 0) + 1;
1759
+ this.windowList.moveToFront(node);
1760
+ this.sketch.increment(key);
1761
+ this._hits++;
1762
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1763
+ return node.value;
1764
+ }
1765
+ node = this.probationMap.get(key);
1766
+ if (node) {
1767
+ node.lastAccessed = now;
1768
+ node.accessCount = (node.accessCount ?? 0) + 1;
1769
+ this.sketch.increment(key);
1770
+ this.probationList.remove(node);
1771
+ this.probationMap.delete(key);
1772
+ this.ensureProtectedCapacity(key, node.value, now);
1773
+ this.protectedList.addToFront(node);
1774
+ this.protectedMap.set(key, node);
1775
+ this._hits++;
1776
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1777
+ return node.value;
1778
+ }
1779
+ node = this.protectedMap.get(key);
1780
+ if (node) {
1781
+ node.lastAccessed = now;
1782
+ node.accessCount = (node.accessCount ?? 0) + 1;
1783
+ this.protectedList.moveToFront(node);
1784
+ this.sketch.increment(key);
1785
+ this._hits++;
1786
+ this.emit({ event: "get", key, value: node.value, timestamp: now });
1787
+ return node.value;
1788
+ }
1789
+ this._misses++;
1790
+ this.emit({ event: "get", key, timestamp: now });
1791
+ return void 0;
1792
+ }
1793
+ set(key, value, _ttl) {
1794
+ const now = this.now();
1795
+ let node = this.windowMap.get(key);
1796
+ if (node) {
1797
+ node.value = value;
1798
+ node.lastAccessed = now;
1799
+ this.windowList.moveToFront(node);
1800
+ this.sketch.increment(key);
1801
+ this.emit({ event: "set", key, value, timestamp: now });
1802
+ return;
1803
+ }
1804
+ node = this.probationMap.get(key);
1805
+ if (node) {
1806
+ node.value = value;
1807
+ node.lastAccessed = now;
1808
+ this.sketch.increment(key);
1809
+ this.emit({ event: "set", key, value, timestamp: now });
1810
+ return;
1811
+ }
1812
+ node = this.protectedMap.get(key);
1813
+ if (node) {
1814
+ node.value = value;
1815
+ node.lastAccessed = now;
1816
+ this.protectedList.moveToFront(node);
1817
+ this.sketch.increment(key);
1818
+ this.emit({ event: "set", key, value, timestamp: now });
1819
+ return;
1820
+ }
1821
+ this.sketch.increment(key);
1822
+ if (this.windowMap.size >= this.windowCapacity) {
1823
+ this.evictFromWindow(key, value, now);
1824
+ }
1825
+ const newNode = createNode(key, value);
1826
+ newNode.metadata = { createdAt: now };
1827
+ newNode.lastAccessed = now;
1828
+ newNode.accessCount = 0;
1829
+ this.windowList.addToFront(newNode);
1830
+ this.windowMap.set(key, newNode);
1831
+ this.emit({ event: "set", key, value, timestamp: now });
1832
+ }
1833
+ evictFromWindow(newKey, newValue, now) {
1834
+ const windowVictim = this.windowList.removeLast();
1835
+ if (!windowVictim) return;
1836
+ this.windowMap.delete(windowVictim.key);
1837
+ const mainSize = this.probationMap.size + this.protectedMap.size;
1838
+ if (mainSize < this.mainCapacity) {
1839
+ this.probationList.addToFront(windowVictim);
1840
+ this.probationMap.set(windowVictim.key, windowVictim);
1841
+ return;
1842
+ }
1843
+ const mainVictim = this.probationList.peekLast();
1844
+ if (!mainVictim) {
1845
+ this._evictions++;
1846
+ this.onEvict?.(windowVictim.key, windowVictim.value);
1847
+ this.emit({
1848
+ event: "evict",
1849
+ key: newKey,
1850
+ value: newValue,
1851
+ evictedKey: windowVictim.key,
1852
+ evictedValue: windowVictim.value,
1853
+ timestamp: now
1854
+ });
1855
+ return;
1856
+ }
1857
+ const candidateFreq = this.sketch.estimate(windowVictim.key);
1858
+ const victimFreq = this.sketch.estimate(mainVictim.key);
1859
+ if (candidateFreq > victimFreq) {
1860
+ this.probationList.removeLast();
1861
+ this.probationMap.delete(mainVictim.key);
1862
+ this._evictions++;
1863
+ this.onEvict?.(mainVictim.key, mainVictim.value);
1864
+ this.emit({
1865
+ event: "evict",
1866
+ key: newKey,
1867
+ value: newValue,
1868
+ evictedKey: mainVictim.key,
1869
+ evictedValue: mainVictim.value,
1870
+ timestamp: now
1871
+ });
1872
+ this.probationList.addToFront(windowVictim);
1873
+ this.probationMap.set(windowVictim.key, windowVictim);
1874
+ } else {
1875
+ this._evictions++;
1876
+ this.onEvict?.(windowVictim.key, windowVictim.value);
1877
+ this.emit({
1878
+ event: "evict",
1879
+ key: newKey,
1880
+ value: newValue,
1881
+ evictedKey: windowVictim.key,
1882
+ evictedValue: windowVictim.value,
1883
+ timestamp: now
1884
+ });
1885
+ }
1886
+ }
1887
+ ensureProtectedCapacity(newKey, newValue, now) {
1888
+ if (this.protectedMap.size >= this.protectedCapacity) {
1889
+ const demoted = this.protectedList.removeLast();
1890
+ if (demoted) {
1891
+ this.protectedMap.delete(demoted.key);
1892
+ this.probationList.addToFront(demoted);
1893
+ this.probationMap.set(demoted.key, demoted);
1894
+ }
1895
+ }
1896
+ const mainSize = this.probationMap.size + this.protectedMap.size;
1897
+ if (mainSize >= this.mainCapacity) {
1898
+ const victim = this.probationList.removeLast();
1899
+ if (victim) {
1900
+ this.probationMap.delete(victim.key);
1901
+ this._evictions++;
1902
+ this.onEvict?.(victim.key, victim.value);
1903
+ this.emit({
1904
+ event: "evict",
1905
+ key: newKey,
1906
+ value: newValue,
1907
+ evictedKey: victim.key,
1908
+ evictedValue: victim.value,
1909
+ timestamp: now
1910
+ });
1911
+ }
1912
+ }
1913
+ }
1914
+ delete(key) {
1915
+ let node = this.windowMap.get(key);
1916
+ if (node) {
1917
+ this.windowList.remove(node);
1918
+ this.windowMap.delete(key);
1919
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
1920
+ return true;
1921
+ }
1922
+ node = this.probationMap.get(key);
1923
+ if (node) {
1924
+ this.probationList.remove(node);
1925
+ this.probationMap.delete(key);
1926
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
1927
+ return true;
1928
+ }
1929
+ node = this.protectedMap.get(key);
1930
+ if (node) {
1931
+ this.protectedList.remove(node);
1932
+ this.protectedMap.delete(key);
1933
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
1934
+ return true;
1935
+ }
1936
+ return false;
1937
+ }
1938
+ has(key) {
1939
+ return this.windowMap.has(key) || this.probationMap.has(key) || this.protectedMap.has(key);
1940
+ }
1941
+ clear() {
1942
+ this.windowList.clear();
1943
+ this.windowMap.clear();
1944
+ this.probationList.clear();
1945
+ this.probationMap.clear();
1946
+ this.protectedList.clear();
1947
+ this.protectedMap.clear();
1948
+ this.sketch.reset();
1949
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
1950
+ }
1951
+ get size() {
1952
+ return this.windowMap.size + this.probationMap.size + this.protectedMap.size;
1953
+ }
1954
+ *keys() {
1955
+ for (const node of this.windowList) yield node.key;
1956
+ for (const node of this.protectedList) yield node.key;
1957
+ for (const node of this.probationList) yield node.key;
1958
+ }
1959
+ *values() {
1960
+ for (const node of this.windowList) yield node.value;
1961
+ for (const node of this.protectedList) yield node.value;
1962
+ for (const node of this.probationList) yield node.value;
1963
+ }
1964
+ *entries() {
1965
+ for (const node of this.windowList) yield [node.key, node.value];
1966
+ for (const node of this.protectedList) yield [node.key, node.value];
1967
+ for (const node of this.probationList) yield [node.key, node.value];
1968
+ }
1969
+ get strategy() {
1970
+ return "W-TINYLFU";
1971
+ }
1972
+ collectEntries() {
1973
+ const result = [];
1974
+ const collect = (list, tier) => {
1975
+ for (const node of list) {
1976
+ result.push({
1977
+ key: node.key,
1978
+ value: node.value,
1979
+ createdAt: node.metadata?.createdAt ?? 0,
1980
+ lastAccessed: node.lastAccessed ?? 0,
1981
+ accessCount: node.accessCount ?? 0,
1982
+ tier
1983
+ });
1984
+ }
1985
+ };
1986
+ collect(this.windowList, "cold");
1987
+ collect(this.protectedList, "hot");
1988
+ collect(this.probationList, "cold");
1989
+ return result;
1990
+ }
1991
+ };
1992
+
1993
+ // src/caches/lru-k.ts
1994
+ var LRUKCache = class extends BaseCache {
1995
+ store = /* @__PURE__ */ new Map();
1996
+ k;
1997
+ /** Keys with < K accesses, in insertion order for FIFO eviction. */
1998
+ correlatedKeys = /* @__PURE__ */ new Set();
1999
+ constructor(options) {
2000
+ super(options);
2001
+ this.k = options.k ?? 2;
2002
+ }
2003
+ get(key) {
2004
+ const entry = this.store.get(key);
2005
+ if (!entry) {
2006
+ this._misses++;
2007
+ this.emit({ event: "get", key, timestamp: this.now() });
2008
+ return void 0;
2009
+ }
2010
+ const now = this.now();
2011
+ const hadFullHistory = entry.history.length >= this.k;
2012
+ entry.lastAccessed = now;
2013
+ entry.accessCount++;
2014
+ entry.history.push(now);
2015
+ if (entry.history.length > this.k) {
2016
+ entry.history.shift();
2017
+ }
2018
+ if (!hadFullHistory && entry.history.length >= this.k) {
2019
+ this.correlatedKeys.delete(key);
2020
+ }
2021
+ this._hits++;
2022
+ this.emit({ event: "get", key, value: entry.value, timestamp: now });
2023
+ return entry.value;
2024
+ }
2025
+ set(key, value, _ttl) {
2026
+ const now = this.now();
2027
+ const existing = this.store.get(key);
2028
+ if (existing) {
2029
+ existing.value = value;
2030
+ existing.lastAccessed = now;
2031
+ this.emit({ event: "set", key, value, timestamp: now });
2032
+ return;
2033
+ }
2034
+ if (this.store.size >= this._capacity) {
2035
+ this.evict(key, value, now);
2036
+ }
2037
+ this.store.set(key, {
2038
+ key,
2039
+ value,
2040
+ createdAt: now,
2041
+ lastAccessed: now,
2042
+ accessCount: 0,
2043
+ history: [now]
2044
+ });
2045
+ if (this.k > 1) {
2046
+ this.correlatedKeys.add(key);
2047
+ }
2048
+ this.emit({ event: "set", key, value, timestamp: now });
2049
+ }
2050
+ evict(newKey, newValue, now) {
2051
+ let victimKey;
2052
+ if (this.correlatedKeys.size > 0) {
2053
+ let oldestTime = Infinity;
2054
+ for (const key of this.correlatedKeys) {
2055
+ const entry = this.store.get(key);
2056
+ const firstAccess = entry.history[0];
2057
+ if (firstAccess < oldestTime) {
2058
+ oldestTime = firstAccess;
2059
+ victimKey = key;
2060
+ }
2061
+ }
2062
+ if (victimKey !== void 0) {
2063
+ this.correlatedKeys.delete(victimKey);
2064
+ }
2065
+ } else {
2066
+ let oldestKth = Infinity;
2067
+ for (const [key, entry] of this.store) {
2068
+ if (this.correlatedKeys.has(key)) continue;
2069
+ const kthAccess = entry.history[0];
2070
+ if (kthAccess < oldestKth) {
2071
+ oldestKth = kthAccess;
2072
+ victimKey = key;
2073
+ }
2074
+ }
2075
+ }
2076
+ if (victimKey !== void 0) {
2077
+ const victim = this.store.get(victimKey);
2078
+ this.store.delete(victimKey);
2079
+ this._evictions++;
2080
+ this.onEvict?.(victimKey, victim.value);
2081
+ this.emit({
2082
+ event: "evict",
2083
+ key: newKey,
2084
+ value: newValue,
2085
+ evictedKey: victimKey,
2086
+ evictedValue: victim.value,
2087
+ timestamp: now
2088
+ });
2089
+ }
2090
+ }
2091
+ delete(key) {
2092
+ const entry = this.store.get(key);
2093
+ if (!entry) return false;
2094
+ this.store.delete(key);
2095
+ this.correlatedKeys.delete(key);
2096
+ this.emit({ event: "delete", key, value: entry.value, timestamp: this.now() });
2097
+ return true;
2098
+ }
2099
+ has(key) {
2100
+ return this.store.has(key);
2101
+ }
2102
+ clear() {
2103
+ this.store.clear();
2104
+ this.correlatedKeys.clear();
2105
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
2106
+ }
2107
+ get size() {
2108
+ return this.store.size;
2109
+ }
2110
+ *keys() {
2111
+ for (const key of this.store.keys()) {
2112
+ yield key;
2113
+ }
2114
+ }
2115
+ *values() {
2116
+ for (const entry of this.store.values()) {
2117
+ yield entry.value;
2118
+ }
2119
+ }
2120
+ *entries() {
2121
+ for (const entry of this.store.values()) {
2122
+ yield [entry.key, entry.value];
2123
+ }
2124
+ }
2125
+ get strategy() {
2126
+ return "LRU-K";
2127
+ }
2128
+ collectEntries() {
2129
+ const result = [];
2130
+ for (const entry of this.store.values()) {
2131
+ result.push({
2132
+ key: entry.key,
2133
+ value: entry.value,
2134
+ createdAt: entry.createdAt,
2135
+ lastAccessed: entry.lastAccessed,
2136
+ accessCount: entry.accessCount
2137
+ });
2138
+ }
2139
+ return result;
2140
+ }
2141
+ };
2142
+
2143
+ // src/caches/sieve.ts
2144
+ var SieveCache = class extends BaseCache {
2145
+ head = null;
2146
+ tail = null;
2147
+ hand = null;
2148
+ map = /* @__PURE__ */ new Map();
2149
+ constructor(options) {
2150
+ super(options);
2151
+ }
2152
+ get(key) {
2153
+ const node = this.map.get(key);
2154
+ if (!node) {
2155
+ this._misses++;
2156
+ this.emit({ event: "get", key, timestamp: this.now() });
2157
+ return void 0;
2158
+ }
2159
+ node.visited = true;
2160
+ node.lastAccessed = this.now();
2161
+ node.accessCount++;
2162
+ this._hits++;
2163
+ this.emit({ event: "get", key, value: node.value, timestamp: this.now() });
2164
+ return node.value;
2165
+ }
2166
+ set(key, value, _ttl) {
2167
+ const now = this.now();
2168
+ const existing = this.map.get(key);
2169
+ if (existing) {
2170
+ existing.value = value;
2171
+ existing.visited = true;
2172
+ existing.lastAccessed = now;
2173
+ this.emit({ event: "set", key, value, timestamp: now });
2174
+ return;
2175
+ }
2176
+ if (this.map.size >= this._capacity) {
2177
+ this.evict(key, value, now);
2178
+ }
2179
+ const node = {
2180
+ key,
2181
+ value,
2182
+ visited: false,
2183
+ createdAt: now,
2184
+ lastAccessed: now,
2185
+ accessCount: 0,
2186
+ prev: null,
2187
+ next: null
2188
+ };
2189
+ if (this.head) {
2190
+ node.next = this.head;
2191
+ this.head.prev = node;
2192
+ this.head = node;
2193
+ } else {
2194
+ this.head = node;
2195
+ this.tail = node;
2196
+ }
2197
+ this.map.set(key, node);
2198
+ this.emit({ event: "set", key, value, timestamp: now });
2199
+ }
2200
+ evict(newKey, newValue, now) {
2201
+ let candidate = this.hand ?? this.tail;
2202
+ if (!candidate) return;
2203
+ while (candidate.visited) {
2204
+ candidate.visited = false;
2205
+ candidate = candidate.next ?? this.head;
2206
+ }
2207
+ this.hand = candidate.next ?? this.head;
2208
+ if (this.hand === candidate) {
2209
+ this.hand = null;
2210
+ }
2211
+ this.removeNode(candidate);
2212
+ this.map.delete(candidate.key);
2213
+ this._evictions++;
2214
+ this.onEvict?.(candidate.key, candidate.value);
2215
+ this.emit({
2216
+ event: "evict",
2217
+ key: newKey,
2218
+ value: newValue,
2219
+ evictedKey: candidate.key,
2220
+ evictedValue: candidate.value,
2221
+ timestamp: now
2222
+ });
2223
+ }
2224
+ delete(key) {
2225
+ const node = this.map.get(key);
2226
+ if (!node) return false;
2227
+ if (this.hand === node) {
2228
+ this.hand = node.next ?? this.head;
2229
+ if (this.hand === node) {
2230
+ this.hand = null;
2231
+ }
2232
+ }
2233
+ this.removeNode(node);
2234
+ this.map.delete(key);
2235
+ this.emit({ event: "delete", key, value: node.value, timestamp: this.now() });
2236
+ return true;
2237
+ }
2238
+ has(key) {
2239
+ return this.map.has(key);
2240
+ }
2241
+ clear() {
2242
+ this.head = null;
2243
+ this.tail = null;
2244
+ this.hand = null;
2245
+ this.map.clear();
2246
+ this.emit({ event: "clear", key: "", timestamp: this.now() });
2247
+ }
2248
+ get size() {
2249
+ return this.map.size;
2250
+ }
2251
+ *keys() {
2252
+ let current = this.head;
2253
+ while (current) {
2254
+ yield current.key;
2255
+ current = current.next;
2256
+ }
2257
+ }
2258
+ *values() {
2259
+ let current = this.head;
2260
+ while (current) {
2261
+ yield current.value;
2262
+ current = current.next;
2263
+ }
2264
+ }
2265
+ *entries() {
2266
+ let current = this.head;
2267
+ while (current) {
2268
+ yield [current.key, current.value];
2269
+ current = current.next;
2270
+ }
2271
+ }
2272
+ get strategy() {
2273
+ return "SIEVE";
2274
+ }
2275
+ collectEntries() {
2276
+ const result = [];
2277
+ let current = this.head;
2278
+ while (current) {
2279
+ result.push({
2280
+ key: current.key,
2281
+ value: current.value,
2282
+ createdAt: current.createdAt,
2283
+ lastAccessed: current.lastAccessed,
2284
+ accessCount: current.accessCount
2285
+ });
2286
+ current = current.next;
2287
+ }
2288
+ return result;
2289
+ }
2290
+ removeNode(node) {
2291
+ if (node.prev) {
2292
+ node.prev.next = node.next;
2293
+ } else {
2294
+ this.head = node.next;
2295
+ }
2296
+ if (node.next) {
2297
+ node.next.prev = node.prev;
2298
+ } else {
2299
+ this.tail = node.prev;
2300
+ }
2301
+ node.prev = null;
2302
+ node.next = null;
2303
+ }
2304
+ };
2305
+ // Annotate the CommonJS export names for ESM import in node:
2306
+ 0 && (module.exports = {
2307
+ ARCCache,
2308
+ BaseCache,
2309
+ ClockCache,
2310
+ FIFOCache,
2311
+ LFUCache,
2312
+ LIFOCache,
2313
+ LRUCache,
2314
+ LRUKCache,
2315
+ MRUCache,
2316
+ RRCache,
2317
+ SLRUCache,
2318
+ SieveCache,
2319
+ TTLCache,
2320
+ TwoTierCache,
2321
+ WTinyLFUCache
2322
+ });