sussy-util
Version:
Util package made by me
197 lines (196 loc) • 6.24 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LRUCache = void 0;
/**
* A node in a doubly linked list.
*/
class DoublyLinkedListNode {
constructor(key) {
this.prev = null;
this.next = null;
this.key = key;
}
}
/**
* A doubly linked list for quick insertion/removal from head/tail.
*/
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
this.addToFront = (node) => {
if (!node)
return;
if (!this.head) {
this.head = node;
this.tail = node;
return;
}
node.next = this.head;
this.head.prev = node;
this.head = node;
};
this.removeNode = (node) => {
if (!node)
return;
const { prev, next } = node;
if (prev)
prev.next = next;
if (next)
next.prev = prev;
if (this.head === node)
this.head = next;
if (this.tail === node)
this.tail = prev;
node.prev = null;
node.next = null;
};
this.moveToFront = (node) => {
if (!node)
return;
if (this.head === node)
return;
this.removeNode(node);
this.addToFront(node);
};
this.removeLast = () => {
if (!this.tail)
return null;
const last = this.tail;
this.removeNode(last);
return last;
};
}
}
/**
* A Least Recently Used (LRU) Cache implementation with a fixed capacity.
* Provides O(1) lookup, insertion, and removal.
*
* @template Key - The type of keys stored in the cache.
* @template Value - The type of values stored in the cache.
*/
class LRUCache {
/**
* @param capacity The maximum number of entries the cache can hold.
*/
constructor(capacity) {
/**
* Retrieve a value from the cache.
* Moves the accessed item to the front of the usage order.
*
* @param key The key to look up.
* @returns The value associated with the key, or undefined if not found.
*/
this.get = (key) => {
const value = this.cache.get(key);
if (value === undefined)
return undefined;
const node = this.nodes.get(key);
if (!node)
return undefined;
this.usageOrder.moveToFront(node);
return value;
};
/**
* Add or update a key-value pair.
* If adding the item causes the cache to exceed capacity, evicts the least recently used item.
*
* @param key The key.
* @param value The value.
*/
this.put = (key, value) => {
// If item already in cache, update and move to front
if (this.cache.has(key)) {
this.cache.set(key, value);
const existingNode = this.nodes.get(key);
if (existingNode)
this.usageOrder.moveToFront(existingNode);
return;
}
// If new entry and over capacity, evict LRU
if (this.cache.size >= this.capacity) {
const lruNode = this.usageOrder.removeLast();
if (lruNode) {
const evictedKey = lruNode.key;
const evictedValue = this.cache.get(evictedKey);
if (evictedValue !== undefined) {
this.evictionCallback(evictedKey, evictedValue);
}
this.cache.delete(evictedKey);
this.nodes.delete(evictedKey);
}
}
// Insert new entry at front
const newNode = new DoublyLinkedListNode(key);
this.usageOrder.addToFront(newNode);
this.cache.set(key, value);
this.nodes.set(key, newNode);
};
/**
* Remove an item from the cache.
*
* @param key The key of the item to remove.
* @returns True if the item was removed, false otherwise.
*/
this.remove = (key) => {
const node = this.nodes.get(key);
if (!node)
return false;
this.usageOrder.removeNode(node);
const removed = this.cache.delete(key);
this.nodes.delete(key);
return removed;
};
/**
* Clear the cache of all entries.
*/
this.clear = () => {
this.cache.clear();
this.nodes.clear();
// Clear the linked list entirely
while (this.usageOrder.removeLast()) {
// just clearing
}
};
/**
* Get all keys currently in the cache (order not guaranteed).
*/
this.getAllKeys = () => {
return Array.from(this.cache.keys());
};
/**
* Get all values currently in the cache (order not guaranteed).
*/
this.getAllValues = () => {
return Array.from(this.cache.values());
};
/**
* Set a callback to be called when an item is evicted.
*
* @param callback The callback function.
*/
this.setEvictionCallback = (callback) => {
if (!callback)
return;
this.evictionCallback = callback;
};
if (capacity <= 0) {
throw new Error('LRUCache capacity must be greater than 0.');
}
this.capacity = capacity;
this.cache = new Map();
this.nodes = new Map();
this.usageOrder = new DoublyLinkedList();
this.evictionCallback = () => { };
}
/**
* Get a generator yielding all entries in the cache (order not guaranteed).
*/
*entries() {
for (const [key, value] of this.cache.entries()) {
yield [key, value];
}
}
}
exports.LRUCache = LRUCache;
exports.default = LRUCache;