Socket
Socket
Sign inDemoInstall

lru

Package Overview
Dependencies
1
Maintainers
2
Versions
16
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0 to 2.0.1

18

example/usage.js
var LRU = require('../')
var cache = new LRU(2);
var cache = new LRU(2)
var evicted
cache.on('evict',function(data) { evicted = data })
cache.on('evict', function (data) {
evicted = data
})
cache.set('foo', 'bar'); // => 'bar'
cache.get('foo'); // => 'bar'
cache.set('foo', 'bar') // => 'bar'
cache.get('foo') // => 'bar'
cache.set('foo2', 'bar2'); // => 'bar2'
cache.get('foo2'); // => 'bar2'
cache.set('foo2', 'bar2') // => 'bar2'
cache.get('foo2') // => 'bar2'
cache.set('foo3', 'bar3'); // => 'bar3'
cache.get('foo3'); // => 'bar3'
cache.set('foo3', 'bar3') // => 'bar3'
cache.get('foo3') // => 'bar3'

@@ -18,0 +20,0 @@ console.log(cache.remove('foo2')) // => { key: 'foo2', value: 'bar2' }

@@ -1,41 +0,47 @@

var events = require('events');
var util = require('util');
var events = require('events')
var inherits = require('inherits')
var LRU = module.exports = function (opts) {
if (!(this instanceof LRU)) return new LRU(opts);
if (typeof opts === 'number') opts = {max: opts};
if (!opts) opts = {};
events.EventEmitter.call(this);
this.cache = {}
this.head = this.tail = null;
this.length = 0;
this.max = opts.max || 1000;
this.maxAge = opts.maxAge || 0;
};
util.inherits(LRU, events.EventEmitter);
module.exports = LRU
function LRU (opts) {
if (!(this instanceof LRU)) return new LRU(opts)
if (typeof opts === 'number') opts = {max: opts}
if (!opts) opts = {}
events.EventEmitter.call(this)
this.cache = {}
this.head = this.tail = null
this.length = 0
this.max = opts.max || 1000
this.maxAge = opts.maxAge || 0
}
inherits(LRU, events.EventEmitter)
LRU.prototype.remove = function (key) {
if (!this.cache.hasOwnProperty(key)) return;
if (typeof key !== 'string') key = '' + key
if (!this.cache.hasOwnProperty(key)) return
var element = this.cache[key];
delete this.cache[key];
var element = this.cache[key]
delete this.cache[key]
this._unlink(key, element.prev, element.next)
return element.value
}
--this.length;
LRU.prototype._unlink = function (key, prev, next) {
this.length--
if (this.length === 0) {
this.head = this.tail = null;
if (this.length === 0) {
this.head = this.tail = null
} else {
if (this.head === key) {
this.head = prev
this.cache[this.head].next = null
} else if (this.tail === key) {
this.tail = next
this.cache[this.tail].prev = null
} else {
if (this.head == key) {
this.head = element.prev;
this.cache[this.head].next = null;
} else if (this.tail == key) {
this.tail = element.next;
this.cache[this.tail].prev = null;
} else {
this.cache[element.prev].next = element.next;
this.cache[element.next].prev = element.prev;
}
this.cache[prev].next = next
this.cache[next].prev = prev
}
return element.value;
}
}

@@ -48,77 +54,73 @@

LRU.prototype.set = function (key, value) {
var element;
if( this.cache.hasOwnProperty(key) ) {
element = this.cache[key]
element.value = value
if (this.maxAge) element.modified = Date.now();
if (typeof key !== 'string') key = '' + key
// If it's already the head, there's nothing more to do:
if( key === this.head ) {
return value;
}
} else {
element = { value:value };
if (this.maxAge) element.modified = Date.now();
var element
this.cache[key] = element;
if (this.cache.hasOwnProperty(key)) {
element = this.cache[key]
element.value = value
if (this.maxAge) element.modified = Date.now()
// Eviction is only possible if the key didn't already exist:
if (this.length === this.max) {
this.evict();
}
++this.length;
}
// If it's already the head, there's nothing more to do:
if (key === this.head) return value
this._unlink(key, element.prev, element.next)
} else {
element = {value: value, modified: 0, next: null, prev: null}
if (this.maxAge) element.modified = Date.now()
this.cache[key] = element
element.next = null;
element.prev = this.head;
// Eviction is only possible if the key didn't already exist:
if (this.length === this.max) this.evict()
}
if (this.head) {
this.cache[this.head].next = key;
}
this.head = key;
this.length++
element.next = null
element.prev = this.head
if(!this.tail) {
this.tail = key;
}
if (this.head) this.cache[this.head].next = key
this.head = key
return value
};
if (!this.tail) this.tail = key
return value
}
LRU.prototype.get = function (key) {
if (!this.cache.hasOwnProperty(key)) return;
var element = this.cache[key];
if (typeof key !== 'string') key = '' + key
if (!this.cache.hasOwnProperty(key)) return
if (this.maxAge && (Date.now() - element.modified) > this.maxAge) {
this.remove(key);
this.emit('evict', {key:key, value:element.value});
return;
var element = this.cache[key]
if (this.maxAge && (Date.now() - element.modified) > this.maxAge) {
this.remove(key)
this.emit('evict', {key: key, value: element.value})
return
}
if (this.head !== key) {
if (key === this.tail) {
this.tail = element.next
this.cache[this.tail].prev = null
} else {
// Set prev.next -> element.next:
this.cache[element.prev].next = element.next
}
if( this.head !== key ) {
if (key === this.tail) {
this.tail = element.next;
this.cache[this.tail].prev = null;
} else {
// Set prev.next -> element.next:
this.cache[element.prev].next = element.next;
}
// Set element.next.prev -> element.prev:
this.cache[element.next].prev = element.prev
// Set element.next.prev -> element.prev:
this.cache[element.next].prev = element.prev;
// Element is the new head
this.cache[this.head].next = key
element.prev = this.head
element.next = null
this.head = key
}
// Element is the new head
this.cache[this.head].next = key;
element.prev = this.head;
element.next = null;
this.head = key;
}
return element.value
}
return element.value;
};
LRU.prototype.evict = function () {
if(!this.tail) { return; }
var key = this.tail;
var removedValue = this.remove(this.tail);
this.emit('evict', {key:key, value:removedValue});
};
if (!this.tail) return
var key = this.tail
var value = this.remove(this.tail)
this.emit('evict', {key: key, value: value})
}
{
"name": "lru",
"description": "A simple O(1) LRU cache",
"version": "2.0.0",
"version": "2.0.1",
"author": "Chris O'Hara <cohara87@gmail.com>",

@@ -20,8 +20,11 @@ "main": "index",

"devDependencies": {
"standard": "^6.0.8",
"vows": "^0.8.1"
},
"scripts": {
"test": "vows test/*.js --spec"
"test": "standard && vows test/*.js --spec"
},
"dependencies": {}
"dependencies": {
"inherits": "^2.0.1"
}
}

