in-memoriam
Version:
Easy to use, high-speed O(1) for all operations, in-memory cache with both ttl and capacity support.
113 lines (96 loc) • 2.42 kB
JavaScript
;
/**
* Doubly linked list whose entries are accessible via keys. Built to
* enable constant time removal of "oldest" entries, reordering of
* updated entries and addition of new ones. This enables our cache
* to grow large with minimal interruption to the system as it is
* updated/queried.
*
* @constructor
*/
module.exports = function () {
var self = this;
var entries = {}; // Hash of linked entries
var newest = null; // Latest added entry
var size = 0; // Number of entries in the hash
/**
* Returns count of elements in the list
*/
self.length = function () {
return size;
};
/**
* Adds a new entry in front of the current newestEntry
*
* @returns {{next: null, previous: *, key: *, value: *, expires: *}}
*/
self.add = function (key, value) {
if (entries[key]) {
throw new Error('Key "' + key + '" is already preset.');
}
// Create the entry
var entry = {
key: key,
value: value
};
// This entry is now the newest, so rewire all the references
// in the double linked circular list
if (newest) {
entry.next = newest;
entry.previous = newest.previous || newest;
newest.previous = entry;
if (entry.previous) {
entry.previous.next = entry;
}
}
// Place it in the indexed collection
entries[key] = entry;
newest = entry;
size++;
return entry;
};
/**
* Gets the value associated with the given key
*
* @param {*} key
* @returns {*}
*/
self.get = function (key) {
return entries[key];
};
/**
* Gets the "last" element in the list
*/
self.getOldest = function () {
return newest && newest.previous;
};
/**
* Removes an entry from this list
*
* @return The removed element or null if not found/empty
*/
self.remove = function (key) {
var entry = entries[key];
if (!entry) {
return null;
}
if (size === 1) {
newest = null;
} else if (size >= 2) {
var next = entry.next;
if (size === 2) {
next.next = next.previous = null;
} else {
next.previous = entry.previous;
entry.previous.next = next;
}
if (newest === entry) {
newest = entry.next;
}
}
// Update the indexed collection
delete entries[key];
size--;
return entry;
};
};