lru-map.ts
1 /** 2 * LRU Map implementation storing key/values up to a provided size limit. Beyond that 3 * size limit, the least recently used entry is evicted. 4 * 5 * @see https://github.pie.apple.com/isao/lru-map 6 */ 7 export class LruMap<K, V> extends Map<K, V> { 8 private sizeLimit: number; 9 10 constructor(sizeLimit: number) { 11 super(); 12 this.setSizeLimit(sizeLimit); 13 // Needed to convince TS that this is set (it's actually handled by setSizeLimit) 14 this.sizeLimit = sizeLimit; 15 } 16 17 /** 18 * Retrieve a value from the map with a given key. 19 * @param key The key for the entry 20 * @return value The entry's value (or undefined if non existent) 21 */ 22 get(key: K): V | undefined { 23 let value: V | undefined; 24 25 if (this.has(key)) { 26 value = super.get(key); 27 28 // Map entries are always in insertion order. So 29 // readding, pushes this entry to the top of the LRU. 30 this.delete(key); 31 super.set(key, value!); 32 } 33 34 return value; 35 } 36 37 set(key: K, value: V): this { 38 super.set(key, value); 39 this.prune(); 40 return this; 41 } 42 43 setSizeLimit(newSizeLimit: number): void { 44 if (newSizeLimit < 0 || !isFinite(newSizeLimit)) { 45 throw new Error( 46 `setSizeLimit expects finite positive number, got: ${newSizeLimit}`, 47 ); 48 } 49 50 this.sizeLimit = newSizeLimit; 51 this.prune(); 52 } 53 54 private prune(): void { 55 while (this.size > this.sizeLimit) { 56 const leastRecentlyUsedKey = this.keys().next().value; 57 this.delete(leastRecentlyUsedKey); 58 } 59 } 60 }