@@ -1,55 +0,55 @@

var assert = require('assert');
var vows = require('vows');
var LRU = require('../');
var assert = require('assert')
var vows = require('vows')
var LRU = require('../')
function keys(obj) {
var result = [];
for(k in obj) {
if(obj.hasOwnProperty(k)) {
result.push(k);
function keys (obj) {
var result = []
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
result.push(k)
}
}
return result;
return result
}
var suite = vows.describe('LRU');
var suite = vows.describe('LRU')
suite.addBatch({
"setting keys doesn't grow past max size": function() {
var lru = new LRU(3);
assert.equal(0, lru.length);
lru.set('foo1', 'bar1');
assert.equal(1, lru.length);
lru.set('foo2', 'bar2');
assert.equal(2, lru.length);
lru.set('foo3', 'bar3');
assert.equal(3, lru.length);
'setting keys doesn\'t grow past max size': function () {
var lru = new LRU(3)
assert.equal(0, lru.length)
lru.set('foo1', 'bar1')
assert.equal(1, lru.length)
lru.set('foo2', 'bar2')
assert.equal(2, lru.length)
lru.set('foo3', 'bar3')
assert.equal(3, lru.length)
lru.set('foo4', 'bar4');
assert.equal(3, lru.length);
lru.set('foo4', 'bar4')
assert.equal(3, lru.length)
}
});
})
suite.addBatch({
"setting keys returns the value": function() {
var lru = new LRU(2);
assert.equal('bar1', lru.set('foo1', 'bar1'));
assert.equal('bar2', lru.set('foo2', 'bar2'));
assert.equal('bar3', lru.set('foo3', 'bar3'));
assert.equal('bar2', lru.get('foo2'));
assert.equal(undefined, lru.get('foo1'));
assert.equal('bar1', lru.set('foo1','bar1'));
'setting keys returns the value': function () {
var lru = new LRU(2)
assert.equal('bar1', lru.set('foo1', 'bar1'))
assert.equal('bar2', lru.set('foo2', 'bar2'))
assert.equal('bar3', lru.set('foo3', 'bar3'))
assert.equal('bar2', lru.get('foo2'))
assert.equal(undefined, lru.get('foo1'))
assert.equal('bar1', lru.set('foo1', 'bar1'))
}
});
})
suite.addBatch({
"lru invariant is maintained for set()": function() {
var lru = new LRU(2);
'lru invariant is maintained for set()': function () {
var lru = new LRU(2)
lru.set('foo1', 'bar1');
lru.set('foo2', 'bar2');
lru.set('foo3', 'bar3');
lru.set('foo4', 'bar4');
lru.set('foo1', 'bar1')
lru.set('foo2', 'bar2')
lru.set('foo3', 'bar3')
lru.set('foo4', 'bar4')
assert.deepEqual(['foo3','foo4'], keys(lru.cache));
assert.deepEqual(['foo3', 'foo4'], keys(lru.cache))
}

@@ -59,7 +59,7 @@ })

suite.addBatch({
"ovrewriting a key updates the value": function() {
var lru = new LRU(2);
lru.set('foo1', 'bar1');
'ovrewriting a key updates the value': function () {
var lru = new LRU(2)
lru.set('foo1', 'bar1')
assert.equal('bar1', lru.get('foo1'))
lru.set('foo1', 'bar2');
lru.set('foo1', 'bar2')
assert.equal('bar2', lru.get('foo1'))

@@ -70,63 +70,63 @@ }

suite.addBatch({
"lru invariant is maintained for get()": function() {
var lru = new LRU(2);
'lru invariant is maintained for get()': function () {
var lru = new LRU(2)
lru.set('foo1', 'bar1');
lru.set('foo2', 'bar2');
lru.set('foo1', 'bar1')
lru.set('foo2', 'bar2')
lru.get('foo1'); //now foo2 should be deleted instead of foo1
lru.get('foo1') // now foo2 should be deleted instead of foo1
lru.set('foo3', 'bar3');
lru.set('foo3', 'bar3')
assert.deepEqual(['foo1','foo3'], keys(lru.cache));
assert.deepEqual(['foo1', 'foo3'], keys(lru.cache))
},
"lru invariant is maintained after set(), get() and remove()": function() {
var lru = new LRU(2);
lru.set('a', 1);
lru.set('b', 2);
assert.deepEqual(lru.get('a'), 1);
lru.remove('a');
lru.set('c', 1);
lru.set('d', 1);
assert.deepEqual(['c','d'], keys(lru.cache));
'lru invariant is maintained after set(), get() and remove()': function () {
var lru = new LRU(2)
lru.set('a', 1)
lru.set('b', 2)
assert.deepEqual(lru.get('a'), 1)
lru.remove('a')
lru.set('c', 1)
lru.set('d', 1)
assert.deepEqual(['c', 'd'], keys(lru.cache))
}
});
})
suite.addBatch({
"lru invariant is maintained for get()": function() {
var lru = new LRU(2);
'lru invariant is maintained for get()': function () {
var lru = new LRU(2)
lru.set('foo1', 'bar1');
lru.set('foo2', 'bar2');
lru.set('foo1', 'bar1')
lru.set('foo2', 'bar2')
lru.get('foo2'); //now foo2 should be deleted instead of foo1
lru.get('foo2') // now foo2 should be deleted instead of foo1
lru.set('foo3', 'bar3');
lru.set('foo3', 'bar3')
assert.deepEqual(['foo2','foo3'], keys(lru.cache));
assert.deepEqual(['foo2', 'foo3'], keys(lru.cache))
},
"lru invariant is maintained in the corner case size == 1": function() {
var lru = new LRU(1);
'lru invariant is maintained in the corner case size == 1': function () {
var lru = new LRU(1)
lru.set('foo1', 'bar1');
lru.set('foo2', 'bar2');
lru.set('foo1', 'bar1')
lru.set('foo2', 'bar2')
lru.get('foo2'); //now foo2 should be deleted instead of foo1
lru.get('foo2') // now foo2 should be deleted instead of foo1
lru.set('foo3', 'bar3');
lru.set('foo3', 'bar3')
assert.deepEqual(['foo3'], keys(lru.cache));
assert.deepEqual(['foo3'], keys(lru.cache))
}
});
})
suite.addBatch({
"get() returns item value": function() {
'get() returns item value': function () {
var lru = new LRU(2)
assert.equal( lru.set('foo','bar'), 'bar')
assert.equal(lru.set('foo', 'bar'), 'bar')
}
});
})
suite.addBatch({
"peek() returns item value without changing the order": function() {
'peek() returns item value without changing the order': function () {
var lru = new LRU(2)

@@ -139,117 +139,117 @@ lru.set('foo', 'bar')

}
});
})
suite.addBatch({
"evicting items by age": {
'evicting items by age': {
topic: function () {
var lru = new LRU({maxAge: 5});
lru.set('foo', 'bar');
assert.equal(lru.get('foo'), 'bar');
var lru = new LRU({maxAge: 5})
lru.set('foo', 'bar')
assert.equal(lru.get('foo'), 'bar')
var callback = this.callback
setTimeout(function () {
callback(null, lru);
}, 100);
callback(null, lru)
}, 100)
},
"the entry is removed if age > max_age": function(lru) {
assert.equal(lru.get('foo'), null);
},
'the entry is removed if age > max_age': function (lru) {
assert.equal(lru.get('foo'), null)
}
},
"evicting items by age (2)": {
'evicting items by age (2)': {
topic: function () {
var lru = new LRU({maxAge: 100000});
lru.set('foo', 'bar');
assert.equal(lru.get('foo'), 'bar');
var lru = new LRU({maxAge: 100000})
lru.set('foo', 'bar')
assert.equal(lru.get('foo'), 'bar')
var callback = this.callback
setTimeout(function () {
callback(null, lru);
}, 100);
callback(null, lru)
}, 100)
},
"the entry is not removed if age < max_age": function(lru) {
assert.equal(lru.get('foo'), 'bar');
'the entry is not removed if age < max_age': function (lru) {
assert.equal(lru.get('foo'), 'bar')
}
}
});
})
suite.addBatch({
"idempotent 'changes'": {
"set() and remove() on empty LRU is idempotent": function() {
var lru = new LRU();
var json1 = JSON.stringify(lru);
'idempotent changes': {
'set() and remove() on empty LRU is idempotent': function () {
var lru = new LRU()
var json1 = JSON.stringify(lru)
lru.set('foo1', 'bar1');
lru.remove('foo1');
var json2 = JSON.stringify(lru);
lru.set('foo1', 'bar1')
lru.remove('foo1')
var json2 = JSON.stringify(lru)
assert.deepEqual(json2, json1);
assert.deepEqual(json2, json1)
},
"2 set()s and 2 remove()s on empty LRU is idempotent": function() {
var lru = new LRU();
var json1 = JSON.stringify(lru);
'2 set()s and 2 remove()s on empty LRU is idempotent': function () {
var lru = new LRU()
var json1 = JSON.stringify(lru)
lru.set('foo1', 'bar1');
lru.set('foo2', 'bar2');
lru.remove('foo1');
lru.remove('foo2');
var json2 = JSON.stringify(lru);
lru.set('foo1', 'bar1')
lru.set('foo2', 'bar2')
lru.remove('foo1')
lru.remove('foo2')
var json2 = JSON.stringify(lru)
assert.deepEqual(json2, json1);
assert.deepEqual(json2, json1)
},
"2 set()s and 2 remove()s (in opposite order) on empty LRU is idempotent": function() {
var lru = new LRU();
var json1 = JSON.stringify(lru);
'2 set()s and 2 remove()s (in opposite order) on empty LRU is idempotent': function () {
var lru = new LRU()
var json1 = JSON.stringify(lru)
lru.set('foo1', 'bar1');
lru.set('foo2', 'bar2');
lru.remove('foo2');
lru.remove('foo1');
var json2 = JSON.stringify(lru);
lru.set('foo1', 'bar1')
lru.set('foo2', 'bar2')
lru.remove('foo2')
lru.remove('foo1')
var json2 = JSON.stringify(lru)
assert.deepEqual(json2, json1);
assert.deepEqual(json2, json1)
},
"after setting one key, get() is idempotent" : function() {
var lru = new LRU(2);
lru.set('a', 'a');
var json1 = JSON.stringify(lru);
'after setting one key, get() is idempotent': function () {
var lru = new LRU(2)
lru.set('a', 'a')
var json1 = JSON.stringify(lru)
lru.get('a');
var json2 = JSON.stringify(lru);
lru.get('a')
var json2 = JSON.stringify(lru)
assert.equal(json2, json1);
assert.equal(json2, json1)
},
"after setting two keys, get() on last-set key is idempotent" : function() {
var lru = new LRU(2);
lru.set('a', 'a');
lru.set('b', 'b');
var json1 = JSON.stringify(lru);
'after setting two keys, get() on last-set key is idempotent': function () {
var lru = new LRU(2)
lru.set('a', 'a')
lru.set('b', 'b')
var json1 = JSON.stringify(lru)
lru.get('b');
var json2 = JSON.stringify(lru);
lru.get('b')
var json2 = JSON.stringify(lru)
assert.equal(json2, json1);
assert.equal(json2, json1)
}
}
});
})
suite.addBatch({
"evict event": {
"'evict' event is fired when evicting old keys": function() {
var lru = new LRU(2);
var events = [];
lru.on('evict', function(element) { events.push(element); });
'evict event': {
'\'evict\' event is fired when evicting old keys': function () {
var lru = new LRU(2)
var events = []
lru.on('evict', function (element) { events.push(element) })
lru.set('foo1', 'bar1');
lru.set('foo2', 'bar2');
lru.set('foo3', 'bar3');
lru.set('foo4', 'bar4');
lru.set('foo1', 'bar1')
lru.set('foo2', 'bar2')
lru.set('foo3', 'bar3')
lru.set('foo4', 'bar4')
var expect = [{key:'foo1', value:'bar1'}, {key:'foo2', value:'bar2'}];
assert.deepEqual(events, expect);
var expect = [{key: 'foo1', value: 'bar1'}, {key: 'foo2', value: 'bar2'}]
assert.deepEqual(events, expect)
}
}
});
})
suite.export(module);
suite.export(module)
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc