map.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  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. import { compare, compareIgnoreCase, compareSubstring, compareSubstringIgnoreCase } from './strings.js';
  7. import { URI } from './uri.js';
  8. export class StringIterator {
  9. constructor() {
  10. this._value = '';
  11. this._pos = 0;
  12. }
  13. reset(key) {
  14. this._value = key;
  15. this._pos = 0;
  16. return this;
  17. }
  18. next() {
  19. this._pos += 1;
  20. return this;
  21. }
  22. hasNext() {
  23. return this._pos < this._value.length - 1;
  24. }
  25. cmp(a) {
  26. const aCode = a.charCodeAt(0);
  27. const thisCode = this._value.charCodeAt(this._pos);
  28. return aCode - thisCode;
  29. }
  30. value() {
  31. return this._value[this._pos];
  32. }
  33. }
  34. export class ConfigKeysIterator {
  35. constructor(_caseSensitive = true) {
  36. this._caseSensitive = _caseSensitive;
  37. }
  38. reset(key) {
  39. this._value = key;
  40. this._from = 0;
  41. this._to = 0;
  42. return this.next();
  43. }
  44. hasNext() {
  45. return this._to < this._value.length;
  46. }
  47. next() {
  48. // this._data = key.split(/[\\/]/).filter(s => !!s);
  49. this._from = this._to;
  50. let justSeps = true;
  51. for (; this._to < this._value.length; this._to++) {
  52. const ch = this._value.charCodeAt(this._to);
  53. if (ch === 46 /* Period */) {
  54. if (justSeps) {
  55. this._from++;
  56. }
  57. else {
  58. break;
  59. }
  60. }
  61. else {
  62. justSeps = false;
  63. }
  64. }
  65. return this;
  66. }
  67. cmp(a) {
  68. return this._caseSensitive
  69. ? compareSubstring(a, this._value, 0, a.length, this._from, this._to)
  70. : compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);
  71. }
  72. value() {
  73. return this._value.substring(this._from, this._to);
  74. }
  75. }
  76. export class PathIterator {
  77. constructor(_splitOnBackslash = true, _caseSensitive = true) {
  78. this._splitOnBackslash = _splitOnBackslash;
  79. this._caseSensitive = _caseSensitive;
  80. }
  81. reset(key) {
  82. this._value = key.replace(/\\$|\/$/, '');
  83. this._from = 0;
  84. this._to = 0;
  85. return this.next();
  86. }
  87. hasNext() {
  88. return this._to < this._value.length;
  89. }
  90. next() {
  91. // this._data = key.split(/[\\/]/).filter(s => !!s);
  92. this._from = this._to;
  93. let justSeps = true;
  94. for (; this._to < this._value.length; this._to++) {
  95. const ch = this._value.charCodeAt(this._to);
  96. if (ch === 47 /* Slash */ || this._splitOnBackslash && ch === 92 /* Backslash */) {
  97. if (justSeps) {
  98. this._from++;
  99. }
  100. else {
  101. break;
  102. }
  103. }
  104. else {
  105. justSeps = false;
  106. }
  107. }
  108. return this;
  109. }
  110. cmp(a) {
  111. return this._caseSensitive
  112. ? compareSubstring(a, this._value, 0, a.length, this._from, this._to)
  113. : compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);
  114. }
  115. value() {
  116. return this._value.substring(this._from, this._to);
  117. }
  118. }
  119. export class UriIterator {
  120. constructor(_ignorePathCasing) {
  121. this._ignorePathCasing = _ignorePathCasing;
  122. this._states = [];
  123. this._stateIdx = 0;
  124. }
  125. reset(key) {
  126. this._value = key;
  127. this._states = [];
  128. if (this._value.scheme) {
  129. this._states.push(1 /* Scheme */);
  130. }
  131. if (this._value.authority) {
  132. this._states.push(2 /* Authority */);
  133. }
  134. if (this._value.path) {
  135. this._pathIterator = new PathIterator(false, !this._ignorePathCasing(key));
  136. this._pathIterator.reset(key.path);
  137. if (this._pathIterator.value()) {
  138. this._states.push(3 /* Path */);
  139. }
  140. }
  141. if (this._value.query) {
  142. this._states.push(4 /* Query */);
  143. }
  144. if (this._value.fragment) {
  145. this._states.push(5 /* Fragment */);
  146. }
  147. this._stateIdx = 0;
  148. return this;
  149. }
  150. next() {
  151. if (this._states[this._stateIdx] === 3 /* Path */ && this._pathIterator.hasNext()) {
  152. this._pathIterator.next();
  153. }
  154. else {
  155. this._stateIdx += 1;
  156. }
  157. return this;
  158. }
  159. hasNext() {
  160. return (this._states[this._stateIdx] === 3 /* Path */ && this._pathIterator.hasNext())
  161. || this._stateIdx < this._states.length - 1;
  162. }
  163. cmp(a) {
  164. if (this._states[this._stateIdx] === 1 /* Scheme */) {
  165. return compareIgnoreCase(a, this._value.scheme);
  166. }
  167. else if (this._states[this._stateIdx] === 2 /* Authority */) {
  168. return compareIgnoreCase(a, this._value.authority);
  169. }
  170. else if (this._states[this._stateIdx] === 3 /* Path */) {
  171. return this._pathIterator.cmp(a);
  172. }
  173. else if (this._states[this._stateIdx] === 4 /* Query */) {
  174. return compare(a, this._value.query);
  175. }
  176. else if (this._states[this._stateIdx] === 5 /* Fragment */) {
  177. return compare(a, this._value.fragment);
  178. }
  179. throw new Error();
  180. }
  181. value() {
  182. if (this._states[this._stateIdx] === 1 /* Scheme */) {
  183. return this._value.scheme;
  184. }
  185. else if (this._states[this._stateIdx] === 2 /* Authority */) {
  186. return this._value.authority;
  187. }
  188. else if (this._states[this._stateIdx] === 3 /* Path */) {
  189. return this._pathIterator.value();
  190. }
  191. else if (this._states[this._stateIdx] === 4 /* Query */) {
  192. return this._value.query;
  193. }
  194. else if (this._states[this._stateIdx] === 5 /* Fragment */) {
  195. return this._value.fragment;
  196. }
  197. throw new Error();
  198. }
  199. }
  200. class TernarySearchTreeNode {
  201. isEmpty() {
  202. return !this.left && !this.mid && !this.right && !this.value;
  203. }
  204. }
  205. export class TernarySearchTree {
  206. constructor(segments) {
  207. this._iter = segments;
  208. }
  209. static forUris(ignorePathCasing = () => false) {
  210. return new TernarySearchTree(new UriIterator(ignorePathCasing));
  211. }
  212. static forStrings() {
  213. return new TernarySearchTree(new StringIterator());
  214. }
  215. static forConfigKeys() {
  216. return new TernarySearchTree(new ConfigKeysIterator());
  217. }
  218. clear() {
  219. this._root = undefined;
  220. }
  221. set(key, element) {
  222. const iter = this._iter.reset(key);
  223. let node;
  224. if (!this._root) {
  225. this._root = new TernarySearchTreeNode();
  226. this._root.segment = iter.value();
  227. }
  228. node = this._root;
  229. while (true) {
  230. const val = iter.cmp(node.segment);
  231. if (val > 0) {
  232. // left
  233. if (!node.left) {
  234. node.left = new TernarySearchTreeNode();
  235. node.left.segment = iter.value();
  236. }
  237. node = node.left;
  238. }
  239. else if (val < 0) {
  240. // right
  241. if (!node.right) {
  242. node.right = new TernarySearchTreeNode();
  243. node.right.segment = iter.value();
  244. }
  245. node = node.right;
  246. }
  247. else if (iter.hasNext()) {
  248. // mid
  249. iter.next();
  250. if (!node.mid) {
  251. node.mid = new TernarySearchTreeNode();
  252. node.mid.segment = iter.value();
  253. }
  254. node = node.mid;
  255. }
  256. else {
  257. break;
  258. }
  259. }
  260. const oldElement = node.value;
  261. node.value = element;
  262. node.key = key;
  263. return oldElement;
  264. }
  265. get(key) {
  266. var _c;
  267. return (_c = this._getNode(key)) === null || _c === void 0 ? void 0 : _c.value;
  268. }
  269. _getNode(key) {
  270. const iter = this._iter.reset(key);
  271. let node = this._root;
  272. while (node) {
  273. const val = iter.cmp(node.segment);
  274. if (val > 0) {
  275. // left
  276. node = node.left;
  277. }
  278. else if (val < 0) {
  279. // right
  280. node = node.right;
  281. }
  282. else if (iter.hasNext()) {
  283. // mid
  284. iter.next();
  285. node = node.mid;
  286. }
  287. else {
  288. break;
  289. }
  290. }
  291. return node;
  292. }
  293. has(key) {
  294. const node = this._getNode(key);
  295. return !((node === null || node === void 0 ? void 0 : node.value) === undefined && (node === null || node === void 0 ? void 0 : node.mid) === undefined);
  296. }
  297. delete(key) {
  298. return this._delete(key, false);
  299. }
  300. deleteSuperstr(key) {
  301. return this._delete(key, true);
  302. }
  303. _delete(key, superStr) {
  304. const iter = this._iter.reset(key);
  305. const stack = [];
  306. let node = this._root;
  307. // find and unset node
  308. while (node) {
  309. const val = iter.cmp(node.segment);
  310. if (val > 0) {
  311. // left
  312. stack.push([1, node]);
  313. node = node.left;
  314. }
  315. else if (val < 0) {
  316. // right
  317. stack.push([-1, node]);
  318. node = node.right;
  319. }
  320. else if (iter.hasNext()) {
  321. // mid
  322. iter.next();
  323. stack.push([0, node]);
  324. node = node.mid;
  325. }
  326. else {
  327. if (superStr) {
  328. // remove children
  329. node.left = undefined;
  330. node.mid = undefined;
  331. node.right = undefined;
  332. }
  333. else {
  334. // remove element
  335. node.value = undefined;
  336. }
  337. // clean up empty nodes
  338. while (stack.length > 0 && node.isEmpty()) {
  339. let [dir, parent] = stack.pop();
  340. switch (dir) {
  341. case 1:
  342. parent.left = undefined;
  343. break;
  344. case 0:
  345. parent.mid = undefined;
  346. break;
  347. case -1:
  348. parent.right = undefined;
  349. break;
  350. }
  351. node = parent;
  352. }
  353. break;
  354. }
  355. }
  356. }
  357. findSubstr(key) {
  358. const iter = this._iter.reset(key);
  359. let node = this._root;
  360. let candidate = undefined;
  361. while (node) {
  362. const val = iter.cmp(node.segment);
  363. if (val > 0) {
  364. // left
  365. node = node.left;
  366. }
  367. else if (val < 0) {
  368. // right
  369. node = node.right;
  370. }
  371. else if (iter.hasNext()) {
  372. // mid
  373. iter.next();
  374. candidate = node.value || candidate;
  375. node = node.mid;
  376. }
  377. else {
  378. break;
  379. }
  380. }
  381. return node && node.value || candidate;
  382. }
  383. findSuperstr(key) {
  384. const iter = this._iter.reset(key);
  385. let node = this._root;
  386. while (node) {
  387. const val = iter.cmp(node.segment);
  388. if (val > 0) {
  389. // left
  390. node = node.left;
  391. }
  392. else if (val < 0) {
  393. // right
  394. node = node.right;
  395. }
  396. else if (iter.hasNext()) {
  397. // mid
  398. iter.next();
  399. node = node.mid;
  400. }
  401. else {
  402. // collect
  403. if (!node.mid) {
  404. return undefined;
  405. }
  406. else {
  407. return this._entries(node.mid);
  408. }
  409. }
  410. }
  411. return undefined;
  412. }
  413. forEach(callback) {
  414. for (const [key, value] of this) {
  415. callback(value, key);
  416. }
  417. }
  418. *[Symbol.iterator]() {
  419. yield* this._entries(this._root);
  420. }
  421. *_entries(node) {
  422. // DFS
  423. if (!node) {
  424. return;
  425. }
  426. const stack = [node];
  427. while (stack.length > 0) {
  428. const node = stack.pop();
  429. if (node) {
  430. if (node.value) {
  431. yield [node.key, node.value];
  432. }
  433. if (node.left) {
  434. stack.push(node.left);
  435. }
  436. if (node.mid) {
  437. stack.push(node.mid);
  438. }
  439. if (node.right) {
  440. stack.push(node.right);
  441. }
  442. }
  443. }
  444. }
  445. }
  446. export class ResourceMap {
  447. constructor(mapOrKeyFn, toKey) {
  448. this[_a] = 'ResourceMap';
  449. if (mapOrKeyFn instanceof ResourceMap) {
  450. this.map = new Map(mapOrKeyFn.map);
  451. this.toKey = toKey !== null && toKey !== void 0 ? toKey : ResourceMap.defaultToKey;
  452. }
  453. else {
  454. this.map = new Map();
  455. this.toKey = mapOrKeyFn !== null && mapOrKeyFn !== void 0 ? mapOrKeyFn : ResourceMap.defaultToKey;
  456. }
  457. }
  458. set(resource, value) {
  459. this.map.set(this.toKey(resource), value);
  460. return this;
  461. }
  462. get(resource) {
  463. return this.map.get(this.toKey(resource));
  464. }
  465. has(resource) {
  466. return this.map.has(this.toKey(resource));
  467. }
  468. get size() {
  469. return this.map.size;
  470. }
  471. clear() {
  472. this.map.clear();
  473. }
  474. delete(resource) {
  475. return this.map.delete(this.toKey(resource));
  476. }
  477. forEach(clb, thisArg) {
  478. if (typeof thisArg !== 'undefined') {
  479. clb = clb.bind(thisArg);
  480. }
  481. for (let [index, value] of this.map) {
  482. clb(value, URI.parse(index), this);
  483. }
  484. }
  485. values() {
  486. return this.map.values();
  487. }
  488. *keys() {
  489. for (let key of this.map.keys()) {
  490. yield URI.parse(key);
  491. }
  492. }
  493. *entries() {
  494. for (let tuple of this.map.entries()) {
  495. yield [URI.parse(tuple[0]), tuple[1]];
  496. }
  497. }
  498. *[(_a = Symbol.toStringTag, Symbol.iterator)]() {
  499. for (let item of this.map) {
  500. yield [URI.parse(item[0]), item[1]];
  501. }
  502. }
  503. }
  504. ResourceMap.defaultToKey = (resource) => resource.toString();
  505. export class LinkedMap {
  506. constructor() {
  507. this[_b] = 'LinkedMap';
  508. this._map = new Map();
  509. this._head = undefined;
  510. this._tail = undefined;
  511. this._size = 0;
  512. this._state = 0;
  513. }
  514. clear() {
  515. this._map.clear();
  516. this._head = undefined;
  517. this._tail = undefined;
  518. this._size = 0;
  519. this._state++;
  520. }
  521. isEmpty() {
  522. return !this._head && !this._tail;
  523. }
  524. get size() {
  525. return this._size;
  526. }
  527. get first() {
  528. var _c;
  529. return (_c = this._head) === null || _c === void 0 ? void 0 : _c.value;
  530. }
  531. get last() {
  532. var _c;
  533. return (_c = this._tail) === null || _c === void 0 ? void 0 : _c.value;
  534. }
  535. has(key) {
  536. return this._map.has(key);
  537. }
  538. get(key, touch = 0 /* None */) {
  539. const item = this._map.get(key);
  540. if (!item) {
  541. return undefined;
  542. }
  543. if (touch !== 0 /* None */) {
  544. this.touch(item, touch);
  545. }
  546. return item.value;
  547. }
  548. set(key, value, touch = 0 /* None */) {
  549. let item = this._map.get(key);
  550. if (item) {
  551. item.value = value;
  552. if (touch !== 0 /* None */) {
  553. this.touch(item, touch);
  554. }
  555. }
  556. else {
  557. item = { key, value, next: undefined, previous: undefined };
  558. switch (touch) {
  559. case 0 /* None */:
  560. this.addItemLast(item);
  561. break;
  562. case 1 /* AsOld */:
  563. this.addItemFirst(item);
  564. break;
  565. case 2 /* AsNew */:
  566. this.addItemLast(item);
  567. break;
  568. default:
  569. this.addItemLast(item);
  570. break;
  571. }
  572. this._map.set(key, item);
  573. this._size++;
  574. }
  575. return this;
  576. }
  577. delete(key) {
  578. return !!this.remove(key);
  579. }
  580. remove(key) {
  581. const item = this._map.get(key);
  582. if (!item) {
  583. return undefined;
  584. }
  585. this._map.delete(key);
  586. this.removeItem(item);
  587. this._size--;
  588. return item.value;
  589. }
  590. shift() {
  591. if (!this._head && !this._tail) {
  592. return undefined;
  593. }
  594. if (!this._head || !this._tail) {
  595. throw new Error('Invalid list');
  596. }
  597. const item = this._head;
  598. this._map.delete(item.key);
  599. this.removeItem(item);
  600. this._size--;
  601. return item.value;
  602. }
  603. forEach(callbackfn, thisArg) {
  604. const state = this._state;
  605. let current = this._head;
  606. while (current) {
  607. if (thisArg) {
  608. callbackfn.bind(thisArg)(current.value, current.key, this);
  609. }
  610. else {
  611. callbackfn(current.value, current.key, this);
  612. }
  613. if (this._state !== state) {
  614. throw new Error(`LinkedMap got modified during iteration.`);
  615. }
  616. current = current.next;
  617. }
  618. }
  619. keys() {
  620. const map = this;
  621. const state = this._state;
  622. let current = this._head;
  623. const iterator = {
  624. [Symbol.iterator]() {
  625. return iterator;
  626. },
  627. next() {
  628. if (map._state !== state) {
  629. throw new Error(`LinkedMap got modified during iteration.`);
  630. }
  631. if (current) {
  632. const result = { value: current.key, done: false };
  633. current = current.next;
  634. return result;
  635. }
  636. else {
  637. return { value: undefined, done: true };
  638. }
  639. }
  640. };
  641. return iterator;
  642. }
  643. values() {
  644. const map = this;
  645. const state = this._state;
  646. let current = this._head;
  647. const iterator = {
  648. [Symbol.iterator]() {
  649. return iterator;
  650. },
  651. next() {
  652. if (map._state !== state) {
  653. throw new Error(`LinkedMap got modified during iteration.`);
  654. }
  655. if (current) {
  656. const result = { value: current.value, done: false };
  657. current = current.next;
  658. return result;
  659. }
  660. else {
  661. return { value: undefined, done: true };
  662. }
  663. }
  664. };
  665. return iterator;
  666. }
  667. entries() {
  668. const map = this;
  669. const state = this._state;
  670. let current = this._head;
  671. const iterator = {
  672. [Symbol.iterator]() {
  673. return iterator;
  674. },
  675. next() {
  676. if (map._state !== state) {
  677. throw new Error(`LinkedMap got modified during iteration.`);
  678. }
  679. if (current) {
  680. const result = { value: [current.key, current.value], done: false };
  681. current = current.next;
  682. return result;
  683. }
  684. else {
  685. return { value: undefined, done: true };
  686. }
  687. }
  688. };
  689. return iterator;
  690. }
  691. [(_b = Symbol.toStringTag, Symbol.iterator)]() {
  692. return this.entries();
  693. }
  694. trimOld(newSize) {
  695. if (newSize >= this.size) {
  696. return;
  697. }
  698. if (newSize === 0) {
  699. this.clear();
  700. return;
  701. }
  702. let current = this._head;
  703. let currentSize = this.size;
  704. while (current && currentSize > newSize) {
  705. this._map.delete(current.key);
  706. current = current.next;
  707. currentSize--;
  708. }
  709. this._head = current;
  710. this._size = currentSize;
  711. if (current) {
  712. current.previous = undefined;
  713. }
  714. this._state++;
  715. }
  716. addItemFirst(item) {
  717. // First time Insert
  718. if (!this._head && !this._tail) {
  719. this._tail = item;
  720. }
  721. else if (!this._head) {
  722. throw new Error('Invalid list');
  723. }
  724. else {
  725. item.next = this._head;
  726. this._head.previous = item;
  727. }
  728. this._head = item;
  729. this._state++;
  730. }
  731. addItemLast(item) {
  732. // First time Insert
  733. if (!this._head && !this._tail) {
  734. this._head = item;
  735. }
  736. else if (!this._tail) {
  737. throw new Error('Invalid list');
  738. }
  739. else {
  740. item.previous = this._tail;
  741. this._tail.next = item;
  742. }
  743. this._tail = item;
  744. this._state++;
  745. }
  746. removeItem(item) {
  747. if (item === this._head && item === this._tail) {
  748. this._head = undefined;
  749. this._tail = undefined;
  750. }
  751. else if (item === this._head) {
  752. // This can only happen if size === 1 which is handled
  753. // by the case above.
  754. if (!item.next) {
  755. throw new Error('Invalid list');
  756. }
  757. item.next.previous = undefined;
  758. this._head = item.next;
  759. }
  760. else if (item === this._tail) {
  761. // This can only happen if size === 1 which is handled
  762. // by the case above.
  763. if (!item.previous) {
  764. throw new Error('Invalid list');
  765. }
  766. item.previous.next = undefined;
  767. this._tail = item.previous;
  768. }
  769. else {
  770. const next = item.next;
  771. const previous = item.previous;
  772. if (!next || !previous) {
  773. throw new Error('Invalid list');
  774. }
  775. next.previous = previous;
  776. previous.next = next;
  777. }
  778. item.next = undefined;
  779. item.previous = undefined;
  780. this._state++;
  781. }
  782. touch(item, touch) {
  783. if (!this._head || !this._tail) {
  784. throw new Error('Invalid list');
  785. }
  786. if ((touch !== 1 /* AsOld */ && touch !== 2 /* AsNew */)) {
  787. return;
  788. }
  789. if (touch === 1 /* AsOld */) {
  790. if (item === this._head) {
  791. return;
  792. }
  793. const next = item.next;
  794. const previous = item.previous;
  795. // Unlink the item
  796. if (item === this._tail) {
  797. // previous must be defined since item was not head but is tail
  798. // So there are more than on item in the map
  799. previous.next = undefined;
  800. this._tail = previous;
  801. }
  802. else {
  803. // Both next and previous are not undefined since item was neither head nor tail.
  804. next.previous = previous;
  805. previous.next = next;
  806. }
  807. // Insert the node at head
  808. item.previous = undefined;
  809. item.next = this._head;
  810. this._head.previous = item;
  811. this._head = item;
  812. this._state++;
  813. }
  814. else if (touch === 2 /* AsNew */) {
  815. if (item === this._tail) {
  816. return;
  817. }
  818. const next = item.next;
  819. const previous = item.previous;
  820. // Unlink the item.
  821. if (item === this._head) {
  822. // next must be defined since item was not tail but is head
  823. // So there are more than on item in the map
  824. next.previous = undefined;
  825. this._head = next;
  826. }
  827. else {
  828. // Both next and previous are not undefined since item was neither head nor tail.
  829. next.previous = previous;
  830. previous.next = next;
  831. }
  832. item.next = undefined;
  833. item.previous = this._tail;
  834. this._tail.next = item;
  835. this._tail = item;
  836. this._state++;
  837. }
  838. }
  839. toJSON() {
  840. const data = [];
  841. this.forEach((value, key) => {
  842. data.push([key, value]);
  843. });
  844. return data;
  845. }
  846. fromJSON(data) {
  847. this.clear();
  848. for (const [key, value] of data) {
  849. this.set(key, value);
  850. }
  851. }
  852. }
  853. export class LRUCache extends LinkedMap {
  854. constructor(limit, ratio = 1) {
  855. super();
  856. this._limit = limit;
  857. this._ratio = Math.min(Math.max(0, ratio), 1);
  858. }
  859. get limit() {
  860. return this._limit;
  861. }
  862. set limit(limit) {
  863. this._limit = limit;
  864. this.checkTrim();
  865. }
  866. get(key, touch = 2 /* AsNew */) {
  867. return super.get(key, touch);
  868. }
  869. peek(key) {
  870. return super.get(key, 0 /* None */);
  871. }
  872. set(key, value) {
  873. super.set(key, value, 2 /* AsNew */);
  874. this.checkTrim();
  875. return this;
  876. }
  877. checkTrim() {
  878. if (this.size > this._limit) {
  879. this.trimOld(Math.round(this._limit * this._ratio));
  880. }
  881. }
  882. }