UNPKG

node-lfu-cache

Version:

A cache object that deletes the least-frequently-used items.

191 lines (189 loc) 3.89 kB
class Item { constructor (value, freq, list) { this.value = value this.list = list this.freq = freq this.next = this.prev = null this.freq.pushItem(this) } bump () { // console.log('bump', this) var cur = this.freq var inc = cur.getNext() if (!inc.next) { this.list.max = inc } cur.removeItem(this) if (!cur.head && !cur.tail) { this.list.removeFreq(cur) } inc.pushItem(this) } } class FreqItem { constructor (num) { this.num = num this.head = this.tail = null this.next = this.prev = null } pushItem (node) { node.freq = this if (!this.head && !this.tail) { this.head = this.tail = node node.next = node.prev = null return } node.prev = this.tail node.next = null this.tail.next = node this.tail = node } removeItem (node) { if (this.head === node) { if (this.tail === node) { this.head = this.tail = null return } this.head = node.next this.head.prev = null return } if (this.tail === node) { this.tail = node.prev this.tail.next = null return } let prev = node.prev let next = node.next prev.next = next next.prev = prev } insertBefore (node) { node.next = this // if (this.prev) { // this.prev.next = node // node.prev = this.prev // } this.prev = node } getNext () { if (!this.next || this.next.num !== this.num + 1) { this.insertAfter(new FreqItem(this.num + 1)) } return this.next } insertAfter (node) { node.prev = this if (this.next) { this.next.prev = node node.next = this.next } this.next = node } } class List { constructor () { this.root = new FreqItem(1) this.max = this.root this.length = 0 } insert (value) { this.length++ if (this.root.num !== 1) { let newRoot = new FreqItem(1) this.root.insertBefore(newRoot) this.root = newRoot } let item = new Item(value, this.root, this) return item } removeFreq (node) { if (this.root === node) { if (this.max === node) { this.root = this.max = new FreqItem(1) return } this.root = node.next this.root.prev = null return } // console.log('this', this) // console.log('node', node) let prev = node.prev let next = node.next prev.next = next if (next) { next.prev = prev } else { this.max = prev } } tail () { return this.root.head } head () { return this.max.tail } remove (node) { // console.log('remove', node.value) this.length-- var freq = node.freq freq.removeItem(node) if (!freq.head && !freq.tail) { this.removeFreq(freq) } } forEach (fn, self) { self = self || this this.forEachRaw((node, i) => { fn.call(self, node.value, i, this) }) } forEachRaw (fn, self) { let freq = this.max let node = freq.tail self = self || this var i = -1 while (node) { fn.call(self, node, ++i, this) if (node.prev) { node = node.prev continue } if (freq.prev) { freq = freq.prev node = freq.tail continue } return } } forEachRawReverse (fn, self) { let freq = this.root let node = freq.head self = self || this var i = -1 while (node) { fn.call(self, node, ++i, this) if (node.next) { node = node.next continue } if (freq.next) { freq = freq.next node = freq.head continue } return } } toArray () { let out = new Array(this.length) this.forEach(function (node, i) { // console.log(value, i) out[i] = node }) return out } } module.exports = List