| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- var _a, _b;
- class ResourceMapEntry {
- constructor(uri, value) {
- this.uri = uri;
- this.value = value;
- }
- }
- export class ResourceMap {
- constructor(mapOrKeyFn, toKey) {
- this[_a] = 'ResourceMap';
- if (mapOrKeyFn instanceof ResourceMap) {
- this.map = new Map(mapOrKeyFn.map);
- this.toKey = toKey !== null && toKey !== void 0 ? toKey : ResourceMap.defaultToKey;
- }
- else {
- this.map = new Map();
- this.toKey = mapOrKeyFn !== null && mapOrKeyFn !== void 0 ? mapOrKeyFn : ResourceMap.defaultToKey;
- }
- }
- set(resource, value) {
- this.map.set(this.toKey(resource), new ResourceMapEntry(resource, value));
- return this;
- }
- get(resource) {
- var _c;
- return (_c = this.map.get(this.toKey(resource))) === null || _c === void 0 ? void 0 : _c.value;
- }
- has(resource) {
- return this.map.has(this.toKey(resource));
- }
- get size() {
- return this.map.size;
- }
- clear() {
- this.map.clear();
- }
- delete(resource) {
- return this.map.delete(this.toKey(resource));
- }
- forEach(clb, thisArg) {
- if (typeof thisArg !== 'undefined') {
- clb = clb.bind(thisArg);
- }
- for (const [_, entry] of this.map) {
- clb(entry.value, entry.uri, this);
- }
- }
- *values() {
- for (const entry of this.map.values()) {
- yield entry.value;
- }
- }
- *keys() {
- for (const entry of this.map.values()) {
- yield entry.uri;
- }
- }
- *entries() {
- for (const entry of this.map.values()) {
- yield [entry.uri, entry.value];
- }
- }
- *[(_a = Symbol.toStringTag, Symbol.iterator)]() {
- for (const [, entry] of this.map) {
- yield [entry.uri, entry.value];
- }
- }
- }
- ResourceMap.defaultToKey = (resource) => resource.toString();
- export class LinkedMap {
- constructor() {
- this[_b] = 'LinkedMap';
- this._map = new Map();
- this._head = undefined;
- this._tail = undefined;
- this._size = 0;
- this._state = 0;
- }
- clear() {
- this._map.clear();
- this._head = undefined;
- this._tail = undefined;
- this._size = 0;
- this._state++;
- }
- isEmpty() {
- return !this._head && !this._tail;
- }
- get size() {
- return this._size;
- }
- get first() {
- var _c;
- return (_c = this._head) === null || _c === void 0 ? void 0 : _c.value;
- }
- get last() {
- var _c;
- return (_c = this._tail) === null || _c === void 0 ? void 0 : _c.value;
- }
- has(key) {
- return this._map.has(key);
- }
- get(key, touch = 0 /* Touch.None */) {
- const item = this._map.get(key);
- if (!item) {
- return undefined;
- }
- if (touch !== 0 /* Touch.None */) {
- this.touch(item, touch);
- }
- return item.value;
- }
- set(key, value, touch = 0 /* Touch.None */) {
- let item = this._map.get(key);
- if (item) {
- item.value = value;
- if (touch !== 0 /* Touch.None */) {
- this.touch(item, touch);
- }
- }
- else {
- item = { key, value, next: undefined, previous: undefined };
- switch (touch) {
- case 0 /* Touch.None */:
- this.addItemLast(item);
- break;
- case 1 /* Touch.AsOld */:
- this.addItemFirst(item);
- break;
- case 2 /* Touch.AsNew */:
- this.addItemLast(item);
- break;
- default:
- this.addItemLast(item);
- break;
- }
- this._map.set(key, item);
- this._size++;
- }
- return this;
- }
- delete(key) {
- return !!this.remove(key);
- }
- remove(key) {
- const item = this._map.get(key);
- if (!item) {
- return undefined;
- }
- this._map.delete(key);
- this.removeItem(item);
- this._size--;
- return item.value;
- }
- shift() {
- if (!this._head && !this._tail) {
- return undefined;
- }
- if (!this._head || !this._tail) {
- throw new Error('Invalid list');
- }
- const item = this._head;
- this._map.delete(item.key);
- this.removeItem(item);
- this._size--;
- return item.value;
- }
- forEach(callbackfn, thisArg) {
- const state = this._state;
- let current = this._head;
- while (current) {
- if (thisArg) {
- callbackfn.bind(thisArg)(current.value, current.key, this);
- }
- else {
- callbackfn(current.value, current.key, this);
- }
- if (this._state !== state) {
- throw new Error(`LinkedMap got modified during iteration.`);
- }
- current = current.next;
- }
- }
- keys() {
- const map = this;
- const state = this._state;
- let current = this._head;
- const iterator = {
- [Symbol.iterator]() {
- return iterator;
- },
- next() {
- if (map._state !== state) {
- throw new Error(`LinkedMap got modified during iteration.`);
- }
- if (current) {
- const result = { value: current.key, done: false };
- current = current.next;
- return result;
- }
- else {
- return { value: undefined, done: true };
- }
- }
- };
- return iterator;
- }
- values() {
- const map = this;
- const state = this._state;
- let current = this._head;
- const iterator = {
- [Symbol.iterator]() {
- return iterator;
- },
- next() {
- if (map._state !== state) {
- throw new Error(`LinkedMap got modified during iteration.`);
- }
- if (current) {
- const result = { value: current.value, done: false };
- current = current.next;
- return result;
- }
- else {
- return { value: undefined, done: true };
- }
- }
- };
- return iterator;
- }
- entries() {
- const map = this;
- const state = this._state;
- let current = this._head;
- const iterator = {
- [Symbol.iterator]() {
- return iterator;
- },
- next() {
- if (map._state !== state) {
- throw new Error(`LinkedMap got modified during iteration.`);
- }
- if (current) {
- const result = { value: [current.key, current.value], done: false };
- current = current.next;
- return result;
- }
- else {
- return { value: undefined, done: true };
- }
- }
- };
- return iterator;
- }
- [(_b = Symbol.toStringTag, Symbol.iterator)]() {
- return this.entries();
- }
- trimOld(newSize) {
- if (newSize >= this.size) {
- return;
- }
- if (newSize === 0) {
- this.clear();
- return;
- }
- let current = this._head;
- let currentSize = this.size;
- while (current && currentSize > newSize) {
- this._map.delete(current.key);
- current = current.next;
- currentSize--;
- }
- this._head = current;
- this._size = currentSize;
- if (current) {
- current.previous = undefined;
- }
- this._state++;
- }
- addItemFirst(item) {
- // First time Insert
- if (!this._head && !this._tail) {
- this._tail = item;
- }
- else if (!this._head) {
- throw new Error('Invalid list');
- }
- else {
- item.next = this._head;
- this._head.previous = item;
- }
- this._head = item;
- this._state++;
- }
- addItemLast(item) {
- // First time Insert
- if (!this._head && !this._tail) {
- this._head = item;
- }
- else if (!this._tail) {
- throw new Error('Invalid list');
- }
- else {
- item.previous = this._tail;
- this._tail.next = item;
- }
- this._tail = item;
- this._state++;
- }
- removeItem(item) {
- if (item === this._head && item === this._tail) {
- this._head = undefined;
- this._tail = undefined;
- }
- else if (item === this._head) {
- // This can only happen if size === 1 which is handled
- // by the case above.
- if (!item.next) {
- throw new Error('Invalid list');
- }
- item.next.previous = undefined;
- this._head = item.next;
- }
- else if (item === this._tail) {
- // This can only happen if size === 1 which is handled
- // by the case above.
- if (!item.previous) {
- throw new Error('Invalid list');
- }
- item.previous.next = undefined;
- this._tail = item.previous;
- }
- else {
- const next = item.next;
- const previous = item.previous;
- if (!next || !previous) {
- throw new Error('Invalid list');
- }
- next.previous = previous;
- previous.next = next;
- }
- item.next = undefined;
- item.previous = undefined;
- this._state++;
- }
- touch(item, touch) {
- if (!this._head || !this._tail) {
- throw new Error('Invalid list');
- }
- if ((touch !== 1 /* Touch.AsOld */ && touch !== 2 /* Touch.AsNew */)) {
- return;
- }
- if (touch === 1 /* Touch.AsOld */) {
- if (item === this._head) {
- return;
- }
- const next = item.next;
- const previous = item.previous;
- // Unlink the item
- if (item === this._tail) {
- // previous must be defined since item was not head but is tail
- // So there are more than on item in the map
- previous.next = undefined;
- this._tail = previous;
- }
- else {
- // Both next and previous are not undefined since item was neither head nor tail.
- next.previous = previous;
- previous.next = next;
- }
- // Insert the node at head
- item.previous = undefined;
- item.next = this._head;
- this._head.previous = item;
- this._head = item;
- this._state++;
- }
- else if (touch === 2 /* Touch.AsNew */) {
- if (item === this._tail) {
- return;
- }
- const next = item.next;
- const previous = item.previous;
- // Unlink the item.
- if (item === this._head) {
- // next must be defined since item was not tail but is head
- // So there are more than on item in the map
- next.previous = undefined;
- this._head = next;
- }
- else {
- // Both next and previous are not undefined since item was neither head nor tail.
- next.previous = previous;
- previous.next = next;
- }
- item.next = undefined;
- item.previous = this._tail;
- this._tail.next = item;
- this._tail = item;
- this._state++;
- }
- }
- toJSON() {
- const data = [];
- this.forEach((value, key) => {
- data.push([key, value]);
- });
- return data;
- }
- fromJSON(data) {
- this.clear();
- for (const [key, value] of data) {
- this.set(key, value);
- }
- }
- }
- export class LRUCache extends LinkedMap {
- constructor(limit, ratio = 1) {
- super();
- this._limit = limit;
- this._ratio = Math.min(Math.max(0, ratio), 1);
- }
- get limit() {
- return this._limit;
- }
- set limit(limit) {
- this._limit = limit;
- this.checkTrim();
- }
- get(key, touch = 2 /* Touch.AsNew */) {
- return super.get(key, touch);
- }
- peek(key) {
- return super.get(key, 0 /* Touch.None */);
- }
- set(key, value) {
- super.set(key, value, 2 /* Touch.AsNew */);
- this.checkTrim();
- return this;
- }
- checkTrim() {
- if (this.size > this._limit) {
- this.trimOld(Math.round(this._limit * this._ratio));
- }
- }
- }
|