map.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var _a, _b;
  6. class ResourceMapEntry {
  7. constructor(uri, value) {
  8. this.uri = uri;
  9. this.value = value;
  10. }
  11. }
  12. export class ResourceMap {
  13. constructor(mapOrKeyFn, toKey) {
  14. this[_a] = 'ResourceMap';
  15. if (mapOrKeyFn instanceof ResourceMap) {
  16. this.map = new Map(mapOrKeyFn.map);
  17. this.toKey = toKey !== null && toKey !== void 0 ? toKey : ResourceMap.defaultToKey;
  18. }
  19. else {
  20. this.map = new Map();
  21. this.toKey = mapOrKeyFn !== null && mapOrKeyFn !== void 0 ? mapOrKeyFn : ResourceMap.defaultToKey;
  22. }
  23. }
  24. set(resource, value) {
  25. this.map.set(this.toKey(resource), new ResourceMapEntry(resource, value));
  26. return this;
  27. }
  28. get(resource) {
  29. var _c;
  30. return (_c = this.map.get(this.toKey(resource))) === null || _c === void 0 ? void 0 : _c.value;
  31. }
  32. has(resource) {
  33. return this.map.has(this.toKey(resource));
  34. }
  35. get size() {
  36. return this.map.size;
  37. }
  38. clear() {
  39. this.map.clear();
  40. }
  41. delete(resource) {
  42. return this.map.delete(this.toKey(resource));
  43. }
  44. forEach(clb, thisArg) {
  45. if (typeof thisArg !== 'undefined') {
  46. clb = clb.bind(thisArg);
  47. }
  48. for (const [_, entry] of this.map) {
  49. clb(entry.value, entry.uri, this);
  50. }
  51. }
  52. *values() {
  53. for (const entry of this.map.values()) {
  54. yield entry.value;
  55. }
  56. }
  57. *keys() {
  58. for (const entry of this.map.values()) {
  59. yield entry.uri;
  60. }
  61. }
  62. *entries() {
  63. for (const entry of this.map.values()) {
  64. yield [entry.uri, entry.value];
  65. }
  66. }
  67. *[(_a = Symbol.toStringTag, Symbol.iterator)]() {
  68. for (const [, entry] of this.map) {
  69. yield [entry.uri, entry.value];
  70. }
  71. }
  72. }
  73. ResourceMap.defaultToKey = (resource) => resource.toString();
  74. export class LinkedMap {
  75. constructor() {
  76. this[_b] = 'LinkedMap';
  77. this._map = new Map();
  78. this._head = undefined;
  79. this._tail = undefined;
  80. this._size = 0;
  81. this._state = 0;
  82. }
  83. clear() {
  84. this._map.clear();
  85. this._head = undefined;
  86. this._tail = undefined;
  87. this._size = 0;
  88. this._state++;
  89. }
  90. isEmpty() {
  91. return !this._head && !this._tail;
  92. }
  93. get size() {
  94. return this._size;
  95. }
  96. get first() {
  97. var _c;
  98. return (_c = this._head) === null || _c === void 0 ? void 0 : _c.value;
  99. }
  100. get last() {
  101. var _c;
  102. return (_c = this._tail) === null || _c === void 0 ? void 0 : _c.value;
  103. }
  104. has(key) {
  105. return this._map.has(key);
  106. }
  107. get(key, touch = 0 /* Touch.None */) {
  108. const item = this._map.get(key);
  109. if (!item) {
  110. return undefined;
  111. }
  112. if (touch !== 0 /* Touch.None */) {
  113. this.touch(item, touch);
  114. }
  115. return item.value;
  116. }
  117. set(key, value, touch = 0 /* Touch.None */) {
  118. let item = this._map.get(key);
  119. if (item) {
  120. item.value = value;
  121. if (touch !== 0 /* Touch.None */) {
  122. this.touch(item, touch);
  123. }
  124. }
  125. else {
  126. item = { key, value, next: undefined, previous: undefined };
  127. switch (touch) {
  128. case 0 /* Touch.None */:
  129. this.addItemLast(item);
  130. break;
  131. case 1 /* Touch.AsOld */:
  132. this.addItemFirst(item);
  133. break;
  134. case 2 /* Touch.AsNew */:
  135. this.addItemLast(item);
  136. break;
  137. default:
  138. this.addItemLast(item);
  139. break;
  140. }
  141. this._map.set(key, item);
  142. this._size++;
  143. }
  144. return this;
  145. }
  146. delete(key) {
  147. return !!this.remove(key);
  148. }
  149. remove(key) {
  150. const item = this._map.get(key);
  151. if (!item) {
  152. return undefined;
  153. }
  154. this._map.delete(key);
  155. this.removeItem(item);
  156. this._size--;
  157. return item.value;
  158. }
  159. shift() {
  160. if (!this._head && !this._tail) {
  161. return undefined;
  162. }
  163. if (!this._head || !this._tail) {
  164. throw new Error('Invalid list');
  165. }
  166. const item = this._head;
  167. this._map.delete(item.key);
  168. this.removeItem(item);
  169. this._size--;
  170. return item.value;
  171. }
  172. forEach(callbackfn, thisArg) {
  173. const state = this._state;
  174. let current = this._head;
  175. while (current) {
  176. if (thisArg) {
  177. callbackfn.bind(thisArg)(current.value, current.key, this);
  178. }
  179. else {
  180. callbackfn(current.value, current.key, this);
  181. }
  182. if (this._state !== state) {
  183. throw new Error(`LinkedMap got modified during iteration.`);
  184. }
  185. current = current.next;
  186. }
  187. }
  188. keys() {
  189. const map = this;
  190. const state = this._state;
  191. let current = this._head;
  192. const iterator = {
  193. [Symbol.iterator]() {
  194. return iterator;
  195. },
  196. next() {
  197. if (map._state !== state) {
  198. throw new Error(`LinkedMap got modified during iteration.`);
  199. }
  200. if (current) {
  201. const result = { value: current.key, done: false };
  202. current = current.next;
  203. return result;
  204. }
  205. else {
  206. return { value: undefined, done: true };
  207. }
  208. }
  209. };
  210. return iterator;
  211. }
  212. values() {
  213. const map = this;
  214. const state = this._state;
  215. let current = this._head;
  216. const iterator = {
  217. [Symbol.iterator]() {
  218. return iterator;
  219. },
  220. next() {
  221. if (map._state !== state) {
  222. throw new Error(`LinkedMap got modified during iteration.`);
  223. }
  224. if (current) {
  225. const result = { value: current.value, done: false };
  226. current = current.next;
  227. return result;
  228. }
  229. else {
  230. return { value: undefined, done: true };
  231. }
  232. }
  233. };
  234. return iterator;
  235. }
  236. entries() {
  237. const map = this;
  238. const state = this._state;
  239. let current = this._head;
  240. const iterator = {
  241. [Symbol.iterator]() {
  242. return iterator;
  243. },
  244. next() {
  245. if (map._state !== state) {
  246. throw new Error(`LinkedMap got modified during iteration.`);
  247. }
  248. if (current) {
  249. const result = { value: [current.key, current.value], done: false };
  250. current = current.next;
  251. return result;
  252. }
  253. else {
  254. return { value: undefined, done: true };
  255. }
  256. }
  257. };
  258. return iterator;
  259. }
  260. [(_b = Symbol.toStringTag, Symbol.iterator)]() {
  261. return this.entries();
  262. }
  263. trimOld(newSize) {
  264. if (newSize >= this.size) {
  265. return;
  266. }
  267. if (newSize === 0) {
  268. this.clear();
  269. return;
  270. }
  271. let current = this._head;
  272. let currentSize = this.size;
  273. while (current && currentSize > newSize) {
  274. this._map.delete(current.key);
  275. current = current.next;
  276. currentSize--;
  277. }
  278. this._head = current;
  279. this._size = currentSize;
  280. if (current) {
  281. current.previous = undefined;
  282. }
  283. this._state++;
  284. }
  285. addItemFirst(item) {
  286. // First time Insert
  287. if (!this._head && !this._tail) {
  288. this._tail = item;
  289. }
  290. else if (!this._head) {
  291. throw new Error('Invalid list');
  292. }
  293. else {
  294. item.next = this._head;
  295. this._head.previous = item;
  296. }
  297. this._head = item;
  298. this._state++;
  299. }
  300. addItemLast(item) {
  301. // First time Insert
  302. if (!this._head && !this._tail) {
  303. this._head = item;
  304. }
  305. else if (!this._tail) {
  306. throw new Error('Invalid list');
  307. }
  308. else {
  309. item.previous = this._tail;
  310. this._tail.next = item;
  311. }
  312. this._tail = item;
  313. this._state++;
  314. }
  315. removeItem(item) {
  316. if (item === this._head && item === this._tail) {
  317. this._head = undefined;
  318. this._tail = undefined;
  319. }
  320. else if (item === this._head) {
  321. // This can only happen if size === 1 which is handled
  322. // by the case above.
  323. if (!item.next) {
  324. throw new Error('Invalid list');
  325. }
  326. item.next.previous = undefined;
  327. this._head = item.next;
  328. }
  329. else if (item === this._tail) {
  330. // This can only happen if size === 1 which is handled
  331. // by the case above.
  332. if (!item.previous) {
  333. throw new Error('Invalid list');
  334. }
  335. item.previous.next = undefined;
  336. this._tail = item.previous;
  337. }
  338. else {
  339. const next = item.next;
  340. const previous = item.previous;
  341. if (!next || !previous) {
  342. throw new Error('Invalid list');
  343. }
  344. next.previous = previous;
  345. previous.next = next;
  346. }
  347. item.next = undefined;
  348. item.previous = undefined;
  349. this._state++;
  350. }
  351. touch(item, touch) {
  352. if (!this._head || !this._tail) {
  353. throw new Error('Invalid list');
  354. }
  355. if ((touch !== 1 /* Touch.AsOld */ && touch !== 2 /* Touch.AsNew */)) {
  356. return;
  357. }
  358. if (touch === 1 /* Touch.AsOld */) {
  359. if (item === this._head) {
  360. return;
  361. }
  362. const next = item.next;
  363. const previous = item.previous;
  364. // Unlink the item
  365. if (item === this._tail) {
  366. // previous must be defined since item was not head but is tail
  367. // So there are more than on item in the map
  368. previous.next = undefined;
  369. this._tail = previous;
  370. }
  371. else {
  372. // Both next and previous are not undefined since item was neither head nor tail.
  373. next.previous = previous;
  374. previous.next = next;
  375. }
  376. // Insert the node at head
  377. item.previous = undefined;
  378. item.next = this._head;
  379. this._head.previous = item;
  380. this._head = item;
  381. this._state++;
  382. }
  383. else if (touch === 2 /* Touch.AsNew */) {
  384. if (item === this._tail) {
  385. return;
  386. }
  387. const next = item.next;
  388. const previous = item.previous;
  389. // Unlink the item.
  390. if (item === this._head) {
  391. // next must be defined since item was not tail but is head
  392. // So there are more than on item in the map
  393. next.previous = undefined;
  394. this._head = next;
  395. }
  396. else {
  397. // Both next and previous are not undefined since item was neither head nor tail.
  398. next.previous = previous;
  399. previous.next = next;
  400. }
  401. item.next = undefined;
  402. item.previous = this._tail;
  403. this._tail.next = item;
  404. this._tail = item;
  405. this._state++;
  406. }
  407. }
  408. toJSON() {
  409. const data = [];
  410. this.forEach((value, key) => {
  411. data.push([key, value]);
  412. });
  413. return data;
  414. }
  415. fromJSON(data) {
  416. this.clear();
  417. for (const [key, value] of data) {
  418. this.set(key, value);
  419. }
  420. }
  421. }
  422. export class LRUCache extends LinkedMap {
  423. constructor(limit, ratio = 1) {
  424. super();
  425. this._limit = limit;
  426. this._ratio = Math.min(Math.max(0, ratio), 1);
  427. }
  428. get limit() {
  429. return this._limit;
  430. }
  431. set limit(limit) {
  432. this._limit = limit;
  433. this.checkTrim();
  434. }
  435. get(key, touch = 2 /* Touch.AsNew */) {
  436. return super.get(key, touch);
  437. }
  438. peek(key) {
  439. return super.get(key, 0 /* Touch.None */);
  440. }
  441. set(key, value) {
  442. super.set(key, value, 2 /* Touch.AsNew */);
  443. this.checkTrim();
  444. return this;
  445. }
  446. checkTrim() {
  447. if (this.size > this._limit) {
  448. this.trimOld(Math.round(this._limit * this._ratio));
  449. }
  450. }
  451. }