map.js 32 KB

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