1
+ const LinkedList = require ( "./linkedlist/index.cjs" ) ;
2
+
1
3
module . exports = class Cache {
4
+ #linkedList = null ;
2
5
#cache = null ;
3
6
#config = {
4
7
ttl : 0 ,
5
- maxLength : 0 ,
8
+ maxLength : 250 ,
6
9
interval : 0 ,
7
10
intervalId : null ,
8
11
enableInterval : false ,
@@ -55,12 +58,12 @@ module.exports = class Cache {
55
58
? options . enableInterval
56
59
: false ;
57
60
58
- this . #config. evictionPolicy = options . evictionPolicy ;
59
61
this . #config. maxLength = options . maxLength ;
60
62
this . #config. ttl = options . ttl ;
61
63
this . #config. interval = options . interval ;
62
64
this . #config. enableInterval =
63
65
options . interval > 0 ? options . enableInterval : false ;
66
+ this . #linkedList = new LinkedList ( ) ;
64
67
this . #cache = new Map ( ) ;
65
68
66
69
// Automatically remove expires cache
@@ -72,7 +75,6 @@ module.exports = class Cache {
72
75
}
73
76
74
77
set ( key , value , options = { } ) {
75
- // Insert a new node at head
76
78
if (
77
79
( typeof options . ttl !== "undefined" && typeof options . ttl !== "number" ) ||
78
80
options . ttl < 0
@@ -83,31 +85,32 @@ module.exports = class Cache {
83
85
options . ttl =
84
86
typeof options . ttl === "number" ? options . ttl : this . #config. ttl ;
85
87
86
- const node = {
88
+ const nodeValue = {
87
89
key : key ,
88
90
value : value ,
89
91
createdAt : Date . now ( ) ,
90
92
expiresAt : null ,
91
93
ttl : options . ttl ,
92
94
frequency : 0 ,
93
95
} ;
94
- if ( node . ttl > 0 ) {
95
- node . expiresAt = node . createdAt + node . ttl ;
96
+ if ( nodeValue . ttl > 0 ) {
97
+ nodeValue . expiresAt = nodeValue . createdAt + nodeValue . ttl ;
96
98
}
97
99
100
+ // Insert a new node at head
101
+ const existingNode = this . #cache. get ( key ) ;
98
102
// Update node data if node is already exists
99
- if ( this . #cache. has ( key ) ) {
100
- const existingNode = this . #cache. get ( key ) ;
101
- existingNode . value = node . value ;
103
+ if ( typeof existingNode !== "undefined" ) {
104
+ existingNode . value = nodeValue ;
102
105
// Move current node to the head
103
- this . #cache. delete ( key ) ;
104
- this . #cache. set ( key , existingNode ) ;
106
+ this . #linkedList. setHead ( existingNode ) ;
105
107
} else {
106
108
// Remove node if cache is full
107
109
if ( this . length === this . #config. maxLength ) {
108
110
this . #evict( ) ;
109
111
}
110
112
// Create new node and make attach it to the head
113
+ const node = this . #linkedList. insertHead ( nodeValue ) ;
111
114
this . #cache. set ( key , node ) ;
112
115
}
113
116
}
@@ -118,26 +121,26 @@ module.exports = class Cache {
118
121
throw new TypeError ( "callback should be a function" ) ;
119
122
}
120
123
121
- if ( this . #cache. has ( key ) ) {
122
- const node = this . #cache. get ( key ) ;
124
+ const node = this . #cache. get ( key ) ;
125
+
126
+ if ( typeof node !== "undefined" ) {
123
127
// Check node is live or not
124
128
if ( this . #isStale( node ) ) {
125
129
this . delete ( key ) ;
126
- throw new Error ( key + " key not found" ) ;
130
+ throw new Error ( key + " Key not found" ) ;
127
131
}
128
132
129
133
// Move current node to the head
130
- this . #cache. delete ( key ) ;
131
- this . #cache. set ( key , node ) ;
134
+ this . #linkedList. setHead ( node ) ;
132
135
133
136
if ( callback ) {
134
- return callback ( null , node . value ) ;
137
+ return callback ( null , node . value . value ) ;
135
138
} else {
136
- return node . value ;
139
+ return node . value . value ;
137
140
}
138
141
}
139
142
140
- throw new Error ( key + " key not found" ) ;
143
+ throw new Error ( key + " Key not found" ) ;
141
144
} catch ( err ) {
142
145
if ( callback ) {
143
146
return callback ( err , undefined ) ;
@@ -148,27 +151,41 @@ module.exports = class Cache {
148
151
}
149
152
150
153
delete ( key ) {
151
- if ( this . #cache. has ( key ) ) {
154
+ const node = this . #cache. get ( key ) ;
155
+
156
+ if ( typeof node !== "undefined" ) {
157
+ this . #linkedList. delete ( node ) ;
152
158
// Delete node
153
159
this . #cache. delete ( key ) ;
154
160
}
155
161
}
156
162
157
163
#evict( ) {
158
- if ( this . length === 0 ) return ;
164
+ if ( this . #linkedList . tail === null ) return ;
159
165
if ( this . length !== this . #config. maxLength ) return ;
160
-
161
- for ( const key of this . #cache. keys ( ) ) {
162
- this . delete ( key ) ;
163
- break ;
164
- }
166
+ this . delete ( this . #linkedList. tail . value . key ) ;
165
167
}
166
168
167
169
clear ( ) {
168
170
// Delete all data from cache
171
+ this . #linkedList. clear ( ) ;
169
172
this . #cache. clear ( ) ;
170
173
}
171
174
175
+ has ( key ) {
176
+ const node = this . #cache. get ( key ) ;
177
+
178
+ if ( typeof node !== "undefined" ) {
179
+ // Check node is live or not
180
+ if ( this . #isStale( node ) ) {
181
+ this . delete ( key ) ;
182
+ } else {
183
+ return true ;
184
+ }
185
+ }
186
+ return false ;
187
+ }
188
+
172
189
startInterval ( ) {
173
190
// Interval already running
174
191
if ( this . #config. intervalId ) return ;
@@ -193,31 +210,21 @@ module.exports = class Cache {
193
210
}
194
211
}
195
212
196
- has ( key ) {
197
- if ( this . #cache. has ( key ) ) {
198
- const node = this . #cache. get ( key ) ;
199
- // Check node is live or not
200
- if ( this . #isStale( node ) ) {
201
- this . delete ( key ) ;
202
- } else {
203
- return true ;
204
- }
205
- }
206
- return false ;
207
- }
208
-
209
213
// Iterate over cache using forEach loop
210
214
forEach ( callback ) {
211
215
if ( callback && typeof callback !== "function" ) {
212
216
throw new TypeError ( "callback should be a function" ) ;
213
217
}
214
218
219
+ let node = this . #linkedList. head ;
215
220
let index = 0 ;
216
- for ( const data of this . #cache . entries ( ) ) {
217
- if ( this . has ( data [ 0 ] ) ) {
218
- callback ( { [ data [ 0 ] ] : data [ 1 ] . value } , index ) ;
219
- index ++ ;
221
+ while ( node ) {
222
+ let next = node . next ;
223
+ if ( this . has ( node . value . key ) ) {
224
+ callback ( { [ node . value . key ] : node . value . value } , index ) ;
220
225
}
226
+ node = next ;
227
+ index ++ ;
221
228
}
222
229
}
223
230
@@ -230,16 +237,19 @@ module.exports = class Cache {
230
237
}
231
238
232
239
#isStale( node ) {
233
- if ( ! node . expiresAt ) return false ;
234
- return node . expiresAt - Date . now ( ) <= 0 ;
240
+ if ( ! node . value . expiresAt ) return false ;
241
+ return node . value . expiresAt - Date . now ( ) <= 0 ;
235
242
}
236
243
237
244
// Iterator to iterate over cache with a 'for...of' loop
238
245
* [ Symbol . iterator ] ( ) {
239
- for ( const data of this . #cache. entries ( ) ) {
240
- if ( this . has ( data [ 0 ] ) ) {
241
- yield { [ data [ 0 ] ] : data [ 1 ] . value } ;
246
+ let node = this . #linkedList. head ;
247
+ while ( node ) {
248
+ let next = node . next ;
249
+ if ( this . has ( node . value . key ) ) {
250
+ yield { [ node . value . key ] : node . value . value } ;
242
251
}
252
+ node = next ;
243
253
}
244
254
}
245
255
} ;
0 commit comments