js-lru
Version:
A finite key-value cache using the Least Recently Used (LRU) cache algorithm where the most recently used objects are keept in cache while less recently used items are purged.
149 lines (137 loc) • 3.83 kB
JavaScript
var LRUCache = require('./lru-core').LRUCache
// ----------------------------------------------------------------------------
// Following code is optional and can be removed without breaking the core
// functionality.
/**
* Check if <key> is in the cache without registering recent use. Feasible if
* you do not want to chage the state of the cache, but only "peek" at it.
* Returns the entry associated with <key> if found, or undefined if not found.
*/
LRUCache.prototype.find = function (key) {
return this._keymap[key]
}
/**
* Update the value of entry with <key>. Returns the old value, or undefined if
* entry was not in the cache.
*/
LRUCache.prototype.set = function (key, value) {
var oldvalue
var entry = this.get(key, true)
if (entry) {
oldvalue = entry.value
entry.value = value
} else {
oldvalue = this.put(key, value)
if (oldvalue) oldvalue = oldvalue.value
}
return oldvalue
}
/**
* Remove entry <key> from cache and return its value. Returns undefined if not
* found.
*/
LRUCache.prototype.remove = function (key) {
var entry = this._keymap[key]
if (!entry) {
return
}
delete this._keymap[entry.key] // need to do delete unfortunately
if (entry.newer && entry.older) {
// relink the older entry with the newer entry
entry.older.newer = entry.newer
entry.newer.older = entry.older
} else if (entry.newer) {
// remove the link to us
entry.newer.older = undefined
// link the newer entry to head
this.head = entry.newer
} else if (entry.older) {
// remove the link to us
entry.older.newer = undefined
// link the newer entry to head
this.tail = entry.older
} else {// if(entry.older === undefined && entry.newer === undefined) {
this.head = this.tail = undefined
}
this.size--
return entry.value
}
/** Removes all entries */
LRUCache.prototype.removeAll = function () {
// This should be safe, as we never expose strong refrences to the outside
this.head = this.tail = undefined
this.size = 0
this._keymap = {}
}
/**
* Return an array containing all keys of entries stored in the cache object, in
* arbitrary order.
*/
if (typeof Object.keys === 'function') {
LRUCache.prototype.keys = function () {
return Object.keys(this._keymap)
}
} else {
LRUCache.prototype.keys = function () {
var keys = []
for (var k in this._keymap) keys.push(k)
return keys
}
}
/**
* Call `fun` for each entry. Starting with the newest entry if `desc` is a true
* value, otherwise starts with the oldest (head) enrty and moves towards the
* tail.
*
* `fun` is called with 3 arguments in the context `context`:
* `fun.call(context, Object key, Object value, LRUCache self)`
*/
LRUCache.prototype.forEach = function (fun, context, desc) {
var entry
if (context === true) {
desc = true
context = undefined
} else if (typeof context !== 'object') {
context = this
}
if (desc) {
entry = this.tail
while (entry) {
fun.call(context, entry.key, entry.value, this)
entry = entry.older
}
} else {
entry = this.head
while (entry) {
fun.call(context, entry.key, entry.value, this)
entry = entry.newer
}
}
}
/** Returns a JSON (array) representation */
LRUCache.prototype.toJSON = function () {
var s = []
var entry = this.head
while (entry) {
s.push({key: entry.key.toJSON(), value: entry.value.toJSON()})
entry = entry.newer
}
return s
}
/** Returns a String representation */
LRUCache.prototype.toString = function () {
var s = ''
var entry = this.head
while (entry) {
s += String(entry.key) + ':' + entry.value
entry = entry.newer
if (entry) {
s += ' < '
}
}
return s
}
// Export ourselves
if (typeof this === 'object') {
this.LRUCache = LRUCache
}