Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

lru-cache

Package Overview
Dependencies
Maintainers
2
Versions
143
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lru-cache - npm Package Compare versions

Comparing version 3.2.0 to 4.0.0

benchmarks/insertion-time.js

470

lib/lru-cache.js

@@ -6,27 +6,77 @@ module.exports = LRUCache

var Map = require('pseudomap')
var util = require('util')
// A linked list to keep track of recently-used-ness
var Yallist = require('yallist')
// use symbols if possible, otherwise just _props
var symbols = {}
var hasSymbol = typeof Symbol === 'function'
var makeSymbol
if (hasSymbol) {
makeSymbol = function (key) {
return Symbol.for(key)
}
} else {
makeSymbol = function (key) {
return '_' + key
}
}
function priv (obj, key, val) {
var sym
if (symbols[key]) {
sym = symbols[key]
} else {
sym = makeSymbol(key)
symbols[key] = sym
}
if (arguments.length === 2) {
return obj[sym]
} else {
obj[sym] = val
return val
}
}
function naiveLength () { return 1 }
// lruList is a yallist where the head is the youngest
// item, and the tail is the oldest. the list contains the Hit
// objects as the entries.
// Each Hit object has a reference to its Yallist.Node. This
// never changes.
//
// cache is a Map (or PseudoMap) that matches the keys to
// the Yallist.Node object.
function LRUCache (options) {
if (!(this instanceof LRUCache))
if (!(this instanceof LRUCache)) {
return new LRUCache(options)
}
if (typeof options === 'number')
if (typeof options === 'number') {
options = { max: options }
}
if (!options)
if (!options) {
options = {}
}
this._max = options.max
var max = priv(this, 'max', options.max)
// Kind of weird to have a default max of Infinity, but oh well.
if (!this._max || !(typeof this._max === "number") || this._max <= 0 )
this._max = Infinity
if (!max ||
!(typeof max === 'number') ||
max <= 0) {
priv(this, 'max', Infinity)
}
this._lengthCalculator = options.length || naiveLength
if (typeof this._lengthCalculator !== "function")
this._lengthCalculator = naiveLength
var lc = options.length || naiveLength
if (typeof lc !== 'function') {
lc = naiveLength
}
priv(this, 'lengthCalculator', lc)
this._allowStale = options.stale || false
this._maxAge = options.maxAge || null
this._dispose = options.dispose
priv(this, 'allowStale', options.stale || false)
priv(this, 'maxAge', options.maxAge || 0)
priv(this, 'dispose', options.dispose)
this.reset()

@@ -36,71 +86,84 @@ }

