| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- /**
- * @file generational-cache.js
- * A generational pseudo-LRU cache with strict maximum size limits.
- */
- /**
- * @template K, V
- */
- export class GenerationalCache {
- #max;
- #boundary;
- #current = new Map();
- #old = new Map();
- /**
- * Initializes a new instance of the GenerationalCache class.
- * @param {number} max - The maximum number of items the cache can hold.
- */
- constructor(max) {
- this.max = max;
- }
- /**
- * Returns the total number of `entries` currently in the cache.
- * @note To optimize for write speed, this library allows temporary key
- * duplication between generations. Therefore, this value may not always
- * reflect the exact count of unique `keys`.
- * @returns {number} The total entry count.
- */
- get size() {
- return this.#current.size + this.#old.size;
- }
- /**
- * Returns the maximum capacity of the cache.
- * @returns {number} The maximum size limit.
- */
- get max() {
- return this.#max;
- }
- /**
- * Sets the maximum capacity of the cache and recalculates the boundary.
- * Clears the cache when updated.
- * @param {number} value - The new maximum capacity to set.
- */
- set max(value) {
- if (Number.isFinite(value) && value > 4) {
- this.#max = value;
- this.#boundary = Math.ceil(value / 2);
- } else {
- this.#max = 4;
- this.#boundary = 2;
- }
- this.clear();
- }
- /**
- * Retrieves an item from the cache.
- * If the item is in the older generation, it gets promoted to the current
- * generation.
- * @param {K} key - The key of the element to return.
- * @returns {V | undefined} The element associated with the specified key, or
- * undefined if the key cannot be found.
- */
- get(key) {
- let value = this.#current.get(key);
- if (value !== undefined) {
- return value;
- }
- value = this.#old.get(key);
- if (value !== undefined) {
- this.set(key, value);
- return value;
- }
- return undefined;
- }
- /**
- * Adds or updates an element with a specified key and a value to the cache.
- * @param {K} key - The key of the element to add.
- * @param {V} value - The value of the element to add.
- * @returns {GenerationalCache} The cache object itself.
- */
- set(key, value) {
- this.#current.set(key, value);
- // Swap generations if the current map reaches the boundary
- if (this.#current.size >= this.#boundary) {
- this.#old = this.#current;
- this.#current = new Map();
- }
- return this;
- }
- /**
- * Returns a boolean indicating whether an element with the specified key
- * exists or not.
- * @param {K} key - The key of the element to test for presence.
- * @returns {boolean} true if an element with the specified key exists in the
- * cache; otherwise false.
- */
- has(key) {
- return this.#current.has(key) || this.#old.has(key);
- }
- /**
- * Removes the specified element from the cache.
- * @param {K} key - The key of the element to remove.
- * @returns {boolean} true if an element in the cache existed and has been
- * removed, or false if the element does not exist.
- */
- delete(key) {
- const deletedFromCurrent = this.#current.delete(key);
- const deletedFromOld = this.#old.delete(key);
- return deletedFromCurrent || deletedFromOld;
- }
- /**
- * Removes all elements from the cache.
- */
- clear() {
- this.#current.clear();
- this.#old.clear();
- }
- }
|