"use strict"; /** * LRU cache based on a double linked list */ function ListElement(before,next,key,value){ this.before = before this.next = next this.key = key this.value = value } ListElement.prototype.setKey = function(key){ this.key = key } ListElement.prototype.setValue = function(value){ this.value = value } function Cache(options){ if(!options) options = {} this.maxSize = options.maxSize this.reset() } Cache.prototype.reset = function(){ this.size = 0 this.cache = {} this.tail = undefined this.head = undefined } Cache.prototype.get = function(key,hit){ var cacheVal = this.cache[key] /* * Define if the egt function should hit the value to move * it to the head of linked list */ hit = hit != undefined && hit != null ? hit : true; if(cacheVal && hit) this.hit(cacheVal) else return undefined return cacheVal.value } Cache.prototype.set = function(key,val,hit){ var actual = this.cache[key] /* * Define if the set function should hit the value to move * it to the head of linked list */ hit = hit != undefined && hit != null ? hit : true; if(actual){ actual.value = val if(hit) this.hit(actual) }else{ var cacheVal if(this.size >= this.maxSize){ var tailKey = this.tail.key this.detach(this.tail) /* * If max is reached we'llreuse object to minimize GC impact * when the objects are cached short time */ cacheVal = this.cache[tailKey] delete this.cache[tailKey] cacheVal.next = undefined cacheVal.before = undefined /* * setters reuse the array object */ cacheVal.setKey(key) cacheVal.setValue(val) } cacheVal = cacheVal ? cacheVal : new ListElement(undefined,undefined,key,val) this.cache[key] = cacheVal this.attach(cacheVal) } } Cache.prototype.del = function(key){ var val = this.cache[key] if(!val) return; this.detach(val) delete this.cache[key] } Cache.prototype.hit = function(cacheVal){ //Send cacheVal to the head of list this.detach(cacheVal) this.attach(cacheVal) } Cache.prototype.attach = function(element){ if(!element) return; element.before = undefined element.next = this.head this.head = element if(!element.next) this.tail = element else element.next.before = element this.size++ } Cache.prototype.detach = function(element){ if(!element) return; var before = element.before var next = element.next if(before){ before.next = next }else{ this.head = next } if(next){ next.before = before }else{ this.tail = before } this.size-- } Cache.prototype.forEach = function(callback){ var self = this Object.keys(this.cache).forEach(function(key){ var val = self.cache[key] callback(val.value,key) }) } module.exports=Cache