lru-cache
Advanced tools
Comparing version 1.0.6 to 1.1.0
@@ -14,6 +14,17 @@ ;(function () { // closure for web browsers | ||
function LRUCache (maxLength) { | ||
function naiveLength () { return 1 } | ||
function LRUCache (maxLength, lengthCalculator) { | ||
if (!(this instanceof LRUCache)) { | ||
return new LRUCache(maxLength) | ||
return new LRUCache(maxLength, lengthCalculator) | ||
} | ||
if (typeof lengthCalculator !== "function") { | ||
lengthCalculator = naiveLength | ||
} | ||
if (!maxLength || !(typeof maxLength === "number") || maxLength <= 0 ) { | ||
maxLength = Infinity | ||
} | ||
var cache = {} // hash of items by key | ||
@@ -24,3 +35,5 @@ , lruList = {} // list of items in order of use recency | ||
, length = 0 // number of items in the list | ||
, itemCount = 0 | ||
// resize the cache when the maxLength changes. | ||
@@ -39,4 +52,26 @@ Object.defineProperty(this, "maxLength", | ||
this.maxLength = maxLength | ||
// resize the cache when the lengthCalculator changes. | ||
Object.defineProperty(this, "lengthCalculator", | ||
{ set : function (lC) { | ||
if (typeof lC !== "function") { | ||
lengthCalculator = naiveLength | ||
length = itemCount | ||
Object.keys(cache).forEach(function (key) { | ||
cache[key].length = 1 | ||
}) | ||
} else { | ||
lengthCalculator = lC | ||
length = 0 | ||
Object.keys(cache).forEach(function (key) { | ||
cache[key].length = lengthCalculator(cache[key].value) | ||
length += cache[key].length | ||
}) | ||
} | ||
if (length > maxLength) trim() | ||
} | ||
, get : function () { return lengthCalculator } | ||
, enumerable : true | ||
}) | ||
Object.defineProperty(this, "length", | ||
@@ -47,2 +82,8 @@ { get : function () { return length } | ||
Object.defineProperty(this, "itemCount", | ||
{ get : function () { return itemCount } | ||
, enumerable : true | ||
}) | ||
this.reset = function () { | ||
@@ -54,2 +95,3 @@ cache = {} | ||
length = 0 | ||
itemCount = 0 | ||
} | ||
@@ -67,7 +109,14 @@ | ||
cache[key].value = value | ||
return undefined | ||
return | ||
} | ||
var hit = {key:key, value:value, lu:mru++} | ||
var hit = {key:key, value:value, lu:mru++, length:lengthCalculator(value)} | ||
// oversized objects fall out of cache automatically. | ||
if (hit.length > maxLength) return | ||
length += hit.length | ||
lruList[hit.lu] = cache[key] = hit | ||
length ++ | ||
itemCount ++ | ||
if (length > maxLength) trim() | ||
@@ -77,3 +126,3 @@ } | ||
this.get = function (key) { | ||
if (!hOP(cache, key)) return undefined | ||
if (!hOP(cache, key)) return | ||
var hit = cache[key] | ||
@@ -88,3 +137,3 @@ delete lruList[hit.lu] | ||
this.del = function (key) { | ||
if (!hOP(cache, key)) return undefined | ||
if (!hOP(cache, key)) return | ||
var hit = cache[key] | ||
@@ -94,3 +143,4 @@ delete cache[key] | ||
if (hit.lu === lru) lruWalk() | ||
length -- | ||
length -= hit.length | ||
itemCount -- | ||
} | ||
@@ -100,13 +150,13 @@ | ||
// lru has been deleted, hop up to the next hit. | ||
lru = Object.keys(lruList).shift() | ||
lru = Object.keys(lruList)[0] | ||
} | ||
function trim () { | ||
if (length <= maxLength) return undefined | ||
var prune = Object.keys(lruList).slice(0, length - maxLength) | ||
for (var i = 0, l = (length - maxLength); i < l; i ++) { | ||
if (length <= maxLength) return | ||
var prune = Object.keys(lruList) | ||
for (var i = 0; i < prune.length && length > maxLength; i ++) { | ||
length -= lruList[prune[i]].length | ||
delete cache[ lruList[prune[i]].key ] | ||
delete lruList[prune[i]] | ||
} | ||
length = maxLength | ||
lruWalk() | ||
@@ -113,0 +163,0 @@ } |
{ "name": "lru-cache" | ||
, "description": "A cache object that deletes the least-recently-used items." | ||
, "version": "1.0.6" | ||
, "version": "1.1.0" | ||
, "author": "Isaac Z. Schlueter <i@izs.me>" | ||
@@ -8,3 +8,3 @@ , "scripts": { "test": "tap test" } | ||
, "repository": "git://github.com/isaacs/node-lru-cache.git" | ||
, "devDependencies": { "tap": "0" } | ||
, "devDependencies": { "tap": "" } | ||
, "license": | ||
@@ -11,0 +11,0 @@ { "type": "MIT" |
@@ -8,3 +8,10 @@ # lru cache | ||
var LRU = require("lru-cache") | ||
, cache = LRU(10) // max 10 items. default = Infinity | ||
, cache = LRU(10, // max length. default = Infinity | ||
// calculate how "big" each item is | ||
// | ||
// defaults to function(){return 1}, ie, just limit | ||
// the item count, without any knowledge as to their | ||
// relative size. | ||
function (item) { return item.length }) | ||
cache.set("key", "value") | ||
@@ -15,2 +22,7 @@ cache.get("key") // "value" | ||
If you put more stuff in it, then items will fall out. | ||
If you try to put an oversized thing in it, then it'll fall out right | ||
away. | ||
RTFS for more info. |
@@ -1,5 +0,5 @@ | ||
var test = require('tap').test | ||
, LRU = require('../') | ||
var test = require("tap").test | ||
, LRU = require("../") | ||
test('basic', function (t) { | ||
test("basic", function (t) { | ||
var cache = new LRU(10) | ||
@@ -14,3 +14,3 @@ cache.set("key", "value") | ||
test('least recently set', function (t) { | ||
test("least recently set", function (t) { | ||
var cache = new LRU(2) | ||
@@ -26,3 +26,3 @@ cache.set("a", "A") | ||
test('lru recently gotten', function (t) { | ||
test("lru recently gotten", function (t) { | ||
var cache = new LRU(2) | ||
@@ -39,3 +39,3 @@ cache.set("a", "A") | ||
test('del', function (t) { | ||
test("del", function (t) { | ||
var cache = new LRU(2) | ||
@@ -48,3 +48,3 @@ cache.set("a", "A") | ||
test('maxLength', function (t) { | ||
test("maxLength", function (t) { | ||
var cache = new LRU(3) | ||
@@ -87,3 +87,3 @@ | ||
test('reset', function (t) { | ||
test("reset", function (t) { | ||
var cache = new LRU(10) | ||
@@ -100,5 +100,6 @@ cache.set("a", "A") | ||
// Note: `<cache>.dump()` is a debugging tool only. No guarantees are made | ||
// about the format/layout of the response. | ||
test('dump', function (t) { | ||
test("dump", function (t) { | ||
var cache = new LRU(10) | ||
@@ -108,6 +109,6 @@ var d = cache.dump(); | ||
cache.set("a", "A") | ||
var d = cache.dump() // { a: { key: 'a', value: 'A', lu: 0 } } | ||
var d = cache.dump() // { a: { key: "a", value: "A", lu: 0 } } | ||
t.ok(d.a) | ||
t.equal(d.a.key, 'a') | ||
t.equal(d.a.value, 'A') | ||
t.equal(d.a.key, "a") | ||
t.equal(d.a.value, "A") | ||
t.equal(d.a.lu, 0) | ||
@@ -119,4 +120,4 @@ | ||
t.ok(d.b) | ||
t.equal(d.b.key, 'b') | ||
t.equal(d.b.value, 'B') | ||
t.equal(d.b.key, "b") | ||
t.equal(d.b.value, "B") | ||
t.equal(d.b.lu, 2) | ||
@@ -126,1 +127,54 @@ | ||
}) | ||
test("basic with weighed length", function (t) { | ||
var cache = new LRU(100, function (item) { return item.size } ) | ||
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")), 50) | ||
t.equal(cache.length, 50) | ||
t.equal(cache.maxLength, 100) | ||
t.end() | ||
}) | ||
test("weighed length item too large", function (t) { | ||
var cache = new LRU(10, function (item) { return item.size } ) | ||
t.equal(cache.maxLength, 10) | ||
// should fall out immediately | ||
cache.set("key", {val: "value", size: 50}) | ||
t.equal(cache.length, 0) | ||
t.equal(cache.get("key"), undefined) | ||
t.end() | ||
}) | ||
test("least recently set with weighed length", function (t) { | ||
var cache = new LRU(8, 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) | ||
t.end() | ||
}) | ||
test("lru recently gotten with weighed length", function (t) { | ||
var cache = new LRU(8, function (item) { return item.length }) | ||
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() | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10634
7
281
27