-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsource.js
164 lines (147 loc) · 3.6 KB
/
source.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
module.exports = makeLRU
function makeLRU (userOptions) {
var lruLength = 0
var keysToLinks = {}
var leastRecentLink
var mostRecentLink
var eventsToCallbacks = {}
userOptions = userOptions || {}
var options = {
expiryIfUnused: userOptions.expiryIfUnused || Infinity,
max: userOptions.max || 1000,
}
var lru = {
clear: clear,
get: get,
length: length,
on: on,
peek: peek,
remove: remove,
set: set,
_debug: _debug
}
return lru
// Methods
function clear () {
keysToLinks = {}
leastRecentLink = null
lruLength = 0
mostRecentLink = null
trigger("clear")
}
function get (key) {
var link = keysToLinks[key]
var keyExists = Boolean(link)
if (keyExists) {
var expired = link.lastUsedAt + options.expiryIfUnused < Date.now()
if (expired) {
remove(link)
link = undefined
} else {
makeMostRecent(link)
}
}
var value = link && link.value
trigger("get", key, value)
return value
}
function length () {
trigger("peek", undefined, lruLength)
return lruLength
}
function on (event, callback) {
if (!eventsToCallbacks[event]) {
eventsToCallbacks[event] = []
}
eventsToCallbacks[event].push(callback)
// TODO return something to let the user unsubscribe
}
function peek (key) {
var value = keysToLinks[key] && keysToLinks[key].value
trigger("peek", key, value)
return value
}
function remove (key) {
var link = keysToLinks[key]
var value = link && link.value
var keyExists = Boolean(link)
if (keyExists) {
delete keysToLinks[key]
removeLinkFromList(link)
lruLength = lruLength - 1
}
trigger("remove", key, value)
return value
}
function set (key, value) {
var link = keysToLinks[key]
var keyExists = Boolean(link)
if (!keyExists) {
link = makeLink(key)
keysToLinks[key] = link
lruLength = lruLength + 1
}
if (!leastRecentLink) {
leastRecentLink = link
}
makeMostRecent(link)
if (lruLength > options.max) {
remove(leastRecentLink.key)
}
link.value = value
trigger("set", key, value)
return value
}
// Helpers
function trigger (event, key, value) {
if (eventsToCallbacks[event]) {
eventsToCallbacks[event].forEach(callback => callback(key, value))
}
}
function makeMostRecent (link) {
link.lastUsedAt = Date.now()
removeLinkFromList(link)
addLinkToHead(link)
}
function removeLeastRecent () {
delete keysToLinks[leastRecentLink.key]
removeLinkFromList(leastRecentLink)
}
function makeLink (key) {
return {
key: key,
lessRecent: null,
moreRecent: null,
value: null,
lastUsedAt: Date.now(),
}
}
function addLinkToHead (link) {
if (mostRecentLink) {
link.lessRecent = mostRecentLink
mostRecentLink.moreRecent = link
mostRecentLink = link
} else {
mostRecentLink = link
leastRecentLink = link
}
}
function removeLinkFromList (link) {
var less = link.lessRecent
var more = link.moreRecent
if (link === leastRecentLink) { leastRecentLink = more }
if (link === mostRecentLink) { mostRecentLink = less }
if (less) { less.moreRecent = more }
if (more) { more.lessRecent = less }
}
function _debug () {
return {
keysToLinks: keysToLinks,
lruLength: lruLength,
leastRecentLink: leastRecentLink && leastRecentLink.key,
mostRecentLink: mostRecentLink && mostRecentLink.key,
eventsToCallbacks: eventsToCallbacks,
options: options,
}
}
}