ternarySearchTree.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. import { compare, compareIgnoreCase, compareSubstring, compareSubstringIgnoreCase } from './strings.js';
  2. export class StringIterator {
  3. constructor() {
  4. this._value = '';
  5. this._pos = 0;
  6. }
  7. reset(key) {
  8. this._value = key;
  9. this._pos = 0;
  10. return this;
  11. }
  12. next() {
  13. this._pos += 1;
  14. return this;
  15. }
  16. hasNext() {
  17. return this._pos < this._value.length - 1;
  18. }
  19. cmp(a) {
  20. const aCode = a.charCodeAt(0);
  21. const thisCode = this._value.charCodeAt(this._pos);
  22. return aCode - thisCode;
  23. }
  24. value() {
  25. return this._value[this._pos];
  26. }
  27. }
  28. export class ConfigKeysIterator {
  29. constructor(_caseSensitive = true) {
  30. this._caseSensitive = _caseSensitive;
  31. }
  32. reset(key) {
  33. this._value = key;
  34. this._from = 0;
  35. this._to = 0;
  36. return this.next();
  37. }
  38. hasNext() {
  39. return this._to < this._value.length;
  40. }
  41. next() {
  42. // this._data = key.split(/[\\/]/).filter(s => !!s);
  43. this._from = this._to;
  44. let justSeps = true;
  45. for (; this._to < this._value.length; this._to++) {
  46. const ch = this._value.charCodeAt(this._to);
  47. if (ch === 46 /* CharCode.Period */) {
  48. if (justSeps) {
  49. this._from++;
  50. }
  51. else {
  52. break;
  53. }
  54. }
  55. else {
  56. justSeps = false;
  57. }
  58. }
  59. return this;
  60. }
  61. cmp(a) {
  62. return this._caseSensitive
  63. ? compareSubstring(a, this._value, 0, a.length, this._from, this._to)
  64. : compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);
  65. }
  66. value() {
  67. return this._value.substring(this._from, this._to);
  68. }
  69. }
  70. export class PathIterator {
  71. constructor(_splitOnBackslash = true, _caseSensitive = true) {
  72. this._splitOnBackslash = _splitOnBackslash;
  73. this._caseSensitive = _caseSensitive;
  74. }
  75. reset(key) {
  76. this._from = 0;
  77. this._to = 0;
  78. this._value = key;
  79. this._valueLen = key.length;
  80. for (let pos = key.length - 1; pos >= 0; pos--, this._valueLen--) {
  81. const ch = this._value.charCodeAt(pos);
  82. if (!(ch === 47 /* CharCode.Slash */ || this._splitOnBackslash && ch === 92 /* CharCode.Backslash */)) {
  83. break;
  84. }
  85. }
  86. return this.next();
  87. }
  88. hasNext() {
  89. return this._to < this._valueLen;
  90. }
  91. next() {
  92. // this._data = key.split(/[\\/]/).filter(s => !!s);
  93. this._from = this._to;
  94. let justSeps = true;
  95. for (; this._to < this._valueLen; this._to++) {
  96. const ch = this._value.charCodeAt(this._to);
  97. if (ch === 47 /* CharCode.Slash */ || this._splitOnBackslash && ch === 92 /* CharCode.Backslash */) {
  98. if (justSeps) {
  99. this._from++;
  100. }
  101. else {
  102. break;
  103. }
  104. }
  105. else {
  106. justSeps = false;
  107. }
  108. }
  109. return this;
  110. }
  111. cmp(a) {
  112. return this._caseSensitive
  113. ? compareSubstring(a, this._value, 0, a.length, this._from, this._to)
  114. : compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);
  115. }
  116. value() {
  117. return this._value.substring(this._from, this._to);
  118. }
  119. }
  120. export class UriIterator {
  121. constructor(_ignorePathCasing, _ignoreQueryAndFragment) {
  122. this._ignorePathCasing = _ignorePathCasing;
  123. this._ignoreQueryAndFragment = _ignoreQueryAndFragment;
  124. this._states = [];
  125. this._stateIdx = 0;
  126. }
  127. reset(key) {
  128. this._value = key;
  129. this._states = [];
  130. if (this._value.scheme) {
  131. this._states.push(1 /* UriIteratorState.Scheme */);
  132. }
  133. if (this._value.authority) {
  134. this._states.push(2 /* UriIteratorState.Authority */);
  135. }
  136. if (this._value.path) {
  137. this._pathIterator = new PathIterator(false, !this._ignorePathCasing(key));
  138. this._pathIterator.reset(key.path);
  139. if (this._pathIterator.value()) {
  140. this._states.push(3 /* UriIteratorState.Path */);
  141. }
  142. }
  143. if (!this._ignoreQueryAndFragment(key)) {
  144. if (this._value.query) {
  145. this._states.push(4 /* UriIteratorState.Query */);
  146. }
  147. if (this._value.fragment) {
  148. this._states.push(5 /* UriIteratorState.Fragment */);
  149. }
  150. }
  151. this._stateIdx = 0;
  152. return this;
  153. }
  154. next() {
  155. if (this._states[this._stateIdx] === 3 /* UriIteratorState.Path */ && this._pathIterator.hasNext()) {
  156. this._pathIterator.next();
  157. }
  158. else {
  159. this._stateIdx += 1;
  160. }
  161. return this;
  162. }
  163. hasNext() {
  164. return (this._states[this._stateIdx] === 3 /* UriIteratorState.Path */ && this._pathIterator.hasNext())
  165. || this._stateIdx < this._states.length - 1;
  166. }
  167. cmp(a) {
  168. if (this._states[this._stateIdx] === 1 /* UriIteratorState.Scheme */) {
  169. return compareIgnoreCase(a, this._value.scheme);
  170. }
  171. else if (this._states[this._stateIdx] === 2 /* UriIteratorState.Authority */) {
  172. return compareIgnoreCase(a, this._value.authority);
  173. }
  174. else if (this._states[this._stateIdx] === 3 /* UriIteratorState.Path */) {
  175. return this._pathIterator.cmp(a);
  176. }
  177. else if (this._states[this._stateIdx] === 4 /* UriIteratorState.Query */) {
  178. return compare(a, this._value.query);
  179. }
  180. else if (this._states[this._stateIdx] === 5 /* UriIteratorState.Fragment */) {
  181. return compare(a, this._value.fragment);
  182. }
  183. throw new Error();
  184. }
  185. value() {
  186. if (this._states[this._stateIdx] === 1 /* UriIteratorState.Scheme */) {
  187. return this._value.scheme;
  188. }
  189. else if (this._states[this._stateIdx] === 2 /* UriIteratorState.Authority */) {
  190. return this._value.authority;
  191. }
  192. else if (this._states[this._stateIdx] === 3 /* UriIteratorState.Path */) {
  193. return this._pathIterator.value();
  194. }
  195. else if (this._states[this._stateIdx] === 4 /* UriIteratorState.Query */) {
  196. return this._value.query;
  197. }
  198. else if (this._states[this._stateIdx] === 5 /* UriIteratorState.Fragment */) {
  199. return this._value.fragment;
  200. }
  201. throw new Error();
  202. }
  203. }
  204. class TernarySearchTreeNode {
  205. constructor() {
  206. this.height = 1;
  207. }
  208. rotateLeft() {
  209. const tmp = this.right;
  210. this.right = tmp.left;
  211. tmp.left = this;
  212. this.updateHeight();
  213. tmp.updateHeight();
  214. return tmp;
  215. }
  216. rotateRight() {
  217. const tmp = this.left;
  218. this.left = tmp.right;
  219. tmp.right = this;
  220. this.updateHeight();
  221. tmp.updateHeight();
  222. return tmp;
  223. }
  224. updateHeight() {
  225. this.height = 1 + Math.max(this.heightLeft, this.heightRight);
  226. }
  227. balanceFactor() {
  228. return this.heightRight - this.heightLeft;
  229. }
  230. get heightLeft() {
  231. var _a, _b;
  232. return (_b = (_a = this.left) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : 0;
  233. }
  234. get heightRight() {
  235. var _a, _b;
  236. return (_b = (_a = this.right) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : 0;
  237. }
  238. }
  239. export class TernarySearchTree {
  240. static forUris(ignorePathCasing = () => false, ignoreQueryAndFragment = () => false) {
  241. return new TernarySearchTree(new UriIterator(ignorePathCasing, ignoreQueryAndFragment));
  242. }
  243. static forStrings() {
  244. return new TernarySearchTree(new StringIterator());
  245. }
  246. static forConfigKeys() {
  247. return new TernarySearchTree(new ConfigKeysIterator());
  248. }
  249. constructor(segments) {
  250. this._iter = segments;
  251. }
  252. clear() {
  253. this._root = undefined;
  254. }
  255. set(key, element) {
  256. const iter = this._iter.reset(key);
  257. let node;
  258. if (!this._root) {
  259. this._root = new TernarySearchTreeNode();
  260. this._root.segment = iter.value();
  261. }
  262. const stack = [];
  263. // find insert_node
  264. node = this._root;
  265. while (true) {
  266. const val = iter.cmp(node.segment);
  267. if (val > 0) {
  268. // left
  269. if (!node.left) {
  270. node.left = new TernarySearchTreeNode();
  271. node.left.segment = iter.value();
  272. }
  273. stack.push([-1 /* Dir.Left */, node]);
  274. node = node.left;
  275. }
  276. else if (val < 0) {
  277. // right
  278. if (!node.right) {
  279. node.right = new TernarySearchTreeNode();
  280. node.right.segment = iter.value();
  281. }
  282. stack.push([1 /* Dir.Right */, node]);
  283. node = node.right;
  284. }
  285. else if (iter.hasNext()) {
  286. // mid
  287. iter.next();
  288. if (!node.mid) {
  289. node.mid = new TernarySearchTreeNode();
  290. node.mid.segment = iter.value();
  291. }
  292. stack.push([0 /* Dir.Mid */, node]);
  293. node = node.mid;
  294. }
  295. else {
  296. break;
  297. }
  298. }
  299. // set value
  300. const oldElement = node.value;
  301. node.value = element;
  302. node.key = key;
  303. // balance
  304. for (let i = stack.length - 1; i >= 0; i--) {
  305. const node = stack[i][1];
  306. node.updateHeight();
  307. const bf = node.balanceFactor();
  308. if (bf < -1 || bf > 1) {
  309. // needs rotate
  310. const d1 = stack[i][0];
  311. const d2 = stack[i + 1][0];
  312. if (d1 === 1 /* Dir.Right */ && d2 === 1 /* Dir.Right */) {
  313. //right, right -> rotate left
  314. stack[i][1] = node.rotateLeft();
  315. }
  316. else if (d1 === -1 /* Dir.Left */ && d2 === -1 /* Dir.Left */) {
  317. // left, left -> rotate right
  318. stack[i][1] = node.rotateRight();
  319. }
  320. else if (d1 === 1 /* Dir.Right */ && d2 === -1 /* Dir.Left */) {
  321. // right, left -> double rotate right, left
  322. node.right = stack[i + 1][1] = stack[i + 1][1].rotateRight();
  323. stack[i][1] = node.rotateLeft();
  324. }
  325. else if (d1 === -1 /* Dir.Left */ && d2 === 1 /* Dir.Right */) {
  326. // left, right -> double rotate left, right
  327. node.left = stack[i + 1][1] = stack[i + 1][1].rotateLeft();
  328. stack[i][1] = node.rotateRight();
  329. }
  330. else {
  331. throw new Error();
  332. }
  333. // patch path to parent
  334. if (i > 0) {
  335. switch (stack[i - 1][0]) {
  336. case -1 /* Dir.Left */:
  337. stack[i - 1][1].left = stack[i][1];
  338. break;
  339. case 1 /* Dir.Right */:
  340. stack[i - 1][1].right = stack[i][1];
  341. break;
  342. case 0 /* Dir.Mid */:
  343. stack[i - 1][1].mid = stack[i][1];
  344. break;
  345. }
  346. }
  347. else {
  348. this._root = stack[0][1];
  349. }
  350. }
  351. }
  352. return oldElement;
  353. }
  354. get(key) {
  355. var _a;
  356. return (_a = this._getNode(key)) === null || _a === void 0 ? void 0 : _a.value;
  357. }
  358. _getNode(key) {
  359. const iter = this._iter.reset(key);
  360. let node = this._root;
  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. node = node.mid;
  375. }
  376. else {
  377. break;
  378. }
  379. }
  380. return node;
  381. }
  382. has(key) {
  383. const node = this._getNode(key);
  384. return !((node === null || node === void 0 ? void 0 : node.value) === undefined && (node === null || node === void 0 ? void 0 : node.mid) === undefined);
  385. }
  386. delete(key) {
  387. return this._delete(key, false);
  388. }
  389. deleteSuperstr(key) {
  390. return this._delete(key, true);
  391. }
  392. _delete(key, superStr) {
  393. var _a;
  394. const iter = this._iter.reset(key);
  395. const stack = [];
  396. let node = this._root;
  397. // find node
  398. while (node) {
  399. const val = iter.cmp(node.segment);
  400. if (val > 0) {
  401. // left
  402. stack.push([-1 /* Dir.Left */, node]);
  403. node = node.left;
  404. }
  405. else if (val < 0) {
  406. // right
  407. stack.push([1 /* Dir.Right */, node]);
  408. node = node.right;
  409. }
  410. else if (iter.hasNext()) {
  411. // mid
  412. iter.next();
  413. stack.push([0 /* Dir.Mid */, node]);
  414. node = node.mid;
  415. }
  416. else {
  417. break;
  418. }
  419. }
  420. if (!node) {
  421. // node not found
  422. return;
  423. }
  424. if (superStr) {
  425. // removing children, reset height
  426. node.left = undefined;
  427. node.mid = undefined;
  428. node.right = undefined;
  429. node.height = 1;
  430. }
  431. else {
  432. // removing element
  433. node.key = undefined;
  434. node.value = undefined;
  435. }
  436. // BST node removal
  437. if (!node.mid && !node.value) {
  438. if (node.left && node.right) {
  439. // full node
  440. // replace deleted-node with the min-node of the right branch.
  441. // If there is no true min-node leave things as they are
  442. const min = this._min(node.right);
  443. if (min.key) {
  444. const { key, value, segment } = min;
  445. this._delete(min.key, false);
  446. node.key = key;
  447. node.value = value;
  448. node.segment = segment;
  449. }
  450. }
  451. else {
  452. // empty or half empty
  453. const newChild = (_a = node.left) !== null && _a !== void 0 ? _a : node.right;
  454. if (stack.length > 0) {
  455. const [dir, parent] = stack[stack.length - 1];
  456. switch (dir) {
  457. case -1 /* Dir.Left */:
  458. parent.left = newChild;
  459. break;
  460. case 0 /* Dir.Mid */:
  461. parent.mid = newChild;
  462. break;
  463. case 1 /* Dir.Right */:
  464. parent.right = newChild;
  465. break;
  466. }
  467. }
  468. else {
  469. this._root = newChild;
  470. }
  471. }
  472. }
  473. // AVL balance
  474. for (let i = stack.length - 1; i >= 0; i--) {
  475. const node = stack[i][1];
  476. node.updateHeight();
  477. const bf = node.balanceFactor();
  478. if (bf > 1) {
  479. // right heavy
  480. if (node.right.balanceFactor() >= 0) {
  481. // right, right -> rotate left
  482. stack[i][1] = node.rotateLeft();
  483. }
  484. else {
  485. // right, left -> double rotate
  486. node.right = node.right.rotateRight();
  487. stack[i][1] = node.rotateLeft();
  488. }
  489. }
  490. else if (bf < -1) {
  491. // left heavy
  492. if (node.left.balanceFactor() <= 0) {
  493. // left, left -> rotate right
  494. stack[i][1] = node.rotateRight();
  495. }
  496. else {
  497. // left, right -> double rotate
  498. node.left = node.left.rotateLeft();
  499. stack[i][1] = node.rotateRight();
  500. }
  501. }
  502. // patch path to parent
  503. if (i > 0) {
  504. switch (stack[i - 1][0]) {
  505. case -1 /* Dir.Left */:
  506. stack[i - 1][1].left = stack[i][1];
  507. break;
  508. case 1 /* Dir.Right */:
  509. stack[i - 1][1].right = stack[i][1];
  510. break;
  511. case 0 /* Dir.Mid */:
  512. stack[i - 1][1].mid = stack[i][1];
  513. break;
  514. }
  515. }
  516. else {
  517. this._root = stack[0][1];
  518. }
  519. }
  520. }
  521. _min(node) {
  522. while (node.left) {
  523. node = node.left;
  524. }
  525. return node;
  526. }
  527. findSubstr(key) {
  528. const iter = this._iter.reset(key);
  529. let node = this._root;
  530. let candidate = undefined;
  531. while (node) {
  532. const val = iter.cmp(node.segment);
  533. if (val > 0) {
  534. // left
  535. node = node.left;
  536. }
  537. else if (val < 0) {
  538. // right
  539. node = node.right;
  540. }
  541. else if (iter.hasNext()) {
  542. // mid
  543. iter.next();
  544. candidate = node.value || candidate;
  545. node = node.mid;
  546. }
  547. else {
  548. break;
  549. }
  550. }
  551. return node && node.value || candidate;
  552. }
  553. findSuperstr(key) {
  554. return this._findSuperstrOrElement(key, false);
  555. }
  556. _findSuperstrOrElement(key, allowValue) {
  557. const iter = this._iter.reset(key);
  558. let node = this._root;
  559. while (node) {
  560. const val = iter.cmp(node.segment);
  561. if (val > 0) {
  562. // left
  563. node = node.left;
  564. }
  565. else if (val < 0) {
  566. // right
  567. node = node.right;
  568. }
  569. else if (iter.hasNext()) {
  570. // mid
  571. iter.next();
  572. node = node.mid;
  573. }
  574. else {
  575. // collect
  576. if (!node.mid) {
  577. if (allowValue) {
  578. return node.value;
  579. }
  580. else {
  581. return undefined;
  582. }
  583. }
  584. else {
  585. return this._entries(node.mid);
  586. }
  587. }
  588. }
  589. return undefined;
  590. }
  591. forEach(callback) {
  592. for (const [key, value] of this) {
  593. callback(value, key);
  594. }
  595. }
  596. *[Symbol.iterator]() {
  597. yield* this._entries(this._root);
  598. }
  599. _entries(node) {
  600. const result = [];
  601. this._dfsEntries(node, result);
  602. return result[Symbol.iterator]();
  603. }
  604. _dfsEntries(node, bucket) {
  605. // DFS
  606. if (!node) {
  607. return;
  608. }
  609. if (node.left) {
  610. this._dfsEntries(node.left, bucket);
  611. }
  612. if (node.value) {
  613. bucket.push([node.key, node.value]);
  614. }
  615. if (node.mid) {
  616. this._dfsEntries(node.mid, bucket);
  617. }
  618. if (node.right) {
  619. this._dfsEntries(node.right, bucket);
  620. }
  621. }
  622. }