d1d1381720cd749c562cc4a5504d9b2b9f6ca3bf
[WP-Themes/CCEOEM.git] /
1 ;(function () { // closure for web browsers
2
3 if (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
10 function hOP (obj, key) {
11   return Object.prototype.hasOwnProperty.call(obj, key)
12 }
13
14 function naiveLength () { return 1 }
15
16 function LRUCache (options) {
17   if (!(this instanceof LRUCache))
18     return new LRUCache(options)
19
20   if (typeof options === 'number')
21     options = { max: options }
22
23   if (!options)
24     options = {}
25
26   this._max = options.max
27   // Kind of weird to have a default max of Infinity, but oh well.
28   if (!this._max || !(typeof this._max === "number") || this._max <= 0 )
29     this._max = Infinity
30
31   this._lengthCalculator = options.length || naiveLength
32   if (typeof this._lengthCalculator !== "function")
33     this._lengthCalculator = naiveLength
34
35   this._allowStale = options.stale || false
36   this._maxAge = options.maxAge || null
37   this._dispose = options.dispose
38   this.reset()
39 }
40
41 // resize the cache when the max changes.
42 Object.defineProperty(LRUCache.prototype, "max",
43   { set : function (mL) {
44       if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
45       this._max = mL
46       if (this._length > this._max) trim(this)
47     }
48   , get : function () { return this._max }
49   , enumerable : true
50   })
51
52 // resize the cache when the lengthCalculator changes.
53 Object.defineProperty(LRUCache.prototype, "lengthCalculator",
54   { set : function (lC) {
55       if (typeof lC !== "function") {
56         this._lengthCalculator = naiveLength
57         this._length = this._itemCount
58         for (var key in this._cache) {
59           this._cache[key].length = 1
60         }
61       } else {
62         this._lengthCalculator = lC
63         this._length = 0
64         for (var key in this._cache) {
65           this._cache[key].length = this._lengthCalculator(this._cache[key].value)
66           this._length += this._cache[key].length
67         }
68       }
69
70       if (this._length > this._max) trim(this)
71     }
72   , get : function () { return this._lengthCalculator }
73   , enumerable : true
74   })
75
76 Object.defineProperty(LRUCache.prototype, "length",
77   { get : function () { return this._length }
78   , enumerable : true
79   })
80
81
82 Object.defineProperty(LRUCache.prototype, "itemCount",
83   { get : function () { return this._itemCount }
84   , enumerable : true
85   })
86
87 LRUCache.prototype.forEach = function (fn, thisp) {
88   thisp = thisp || this
89   var i = 0;
90   for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
91     i++
92     var hit = this._lruList[k]
93     if (this._maxAge && (Date.now() - hit.now > this._maxAge)) {
94       del(this, hit)
95       if (!this._allowStale) hit = undefined
96     }
97     if (hit) {
98       fn.call(thisp, hit.value, hit.key, this)
99     }
100   }
101 }
102
103 LRUCache.prototype.keys = function () {
104   var keys = new Array(this._itemCount)
105   var i = 0
106   for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
107     var hit = this._lruList[k]
108     keys[i++] = hit.key
109   }
110   return keys
111 }
112
113 LRUCache.prototype.values = function () {
114   var values = 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     values[i++] = hit.value
119   }
120   return values
121 }
122
123 LRUCache.prototype.reset = function () {
124   if (this._dispose && this._cache) {
125     for (var k in this._cache) {
126       this._dispose(k, this._cache[k].value)
127     }
128   }
129
130   this._cache = Object.create(null) // hash of items by key
131   this._lruList = Object.create(null) // list of items in order of use recency
132   this._mru = 0 // most recently used
133   this._lru = 0 // least recently used
134   this._length = 0 // number of items in the list
135   this._itemCount = 0
136 }
137
138 // Provided for debugging/dev purposes only. No promises whatsoever that
139 // this API stays stable.
140 LRUCache.prototype.dump = function () {
141   return this._cache
142 }
143
144 LRUCache.prototype.dumpLru = function () {
145   return this._lruList
146 }
147
148 LRUCache.prototype.set = function (key, value) {
149   if (hOP(this._cache, key)) {
150     // dispose of the old one before overwriting
151     if (this._dispose) this._dispose(key, this._cache[key].value)
152     if (this._maxAge) this._cache[key].now = Date.now()
153     this._cache[key].value = value
154     this.get(key)
155     return true
156   }
157
158   var len = this._lengthCalculator(value)
159   var age = this._maxAge ? Date.now() : 0
160   var hit = new Entry(key, value, this._mru++, len, age)
161
162   // oversized objects fall out of cache automatically.
163   if (hit.length > this._max) {
164     if (this._dispose) this._dispose(key, value)
165     return false
166   }
167
168   this._length += hit.length
169   this._lruList[hit.lu] = this._cache[key] = hit
170   this._itemCount ++
171
172   if (this._length > this._max) trim(this)
173   return true
174 }
175
176 LRUCache.prototype.has = function (key) {
177   if (!hOP(this._cache, key)) return false
178   var hit = this._cache[key]
179   if (this._maxAge && (Date.now() - hit.now > this._maxAge)) {
180     return false
181   }
182   return true
183 }
184
185 LRUCache.prototype.get = function (key) {
186   return get(this, key, true)
187 }
188
189 LRUCache.prototype.peek = function (key) {
190   return get(this, key, false)
191 }
192
193 LRUCache.prototype.pop = function () {
194   var hit = this._lruList[this._lru]
195   del(this, hit)
196   return hit || null
197 }
198
199 LRUCache.prototype.del = function (key) {
200   del(this, this._cache[key])
201 }
202
203 function get (self, key, doUse) {
204   var hit = self._cache[key]
205   if (hit) {
206     if (self._maxAge && (Date.now() - hit.now > self._maxAge)) {
207       del(self, hit)
208       if (!self._allowStale) hit = undefined
209     } else {
210       if (doUse) use(self, hit)
211     }
212     if (hit) hit = hit.value
213   }
214   return hit
215 }
216
217 function use (self, hit) {
218   shiftLU(self, hit)
219   hit.lu = self._mru ++
220   self._lruList[hit.lu] = hit
221 }
222
223 function trim (self) {
224   while (self._lru < self._mru && self._length > self._max)
225     del(self, self._lruList[self._lru])
226 }
227
228 function shiftLU (self, hit) {
229   delete self._lruList[ hit.lu ]
230   while (self._lru < self._mru && !self._lruList[self._lru]) self._lru ++
231 }
232
233 function del (self, hit) {
234   if (hit) {
235     if (self._dispose) self._dispose(hit.key, hit.value)
236     self._length -= hit.length
237     self._itemCount --
238     delete self._cache[ hit.key ]
239     shiftLU(self, hit)
240   }
241 }
242
243 // classy, since V8 prefers predictable objects.
244 function Entry (key, value, lu, length, now) {
245   this.key = key
246   this.value = value
247   this.lu = lu
248   this.length = length
249   this.now = now
250 }
251
252 })()