// resize the cache when the max changes.
Object.defineProperty(LRUCache.prototype, "max",
{ set : function (mL) {
if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
this._max = mL
if (this._length > this._max) trim(this)
Object.defineProperty(LRUCache.prototype, 'max', {
set: function (mL) {
if (!mL || !(typeof mL === 'number') || mL <= 0) {
mL = Infinity
}
, get : function () { return this._max }
, enumerable : true
})
priv(this, 'max', mL)
trim(this)
},
get: function () {
return priv(this, 'max')
},
enumerable: true
})
// resize the cache when the lengthCalculator changes.
Object.defineProperty(LRUCache.prototype, "lengthCalculator",
{ set : function (lC) {
if (typeof lC !== "function") {
this._lengthCalculator = naiveLength
this._length = this._lruList.size
this._cache.forEach(function (value, key) {
value.length = 1
})
} else {
this._lengthCalculator = lC
this._length = 0
this._cache.forEach(function (value, key) {
value.length = this._lengthCalculator(value.value, key)
this._length += value.length
}, this)
}
Object.defineProperty(LRUCache.prototype, 'allowStale', {
set: function (allowStale) {
priv(this, 'allowStale', !!allowStale)
},
get: function () {
return priv(this, 'allowStale')
},
enumerable: true
})
if (this._length > this._max) trim(this)
Object.defineProperty(LRUCache.prototype, 'maxAge', {
set: function (mA) {
if (!mA || !(typeof mA === 'number') || mA < 0) {
mA = 0
}
, get : function () { return this._lengthCalculator }
, enumerable : true
})
priv(this, 'maxAge', mA)
trim(this)
},
get: function () {
return priv(this, 'maxAge')
},
enumerable: true
})
Object.defineProperty(LRUCache.prototype, "length",
{ get : function () { return this._length }
, enumerable : true
})
// resize the cache when the lengthCalculator changes.
Object.defineProperty(LRUCache.prototype, 'lengthCalculator', {
set: function (lC) {
if (typeof lC !== 'function') {
lC = naiveLength
}
if (lC !== priv(this, 'lengthCalculator')) {
priv(this, 'lengthCalculator', lC)
priv(this, 'length', 0)
priv(this, 'lruList').forEach(function (hit) {
hit.length = priv(this, 'lengthCalculator').call(this, hit.value, hit.key)
priv(this, 'length', priv(this, 'length') + hit.length)
}, this)
}
trim(this)
},
get: function () { return priv(this, 'lengthCalculator') },
enumerable: true
})
Object.defineProperty(LRUCache.prototype, "itemCount",
{ get : function () { return this._lruList.size }
, enumerable : true
})
Object.defineProperty(LRUCache.prototype, 'length', {
get: function () { return priv(this, 'length') },
enumerable: true
})
function reverseKeys (map) {
// keys live in lruList map in insertion order.
// we want them in reverse insertion order.
// flip the list of keys.
var itemCount = map.size
var keys = new Array(itemCount)
var i = itemCount
map.forEach(function (value, key) {
keys[--i] = key
})
Object.defineProperty(LRUCache.prototype, 'itemCount', {
get: function () { return priv(this, 'lruList').length },
enumerable: true
})
return keys
}
LRUCache.prototype.rforEach = function (fn, thisp) {
thisp = thisp || this
this._lruList.forEach(function (hit) {
forEachStep(this, fn, hit, thisp)
}, this)
for (var walker = priv(this, 'lruList').tail; walker !== null;) {
var prev = walker.prev
forEachStep(this, fn, walker, thisp)
walker = prev
}
}
function forEachStep (self, fn, hit, thisp) {
function forEachStep (self, fn, node, thisp) {
var hit = node.value
if (isStale(self, hit)) {
del(self, hit)
if (!self._allowStale) {
del(self, node)
if (!priv(self, 'allowStale')) {
hit = undefined

@@ -114,10 +177,8 @@ }

LRUCache.prototype.forEach = function (fn, thisp) {
thisp = thisp || this
var keys = reverseKeys(this._lruList)
for (var k = 0; k < keys.length; k++) {
var hit = this._lruList.get(keys[k])
forEachStep(this, fn, hit, thisp)
for (var walker = priv(this, 'lruList').head; walker !== null;) {
var next = walker.next
forEachStep(this, fn, walker, thisp)
walker = next
}

@@ -127,4 +188,4 @@ }

LRUCache.prototype.keys = function () {
return reverseKeys(this._lruList).map(function (k) {
return this._lruList.get(k).key
return priv(this, 'lruList').toArray().map(function (k) {
return k.key
}, this)

@@ -134,4 +195,4 @@ }

LRUCache.prototype.values = function () {
return reverseKeys(this._lruList).map(function (k) {
return this._lruList.get(k).value
return priv(this, 'lruList').toArray().map(function (k) {
return k.value
}, this)

@@ -141,21 +202,17 @@ }

LRUCache.prototype.reset = function () {
if (this._dispose && this._cache) {
this._cache.forEach(function (entry, key) {
this._dispose(key, entry.value)
if (priv(this, 'dispose') &&
priv(this, 'lruList') &&
priv(this, 'lruList').length) {
priv(this, 'lruList').forEach(function (hit) {
priv(this, 'dispose').call(this, hit.key, hit.value)
}, this)
}
this._cache = new Map() // hash of items by key
this._lruList = new Map() // list of items in order of use recency
this._mru = 0 // most recently used
this._lru = 0 // least recently used
this._length = 0 // number of items in the list
priv(this, 'cache', new Map()) // hash of items by key
priv(this, 'lruList', new Yallist()) // list of items in order of use recency
priv(this, 'length', 0) // length of items in the list
}
LRUCache.prototype.dump = function () {
var arr = []
var i = 0
var size = this._lruList.size
return reverseKeys(this._lruList).map(function (k) {
var hit = this._lruList.get(k)
return priv(this, 'lruList').map(function (hit) {
if (!isStale(this, hit)) {

@@ -168,3 +225,3 @@ return {

}
}, this).filter(function (h) {
}, this).toArray().filter(function (h) {
return h

@@ -175,22 +232,96 @@ })

LRUCache.prototype.dumpLru = function () {
return this._lruList
return priv(this, 'lruList')
}
LRUCache.prototype.inspect = function (n, opts) {
var str = 'LRUCache {'
var extras = false
var as = priv(this, 'allowStale')
if (as) {
str += '\n allowStale: true'
extras = true
}
var max = priv(this, 'max')
if (max && max !== Infinity) {
if (extras) {
str += ','
}
str += '\n max: ' + util.inspect(max, opts)
extras = true
}
var maxAge = priv(this, 'maxAge')
if (maxAge) {
if (extras) {
str += ','
}
str += '\n maxAge: ' + util.inspect(maxAge, opts)
extras = true
}
var lc = priv(this, 'lengthCalculator')
if (lc && lc !== naiveLength) {
if (extras) {
str += ','
}
str += '\n length: ' + util.inspect(priv(this, 'length'), opts)
extras = true
}
var didFirst = false
priv(this, 'lruList').forEach(function (item) {
if (didFirst) {
str += ',\n '
} else {
if (extras) {
str += ',\n'
}
didFirst = true
str += '\n '
}
var key = util.inspect(item.key).split('\n').join('\n ')
var val = { value: item.value }
if (item.maxAge !== maxAge) {
val.maxAge = item.maxAge
}
if (lc !== naiveLength) {
val.length = item.length
}
if (isStale(this, item)) {
val.stale = true
}
val = util.inspect(val, opts).split('\n').join('\n ')
str += key + ' => ' + val
})
if (didFirst || extras) {
str += '\n'
}
str += '}'
return str
}
LRUCache.prototype.set = function (key, value, maxAge) {
maxAge = maxAge || this._maxAge
maxAge = maxAge || priv(this, 'maxAge')
var now = maxAge ? Date.now() : 0
var len = this._lengthCalculator(value, key)
var len = priv(this, 'lengthCalculator').call(this, value, key)
if (this._cache.has(key)) {
if (len > this._max) {
del(this, this._cache.get(key))
if (priv(this, 'cache').has(key)) {
if (len > priv(this, 'max')) {
del(this, priv(this, 'cache').get(key))
return false
}
var item = this._cache.get(key)
var node = priv(this, 'cache').get(key)
var item = node.value
// dispose of the old one before overwriting
if (this._dispose)
this._dispose(key, item.value)
if (priv(this, 'dispose')) {
priv(this, 'dispose').call(this, key, item.value)
}

@@ -200,28 +331,23 @@ item.now = now

item.value = value
this._length += (len - item.length)
priv(this, 'length', priv(this, 'length') + (len - item.length))
item.length = len
this.get(key)
if (this._length > this._max)
trim(this)
trim(this)
return true
}
var hit = new Entry(key, value, this._mru, len, now, maxAge)
incMru(this)
var hit = new Entry(key, value, len, now, maxAge)
// oversized objects fall out of cache automatically.
if (hit.length > this._max) {
if (this._dispose) this._dispose(key, value)
if (hit.length > priv(this, 'max')) {
if (priv(this, 'dispose')) {
priv(this, 'dispose').call(this, key, value)
}
return false
}
this._length += hit.length
this._cache.set(key, hit)
this._lruList.set(hit.lu, hit)
if (this._length > this._max)
trim(this)
priv(this, 'length', priv(this, 'length') + hit.length)
priv(this, 'lruList').unshift(hit)
priv(this, 'cache').set(key, priv(this, 'lruList').head)
trim(this)
return true

@@ -231,4 +357,4 @@ }

LRUCache.prototype.has = function (key) {
if (!this._cache.has(key)) return false
var hit = this._cache.get(key)
if (!priv(this, 'cache').has(key)) return false
var hit = priv(this, 'cache').get(key).value
if (isStale(this, hit)) {

@@ -249,14 +375,15 @@ return false

LRUCache.prototype.pop = function () {
var hit = this._lruList.get(this._lru)
del(this, hit)
return hit || null
var node = priv(this, 'lruList').tail
if (!node) return null
del(this, node)
return node.value
}
LRUCache.prototype.del = function (key) {
del(this, this._cache.get(key))
del(this, priv(this, 'cache').get(key))
}
LRUCache.prototype.load = function (arr) {
//reset the cache
this.reset();
// reset the cache
this.reset()

@@ -281,10 +408,20 @@ var now = Date.now()

LRUCache.prototype.prune = function () {
var self = this
priv(this, 'cache').forEach(function (value, key) {
get(self, key, false)
})
}
function get (self, key, doUse) {
var hit = self._cache.get(key)
if (hit) {
var node = priv(self, 'cache').get(key)
if (node) {
var hit = node.value
if (isStale(self, hit)) {
del(self, hit)
if (!self._allowStale) hit = undefined
del(self, node)
if (!priv(self, 'allowStale')) hit = undefined
} else {
if (doUse) use(self, hit)
if (doUse) {
priv(self, 'lruList').unshiftNode(node)
}
}

@@ -296,5 +433,7 @@ if (hit) hit = hit.value

function isStale(self, hit) {
if (!hit || (!hit.maxAge && !self._maxAge)) return false
var stale = false;
function isStale (self, hit) {
if (!hit || (!hit.maxAge && !priv(self, 'maxAge'))) {
return false
}
var stale = false
var diff = Date.now() - hit.now

@@ -304,23 +443,17 @@ if (hit.maxAge) {

} else {
stale = self._maxAge && (diff > self._maxAge)
stale = priv(self, 'maxAge') && (diff > priv(self, 'maxAge'))
}
return stale;
return stale
}
function use (self, hit) {
shiftLU(self, hit)
hit.lu = self._mru
incMru(self)
self._lruList.set(hit.lu, hit)
}
function trim (self) {
if (self._length > self._max) {
var keys = reverseKeys(self._lruList)
for (var k = keys.length - 1; self._length > self._max; k--) {
if (priv(self, 'length') > priv(self, 'max')) {
for (var walker = priv(self, 'lruList').tail;
priv(self, 'length') > priv(self, 'max') && walker !== null;) {
// We know that we're about to delete this one, and also
// what the next least recently used key will be, so just
// go ahead and set it now.
self._lru = keys[k - 1]
del(self, self._lruList.get(keys[k]))
var prev = walker.prev
del(self, walker)
walker = prev
}

@@ -330,14 +463,11 @@ }

function shiftLU (self, hit) {
self._lruList.delete(hit.lu)
if (hit.lu === self._lru)
self._lru = reverseKeys(self._lruList).pop()
}
function del (self, hit) {
if (hit) {
if (self._dispose) self._dispose(hit.key, hit.value)
self._length -= hit.length
self._cache.delete(hit.key)
shiftLU(self, hit)
function del (self, node) {
if (node) {
var hit = node.value
if (priv(self, 'dispose')) {
priv(self, 'dispose').call(this, hit.key, hit.value)
}
priv(self, 'length', priv(self, 'length') - hit.length)
priv(self, 'cache').delete(hit.key)
priv(self, 'lruList').removeNode(node)
}

@@ -347,26 +477,8 @@ }

// classy, since V8 prefers predictable objects.
function Entry (key, value, lu, length, now, maxAge) {
function Entry (key, value, length, now, maxAge) {
this.key = key
this.value = value
this.lu = lu
this.length = length
this.now = now
if (maxAge) this.maxAge = maxAge
this.maxAge = maxAge || 0
}
// Incrementers and decrementers that loop at MAX_SAFE_INTEGER
// only relevant for the lu, lru, and mru counters, since they
// get touched a lot and can get very large. Also, since they
// only go upwards, and the sets will tend to be much smaller than
// the max, we can very well assume that a very small number comes
// after a very large number, rather than before it.
var maxSafeInt = Number.MAX_SAFE_INTEGER || 9007199254740991
function intInc (number) {
return (number === maxSafeInt) ? 0 : number + 1
}
function incMru (self) {
do {
self._mru = intInc(self._mru)
} while (self._lruList.has(self._mru))
}
{
"name": "lru-cache",
"description": "A cache object that deletes the least-recently-used items.",
"version": "3.2.0",
"version": "4.0.0",
"author": "Isaac Z. Schlueter <i@izs.me>",

@@ -12,3 +12,4 @@ "keywords": [

"scripts": {
"test": "tap test --gc"
"test": "tap test --cov",
"posttest": "standard test/*.js lib/*.js"
},

@@ -18,9 +19,10 @@ "main": "lib/lru-cache.js",

"devDependencies": {
"tap": "^1.2.0",
"weak": ""
"standard": "^5.4.1",
"tap": "^2.3.3"
},
"license": "ISC",
"dependencies": {
"pseudomap": "^1.0.1"
"pseudomap": "^1.0.1",
"yallist": "^2.0.0"
}
}

@@ -5,2 +5,4 @@ # lru cache

[![Build Status](https://travis-ci.org/isaacs/node-lru-cache.svg?branch=master)](https://travis-ci.org/isaacs/node-lru-cache) [![Coverage Status](https://coveralls.io/repos/isaacs/node-lru-cache/badge.svg?service=github)](https://coveralls.io/github/isaacs/node-lru-cache)
## Usage:

@@ -69,5 +71,9 @@

Both of these will update the "recently used"-ness of the key.
They do what you think. `max` is optional and overrides the
cache `max` option if provided.
They do what you think. `maxAge` is optional and overrides the
cache `maxAge` option if provided.
If the key is not found, `get()` will return `undefined`.
The key and val can be any value.
* `peek(key)`

@@ -135,1 +141,5 @@

into the cache. The destination cache is reset before loading new entries
* `prune()`
Manually iterates over the entire cache proactively pruning old entries

@@ -1,9 +0,9 @@

var test = require("tap").test
, LRU = require("../")
var test = require('tap').test
var LRU = require('../')
test("basic", function (t) {
test('basic', function (t) {
var cache = new LRU({max: 10})
cache.set("key", "value")
t.equal(cache.get("key"), "value")
t.equal(cache.get("nada"), undefined)
cache.set('key', 'value')
t.equal(cache.get('key'), 'value')
t.equal(cache.get('nada'), undefined)
t.equal(cache.length, 1)

@@ -14,34 +14,34 @@ t.equal(cache.max, 10)

test("least recently set", function (t) {
test('least recently set', function (t) {
var cache = new LRU(2)
cache.set("a", "A")
cache.set("b", "B")
cache.set("c", "C")
t.equal(cache.get("c"), "C")
t.equal(cache.get("b"), "B")
t.equal(cache.get("a"), undefined)
cache.set('a', 'A')
cache.set('b', 'B')
cache.set('c', 'C')
t.equal(cache.get('c'), 'C')
t.equal(cache.get('b'), 'B')
t.equal(cache.get('a'), undefined)
t.end()
})
test("lru recently gotten", function (t) {
test('lru recently gotten', function (t) {
var cache = new LRU(2)
cache.set("a", "A")
cache.set("b", "B")
cache.get("a")
cache.set("c", "C")
t.equal(cache.get("c"), "C")
t.equal(cache.get("b"), undefined)
t.equal(cache.get("a"), "A")
cache.set('a', 'A')
cache.set('b', 'B')
cache.get('a')
cache.set('c', 'C')
t.equal(cache.get('c'), 'C')
t.equal(cache.get('b'), undefined)
t.equal(cache.get('a'), 'A')
t.end()
})
test("del", function (t) {
test('del', function (t) {
var cache = new LRU(2)
cache.set("a", "A")
cache.del("a")
t.equal(cache.get("a"), undefined)
cache.set('a', 'A')
cache.del('a')
t.equal(cache.get('a'), undefined)
t.end()
})
test("max", function (t) {
test('max', function (t) {
var cache = new LRU(3)

@@ -51,5 +51,6 @@

cache.max = 100
for (var i = 0; i < 100; i ++) cache.set(i, i)
var i
for (i = 0; i < 100; i++) cache.set(i, i)
t.equal(cache.length, 100)
for (var i = 0; i < 100; i ++) {
for (i = 0; i < 100; i++) {
t.equal(cache.get(i), i)

@@ -59,6 +60,6 @@ }

t.equal(cache.length, 3)
for (var i = 0; i < 97; i ++) {
for (i = 0; i < 97; i++) {
t.equal(cache.get(i), undefined)
}
for (var i = 98; i < 100; i ++) {
for (i = 98; i < 100; i++) {
t.equal(cache.get(i), i)

@@ -68,6 +69,6 @@ }

// now remove the max restriction, and try again.
cache.max = "hello"
for (var i = 0; i < 100; i ++) cache.set(i, i)
cache.max = 'hello'
for (i = 0; i < 100; i++) cache.set(i, i)
t.equal(cache.length, 100)
for (var i = 0; i < 100; i ++) {
for (i = 0; i < 100; i++) {
t.equal(cache.get(i), i)

@@ -78,6 +79,6 @@ }

t.equal(cache.length, 3)
for (var i = 0; i < 97; i ++) {
for (i = 0; i < 97; i++) {
t.equal(cache.get(i), undefined)
}
for (var i = 98; i < 100; i ++) {
for (i = 98; i < 100; i++) {
t.equal(cache.get(i), i)

@@ -88,16 +89,15 @@ }

test("reset", function (t) {
test('reset', function (t) {
var cache = new LRU(10)
cache.set("a", "A")
cache.set("b", "B")
cache.set('a', 'A')
cache.set('b', 'B')
cache.reset()
t.equal(cache.length, 0)
t.equal(cache.max, 10)
t.equal(cache.get("a"), undefined)
t.equal(cache.get("b"), undefined)
t.equal(cache.get('a'), undefined)
t.equal(cache.get('b'), undefined)
t.end()
})
test("basic with weighed length", function (t) {
test('basic with weighed length', function (t) {
var cache = new LRU({

@@ -110,6 +110,6 @@ max: 100,

})
cache.set("key", {val: "value", size: 50})
t.equal(cache.get("key").val, "value")
t.equal(cache.get("nada"), undefined)
t.equal(cache.lengthCalculator(cache.get("key"), 'key'), 50)
cache.set('key', {val: 'value', size: 50})
t.equal(cache.get('key').val, 'value')
t.equal(cache.get('nada'), undefined)
t.equal(cache.lengthCalculator(cache.get('key'), 'key'), 50)
t.equal(cache.length, 50)

@@ -120,4 +120,3 @@ t.equal(cache.max, 100)

test("weighed length item too large", function (t) {
test('weighed length item too large', function (t) {
var cache = new LRU({

@@ -130,26 +129,26 @@ max: 10,

// should fall out immediately
cache.set("key", {val: "value", size: 50})
cache.set('key', {val: 'value', size: 50})
t.equal(cache.length, 0)
t.equal(cache.get("key"), undefined)
t.equal(cache.get('key'), undefined)
t.end()
})
test("least recently set with weighed length", function (t) {
test('least recently set with weighed length', function (t) {
var cache = new LRU({
max:8,
max: 8,
length: function (item) { return item.length }
})
cache.set("a", "A")
cache.set("b", "BB")
cache.set("c", "CCC")
cache.set("d", "DDDD")
t.equal(cache.get("d"), "DDDD")
t.equal(cache.get("c"), "CCC")
t.equal(cache.get("b"), undefined)
t.equal(cache.get("a"), undefined)
cache.set('a', 'A')
cache.set('b', 'BB')
cache.set('c', 'CCC')
cache.set('d', 'DDDD')
t.equal(cache.get('d'), 'DDDD')
t.equal(cache.get('c'), 'CCC')
t.equal(cache.get('b'), undefined)
t.equal(cache.get('a'), undefined)
t.end()
})
test("lru recently gotten with weighed length", function (t) {
test('lru recently gotten with weighed length', function (t) {
var cache = new LRU({

@@ -159,16 +158,16 @@ max: 8,

})
cache.set("a", "A")
cache.set("b", "BB")
cache.set("c", "CCC")
cache.get("a")
cache.get("b")
cache.set("d", "DDDD")
t.equal(cache.get("c"), undefined)
t.equal(cache.get("d"), "DDDD")
t.equal(cache.get("b"), "BB")
t.equal(cache.get("a"), "A")
cache.set('a', 'A')
cache.set('b', 'BB')
cache.set('c', 'CCC')
cache.get('a')
cache.get('b')
cache.set('d', 'DDDD')
t.equal(cache.get('c'), undefined)
t.equal(cache.get('d'), 'DDDD')
t.equal(cache.get('b'), 'BB')
t.equal(cache.get('a'), 'A')
t.end()
})
test("lru recently updated with weighed length", function (t) {
test('lru recently updated with weighed length', function (t) {
var cache = new LRU({

@@ -178,24 +177,24 @@ max: 8,

})
cache.set("a", "A")
cache.set("b", "BB")
cache.set("c", "CCC")
t.equal(cache.length, 6) //CCC BB A
cache.set("a", "+A")
t.equal(cache.length, 7) //+A CCC BB
cache.set("b", "++BB")
t.equal(cache.length, 6) //++BB +A
t.equal(cache.get("c"), undefined)
cache.set('a', 'A')
cache.set('b', 'BB')
cache.set('c', 'CCC')
t.equal(cache.length, 6) // CCC BB A
cache.set('a', '+A')
t.equal(cache.length, 7) // +A CCC BB
cache.set('b', '++BB')
t.equal(cache.length, 6) // ++BB +A
t.equal(cache.get('c'), undefined)
cache.set("c", "oversized")
t.equal(cache.length, 6) //++BB +A
t.equal(cache.get("c"), undefined)
cache.set('c', 'oversized')
t.equal(cache.length, 6) // ++BB +A
t.equal(cache.get('c'), undefined)
cache.set("a", "oversized")
t.equal(cache.length, 4) //++BB
t.equal(cache.get("a"), undefined)
t.equal(cache.get("b"), "++BB")
cache.set('a', 'oversized')
t.equal(cache.length, 4) // ++BB
t.equal(cache.get('a'), undefined)
t.equal(cache.get('b'), '++BB')
t.end()
})
test("set returns proper booleans", function(t) {
test('set returns proper booleans', function (t) {
var cache = new LRU({

@@ -206,13 +205,13 @@ max: 5,

t.equal(cache.set("a", "A"), true)
t.equal(cache.set('a', 'A'), true)
// should return false for max exceeded
t.equal(cache.set("b", "donuts"), false)
t.equal(cache.set('b', 'donuts'), false)
t.equal(cache.set("b", "B"), true)
t.equal(cache.set("c", "CCCC"), true)
t.equal(cache.set('b', 'B'), true)
t.equal(cache.set('c', 'CCCC'), true)
t.end()
})
test("drop the old items", function(t) {
test('drop the old items', function (t) {
var cache = new LRU({

@@ -223,22 +222,22 @@ max: 5,

cache.set("a", "A")
cache.set('a', 'A')
setTimeout(function () {
cache.set("b", "b")
t.equal(cache.get("a"), "A")
cache.set('b', 'b')
t.equal(cache.get('a'), 'A')
}, 25)
setTimeout(function () {
cache.set("c", "C")
cache.set('c', 'C')
// timed out
t.notOk(cache.get("a"))
t.notOk(cache.get('a'))
}, 60 + 25)
setTimeout(function () {
t.notOk(cache.get("b"))
t.equal(cache.get("c"), "C")
t.notOk(cache.get('b'))
t.equal(cache.get('c'), 'C')
}, 90)
setTimeout(function () {
t.notOk(cache.get("c"))
t.notOk(cache.get('c'))
t.end()

@@ -248,3 +247,3 @@ }, 155)

test("individual item can have its own maxAge", function(t) {
test('manual pruning', function (t) {
var cache = new LRU({

@@ -255,10 +254,31 @@ max: 5,

cache.set("a", "A", 20)
cache.set('a', 'A')
cache.set('b', 'b')
cache.set('c', 'C')
setTimeout(function () {
t.notOk(cache.get("a"))
cache.prune()
t.notOk(cache.get('a'))
t.notOk(cache.get('b'))
t.notOk(cache.get('c'))
t.end()
}, 100)
})
test('individual item can have its own maxAge', function (t) {
var cache = new LRU({
max: 5,
maxAge: 50
})
cache.set('a', 'A', 20)
setTimeout(function () {
t.notOk(cache.get('a'))
t.end()
}, 25)
})
test("individual item can have its own maxAge > cache's", function(t) {
test('individual item can have its own maxAge > cache', function (t) {
var cache = new LRU({

@@ -269,5 +289,5 @@ max: 5,

cache.set("a", "A", 50)
cache.set('a', 'A', 50)
setTimeout(function () {
t.equal(cache.get("a"), "A")
t.equal(cache.get('a'), 'A')
t.end()

@@ -277,3 +297,3 @@ }, 25)

test("disposal function", function(t) {
test('disposal function', function (t) {
var disposed = false

@@ -290,4 +310,6 @@ var cache = new LRU({

t.equal(disposed, 1)
cache.set(2, 10)
t.equal(disposed, 2)
cache.set(3, 3)
t.equal(disposed, 2)
t.equal(disposed, 10)
cache.reset()

@@ -298,3 +320,3 @@ t.equal(disposed, 3)

test("disposal function on too big of item", function(t) {
test('disposal function on too big of item', function (t) {
var disposed = false

@@ -313,3 +335,3 @@ var cache = new LRU({

t.equal(disposed, false)
cache.set("obj", obj)
cache.set('obj', obj)
t.equal(disposed, obj)

@@ -319,3 +341,3 @@ t.end()

test("has()", function(t) {
test('has()', function (t) {
var cache = new LRU({

@@ -331,3 +353,3 @@ max: 1,

t.equal(cache.has('blu'), true)
setTimeout(function() {
setTimeout(function () {
t.equal(cache.has('blu'), false)

@@ -338,3 +360,3 @@ t.end()

test("stale", function(t) {
test('stale', function (t) {
var cache = new LRU({

@@ -345,6 +367,8 @@ maxAge: 10,

t.equal(cache.allowStale, true)
cache.set('foo', 'bar')
t.equal(cache.get('foo'), 'bar')
t.equal(cache.has('foo'), true)
setTimeout(function() {
setTimeout(function () {
t.equal(cache.has('foo'), false)

@@ -357,10 +381,10 @@ t.equal(cache.get('foo'), 'bar')

test("lru update via set", function(t) {
var cache = LRU({ max: 2 });
test('lru update via set', function (t) {
var cache = LRU({ max: 2 })
cache.set('foo', 1);
cache.set('bar', 2);
cache.del('bar');
cache.set('baz', 3);
cache.set('qux', 4);
cache.set('foo', 1)
cache.set('bar', 2)
cache.del('bar')
cache.set('baz', 3)
cache.set('qux', 4)

@@ -374,21 +398,21 @@ t.equal(cache.get('foo'), undefined)

test("least recently set w/ peek", function (t) {
test('least recently set w/ peek', function (t) {
var cache = new LRU(2)
cache.set("a", "A")
cache.set("b", "B")
t.equal(cache.peek("a"), "A")
cache.set("c", "C")
t.equal(cache.get("c"), "C")
t.equal(cache.get("b"), "B")
t.equal(cache.get("a"), undefined)
cache.set('a', 'A')
cache.set('b', 'B')
t.equal(cache.peek('a'), 'A')
cache.set('c', 'C')
t.equal(cache.get('c'), 'C')
t.equal(cache.get('b'), 'B')
t.equal(cache.get('a'), undefined)
t.end()
})
test("pop the least used item", function (t) {
test('pop the least used item', function (t) {
var cache = new LRU(3)
, last
var last
cache.set("a", "A")
cache.set("b", "B")
cache.set("c", "C")
cache.set('a', 'A')
cache.set('b', 'B')
cache.set('c', 'C')

@@ -399,7 +423,7 @@ t.equal(cache.length, 3)

// Ensure we pop a, c, b
cache.get("b", "B")
cache.get('b', 'B')
last = cache.pop()
t.equal(last.key, "a")
t.equal(last.value, "A")
t.equal(last.key, 'a')
t.equal(last.value, 'A')
t.equal(cache.length, 2)

@@ -409,4 +433,4 @@ t.equal(cache.max, 3)

last = cache.pop()
t.equal(last.key, "c")
t.equal(last.value, "C")
t.equal(last.key, 'c')
t.equal(last.value, 'C')
t.equal(cache.length, 1)

@@ -416,4 +440,4 @@ t.equal(cache.max, 3)

last = cache.pop()
t.equal(last.key, "b")
t.equal(last.value, "B")
t.equal(last.key, 'b')
t.equal(last.value, 'B')
t.equal(cache.length, 0)

@@ -430,9 +454,9 @@ t.equal(cache.max, 3)

test("get and set only accepts strings and numbers as keys", function(t) {
test('get and set only accepts strings and numbers as keys', function (t) {
var cache = new LRU()
cache.set("key", "value")
cache.set('key', 'value')
cache.set(123, 456)
t.equal(cache.get("key"), "value")
t.equal(cache.get('key'), 'value')
t.equal(cache.get(123), 456)

@@ -443,13 +467,13 @@

test("peek with wierd keys", function(t) {
test('peek with wierd keys', function (t) {
var cache = new LRU()
cache.set("key", "value")
cache.set('key', 'value')
cache.set(123, 456)
t.equal(cache.peek("key"), "value")
t.equal(cache.peek('key'), 'value')
t.equal(cache.peek(123), 456)
t.equal(cache.peek({
toString: function() { return "key" }
toString: function () { return 'key' }
}), undefined)

@@ -459,1 +483,70 @@

})
test('invalid length calc results in basic length', function (t) {
var l = new LRU({ length: true })
t.isa(l.lengthCalculator, 'function')
l.lengthCalculator = 'not a function'
t.isa(l.lengthCalculator, 'function')
t.end()
})
test('change length calculator recalculates', function (t) {
var l = new LRU({ max: 3 })
l.set(2, 2)
l.set(1, 1)
l.lengthCalculator = function (key, val) {
return key + val
}
t.equal(l.itemCount, 1)
t.equal(l.get(2), undefined)
t.equal(l.get(1), 1)
l.set(0, 1)
t.equal(l.itemCount, 2)
l.lengthCalculator = function (key, val) {
return key
}
t.equal(l.lengthCalculator(1, 10), 1)
t.equal(l.lengthCalculator(10, 1), 10)
l.lengthCalculator = { not: 'a function' }
t.equal(l.lengthCalculator(1, 10), 1)
t.equal(l.lengthCalculator(10, 1), 1)
t.end()
})
test('delete non-existent item has no effect', function (t) {
var l = new LRU({ max: 2 })
l.set('foo', 1)
l.set('bar', 2)
l.del('baz')
t.same(l.dumpLru().toArray().map(function (hit) {
return hit.key
}), [ 'bar', 'foo' ])
t.end()
})
test('maxAge on list, cleared in forEach', function (t) {
var l = new LRU({ stale: true })
l.set('foo', 1)
// hacky. make it seem older.
l.dumpLru().head.value.now = Date.now() - 100000
// setting maxAge to invalid values does nothing.
t.equal(l.maxAge, 0)
l.maxAge = -100
t.equal(l.maxAge, 0)
l.maxAge = {}
t.equal(l.maxAge, 0)
l.maxAge = 1
var saw = false
l.forEach(function (val, key) {
saw = true
t.equal(key, 'foo')
})
t.ok(saw)
t.equal(l.length, 0)
t.end()
})

@@ -6,7 +6,8 @@ var test = require('tap').test

var l = new LRU(5)
for (var i = 0; i < 10; i ++) {
var i
for (i = 0; i < 10; i++) {
l.set(i, i.toString(2))
}
var i = 9
i = 9
l.forEach(function (val, key, cache) {

@@ -24,6 +25,6 @@ t.equal(cache, l)

var order = [ 8, 6, 9, 7, 5 ]
var i = 0
i = 0
l.forEach(function (val, key, cache) {
var j = order[i ++]
var j = order[i++]
t.equal(cache, l)

@@ -38,3 +39,3 @@ t.equal(key, j)

l.rforEach(function (val, key, cache) {
var j = order[i ++]
var j = order[i++]
t.equal(cache, l)

@@ -51,3 +52,4 @@ t.equal(key, j)

var l = new LRU(5)
for (var i = 0; i < 10; i ++) {
var i
for (i = 0; i < 10; i++) {
l.set(i, i.toString(2))

@@ -69,9 +71,10 @@ }

test('all entries are iterated over', function(t) {
test('all entries are iterated over', function (t) {
var l = new LRU(5)
for (var i = 0; i < 10; i ++) {
var i
for (i = 0; i < 10; i++) {
l.set(i.toString(), i.toString(2))
}
var i = 0
i = 0
l.forEach(function (val, key, cache) {

@@ -90,9 +93,10 @@ if (i > 0) {

test('all stale entries are removed', function(t) {
test('all stale entries are removed', function (t) {
var l = new LRU({ max: 5, maxAge: -5, stale: true })
for (var i = 0; i < 10; i ++) {
var i
for (i = 0; i < 10; i++) {
l.set(i.toString(), i.toString(2))
}
var i = 0
i = 0
l.forEach(function () {

@@ -113,7 +117,8 @@ i += 1

})
for (var i = 0; i < 10; i++) {
var i
for (i = 0; i < 10; i++) {
l.set(i.toString(), i.toString(2), ((i % 2) ? 25 : undefined))
}
var i = 0
i = 0
var order = [ 8, 6, 4, 2, 0 ]

@@ -127,12 +132,11 @@ setTimeout(function () {

})
t.equal(i, order.length);
t.equal(i, order.length)
setTimeout(function () {
var count = 0;
l.forEach(function (val, key, cache) { count++; })
t.equal(0, count);
var count = 0
l.forEach(function (val, key, cache) { count++ })
t.equal(0, count)
t.end()
}, 25)
}, 26)
})
var test = require('tap').test
var LRU = require('../')
var Yallist = require('yallist')

@@ -7,9 +8,9 @@ test('dump', function (t) {

t.equal(cache.dump().length, 0, "nothing in dump for empty cache")
t.equal(cache.dump().length, 0, 'nothing in dump for empty cache')
cache.set("a", "A")
cache.set("b", "B")
cache.set('a', 'A')
cache.set('b', 'B')
t.deepEqual(cache.dump(), [
{ k: "b", v: "B", e: 0 },
{ k: "a", v: "A", e: 0 }
{ k: 'b', v: 'B', e: 0 },
{ k: 'a', v: 'A', e: 0 }
])

@@ -20,22 +21,22 @@

{ k: 123, v: 456, e: 0 },
{ k: "b", v: "B", e: 0 },
{ k: "a", v: "A", e: 0 },
{ k: 'b', v: 'B', e: 0 },
{ k: 'a', v: 'A', e: 0 }
])
cache.del(123)
cache.set("a", "A");
cache.set('a', 'A')
t.deepEqual(cache.dump(), [
{ k: "a", v: "A", e: 0 },
{ k: "b", v: "B", e: 0 }
{ k: 'a', v: 'A', e: 0 },
{ k: 'b', v: 'B', e: 0 }
])
cache.get("b");
cache.get('b')
t.deepEqual(cache.dump(), [
{ k: "b", v: "B", e: 0 },
{ k: "a", v: "A", e: 0 }
{ k: 'b', v: 'B', e: 0 },
{ k: 'a', v: 'A', e: 0 }
])
cache.del("a");
cache.del('a')
t.deepEqual(cache.dump(), [
{ k: "b", v: "B", e: 0 }
{ k: 'b', v: 'B', e: 0 }
])

@@ -46,3 +47,3 @@

test("do not dump stale items", function(t) {
test('do not dump stale items', function (t) {
var cache = new LRU({

@@ -53,30 +54,30 @@ max: 5,

//expires at 50
cache.set("a", "A")
// expires at 50
cache.set('a', 'A')
setTimeout(function () {
//expires at 75
cache.set("b", "B")
// expires at 75
cache.set('b', 'B')
var s = cache.dump()
t.equal(s.length, 2)
t.equal(s[0].k, "b")
t.equal(s[1].k, "a")
t.equal(s[0].k, 'b')
t.equal(s[1].k, 'a')
}, 25)
setTimeout(function () {
//expires at 110
cache.set("c", "C")
// expires at 110
cache.set('c', 'C')
var s = cache.dump()
t.equal(s.length, 2)
t.equal(s[0].k, "c")
t.equal(s[1].k, "b")
t.equal(s[0].k, 'c')
t.equal(s[1].k, 'b')
}, 60)
setTimeout(function () {
//expires at 130
cache.set("d", "D", 40)
// expires at 130
cache.set('d', 'D', 40)
var s = cache.dump()
t.equal(s.length, 2)
t.equal(s[0].k, "d")
t.equal(s[1].k, "c")
t.equal(s[0].k, 'd')
t.equal(s[1].k, 'c')
}, 90)

@@ -87,3 +88,3 @@

t.equal(s.length, 1)
t.equal(s[0].k, "d")
t.equal(s[0].k, 'd')
}, 120)

@@ -98,8 +99,8 @@

test("load basic cache", function(t) {
var cache = new LRU(),
copy = new LRU()
test('load basic cache', function (t) {
var cache = new LRU()
var copy = new LRU()
cache.set("a", "A")
cache.set("b", "B")
cache.set('a', 'A')
cache.set('b', 'B')
cache.set(123, 456)

@@ -113,13 +114,12 @@

test('load staled cache', function (t) {
var cache = new LRU({maxAge: 50})
var copy = new LRU({maxAge: 50})
var arr
test("load staled cache", function(t) {
var cache = new LRU({maxAge: 50}),
copy = new LRU({maxAge: 50}),
arr
//expires at 50
cache.set("a", "A")
// expires at 50
cache.set('a', 'A')
setTimeout(function () {
//expires at 80
cache.set("b", "B")
// expires at 80
cache.set('b', 'B')
arr = cache.dump()

@@ -131,8 +131,8 @@ t.equal(arr.length, 2)

copy.load(arr)
t.equal(copy.get("a"), undefined)
t.equal(copy.get("b"), "B")
t.equal(copy.get('a'), undefined)
t.equal(copy.get('b'), 'B')
}, 60)
setTimeout(function () {
t.equal(copy.get("b"), undefined)
t.equal(copy.get('b'), undefined)
t.end()

@@ -142,18 +142,18 @@ }, 90)

test("load to other size cache", function(t) {
var cache = new LRU({max: 2}),
copy = new LRU({max: 1})
test('load to other size cache', function (t) {
var cache = new LRU({max: 2})
var copy = new LRU({max: 1})
cache.set("a", "A")
cache.set("b", "B")
cache.set('a', 'A')
cache.set('b', 'B')
copy.load(cache.dump())
t.equal(copy.get("a"), undefined)
t.equal(copy.get("b"), "B")
t.equal(copy.get('a'), undefined)
t.equal(copy.get('b'), 'B')
//update the last read from original cache
cache.get("a")
// update the last read from original cache
cache.get('a')
copy.load(cache.dump())
t.equal(copy.get("a"), "A")
t.equal(copy.get("b"), undefined)
t.equal(copy.get('a'), 'A')
t.equal(copy.get('b'), undefined)

@@ -163,72 +163,75 @@ t.end()

test('load to other age cache', function (t) {
var cache = new LRU({maxAge: 250})
var aged = new LRU({maxAge: 500})
var simple = new LRU()
var arr
test("load to other age cache", function(t) {
var cache = new LRU({maxAge: 50}),
aged = new LRU({maxAge: 100}),
simple = new LRU(),
arr,
expired
//created at 0
//a would be valid till 0 + 50
cache.set("a", "A")
// created at 0
// a would be valid till 0 + 250
cache.set('a', 'A')
setTimeout(function () {
//created at 20
//b would be valid till 20 + 50
cache.set("b", "B")
//b would be valid till 20 + 70
cache.set("c", "C", 70)
// created at 20
// b would be valid till 100 + 250
cache.set('b', 'B')
// b would be valid till 100 + 350
cache.set('c', 'C', 350)
arr = cache.dump()
t.equal(arr.length, 3)
}, 20)
}, 100)
setTimeout(function () {
t.equal(cache.get("a"), undefined)
t.equal(cache.get("b"), "B")
t.equal(cache.get("c"), "C")
t.equal(cache.get('a'), undefined)
t.equal(cache.get('b'), 'B')
t.equal(cache.get('c'), 'C')
aged.load(arr)
t.equal(aged.get("a"), undefined)
t.equal(aged.get("b"), "B")
t.equal(aged.get("c"), "C")
t.equal(aged.get('a'), undefined)
t.equal(aged.get('b'), 'B')
t.equal(aged.get('c'), 'C')
simple.load(arr)
t.equal(simple.get("a"), undefined)
t.equal(simple.get("b"), "B")
t.equal(simple.get("c"), "C")
}, 60)
t.equal(simple.get('a'), undefined)
t.equal(simple.get('b'), 'B')
t.equal(simple.get('c'), 'C')
}, 300)
setTimeout(function () {
t.equal(cache.get("a"), undefined)
t.equal(cache.get("b"), undefined)
t.equal(cache.get("c"), "C")
t.equal(cache.get('a'), undefined)
t.equal(cache.get('b'), undefined)
t.equal(cache.get('c'), 'C')
aged.load(arr)
t.equal(aged.get("a"), undefined)
t.equal(aged.get("b"), undefined)
t.equal(aged.get("c"), "C")
t.equal(aged.get('a'), undefined)
t.equal(aged.get('b'), undefined)
t.equal(aged.get('c'), 'C')
simple.load(arr)
t.equal(simple.get("a"), undefined)
t.equal(simple.get("b"), undefined)
t.equal(simple.get("c"), "C")
}, 80)
t.equal(simple.get('a'), undefined)
t.equal(simple.get('b'), undefined)
t.equal(simple.get('c'), 'C')
}, 400)
setTimeout(function () {
t.equal(cache.get("a"), undefined)
t.equal(cache.get("b"), undefined)
t.equal(cache.get("c"), undefined)
t.equal(cache.get('a'), undefined)
t.equal(cache.get('b'), undefined)
t.equal(cache.get('c'), undefined)
aged.load(arr)
t.equal(aged.get("a"), undefined)
t.equal(aged.get("b"), undefined)
t.equal(aged.get("c"), undefined)
t.equal(aged.get('a'), undefined)
t.equal(aged.get('b'), undefined)
t.equal(aged.get('c'), undefined)
simple.load(arr)
t.equal(simple.get("a"), undefined)
t.equal(simple.get("b"), undefined)
t.equal(simple.get("c"), undefined)
t.equal(simple.get('a'), undefined)
t.equal(simple.get('b'), undefined)
t.equal(simple.get('c'), undefined)
t.end()
}, 100)
}, 500)
})
test('dumpLru', function (t) {
var l = LRU()
t.isa(l.dumpLru(), Yallist)
t.end()
})

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc