Skip to content

Commit

Permalink
Use a Map on newer systems, polyfill for older JS
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Nov 25, 2015
1 parent 789943a commit e3db670
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 16 deletions.
64 changes: 48 additions & 16 deletions lib/lru-cache.js
Expand Up @@ -7,6 +7,41 @@ if (typeof module === 'object' && module.exports) {
this.LRUCache = LRUCache
}

var hasOwnProperty = Object.prototype.hasOwnProperty

var MyMap

if (typeof Map === 'function')
MyMap = Map
else {
MyMap = function MyMap () {
this._data = Object.create(null)
}

MyMap.prototype.forEach = function (fn, thisp) {
thisp = thisp || this
Object.keys(this._data).forEach(function (k) {
fn.call(thisp, this._data[k], k)
}, this)
}

MyMap.prototype.has = function (k) {
return hasOwnProperty.call(this._data, k)
}

MyMap.prototype.get = function (k) {
return this._data[k]
}

MyMap.prototype.set = function (k, v) {
this._data[k] = v
}

MyMap.prototype.delete = function (k) {
delete this._data[k]
}
}

function naiveLength () { return 1 }

function typeCheckKey(key) {
Expand Down Expand Up @@ -56,16 +91,16 @@ Object.defineProperty(LRUCache.prototype, "lengthCalculator",
if (typeof lC !== "function") {
this._lengthCalculator = naiveLength
this._length = this._itemCount
for (var value of this._cache.values()) {
this._cache.forEach(function (value, key) {
value.length = 1
}
})
} else {
this._lengthCalculator = lC
this._length = 0
for (var value of this._cache.values()) {
this._cache.forEach(function (value, key) {
value.length = this._lengthCalculator(value.value)
this._length += value.length
}
})
}

if (this._length > this._max) trim(this)
Expand Down Expand Up @@ -125,13 +160,13 @@ LRUCache.prototype.values = function () {

LRUCache.prototype.reset = function () {
if (this._dispose && this._cache) {
for (var entry of this._cache) {
this._dispose(entry[0], entry[1].value)
}
this._cache.forEach(function (entry, key) {
this._dispose(key, entry.value)
}, this)
}

this._cache = new Map() // hash of items by key
this._lruList = new Map() // list of items in order of use recency
this._cache = new MyMap() // hash of items by key
this._lruList = new MyMap() // 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
Expand Down Expand Up @@ -163,13 +198,11 @@ LRUCache.prototype.dumpLru = function () {
}

LRUCache.prototype.set = function (key, value, maxAge) {
// Map allows any type of `key` (objects, number, etc). For backwards
// compatibility, coerce to a string.
key = String(key)

maxAge = maxAge || this._maxAge
typeCheckKey(key)

key = String(key)

var now = maxAge ? Date.now() : 0
var len = this._lengthCalculator(value)

Expand Down Expand Up @@ -250,6 +283,7 @@ LRUCache.prototype.pop = function () {
LRUCache.prototype.del = function (key) {
if (typeof key !== 'string' && typeof key !== 'number')
return
key = String(key)
del(this, this._cache.get(key))
}

Expand All @@ -276,10 +310,8 @@ LRUCache.prototype.load = function (arr) {

function get (self, key, doUse) {
typeCheckKey(key)
// Map allows any type of `key` (objects, number, etc). For backwards
// compatibility, coerce to a string.
key = String(key)

key = String(key)
var hit = self._cache.get(key)
if (hit) {
if (isStale(self, hit)) {
Expand Down
5 changes: 5 additions & 0 deletions test/basic.js
Expand Up @@ -423,6 +423,11 @@ test("peek only accepts strings and numbers as keys", function(t) {

t.equal(cache.peek("key"), "value")
t.equal(cache.peek(123), 456)

t.equal(cache.peek({
toString: function() { return "key" }
}), undefined)

t.end()
})

Expand Down

0 comments on commit e3db670

Please sign in to comment.