PageRenderTime 64ms CodeModel.GetById 19ms app.highlight 40ms RepoModel.GetById 2ms app.codeStats 0ms

/node_modules/lru-cache/lib/lru-cache.js

https://bitbucket.org/coleman333/smartsite
JavaScript | 334 lines | 270 code | 51 blank | 13 comment | 81 complexity | 8f55a3b448e2983c62489af004f0adb8 MD5 | raw file
  1;(function () { // closure for web browsers
  2
  3if (typeof module === 'object' && module.exports) {
  4  module.exports = LRUCache
  5} else {
  6  // just set the global for non-node platforms.
  7  this.LRUCache = LRUCache
  8}
  9
 10function hOP (obj, key) {
 11  return Object.prototype.hasOwnProperty.call(obj, key)
 12}
 13
 14function naiveLength () { return 1 }
 15
 16var didTypeWarning = false
 17function typeCheckKey(key) {
 18  if (!didTypeWarning && typeof key !== 'string' && typeof key !== 'number') {
 19    didTypeWarning = true
 20    console.error(new TypeError("LRU: key must be a string or number. Almost certainly a bug! " + typeof key).stack)
 21  }
 22}
 23
 24function LRUCache (options) {
 25  if (!(this instanceof LRUCache))
 26    return new LRUCache(options)
 27
 28  if (typeof options === 'number')
 29    options = { max: options }
 30
 31  if (!options)
 32    options = {}
 33
 34  this._max = options.max
 35  // Kind of weird to have a default max of Infinity, but oh well.
 36  if (!this._max || !(typeof this._max === "number") || this._max <= 0 )
 37    this._max = Infinity
 38
 39  this._lengthCalculator = options.length || naiveLength
 40  if (typeof this._lengthCalculator !== "function")
 41    this._lengthCalculator = naiveLength
 42
 43  this._allowStale = options.stale || false
 44  this._maxAge = options.maxAge || null
 45  this._dispose = options.dispose
 46  this.reset()
 47}
 48
 49// resize the cache when the max changes.
 50Object.defineProperty(LRUCache.prototype, "max",
 51  { set : function (mL) {
 52      if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
 53      this._max = mL
 54      if (this._length > this._max) trim(this)
 55    }
 56  , get : function () { return this._max }
 57  , enumerable : true
 58  })
 59
 60// resize the cache when the lengthCalculator changes.
 61Object.defineProperty(LRUCache.prototype, "lengthCalculator",
 62  { set : function (lC) {
 63      if (typeof lC !== "function") {
 64        this._lengthCalculator = naiveLength
 65        this._length = this._itemCount
 66        for (var key in this._cache) {
 67          this._cache[key].length = 1
 68        }
 69      } else {
 70        this._lengthCalculator = lC
 71        this._length = 0
 72        for (var key in this._cache) {
 73          this._cache[key].length = this._lengthCalculator(this._cache[key].value)
 74          this._length += this._cache[key].length
 75        }
 76      }
 77
 78      if (this._length > this._max) trim(this)
 79    }
 80  , get : function () { return this._lengthCalculator }
 81  , enumerable : true
 82  })
 83
 84Object.defineProperty(LRUCache.prototype, "length",
 85  { get : function () { return this._length }
 86  , enumerable : true
 87  })
 88
 89
 90Object.defineProperty(LRUCache.prototype, "itemCount",
 91  { get : function () { return this._itemCount }
 92  , enumerable : true
 93  })
 94
 95LRUCache.prototype.forEach = function (fn, thisp) {
 96  thisp = thisp || this
 97  var i = 0
 98  var itemCount = this._itemCount
 99
100  for (var k = this._mru - 1; k >= 0 && i < itemCount; k--) if (this._lruList[k]) {
101    i++
102    var hit = this._lruList[k]
103    if (isStale(this, hit)) {
104      del(this, hit)
105      if (!this._allowStale) hit = undefined
106    }
107    if (hit) {
108      fn.call(thisp, hit.value, hit.key, this)
109    }
110  }
111}
112
113LRUCache.prototype.keys = function () {
114  var keys = new Array(this._itemCount)
115  var i = 0
116  for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
117    var hit = this._lruList[k]
118    keys[i++] = hit.key
119  }
120  return keys
121}
122
123LRUCache.prototype.values = function () {
124  var values = new Array(this._itemCount)
125  var i = 0
126  for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
127    var hit = this._lruList[k]
128    values[i++] = hit.value
129  }
130  return values
131}
132
133LRUCache.prototype.reset = function () {
134  if (this._dispose && this._cache) {
135    for (var k in this._cache) {
136      this._dispose(k, this._cache[k].value)
137    }
138  }
139
140  this._cache = Object.create(null) // hash of items by key
141  this._lruList = Object.create(null) // list of items in order of use recency
142  this._mru = 0 // most recently used
143  this._lru = 0 // least recently used
144  this._length = 0 // number of items in the list
145  this._itemCount = 0
146}
147
148LRUCache.prototype.dump = function () {
149  var arr = []
150  var i = 0
151
152  for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
153    var hit = this._lruList[k]
154    if (!isStale(this, hit)) {
155      //Do not store staled hits
156      ++i
157      arr.push({
158        k: hit.key,
159        v: hit.value,
160        e: hit.now + (hit.maxAge || 0)
161      });
162    }
163  }
164  //arr has the most read first
165  return arr
166}
167
168LRUCache.prototype.dumpLru = function () {
169  return this._lruList
170}
171
172LRUCache.prototype.set = function (key, value, maxAge) {
173  maxAge = maxAge || this._maxAge
174  typeCheckKey(key)
175
176  var now = maxAge ? Date.now() : 0
177  var len = this._lengthCalculator(value)
178
179  if (hOP(this._cache, key)) {
180    if (len > this._max) {
181      del(this, this._cache[key])
182      return false
183    }
184    // dispose of the old one before overwriting
185    if (this._dispose)
186      this._dispose(key, this._cache[key].value)
187
188    this._cache[key].now = now
189    this._cache[key].maxAge = maxAge
190    this._cache[key].value = value
191    this._length += (len - this._cache[key].length)
192    this._cache[key].length = len
193    this.get(key)
194
195    if (this._length > this._max)
196      trim(this)
197
198    return true
199  }
200
201  var hit = new Entry(key, value, this._mru++, len, now, maxAge)
202
203  // oversized objects fall out of cache automatically.
204  if (hit.length > this._max) {
205    if (this._dispose) this._dispose(key, value)
206    return false
207  }
208
209  this._length += hit.length
210  this._lruList[hit.lu] = this._cache[key] = hit
211  this._itemCount ++
212
213  if (this._length > this._max)
214    trim(this)
215
216  return true
217}
218
219LRUCache.prototype.has = function (key) {
220  typeCheckKey(key)
221  if (!hOP(this._cache, key)) return false
222  var hit = this._cache[key]
223  if (isStale(this, hit)) {
224    return false
225  }
226  return true
227}
228
229LRUCache.prototype.get = function (key) {
230  typeCheckKey(key)
231  return get(this, key, true)
232}
233
234LRUCache.prototype.peek = function (key) {
235  typeCheckKey(key)
236  return get(this, key, false)
237}
238
239LRUCache.prototype.pop = function () {
240  var hit = this._lruList[this._lru]
241  del(this, hit)
242  return hit || null
243}
244
245LRUCache.prototype.del = function (key) {
246  typeCheckKey(key)
247  del(this, this._cache[key])
248}
249
250LRUCache.prototype.load = function (arr) {
251  //reset the cache
252  this.reset();
253
254  var now = Date.now()
255  //A previous serialized cache has the most recent items first
256  for (var l = arr.length - 1; l >= 0; l-- ) {
257    var hit = arr[l]
258    typeCheckKey(hit.k)
259    var expiresAt = hit.e || 0
260    if (expiresAt === 0) {
261      //the item was created without expiration in a non aged cache
262      this.set(hit.k, hit.v)
263    } else {
264      var maxAge = expiresAt - now
265      //dont add already expired items
266      if (maxAge > 0) this.set(hit.k, hit.v, maxAge)
267    }
268  }
269}
270
271function get (self, key, doUse) {
272  typeCheckKey(key)
273  var hit = self._cache[key]
274  if (hit) {
275    if (isStale(self, hit)) {
276      del(self, hit)
277      if (!self._allowStale) hit = undefined
278    } else {
279      if (doUse) use(self, hit)
280    }
281    if (hit) hit = hit.value
282  }
283  return hit
284}
285
286function isStale(self, hit) {
287  if (!hit || (!hit.maxAge && !self._maxAge)) return false
288  var stale = false;
289  var diff = Date.now() - hit.now
290  if (hit.maxAge) {
291    stale = diff > hit.maxAge
292  } else {
293    stale = self._maxAge && (diff > self._maxAge)
294  }
295  return stale;
296}
297
298function use (self, hit) {
299  shiftLU(self, hit)
300  hit.lu = self._mru ++
301  self._lruList[hit.lu] = hit
302}
303
304function trim (self) {
305  while (self._lru < self._mru && self._length > self._max)
306    del(self, self._lruList[self._lru])
307}
308
309function shiftLU (self, hit) {
310  delete self._lruList[ hit.lu ]
311  while (self._lru < self._mru && !self._lruList[self._lru]) self._lru ++
312}
313
314function del (self, hit) {
315  if (hit) {
316    if (self._dispose) self._dispose(hit.key, hit.value)
317    self._length -= hit.length
318    self._itemCount --
319    delete self._cache[ hit.key ]
320    shiftLU(self, hit)
321  }
322}
323
324// classy, since V8 prefers predictable objects.
325function Entry (key, value, lu, length, now, maxAge) {
326  this.key = key
327  this.value = value
328  this.lu = lu
329  this.length = length
330  this.now = now
331  if (maxAge) this.maxAge = maxAge
332}
333
334})()