2 /*---------------------------------------------------------------------------------------------
3 * Copyright (c) Microsoft Corporation. All rights reserved.
4 * Licensed under the MIT License. See License.txt in the project root for license information.
5 *--------------------------------------------------------------------------------------------*/
6 Object.defineProperty(exports, "__esModule", { value: true });
7 exports.LRUCache = exports.LinkedMap = exports.Touch = void 0;
12 Touch.AsOld = Touch.First;
14 Touch.AsNew = Touch.Last;
15 })(Touch = exports.Touch || (exports.Touch = {}));
18 this[Symbol.toStringTag] = 'LinkedMap';
19 this._map = new Map();
20 this._head = undefined;
21 this._tail = undefined;
27 this._head = undefined;
28 this._tail = undefined;
33 return !this._head && !this._tail;
40 return (_a = this._head) === null || _a === void 0 ? void 0 : _a.value;
44 return (_a = this._tail) === null || _a === void 0 ? void 0 : _a.value;
47 return this._map.has(key);
49 get(key, touch = Touch.None) {
50 const item = this._map.get(key);
54 if (touch !== Touch.None) {
55 this.touch(item, touch);
59 set(key, value, touch = Touch.None) {
60 let item = this._map.get(key);
63 if (touch !== Touch.None) {
64 this.touch(item, touch);
68 item = { key, value, next: undefined, previous: undefined };
71 this.addItemLast(item);
74 this.addItemFirst(item);
77 this.addItemLast(item);
80 this.addItemLast(item);
83 this._map.set(key, item);
89 return !!this.remove(key);
92 const item = this._map.get(key);
96 this._map.delete(key);
97 this.removeItem(item);
102 if (!this._head && !this._tail) {
105 if (!this._head || !this._tail) {
106 throw new Error('Invalid list');
108 const item = this._head;
109 this._map.delete(item.key);
110 this.removeItem(item);
114 forEach(callbackfn, thisArg) {
115 const state = this._state;
116 let current = this._head;
119 callbackfn.bind(thisArg)(current.value, current.key, this);
122 callbackfn(current.value, current.key, this);
124 if (this._state !== state) {
125 throw new Error(`LinkedMap got modified during iteration.`);
127 current = current.next;
132 const state = this._state;
133 let current = this._head;
135 [Symbol.iterator]() {
139 if (map._state !== state) {
140 throw new Error(`LinkedMap got modified during iteration.`);
143 const result = { value: current.key, done: false };
144 current = current.next;
148 return { value: undefined, done: true };
156 const state = this._state;
157 let current = this._head;
159 [Symbol.iterator]() {
163 if (map._state !== state) {
164 throw new Error(`LinkedMap got modified during iteration.`);
167 const result = { value: current.value, done: false };
168 current = current.next;
172 return { value: undefined, done: true };
180 const state = this._state;
181 let current = this._head;
183 [Symbol.iterator]() {
187 if (map._state !== state) {
188 throw new Error(`LinkedMap got modified during iteration.`);
191 const result = { value: [current.key, current.value], done: false };
192 current = current.next;
196 return { value: undefined, done: true };
202 [Symbol.iterator]() {
203 return this.entries();
206 if (newSize >= this.size) {
213 let current = this._head;
214 let currentSize = this.size;
215 while (current && currentSize > newSize) {
216 this._map.delete(current.key);
217 current = current.next;
220 this._head = current;
221 this._size = currentSize;
223 current.previous = undefined;
229 if (!this._head && !this._tail) {
232 else if (!this._head) {
233 throw new Error('Invalid list');
236 item.next = this._head;
237 this._head.previous = item;
244 if (!this._head && !this._tail) {
247 else if (!this._tail) {
248 throw new Error('Invalid list');
251 item.previous = this._tail;
252 this._tail.next = item;
258 if (item === this._head && item === this._tail) {
259 this._head = undefined;
260 this._tail = undefined;
262 else if (item === this._head) {
263 // This can only happend if size === 1 which is handle
264 // by the case above.
266 throw new Error('Invalid list');
268 item.next.previous = undefined;
269 this._head = item.next;
271 else if (item === this._tail) {
272 // This can only happend if size === 1 which is handle
273 // by the case above.
274 if (!item.previous) {
275 throw new Error('Invalid list');
277 item.previous.next = undefined;
278 this._tail = item.previous;
281 const next = item.next;
282 const previous = item.previous;
283 if (!next || !previous) {
284 throw new Error('Invalid list');
286 next.previous = previous;
287 previous.next = next;
289 item.next = undefined;
290 item.previous = undefined;
294 if (!this._head || !this._tail) {
295 throw new Error('Invalid list');
297 if ((touch !== Touch.First && touch !== Touch.Last)) {
300 if (touch === Touch.First) {
301 if (item === this._head) {
304 const next = item.next;
305 const previous = item.previous;
307 if (item === this._tail) {
308 // previous must be defined since item was not head but is tail
309 // So there are more than on item in the map
310 previous.next = undefined;
311 this._tail = previous;
314 // Both next and previous are not undefined since item was neither head nor tail.
315 next.previous = previous;
316 previous.next = next;
318 // Insert the node at head
319 item.previous = undefined;
320 item.next = this._head;
321 this._head.previous = item;
325 else if (touch === Touch.Last) {
326 if (item === this._tail) {
329 const next = item.next;
330 const previous = item.previous;
332 if (item === this._head) {
333 // next must be defined since item was not tail but is head
334 // So there are more than on item in the map
335 next.previous = undefined;
339 // Both next and previous are not undefined since item was neither head nor tail.
340 next.previous = previous;
341 previous.next = next;
343 item.next = undefined;
344 item.previous = this._tail;
345 this._tail.next = item;
352 this.forEach((value, key) => {
353 data.push([key, value]);
359 for (const [key, value] of data) {
360 this.set(key, value);
364 exports.LinkedMap = LinkedMap;
365 class LRUCache extends LinkedMap {
366 constructor(limit, ratio = 1) {
369 this._ratio = Math.min(Math.max(0, ratio), 1);
382 this._ratio = Math.min(Math.max(0, ratio), 1);
385 get(key, touch = Touch.AsNew) {
386 return super.get(key, touch);
389 return super.get(key, Touch.None);
392 super.set(key, value, Touch.Last);
397 if (this.size > this._limit) {
398 this.trimOld(Math.round(this._limit * this._ratio));
402 exports.LRUCache = LRUCache;
403 //# sourceMappingURL=linkedMap.js.map