-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.js
98 lines (78 loc) · 2.27 KB
/
cache.js
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
/*jshint asi:true, expr:true */
-function () {
'use strict';
function Cache (threshold) {
function invalid () {
throw new Error("Cannot build cache with a threshold less than 1")
}
!threshold && invalid()
threshold < 1 && invalid()
this.threshold = threshold
this.cache = {} , this.orderLookup = {}
this.head = null , this.tail = null
this.count = 0
}
Cache.prototype.insert = function (key, value) {
var node = new Node(key)
node.next = this.head
node.next === null || (node.next.prev = node)
this.tail === null && (this.tail = node)
this.head = node, this.orderLookup[key] = node
++this.count > this.threshold && evictOldest(this)
this.cache[key] = value
}
Cache.prototype.update = function (key, value) {
updateOrdering(this, key)
var was = this.cache[key]
was && (this.cache[key] = value)
return was
}
Cache.prototype.remove = function (key) {
var node = this.orderLookup[key]
this.head === node && (this.head = node.next)
this.tail === node && (this.tail = node.prev)
linkAdjacent(node)
remove(this, key)
}
Cache.prototype.get = function (key) {
var hit = this.cache[key]
hit && updateOrdering(this, key)
return hit
}
Cache.prototype.onEvict = function (λ) {
(this.afterEvict || (this.afterEvict =[])).push(λ)
}
function updateOrdering (cache, key) {
var node = cache.orderLookup[key]
function updateNode (node) {
node === cache.tail && (cache.tail = node.prev)
linkAdjacent(node)
node.next = cache.head
cache.head = node
}
node && updateNode(node)
}
function linkAdjacent (node) {
node.prev && (node.prev.next = node.next)
node.next && (node.next.prev = node.prev)
}
function evictOldest (cache, key) {
var oldestKey = cache.tail.key
cache.tail = cache.tail.prev
var removed = remove(cache, oldestKey)
cache.afterEvict && cache.afterEvict.map(function (λ) { λ(removed) })
}
function remove (cache, key) {
delete cache.orderLookup[key]
var was = cache.cache[key]
;delete cache.cache[key]
cache.count--
return was
}
function Node (key) {
this.prev = null
this.next = null
this.key = key
}
module.exports = Cache
}()