Gathering detailed insights and metrics for ts_lru_map
Gathering detailed insights and metrics for ts_lru_map
Gathering detailed insights and metrics for ts_lru_map
Gathering detailed insights and metrics for ts_lru_map
A fast, simple & universal Least Recently Used (LRU) map for TypeScript
npm install ts_lru_map
Typescript
Module System
Node Version
NPM Version
70.7
Supply Chain
99.3
Quality
75.4
Maintenance
100
Vulnerability
100
License
TypeScript (47.42%)
JavaScript (44.68%)
HTML (7.91%)
Total Downloads
1,561
Last Day
6
Last Week
34
Last Month
49
Last Year
1,561
82 Commits
1 Branches
1 Contributors
Updated on Jun 06, 2024
Minified
Minified + Gzipped
Latest Version
1.0.2
Package Id
ts_lru_map@1.0.2
Unpacked Size
17.94 kB
Size
5.84 kB
File Count
6
NPM Version
10.5.0
Node Version
20.12.0
Published on
Jun 06, 2024
Cumulative downloads
Total Downloads
Last Day
0%
6
Compared to previous day
Last Week
1,033.3%
34
Compared to previous week
Last Month
58.1%
49
Compared to previous month
Last Year
0%
1,561
Compared to previous year
A TypeScript implemenation of the lru_map package.
A finite key-value map using the Least Recently Used (LRU) algorithm, where the most recently-used items are "kept alive" while older, less-recently used items are evicted to make room for newer items.
Useful when you want to limit use of memory to only hold commonly-used things.
Based on a doubly-linked list for low complexity random shuffling of entries.
The cache object iself has a "head" (least recently used entry) and a "tail" (most recently used entry).
The "oldest" and "newest" are list entries -- an entry might have a "newer" and an "older" entry (doubly-linked, "older" being close to "head" and "newer" being closer to "tail").
Key lookup is done through a key-entry mapping native object, which on most
platforms mean O(1)
complexity. This comes at a very low memory cost (for
storing two extra pointers for each entry).
Fancy ASCII art illustration of the general design:
1 entry entry entry entry 2 ______ ______ ______ ______ 3 | head |.newer => | |.newer => | |.newer => | tail | 4.oldest = | A | | B | | C | | D | = .newest 5 |______| <= older.|______| <= older.|______| <= older.|______| 6 7 removed <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- added
1let c = new LRUMap(3) 2c.set('adam', 29) 3c.set('john', 26) 4c.set('angela', 24) 5c.toString() // -> "adam:29 < john:26 < angela:24" 6c.get('john') // -> 26 7 8// Now 'john' is the most recently used entry, since we just requested it 9c.toString() // -> "adam:29 < angela:24 < john:26" 10c.set('zorro', 141) // -> {key:adam, value:29} 11 12// Because we only have room for 3 entries, adding 'zorro' caused 'adam' 13// to be removed in order to make room for the new entry 14c.toString() // -> "angela:24 < john:26 < zorro:141"
Using NPM: npm install ts_lru_map
Testing:
npm test
npm run benchmark
The API imitates that of Map
, which means that in most cases you can use LRUMap
as a drop-in replacement for Map
.
1export class LRUMap<K,V> { 2 // Construct a new cache object which will hold up to limit entries. 3 // When the size == limit, a `put` operation will evict the oldest entry. 4 // 5 // If `entries` is provided, all entries are added to the new map. 6 // `entries` should be an Array or other iterable object whose elements are 7 // key-value pairs (2-element Arrays). Each key-value pair is added to the new Map. 8 // null is treated as undefined. 9 constructor(limit :number, entries? :Iterable<[K,V]>); 10 11 // Current number of items 12 size :number; 13 14 // Maximum number of items this map can hold 15 limit :number; 16 17 // Least recently-used entry. Invalidated when map is modified. 18 oldest :Entry<K,V>; 19 20 // Most recently-used entry. Invalidated when map is modified. 21 newest :Entry<K,V>; 22 23 // Replace all values in this map with key-value pairs (2-element Arrays) from 24 // provided iterable. 25 assign(entries :Iterable<[K,V]>) : void; 26 27 // Put <value> into the cache associated with <key>. Replaces any existing entry 28 // with the same key. Returns `this`. 29 set(key :K, value :V) : LRUMap<K,V>; 30 31 // Purge the least recently used (oldest) entry from the cache. 32 // Returns the removed entry or undefined if the cache was empty. 33 shift() : [K,V] | undefined; 34 35 // Get and register recent use of <key>. 36 // Returns the value associated with <key> or undefined if not in cache. 37 get(key :K) : V | undefined; 38 39 // Check if there's a value for key in the cache without registering recent use. 40 has(key :K) : boolean; 41 42 // Access value for <key> without registering recent use. Useful if you do not 43 // want to chage the state of the map, but only "peek" at it. 44 // Returns the value associated with <key> if found, or undefined if not found. 45 find(key :K) : V | undefined; 46 47 // Remove entry <key> from cache and return its value. 48 // Returns the removed value, or undefined if not found. 49 delete(key :K) : V | undefined; 50 51 // Removes all entries 52 clear() : void; 53 54 // Returns an iterator over all keys, starting with the oldest. 55 keys() : Iterator<K>; 56 57 // Returns an iterator over all values, starting with the oldest. 58 values() : Iterator<V>; 59 60 // Returns an iterable over all entries, starting with the oldest. 61 entries() : Iterable<[K,V]>; 62 63 // Returns an iterator over all entries, starting with the oldest. 64 [Symbol.iterator]() : Iterator<[K,V]>; 65 66 // Call `fun` for each entry, starting with the oldest entry. 67 forEach(fun :(value :V, key :K, m :LRUMap<K,V>)=>void, thisArg? :any) : void; 68 69 // Returns an object suitable for JSON encoding 70 toJSON() : Array<{key :K, value :V}>; 71 72 // Returns a human-readable text representation 73 toString() : string; 74} 75 76// An entry holds the key and value, and pointers to any older and newer entries. 77// Entries might hold references to adjacent entries in the internal linked-list. 78// Therefore you should never store or modify Entry objects. Instead, reference the 79// key and value of an entry when needed. 80interface Entry<K,V> { 81 key :K; 82 value :V; 83}
If you need to perform any form of finalization of items as they are evicted from the cache, wrapping the shift
method is a good way to do it:
1let c = new LRUMap(123); 2c.shift = function() { 3 let entry = LRUMap.prototype.shift.call(this); 4 doSomethingWith(entry); 5 return entry; 6}
The internals calls shift
as entries need to be evicted, so this method is guaranteed to be called for any item that's removed from the cache. The returned entry must not include any strong references to other entries. See note in the documentation of LRUMap.prototype.set()
.
No vulnerabilities found.
No security vulnerabilities found.