1 ;(function () { // closure for web browsers
3 if (typeof module === 'object' && module.exports) {
4 module.exports = LRUCache
6 // just set the global for non-node platforms.
7 this.LRUCache = LRUCache
10 function hOP (obj, key) {
11 return Object.prototype.hasOwnProperty.call(obj, key)
14 function naiveLength () { return 1 }
16 function LRUCache (options) {
17 if (!(this instanceof LRUCache)) {
18 return new LRUCache(options)
22 if (typeof options === 'number') {
24 options = { max: max }
28 if (!options) options = {}
30 var lengthCalculator = options.length || naiveLength
32 if (typeof lengthCalculator !== "function") {
33 lengthCalculator = naiveLength
35 if (!max || !(typeof max === "number") || max <= 0 ) {
36 // a little bit silly. maybe this should throw?
40 var maxAge = options.maxAge || null
42 var dispose = options.dispose
44 var cache = Object.create(null) // hash of items by key
45 , lruList = Object.create(null) // list of items in order of use recency
46 , mru = 0 // most recently used
47 , length = 0 // number of items in the list
51 // resize the cache when the max changes.
52 Object.defineProperty(this, "max",
53 { set : function (mL) {
54 if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
56 // if it gets above double max, trim right away.
57 // otherwise, do it whenever it's convenient.
58 if (length > max) trim()
60 , get : function () { return max }
64 // resize the cache when the lengthCalculator changes.
65 Object.defineProperty(this, "lengthCalculator",
66 { set : function (lC) {
67 if (typeof lC !== "function") {
68 lengthCalculator = naiveLength
70 for (var key in cache) {
76 for (var key in cache) {
77 cache[key].length = lengthCalculator(cache[key].value)
78 length += cache[key].length
82 if (length > max) trim()
84 , get : function () { return lengthCalculator }
88 Object.defineProperty(this, "length",
89 { get : function () { return length }
94 Object.defineProperty(this, "itemCount",
95 { get : function () { return itemCount }
99 this.reset = function () {
101 for (var k in cache) {
102 dispose(k, cache[k].value)
112 // Provided for debugging/dev purposes only. No promises whatsoever that
113 // this API stays stable.
114 this.dump = function () {
118 this.set = function (key, value) {
119 if (hOP(cache, key)) {
120 // dispose of the old one before overwriting
121 if (dispose) dispose(key, cache[key].value)
122 if (maxAge) cache[key].now = Date.now()
123 cache[key].value = value
128 var len = lengthCalculator(value)
129 var age = maxAge ? Date.now() : 0
130 var hit = new Entry(key, value, mru++, len, age)
132 // oversized objects fall out of cache automatically.
133 if (hit.length > max) {
134 if (dispose) dispose(key, value)
139 lruList[hit.lu] = cache[key] = hit
142 if (length > max) trim()
146 this.get = function (key) {
147 if (!hOP(cache, key)) return
149 if (maxAge && (Date.now() - hit.now > maxAge)) {
153 delete lruList[hit.lu]
155 lruList[hit.lu] = hit
159 this.del = function (key) {
160 if (!hOP(cache, key)) return
162 if (dispose) dispose(key, hit.value)
164 delete lruList[hit.lu]
170 if (length <= max) return
171 for (var k in lruList) {
172 if (length <= max) break;
174 if (dispose) dispose(hit.key, hit.value)
176 delete cache[ hit.key ]
182 // classy, since V8 prefers predictable objects.
183 function Entry (key, value, mru, len, age) {