aboutsummaryrefslogtreecommitdiff
path: root/node_modules/lru-cache/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/lru-cache/index.js')
-rw-r--r--node_modules/lru-cache/index.js468
1 files changed, 468 insertions, 0 deletions
diff --git a/node_modules/lru-cache/index.js b/node_modules/lru-cache/index.js
new file mode 100644
index 0000000..bd35b53
--- /dev/null
+++ b/node_modules/lru-cache/index.js
@@ -0,0 +1,468 @@
+'use strict'
+
+module.exports = LRUCache
+
+// This will be a proper iterable 'Map' in engines that support it,
+// or a fakey-fake PseudoMap in older versions.
+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 hasSymbol = typeof Symbol === 'function' && process.env._nodeLRUCacheForceNoSymbol !== '1'
+var makeSymbol
+if (hasSymbol) {
+ makeSymbol = function (key) {
+ return Symbol(key)
+ }
+} else {
+ makeSymbol = function (key) {
+ return '_' + key
+ }
+}
+
+var MAX = makeSymbol('max')
+var LENGTH = makeSymbol('length')
+var LENGTH_CALCULATOR = makeSymbol('lengthCalculator')
+var ALLOW_STALE = makeSymbol('allowStale')
+var MAX_AGE = makeSymbol('maxAge')
+var DISPOSE = makeSymbol('dispose')
+var NO_DISPOSE_ON_SET = makeSymbol('noDisposeOnSet')
+var LRU_LIST = makeSymbol('lruList')
+var CACHE = makeSymbol('cache')
+
+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)) {
+ return new LRUCache(options)
+ }
+
+ if (typeof options === 'number') {
+ options = { max: options }
+ }
+
+ if (!options) {
+ options = {}
+ }
+
+ var max = this[MAX] = options.max
+ // Kind of weird to have a default max of Infinity, but oh well.
+ if (!max ||
+ !(typeof max === 'number') ||
+ max <= 0) {
+ this[MAX] = Infinity
+ }
+
+ var lc = options.length || naiveLength
+ if (typeof lc !== 'function') {
+ lc = naiveLength
+ }
+ this[LENGTH_CALCULATOR] = lc
+
+ this[ALLOW_STALE] = options.stale || false
+ this[MAX_AGE] = options.maxAge || 0
+ this[DISPOSE] = options.dispose
+ this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
+ this.reset()
+}
+
+// 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
+ trim(this)
+ },
+ get: function () {
+ return this[MAX]
+ },
+ enumerable: true
+})
+
+Object.defineProperty(LRUCache.prototype, 'allowStale', {
+ set: function (allowStale) {
+ this[ALLOW_STALE] = !!allowStale
+ },
+ get: function () {
+ return this[ALLOW_STALE]
+ },
+ enumerable: true
+})
+
+Object.defineProperty(LRUCache.prototype, 'maxAge', {
+ set: function (mA) {
+ if (!mA || !(typeof mA === 'number') || mA < 0) {
+ mA = 0
+ }
+ this[MAX_AGE] = mA
+ trim(this)
+ },
+ get: function () {
+ return this[MAX_AGE]
+ },
+ 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 !== this[LENGTH_CALCULATOR]) {
+ this[LENGTH_CALCULATOR] = lC
+ this[LENGTH] = 0
+ this[LRU_LIST].forEach(function (hit) {
+ hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
+ this[LENGTH] += hit.length
+ }, this)
+ }
+ trim(this)
+ },
+ get: function () { return this[LENGTH_CALCULATOR] },
+ enumerable: true
+})
+
+Object.defineProperty(LRUCache.prototype, 'length', {
+ get: function () { return this[LENGTH] },
+ enumerable: true
+})
+
+Object.defineProperty(LRUCache.prototype, 'itemCount', {
+ get: function () { return this[LRU_LIST].length },
+ enumerable: true
+})
+
+LRUCache.prototype.rforEach = function (fn, thisp) {
+ thisp = thisp || this
+ for (var walker = this[LRU_LIST].tail; walker !== null;) {
+ var prev = walker.prev
+ forEachStep(this, fn, walker, thisp)
+ walker = prev
+ }
+}
+
+function forEachStep (self, fn, node, thisp) {
+ var hit = node.value
+ if (isStale(self, hit)) {
+ del(self, node)
+ if (!self[ALLOW_STALE]) {
+ hit = undefined
+ }
+ }
+ if (hit) {
+ fn.call(thisp, hit.value, hit.key, self)
+ }
+}
+
+LRUCache.prototype.forEach = function (fn, thisp) {
+ thisp = thisp || this
+ for (var walker = this[LRU_LIST].head; walker !== null;) {
+ var next = walker.next
+ forEachStep(this, fn, walker, thisp)
+ walker = next
+ }
+}
+
+LRUCache.prototype.keys = function () {
+ return this[LRU_LIST].toArray().map(function (k) {
+ return k.key
+ }, this)
+}
+
+LRUCache.prototype.values = function () {
+ return this[LRU_LIST].toArray().map(function (k) {
+ return k.value
+ }, this)
+}
+
+LRUCache.prototype.reset = function () {
+ if (this[DISPOSE] &&
+ this[LRU_LIST] &&
+ this[LRU_LIST].length) {
+ this[LRU_LIST].forEach(function (hit) {
+ this[DISPOSE](hit.key, hit.value)
+ }, this)
+ }
+
+ this[CACHE] = new Map() // hash of items by key
+ this[LRU_LIST] = new Yallist() // list of items in order of use recency
+ this[LENGTH] = 0 // length of items in the list
+}
+
+LRUCache.prototype.dump = function () {
+ return this[LRU_LIST].map(function (hit) {
+ if (!isStale(this, hit)) {
+ return {
+ k: hit.key,
+ v: hit.value,
+ e: hit.now + (hit.maxAge || 0)
+ }
+ }
+ }, this).toArray().filter(function (h) {
+ return h
+ })
+}
+
+LRUCache.prototype.dumpLru = function () {
+ return this[LRU_LIST]
+}
+
+/* istanbul ignore next */
+LRUCache.prototype.inspect = function (n, opts) {
+ var str = 'LRUCache {'
+ var extras = false
+
+ var as = this[ALLOW_STALE]
+ if (as) {
+ str += '\n allowStale: true'
+ extras = true
+ }
+
+ var max = this[MAX]
+ if (max && max !== Infinity) {
+ if (extras) {
+ str += ','
+ }
+ str += '\n max: ' + util.inspect(max, opts)
+ extras = true
+ }
+
+ var maxAge = this[MAX_AGE]
+ if (maxAge) {
+ if (extras) {
+ str += ','
+ }
+ str += '\n maxAge: ' + util.inspect(maxAge, opts)
+ extras = true
+ }
+
+ var lc = this[LENGTH_CALCULATOR]
+ if (lc && lc !== naiveLength) {
+ if (extras) {
+ str += ','
+ }
+ str += '\n length: ' + util.inspect(this[LENGTH], opts)
+ extras = true
+ }
+
+ var didFirst = false
+ this[LRU_LIST].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[MAX_AGE]
+
+ var now = maxAge ? Date.now() : 0
+ var len = this[LENGTH_CALCULATOR](value, key)
+
+ if (this[CACHE].has(key)) {
+ if (len > this[MAX]) {
+ del(this, this[CACHE].get(key))
+ return false
+ }
+
+ var node = this[CACHE].get(key)
+ var item = node.value
+
+ // dispose of the old one before overwriting
+ // split out into 2 ifs for better coverage tracking
+ if (this[DISPOSE]) {
+ if (!this[NO_DISPOSE_ON_SET]) {
+ this[DISPOSE](key, item.value)
+ }
+ }
+
+ item.now = now
+ item.maxAge = maxAge
+ item.value = value
+ this[LENGTH] += len - item.length
+ item.length = len
+ this.get(key)
+ trim(this)
+ return true
+ }
+
+ 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)
+ }
+ return false
+ }
+
+ this[LENGTH] += hit.length
+ this[LRU_LIST].unshift(hit)
+ this[CACHE].set(key, this[LRU_LIST].head)
+ trim(this)
+ return true
+}
+
+LRUCache.prototype.has = function (key) {
+ if (!this[CACHE].has(key)) return false
+ var hit = this[CACHE].get(key).value
+ if (isStale(this, hit)) {
+ return false
+ }
+ return true
+}
+
+LRUCache.prototype.get = function (key) {
+ return get(this, key, true)
+}
+
+LRUCache.prototype.peek = function (key) {
+ return get(this, key, false)
+}
+
+LRUCache.prototype.pop = function () {
+ var node = this[LRU_LIST].tail
+ if (!node) return null
+ del(this, node)
+ return node.value
+}
+
+LRUCache.prototype.del = function (key) {
+ del(this, this[CACHE].get(key))
+}
+
+LRUCache.prototype.load = function (arr) {
+ // reset the cache
+ this.reset()
+
+ var now = Date.now()
+ // A previous serialized cache has the most recent items first
+ for (var l = arr.length - 1; l >= 0; l--) {
+ var hit = arr[l]
+ var expiresAt = hit.e || 0
+ if (expiresAt === 0) {
+ // the item was created without expiration in a non aged cache
+ this.set(hit.k, hit.v)
+ } else {
+ var maxAge = expiresAt - now
+ // dont add already expired items
+ if (maxAge > 0) {
+ this.set(hit.k, hit.v, maxAge)
+ }
+ }
+ }
+}
+
+LRUCache.prototype.prune = function () {
+ var self = this
+ this[CACHE].forEach(function (value, key) {
+ get(self, key, false)
+ })
+}
+
+function get (self, key, doUse) {
+ var node = self[CACHE].get(key)
+ if (node) {
+ var hit = node.value
+ if (isStale(self, hit)) {
+ del(self, node)
+ if (!self[ALLOW_STALE]) hit = undefined
+ } else {
+ if (doUse) {
+ self[LRU_LIST].unshiftNode(node)
+ }
+ }
+ if (hit) hit = hit.value
+ }
+ return hit
+}
+
+function isStale (self, hit) {
+ if (!hit || (!hit.maxAge && !self[MAX_AGE])) {
+ return false
+ }
+ var stale = false
+ var diff = Date.now() - hit.now
+ if (hit.maxAge) {
+ stale = diff > hit.maxAge
+ } else {
+ stale = self[MAX_AGE] && (diff > self[MAX_AGE])
+ }
+ return stale
+}
+
+function trim (self) {
+ if (self[LENGTH] > self[MAX]) {
+ for (var walker = self[LRU_LIST].tail;
+ self[LENGTH] > 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.
+ var prev = walker.prev
+ del(self, walker)
+ walker = prev
+ }
+ }
+}
+
+function del (self, node) {
+ if (node) {
+ var hit = node.value
+ if (self[DISPOSE]) {
+ self[DISPOSE](hit.key, hit.value)
+ }
+ self[LENGTH] -= hit.length
+ self[CACHE].delete(hit.key)
+ self[LRU_LIST].removeNode(node)
+ }
+}
+
+// classy, since V8 prefers predictable objects.
+function Entry (key, value, length, now, maxAge) {
+ this.key = key
+ this.value = value
+ this.length = length
+ this.now = now
+ this.maxAge = maxAge || 0
+}