All files / src lru.js

69.35% Statements 43/62
76.92% Branches 20/26
75% Functions 6/8
69.35% Lines 43/62

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109      84x     84x     84x 84x 84x 84x           93x 93x 93x       93x 93x 93x       84x 84x 84x 39x   84x 84x 45x   84x 84x       49x 49x 35x 35x   14x             49x       49x 35x 35x 35x 35x 35x     14x         70x 70x 2x   68x   70x 36x   34x   70x 70x                                              
// Based on https://chrisrng.svbtle.com/lru-cache-in-javascript
class LRUNode {
  constructor(key, value) {
    Iif (typeof key === 'undefined' || key === null) {
      throw 'Cannot have an undefined or null key for a LRUNode'
    }
    Iif (typeof value === 'undefined' || value === null) {
      throw 'Cannot have an undefined or null value for a LRUNode'
    }
    this.key = key
    this.value = value
    this.prev = null
    this.next = null
  }
}
 
export default class LRU {
  constructor(limit) {
    this.size = 0
    Eif (typeof limit === 'number') {
      this.limit = limit
    } else {
      this.limit = 10
    }
    this.map = {}
    this.head = null
    this.tail = null
  }
 
  setHead(node) {
    node.next = this.head
    node.prev = null
    if (this.head !== null) {
      this.head.prev = node
    }
    this.head = node
    if (this.tail === null) {
      this.tail = node
    }
    this.size++
    this.map[node.key] = node
  }
 
  set(key, value) {
    const node = new LRUNode(key, value)
    if (this.map[key]) {
      this.map[key].value = node.value
      this.remove(node.key)
    } else {
      Iif (this.size >= this.limit) {
        delete this.map[this.tail.key]
        this.size--
        this.tail = this.tail.prev
        this.tail.next = null
      }
    }
    this.setHead(node)
  }
 
  get(key) {
    if (this.map[key]) {
      const value = this.map[key].value
      const node = new LRUNode(key, value)
      this.remove(key)
      this.setHead(node)
      return value
    } else {
      // console.log('Key ' + key + ' does not exist in the cache.')
      return null // Return null because null cannot be a LRUNode value
    }
  }
 
  remove(key) {
    const node = this.map[key]
    if (node.prev !== null) {
      node.prev.next = node.next
    } else {
      this.head = node.next
    }
    if (node.next !== null) {
      node.next.prev = node.prev
    } else {
      this.tail = node.prev
    }
    delete this.map[key]
    this.size--
  }
 
  removeAll(limit) {
    this.size = 0
    this.map = {}
    this.head = null
    this.tail = null
    if (typeof limit === 'number') {
      this.limit = limit
    }
  }
 
  forEach(callback) {
    let node = this.head
    let i = 0
    while (node) {
      callback(node, i)
      i++
      node = node.next
    }
  }
}