@yorkie-js/react 0.7.11-rc → 0.7.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6569,447 +6569,432 @@ class Operation {
6569
6569
  this.executedAt = executedAt;
6570
6570
  }
6571
6571
  }
6572
- class SplayNode {
6572
+ class TreeListNode {
6573
6573
  value;
6574
6574
  left;
6575
6575
  right;
6576
6576
  parent;
6577
6577
  weight;
6578
+ count;
6579
+ red;
6578
6580
  constructor(value) {
6579
6581
  this.value = value;
6580
- this.initWeight();
6581
- }
6582
- /**
6583
- * `getNodeString` returns a string of weight and value of this node.
6584
- */
6585
- getNodeString() {
6586
- return `${this.weight}${this.value}`;
6582
+ this.red = true;
6583
+ this.weight = this.size();
6584
+ this.count = 1;
6587
6585
  }
6588
6586
  /**
6589
- * `getValue` returns value of this node.
6587
+ * `getValue` returns the value of this node.
6590
6588
  */
6591
6589
  getValue() {
6592
6590
  return this.value;
6593
6591
  }
6594
6592
  /**
6595
- * `getLeftWeight` returns left weight of this node.
6593
+ * `size` returns 1 if the node is live, 0 if removed (tombstone).
6596
6594
  */
6597
- getLeftWeight() {
6598
- return !this.hasLeft() ? 0 : this.left.getWeight();
6595
+ size() {
6596
+ return this.value.isRemoved() ? 0 : 1;
6599
6597
  }
6600
6598
  /**
6601
- * `getRightWeight` returns right weight of this node.
6599
+ * `getLeft` returns the left child.
6602
6600
  */
6603
- getRightWeight() {
6604
- return !this.hasRight() ? 0 : this.right.getWeight();
6601
+ getLeft() {
6602
+ return this.left;
6605
6603
  }
6606
6604
  /**
6607
- * `getWeight` returns weight of this node.
6605
+ * `setLeft` sets the left child.
6608
6606
  */
6609
- getWeight() {
6610
- return this.weight;
6607
+ setLeft(node) {
6608
+ this.left = node;
6611
6609
  }
6612
6610
  /**
6613
- * `getLeft` returns a left node.
6611
+ * `getRight` returns the right child.
6614
6612
  */
6615
- getLeft() {
6616
- return this.left;
6613
+ getRight() {
6614
+ return this.right;
6617
6615
  }
6618
6616
  /**
6619
- * `getRight` returns a right node.
6617
+ * `setRight` sets the right child.
6620
6618
  */
6621
- getRight() {
6622
- return this.right;
6619
+ setRight(node) {
6620
+ this.right = node;
6623
6621
  }
6624
6622
  /**
6625
- * `getParent` returns parent of this node.
6623
+ * `getParent` returns the parent.
6626
6624
  */
6627
6625
  getParent() {
6628
6626
  return this.parent;
6629
6627
  }
6630
6628
  /**
6631
- * `hasLeft` check if the left node exists
6629
+ * `setParent` sets the parent.
6632
6630
  */
6633
- hasLeft() {
6634
- return !!this.left;
6631
+ setParent(node) {
6632
+ this.parent = node;
6635
6633
  }
6636
6634
  /**
6637
- * `hasRight` check if the right node exists
6635
+ * `getWeight` returns the cached live-node weight of this subtree.
6638
6636
  */
6639
- hasRight() {
6640
- return !!this.right;
6637
+ getWeight() {
6638
+ return this.weight;
6641
6639
  }
6642
6640
  /**
6643
- * `hasParent` check if the parent node exists
6641
+ * `setWeight` sets the cached live-node weight of this subtree.
6644
6642
  */
6645
- hasParent() {
6646
- return !!this.parent;
6643
+ setWeight(w) {
6644
+ this.weight = w;
6647
6645
  }
6648
6646
  /**
6649
- * `setLeft` sets a left node.
6647
+ * `getCount` returns the cached total node count of this subtree.
6650
6648
  */
6651
- setLeft(left) {
6652
- this.left = left;
6649
+ getCount() {
6650
+ return this.count;
6653
6651
  }
6654
6652
  /**
6655
- * `setRight` sets a right node.
6653
+ * `setCount` sets the cached total node count of this subtree.
6656
6654
  */
6657
- setRight(right) {
6658
- this.right = right;
6655
+ setCount(c) {
6656
+ this.count = c;
6659
6657
  }
6660
6658
  /**
6661
- * `setParent` sets a parent node.
6659
+ * `isRed` reports whether this node is colored red.
6662
6660
  */
6663
- setParent(parent) {
6664
- this.parent = parent;
6661
+ isRed() {
6662
+ return this.red;
6665
6663
  }
6666
6664
  /**
6667
- * `unlink` unlink parent, right and left node.
6665
+ * `setRed` sets the color of this node.
6668
6666
  */
6669
- unlink() {
6670
- this.parent = void 0;
6671
- this.right = void 0;
6672
- this.left = void 0;
6667
+ setRed(red) {
6668
+ this.red = red;
6673
6669
  }
6674
6670
  /**
6675
- * `hasLinks` checks if parent, right and left node exists.
6671
+ * `leftWeight` returns the live-node weight of the left subtree, or 0 if absent.
6676
6672
  */
6677
- hasLinks() {
6678
- return this.hasParent() || this.hasLeft() || this.hasRight();
6673
+ leftWeight() {
6674
+ return this.left ? this.left.weight : 0;
6679
6675
  }
6680
6676
  /**
6681
- * `increaseWeight` increases weight.
6677
+ * `rightWeight` returns the live-node weight of the right subtree, or 0 if absent.
6682
6678
  */
6683
- increaseWeight(weight) {
6684
- this.weight += weight;
6679
+ rightWeight() {
6680
+ return this.right ? this.right.weight : 0;
6685
6681
  }
6686
6682
  /**
6687
- * `initWeight` sets initial weight of this node.
6683
+ * `leftCount` returns the total node count of the left subtree, or 0 if absent.
6688
6684
  */
6689
- initWeight() {
6690
- this.weight = this.getLength();
6685
+ leftCount() {
6686
+ return this.left ? this.left.count : 0;
6687
+ }
6688
+ /**
6689
+ * `rightCount` returns the total node count of the right subtree, or 0 if absent.
6690
+ */
6691
+ rightCount() {
6692
+ return this.right ? this.right.count : 0;
6691
6693
  }
6692
6694
  }
6693
- class SplayTree {
6695
+ function isRed(node) {
6696
+ return !!node && node.isRed();
6697
+ }
6698
+ function updateNode(node) {
6699
+ node.setWeight(node.leftWeight() + node.size() + node.rightWeight());
6700
+ node.setCount(node.leftCount() + 1 + node.rightCount());
6701
+ }
6702
+ function rotateLeft(node) {
6703
+ const right = node.getRight();
6704
+ node.setRight(right.getLeft());
6705
+ if (node.getRight()) {
6706
+ node.getRight().setParent(node);
6707
+ }
6708
+ right.setLeft(node);
6709
+ right.setParent(node.getParent());
6710
+ node.setParent(right);
6711
+ right.setRed(node.isRed());
6712
+ node.setRed(true);
6713
+ updateNode(node);
6714
+ updateNode(right);
6715
+ return right;
6716
+ }
6717
+ function rotateRight(node) {
6718
+ const left = node.getLeft();
6719
+ node.setLeft(left.getRight());
6720
+ if (node.getLeft()) {
6721
+ node.getLeft().setParent(node);
6722
+ }
6723
+ left.setRight(node);
6724
+ left.setParent(node.getParent());
6725
+ node.setParent(left);
6726
+ left.setRed(node.isRed());
6727
+ node.setRed(true);
6728
+ updateNode(node);
6729
+ updateNode(left);
6730
+ return left;
6731
+ }
6732
+ function flipColors(node) {
6733
+ node.setRed(!node.isRed());
6734
+ node.getLeft().setRed(!node.getLeft().isRed());
6735
+ node.getRight().setRed(!node.getRight().isRed());
6736
+ }
6737
+ function moveRedLeft(node) {
6738
+ flipColors(node);
6739
+ if (isRed(node.getRight().getLeft())) {
6740
+ node.setRight(rotateRight(node.getRight()));
6741
+ node.getRight().setParent(node);
6742
+ node = rotateLeft(node);
6743
+ flipColors(node);
6744
+ }
6745
+ return node;
6746
+ }
6747
+ function moveRedRight(node) {
6748
+ flipColors(node);
6749
+ if (isRed(node.getLeft().getLeft())) {
6750
+ node = rotateRight(node);
6751
+ flipColors(node);
6752
+ }
6753
+ return node;
6754
+ }
6755
+ function removeMin(node) {
6756
+ if (!node.getLeft()) {
6757
+ return void 0;
6758
+ }
6759
+ if (!isRed(node.getLeft()) && !isRed(node.getLeft().getLeft())) {
6760
+ node = moveRedLeft(node);
6761
+ }
6762
+ node.setLeft(removeMin(node.getLeft()));
6763
+ if (node.getLeft()) {
6764
+ node.getLeft().setParent(node);
6765
+ }
6766
+ return fixUp(node);
6767
+ }
6768
+ function minNode(node) {
6769
+ while (node.getLeft()) {
6770
+ node = node.getLeft();
6771
+ }
6772
+ return node;
6773
+ }
6774
+ function fixUp(node) {
6775
+ if (isRed(node.getRight()) && !isRed(node.getLeft())) {
6776
+ node = rotateLeft(node);
6777
+ }
6778
+ if (isRed(node.getLeft()) && isRed(node.getLeft().getLeft())) {
6779
+ node = rotateRight(node);
6780
+ }
6781
+ if (isRed(node.getLeft()) && isRed(node.getRight())) {
6782
+ flipColors(node);
6783
+ }
6784
+ updateNode(node);
6785
+ return node;
6786
+ }
6787
+ function traverseInOrder(node, cb) {
6788
+ if (!node) {
6789
+ return;
6790
+ }
6791
+ traverseInOrder(node.getLeft(), cb);
6792
+ cb(node);
6793
+ traverseInOrder(node.getRight(), cb);
6794
+ }
6795
+ class TreeList {
6694
6796
  root;
6695
6797
  constructor(root) {
6798
+ if (root) {
6799
+ root.setRed(false);
6800
+ }
6696
6801
  this.root = root;
6697
6802
  }
6698
6803
  /**
6699
- * `length` returns the size of this tree.
6804
+ * `length` returns the number of non-removed (live) nodes.
6700
6805
  */
6701
6806
  get length() {
6702
6807
  return this.root ? this.root.getWeight() : 0;
6703
6808
  }
6704
6809
  /**
6705
- * `findForText` returns the Node and offset of the given position (cursor).
6706
- * Used for Text where cursor placed between characters.
6810
+ * `insertAfter` inserts the target node right after prev in the in-order
6811
+ * traversal. It uses structural (count-based) indexing to correctly handle
6812
+ * tombstone nodes.
6707
6813
  */
6708
- findForText(pos) {
6709
- if (!this.root || pos < 0) {
6710
- return [void 0, 0];
6814
+ insertAfter(prev, target) {
6815
+ if (!prev || !target) {
6816
+ return;
6711
6817
  }
6712
- let node = this.root;
6713
- for (; ; ) {
6714
- if (node.hasLeft() && pos <= node.getLeftWeight()) {
6715
- node = node.getLeft();
6716
- } else if (node.hasRight() && node.getLeftWeight() + node.getLength() < pos) {
6717
- pos -= node.getLeftWeight() + node.getLength();
6718
- node = node.getRight();
6719
- } else {
6720
- pos -= node.getLeftWeight();
6721
- break;
6722
- }
6818
+ target.setLeft(void 0);
6819
+ target.setRight(void 0);
6820
+ target.setParent(void 0);
6821
+ target.setRed(true);
6822
+ target.setWeight(target.size());
6823
+ target.setCount(1);
6824
+ const idx = this.structuralIndexOf(prev);
6825
+ this.root = this.insertByCount(this.root, idx + 1, target);
6826
+ this.root.setRed(false);
6827
+ this.root.setParent(void 0);
6828
+ }
6829
+ /**
6830
+ * `insertByCount` inserts newNode at the given structural index within the
6831
+ * subtree rooted at node, descending the tree using each node's left count
6832
+ * (tombstones included) and rebalancing on the way back up.
6833
+ */
6834
+ insertByCount(node, index, newNode) {
6835
+ if (!node) {
6836
+ return newNode;
6723
6837
  }
6724
- if (pos > node.getLength()) {
6725
- throw new YorkieError(
6726
- Code.ErrInvalidArgument,
6727
- `out of index range: pos: ${pos} > node.length: ${node.getLength()}`
6838
+ if (index <= node.leftCount()) {
6839
+ node.setLeft(this.insertByCount(node.getLeft(), index, newNode));
6840
+ node.getLeft().setParent(node);
6841
+ } else {
6842
+ node.setRight(
6843
+ this.insertByCount(
6844
+ node.getRight(),
6845
+ index - node.leftCount() - 1,
6846
+ newNode
6847
+ )
6728
6848
  );
6849
+ node.getRight().setParent(node);
6729
6850
  }
6730
- this.splayNode(node);
6731
- return [node, pos];
6851
+ return fixUp(node);
6732
6852
  }
6733
6853
  /**
6734
- * `findForArray` returns the Node of the given position (index).
6735
- * Used for Array where index points to the element.
6854
+ * `find` returns the node at the given logical index (among non-removed
6855
+ * nodes). Throws when the index is out of range.
6736
6856
  */
6737
- findForArray(idx) {
6738
- if (!this.root) {
6739
- return void 0;
6740
- }
6741
- if (idx < 0 || idx >= this.length) {
6857
+ find(index) {
6858
+ if (!this.root || index < 0 || index >= this.length) {
6742
6859
  throw new YorkieError(
6743
6860
  Code.ErrInvalidArgument,
6744
- `out of index range: idx: ${idx}, length: ${this.length}`
6861
+ `out of index: tree size ${this.length}, index ${index}`
6745
6862
  );
6746
6863
  }
6747
6864
  let node = this.root;
6748
6865
  for (; ; ) {
6749
- if (node.hasLeft() && idx < node.getLeftWeight()) {
6866
+ if (index < node.leftWeight()) {
6750
6867
  node = node.getLeft();
6751
- } else if (node.hasRight() && node.getLeftWeight() + node.getLength() <= idx) {
6752
- idx -= node.getLeftWeight() + node.getLength();
6753
- node = node.getRight();
6754
- } else {
6868
+ } else if (index < node.leftWeight() + node.size()) {
6755
6869
  break;
6870
+ } else {
6871
+ index -= node.leftWeight() + node.size();
6872
+ node = node.getRight();
6756
6873
  }
6757
6874
  }
6758
- this.splayNode(node);
6759
6875
  return node;
6760
6876
  }
6761
6877
  /**
6762
- * Find the index of the given node in BST.
6763
- *
6764
- * @param node - the given node
6765
- * @returns the index of given node
6878
+ * `delete` physically removes a node from the tree. Unlike tombstoning,
6879
+ * this completely removes the node from the tree structure. It uses
6880
+ * structural (count-based) indexing and swaps the node structure (not
6881
+ * values) with its successor to preserve node identity.
6766
6882
  */
6767
- indexOf(node) {
6768
- if (!node || node !== this.root && !node.hasLinks()) {
6769
- return -1;
6883
+ delete(node) {
6884
+ if (!node || !this.root) {
6885
+ return;
6886
+ }
6887
+ if (!isRed(this.root.getLeft()) && !isRed(this.root.getRight())) {
6888
+ this.root.setRed(true);
6889
+ }
6890
+ const idx = this.structuralIndexOf(node);
6891
+ this.root = this.deleteByCount(this.root, idx);
6892
+ if (this.root) {
6893
+ this.root.setRed(false);
6894
+ this.root.setParent(void 0);
6770
6895
  }
6771
- this.splayNode(node);
6772
- return this.root.getLeftWeight();
6773
- }
6774
- /**
6775
- * `getRoot` returns root of this tree.
6776
- */
6777
- getRoot() {
6778
- return this.root;
6779
- }
6780
- /**
6781
- * `insert` inserts the node at the last.
6782
- */
6783
- insert(newNode) {
6784
- return this.insertAfter(this.root, newNode);
6785
6896
  }
6786
6897
  /**
6787
- * `insertAfter` inserts the node after the given previous node.
6898
+ * `deleteByCount` removes the node at the given structural index within the
6899
+ * subtree rooted at node. When deleting an internal node, it swaps in the
6900
+ * in-order successor by re-parenting rather than copying values so external
6901
+ * references to the surviving node remain valid.
6788
6902
  */
6789
- insertAfter(target, newNode) {
6790
- if (!target) {
6791
- this.root = newNode;
6792
- return newNode;
6793
- }
6794
- this.splayNode(target);
6795
- this.root = newNode;
6796
- newNode.setRight(target.getRight());
6797
- if (target.hasRight()) {
6798
- target.getRight().setParent(newNode);
6903
+ deleteByCount(node, index) {
6904
+ if (index < node.leftCount()) {
6905
+ if (!isRed(node.getLeft()) && !isRed(node.getLeft().getLeft())) {
6906
+ node = moveRedLeft(node);
6907
+ }
6908
+ node.setLeft(this.deleteByCount(node.getLeft(), index));
6909
+ if (node.getLeft()) {
6910
+ node.getLeft().setParent(node);
6911
+ }
6912
+ } else {
6913
+ if (isRed(node.getLeft())) {
6914
+ node = rotateRight(node);
6915
+ }
6916
+ if (index === node.leftCount() && !node.getRight()) {
6917
+ return void 0;
6918
+ }
6919
+ if (!isRed(node.getRight()) && !isRed(node.getRight().getLeft())) {
6920
+ node = moveRedRight(node);
6921
+ }
6922
+ if (index === node.leftCount()) {
6923
+ const successor = minNode(node.getRight());
6924
+ const newRight = removeMin(node.getRight());
6925
+ successor.setLeft(node.getLeft());
6926
+ successor.setRight(newRight);
6927
+ successor.setRed(node.isRed());
6928
+ if (successor.getLeft()) {
6929
+ successor.getLeft().setParent(successor);
6930
+ }
6931
+ if (successor.getRight()) {
6932
+ successor.getRight().setParent(successor);
6933
+ }
6934
+ node.setLeft(void 0);
6935
+ node.setRight(void 0);
6936
+ node.setParent(void 0);
6937
+ node = successor;
6938
+ } else {
6939
+ node.setRight(
6940
+ this.deleteByCount(node.getRight(), index - node.leftCount() - 1)
6941
+ );
6942
+ if (node.getRight()) {
6943
+ node.getRight().setParent(node);
6944
+ }
6945
+ }
6799
6946
  }
6800
- newNode.setLeft(target);
6801
- target.setParent(newNode);
6802
- target.setRight();
6803
- this.updateWeight(target);
6804
- this.updateWeight(newNode);
6805
- return newNode;
6947
+ return fixUp(node);
6806
6948
  }
6807
6949
  /**
6808
- * `updateWeight` recalculates the weight of this node with the value and children.
6950
+ * `updateWeight` propagates weight changes from the given node up to the
6951
+ * root. Call this after a node's isRemoved() status changes (i.e., after
6952
+ * tombstoning).
6809
6953
  */
6810
6954
  updateWeight(node) {
6811
- node.initWeight();
6812
- if (node.hasLeft()) {
6813
- node.increaseWeight(node.getLeftWeight());
6814
- }
6815
- if (node.hasRight()) {
6816
- node.increaseWeight(node.getRightWeight());
6955
+ for (let cur = node; cur !== void 0; cur = cur.getParent()) {
6956
+ cur.setWeight(cur.leftWeight() + cur.size() + cur.rightWeight());
6817
6957
  }
6818
6958
  }
6819
- updateTreeWeight(node) {
6820
- while (node) {
6821
- this.updateWeight(node);
6822
- node = node.getParent();
6823
- }
6959
+ /**
6960
+ * `toTestString` returns a string containing the metadata of the node for
6961
+ * debugging purpose.
6962
+ */
6963
+ toTestString() {
6964
+ let s = "";
6965
+ traverseInOrder(this.root, (node) => {
6966
+ s += `[${node.getWeight()},${node.size()}]${node.getValue().toString()}`;
6967
+ });
6968
+ return s;
6824
6969
  }
6825
6970
  /**
6826
- * `splayNode` moves the given node to the root.
6971
+ * `indexOf` returns the logical (live-node) index of the given node, or -1
6972
+ * if the node is a tombstone.
6827
6973
  */
6828
- splayNode(node) {
6829
- if (!node) {
6830
- return;
6974
+ indexOf(node) {
6975
+ if (node.size() === 0) {
6976
+ return -1;
6831
6977
  }
6832
- for (; ; ) {
6833
- if (this.isLeftChild(node.getParent()) && this.isRightChild(node)) {
6834
- this.rotateLeft(node);
6835
- this.rotateRight(node);
6836
- } else if (this.isRightChild(node.getParent()) && this.isLeftChild(node)) {
6837
- this.rotateRight(node);
6838
- this.rotateLeft(node);
6839
- } else if (this.isLeftChild(node.getParent()) && this.isLeftChild(node)) {
6840
- this.rotateRight(node.getParent());
6841
- this.rotateRight(node);
6842
- } else if (this.isRightChild(node.getParent()) && this.isRightChild(node)) {
6843
- this.rotateLeft(node.getParent());
6844
- this.rotateLeft(node);
6845
- } else {
6846
- if (this.isLeftChild(node)) {
6847
- this.rotateRight(node);
6848
- } else if (this.isRightChild(node)) {
6849
- this.rotateLeft(node);
6850
- }
6851
- this.updateWeight(node);
6852
- return;
6978
+ let index = node.leftWeight();
6979
+ for (let cur = node; cur.getParent() !== void 0; cur = cur.getParent()) {
6980
+ if (cur === cur.getParent().getRight()) {
6981
+ index += cur.getParent().leftWeight() + cur.getParent().size();
6853
6982
  }
6854
6983
  }
6984
+ return index;
6855
6985
  }
6856
6986
  /**
6857
- * `delete` deletes target node of this tree.
6987
+ * `structuralIndexOf` returns the structural position of the node, counting
6988
+ * all nodes including tombstones.
6858
6989
  */
6859
- delete(node) {
6860
- this.splayNode(node);
6861
- const leftTree = new SplayTree(node.getLeft());
6862
- if (leftTree.root) {
6863
- leftTree.root.setParent();
6864
- }
6865
- const rightTree = new SplayTree(node.getRight());
6866
- if (rightTree.root) {
6867
- rightTree.root.setParent();
6990
+ structuralIndexOf(node) {
6991
+ let index = node.leftCount();
6992
+ for (let cur = node; cur.getParent() !== void 0; cur = cur.getParent()) {
6993
+ if (cur === cur.getParent().getRight()) {
6994
+ index += cur.getParent().leftCount() + 1;
6995
+ }
6868
6996
  }
6869
- if (leftTree.root) {
6870
- const rightmostNode = leftTree.getRightmost();
6871
- leftTree.splayNode(rightmostNode);
6872
- leftTree.root.setRight(rightTree.root);
6873
- if (rightTree.root) {
6874
- rightTree.root.setParent(leftTree.root);
6875
- }
6876
- this.root = leftTree.root;
6877
- } else {
6878
- this.root = rightTree.root;
6879
- }
6880
- node.unlink();
6881
- if (this.root) {
6882
- this.updateWeight(this.root);
6883
- }
6884
- }
6885
- /**
6886
- * `deleteRange` separates the range between given 2 boundaries from this Tree.
6887
- * This function separates the range to delete as a subtree
6888
- * by splaying outer boundary nodes.
6889
- * leftBoundary must exist because of 0-indexed initial dummy node of tree,
6890
- * but rightBoundary can be nil means range to delete includes the end of tree.
6891
- * Refer to the design document in https://github.com/yorkie-team/yorkie/tree/main/design
6892
- */
6893
- deleteRange(leftBoundary, rightBoundary) {
6894
- if (!rightBoundary) {
6895
- this.splayNode(leftBoundary);
6896
- this.cutOffRight(leftBoundary);
6897
- return;
6898
- }
6899
- this.splayNode(leftBoundary);
6900
- this.splayNode(rightBoundary);
6901
- if (rightBoundary.getLeft() != leftBoundary) {
6902
- this.rotateRight(leftBoundary);
6903
- }
6904
- this.cutOffRight(leftBoundary);
6905
- }
6906
- cutOffRight(root) {
6907
- const nodesToFreeWeight = [];
6908
- this.traversePostorder(root.getRight(), nodesToFreeWeight);
6909
- for (const node of nodesToFreeWeight) {
6910
- node.initWeight();
6911
- }
6912
- this.updateTreeWeight(root);
6913
- }
6914
- /**
6915
- * `toTestString` returns a string containing the meta data of the Node
6916
- * for debugging purpose.
6917
- */
6918
- toTestString() {
6919
- const metaString = [];
6920
- this.traverseInorder(this.root, metaString);
6921
- return metaString.map((n) => `[${n.getWeight()},${n.getLength()}]${n.getValue() || ""}`).join("");
6922
- }
6923
- /**
6924
- * `checkWeight` returns false when there is an incorrect weight node.
6925
- * for debugging purpose.
6926
- */
6927
- checkWeight() {
6928
- const nodes = [];
6929
- this.traverseInorder(this.root, nodes);
6930
- for (const node of nodes) {
6931
- if (node.getWeight() != node.getLength() + node.getLeftWeight() + node.getRightWeight()) {
6932
- return false;
6933
- }
6934
- }
6935
- return true;
6936
- }
6937
- getRightmost() {
6938
- let node = this.root;
6939
- while (node.hasRight()) {
6940
- node = node.getRight();
6941
- }
6942
- return node;
6943
- }
6944
- traverseInorder(node, stack) {
6945
- if (!node) {
6946
- return;
6947
- }
6948
- this.traverseInorder(node.getLeft(), stack);
6949
- stack.push(node);
6950
- this.traverseInorder(node.getRight(), stack);
6951
- }
6952
- traversePostorder(node, stack) {
6953
- if (!node) {
6954
- return;
6955
- }
6956
- this.traversePostorder(node.getLeft(), stack);
6957
- this.traversePostorder(node.getRight(), stack);
6958
- stack.push(node);
6959
- }
6960
- rotateLeft(pivot) {
6961
- const root = pivot.getParent();
6962
- if (root.hasParent()) {
6963
- if (root === root.getParent().getLeft()) {
6964
- root.getParent().setLeft(pivot);
6965
- } else {
6966
- root.getParent().setRight(pivot);
6967
- }
6968
- } else {
6969
- this.root = pivot;
6970
- }
6971
- pivot.setParent(root.getParent());
6972
- root.setRight(pivot.getLeft());
6973
- if (root.hasRight()) {
6974
- root.getRight().setParent(root);
6975
- }
6976
- pivot.setLeft(root);
6977
- pivot.getLeft().setParent(pivot);
6978
- this.updateWeight(root);
6979
- this.updateWeight(pivot);
6980
- }
6981
- rotateRight(pivot) {
6982
- const root = pivot.getParent();
6983
- if (root.hasParent()) {
6984
- if (root === root.getParent().getLeft()) {
6985
- root.getParent().setLeft(pivot);
6986
- } else {
6987
- root.getParent().setRight(pivot);
6988
- }
6989
- } else {
6990
- this.root = pivot;
6991
- }
6992
- pivot.setParent(root.getParent());
6993
- root.setLeft(pivot.getRight());
6994
- if (root.hasLeft()) {
6995
- root.getLeft().setParent(root);
6996
- }
6997
- pivot.setRight(root);
6998
- pivot.getRight().setParent(pivot);
6999
- this.updateWeight(root);
7000
- this.updateWeight(pivot);
7001
- }
7002
- isLeftChild(node) {
7003
- if (node && node.hasParent()) {
7004
- return node.getParent().getLeft() === node;
7005
- }
7006
- return false;
7007
- }
7008
- isRightChild(node) {
7009
- if (node && node.hasParent()) {
7010
- return node.getParent().getRight() === node;
7011
- }
7012
- return false;
6997
+ return index;
7013
6998
  }
7014
6999
  }
7015
7000
  const removeDecimal = (number) => number < 0 ? Math.ceil(number) : Math.floor(number);
@@ -7299,14 +7284,14 @@ class ElementEntry {
7299
7284
  this.elem = elem;
7300
7285
  }
7301
7286
  }
7302
- class RGATreeListNode extends SplayNode {
7287
+ class RGATreeListNode {
7288
+ indexNode;
7303
7289
  _elementEntry;
7304
7290
  _createdAt;
7305
7291
  _removedAt;
7306
7292
  prev;
7307
7293
  next;
7308
- constructor(elem, createdAt) {
7309
- super(elem);
7294
+ constructor(createdAt) {
7310
7295
  this._createdAt = createdAt;
7311
7296
  }
7312
7297
  /**
@@ -7314,9 +7299,10 @@ class RGATreeListNode extends SplayNode {
7314
7299
  */
7315
7300
  static createWithElement(elem) {
7316
7301
  const entry = new ElementEntry(elem);
7317
- const node = new RGATreeListNode(elem, elem.getCreatedAt());
7318
- entry.positionNode = node;
7302
+ const node = new RGATreeListNode(elem.getCreatedAt());
7319
7303
  node._elementEntry = entry;
7304
+ entry.positionNode = node;
7305
+ node.indexNode = new TreeListNode(node);
7320
7306
  return node;
7321
7307
  }
7322
7308
  /**
@@ -7324,7 +7310,9 @@ class RGATreeListNode extends SplayNode {
7324
7310
  * (used for move).
7325
7311
  */
7326
7312
  static createBarePosition(createdAt) {
7327
- return new RGATreeListNode(void 0, createdAt);
7313
+ const node = new RGATreeListNode(createdAt);
7314
+ node.indexNode = new TreeListNode(node);
7315
+ return node;
7328
7316
  }
7329
7317
  /**
7330
7318
  * `createAfter` creates a new node with the given element after
@@ -7396,14 +7384,14 @@ class RGATreeListNode extends SplayNode {
7396
7384
  this.next = void 0;
7397
7385
  }
7398
7386
  /**
7399
- * `getLength` returns the length of this node.
7400
- * Dead nodes (no element) return 0, removed elements return 0.
7387
+ * `toString` returns a string representation of this node's value, used by
7388
+ * TreeList for debugging.
7401
7389
  */
7402
- getLength() {
7403
- if (!this._elementEntry || this.isRemoved()) {
7404
- return 0;
7390
+ toString() {
7391
+ if (!this._elementEntry) {
7392
+ return "";
7405
7393
  }
7406
- return 1;
7394
+ return this._elementEntry.elem.toJSON();
7407
7395
  }
7408
7396
  /**
7409
7397
  * `getPrev` returns a previous node.
@@ -7421,9 +7409,6 @@ class RGATreeListNode extends SplayNode {
7421
7409
  * `getValue` returns the element value.
7422
7410
  */
7423
7411
  getValue() {
7424
- if (!this._elementEntry) {
7425
- return this.value;
7426
- }
7427
7412
  return this._elementEntry.elem;
7428
7413
  }
7429
7414
  /**
@@ -7512,10 +7497,11 @@ class RGATreeList {
7512
7497
  dummyValue.setRemovedAt(InitialTimeTicket);
7513
7498
  this.dummyHead = RGATreeListNode.createWithElement(dummyValue);
7514
7499
  this.last = this.dummyHead;
7515
- this.nodeMapByIndex = new SplayTree();
7500
+ this.nodeMapByIndex = new TreeList(
7501
+ this.dummyHead.indexNode
7502
+ );
7516
7503
  this.nodeMapByCreatedAt = /* @__PURE__ */ new Map();
7517
7504
  this.elementMapByCreatedAt = /* @__PURE__ */ new Map();
7518
- this.nodeMapByIndex.insert(this.dummyHead);
7519
7505
  this.nodeMapByCreatedAt.set(
7520
7506
  this.dummyHead.getCreatedAt().toIDString(),
7521
7507
  this.dummyHead
@@ -7548,7 +7534,7 @@ class RGATreeList {
7548
7534
  this.last = node.getPrev();
7549
7535
  }
7550
7536
  node.release();
7551
- this.nodeMapByIndex.delete(node);
7537
+ this.nodeMapByIndex.delete(node.indexNode);
7552
7538
  this.nodeMapByCreatedAt.delete(node.getPositionCreatedAt().toIDString());
7553
7539
  }
7554
7540
  /**
@@ -7576,7 +7562,7 @@ class RGATreeList {
7576
7562
  if (prevNode === this.last) {
7577
7563
  this.last = newNode;
7578
7564
  }
7579
- this.nodeMapByIndex.insertAfter(prevNode, newNode);
7565
+ this.nodeMapByIndex.insertAfter(prevNode.indexNode, newNode.indexNode);
7580
7566
  this.nodeMapByCreatedAt.set(value.getCreatedAt().toIDString(), newNode);
7581
7567
  this.elementMapByCreatedAt.set(
7582
7568
  value.getCreatedAt().toIDString(),
@@ -7603,7 +7589,7 @@ class RGATreeList {
7603
7589
  if (prevNode === this.last) {
7604
7590
  this.last = newNode;
7605
7591
  }
7606
- this.nodeMapByIndex.insertAfter(prevNode, newNode);
7592
+ this.nodeMapByIndex.insertAfter(prevNode.indexNode, newNode.indexNode);
7607
7593
  this.nodeMapByCreatedAt.set(executedAt.toIDString(), newNode);
7608
7594
  return newNode;
7609
7595
  }
@@ -7632,19 +7618,19 @@ class RGATreeList {
7632
7618
  }
7633
7619
  const deadPosNode = this.insertPositionAfter(prevCreatedAt, executedAt);
7634
7620
  deadPosNode.setRemovedAt(executedAt);
7635
- this.nodeMapByIndex.splayNode(deadPosNode);
7621
+ this.nodeMapByIndex.updateWeight(deadPosNode.indexNode);
7636
7622
  return deadPosNode;
7637
7623
  }
7638
7624
  const newPosNode = this.insertPositionAfter(prevCreatedAt, executedAt);
7639
7625
  const oldPosNode = entry.positionNode;
7640
7626
  oldPosNode.setElementEntry(void 0);
7641
7627
  oldPosNode.setRemovedAt(executedAt);
7642
- this.nodeMapByIndex.splayNode(oldPosNode);
7628
+ this.nodeMapByIndex.updateWeight(oldPosNode.indexNode);
7643
7629
  newPosNode.setElementEntry(entry);
7644
7630
  entry.positionNode = newPosNode;
7645
7631
  entry.posMovedAt = executedAt;
7646
7632
  entry.elem.setMovedAt(executedAt);
7647
- this.nodeMapByIndex.splayNode(newPosNode);
7633
+ this.nodeMapByIndex.updateWeight(newPosNode.indexNode);
7648
7634
  return oldPosNode;
7649
7635
  }
7650
7636
  /**
@@ -7675,9 +7661,9 @@ class RGATreeList {
7675
7661
  if (!node) {
7676
7662
  return;
7677
7663
  }
7678
- return String(this.nodeMapByIndex.indexOf(node));
7664
+ return String(this.nodeMapByIndex.indexOf(node.indexNode));
7679
7665
  }
7680
- return String(this.nodeMapByIndex.indexOf(entry.positionNode));
7666
+ return String(this.nodeMapByIndex.indexOf(entry.positionNode.indexNode));
7681
7667
  }
7682
7668
  /**
7683
7669
  * `purge` physically purges the given child. Handles both dead
@@ -7710,8 +7696,7 @@ class RGATreeList {
7710
7696
  if (idx >= this.length) {
7711
7697
  return;
7712
7698
  }
7713
- const node = this.nodeMapByIndex.findForArray(idx);
7714
- return node;
7699
+ return this.nodeMapByIndex.find(idx).getValue();
7715
7700
  }
7716
7701
  /**
7717
7702
  * `findPrevCreatedAt` returns the position node's createdAt of the
@@ -7759,7 +7744,7 @@ class RGATreeList {
7759
7744
  const node = entry.positionNode;
7760
7745
  const alreadyRemoved = node.isRemoved();
7761
7746
  if (entry.elem.remove(editedAt) && !alreadyRemoved) {
7762
- this.nodeMapByIndex.splayNode(node);
7747
+ this.nodeMapByIndex.updateWeight(node.indexNode);
7763
7748
  }
7764
7749
  return entry.elem;
7765
7750
  }
@@ -7785,7 +7770,7 @@ class RGATreeList {
7785
7770
  return;
7786
7771
  }
7787
7772
  if (node.remove(editedAt)) {
7788
- this.nodeMapByIndex.splayNode(node);
7773
+ this.nodeMapByIndex.updateWeight(node.indexNode);
7789
7774
  }
7790
7775
  return node.getValue();
7791
7776
  }
@@ -7796,10 +7781,15 @@ class RGATreeList {
7796
7781
  return this.dummyHead.getValue();
7797
7782
  }
7798
7783
  /**
7799
- * `getLast` returns the value of last elements.
7784
+ * `getLast` returns the value of last elements. Skips bare position nodes
7785
+ * (created by moveAfter/addDeadPosition) that have no element.
7800
7786
  */
7801
7787
  getLast() {
7802
- return this.last.getValue();
7788
+ let node = this.last;
7789
+ while (!node.getElementEntry() && node !== this.dummyHead) {
7790
+ node = node.getPrev();
7791
+ }
7792
+ return node.getValue();
7803
7793
  }
7804
7794
  /**
7805
7795
  * `getLastCreatedAt` returns the position node's createdAt of the
@@ -7834,7 +7824,7 @@ class RGATreeList {
7834
7824
  const prevNode = this.last;
7835
7825
  RGATreeListNode.insertNodeAfter(prevNode, node);
7836
7826
  this.last = node;
7837
- this.nodeMapByIndex.insertAfter(prevNode, node);
7827
+ this.nodeMapByIndex.insertAfter(prevNode.indexNode, node.indexNode);
7838
7828
  this.nodeMapByCreatedAt.set(posCreatedAt.toIDString(), node);
7839
7829
  }
7840
7830
  /**
@@ -7850,7 +7840,7 @@ class RGATreeList {
7850
7840
  const prevNode = this.last;
7851
7841
  RGATreeListNode.insertNodeAfter(prevNode, node);
7852
7842
  this.last = node;
7853
- this.nodeMapByIndex.insertAfter(prevNode, node);
7843
+ this.nodeMapByIndex.insertAfter(prevNode.indexNode, node.indexNode);
7854
7844
  this.nodeMapByCreatedAt.set(posCreatedAt.toIDString(), node);
7855
7845
  this.elementMapByCreatedAt.set(elem.getCreatedAt().toIDString(), entry);
7856
7846
  }
@@ -8016,9 +8006,10 @@ class CRDTArray extends CRDTContainer {
8016
8006
  */
8017
8007
  *[Symbol.iterator]() {
8018
8008
  for (const node of this.elements) {
8019
- if (node.getElementEntry() && !node.isRemoved()) {
8020
- yield node.getValue();
8009
+ if (node.isRemoved()) {
8010
+ continue;
8021
8011
  }
8012
+ yield node.getValue();
8022
8013
  }
8023
8014
  }
8024
8015
  /**
@@ -8566,6 +8557,449 @@ class MoveOperation extends Operation {
8566
8557
  this.createdAt = createdAt;
8567
8558
  }
8568
8559
  }
8560
+ class SplayNode {
8561
+ value;
8562
+ left;
8563
+ right;
8564
+ parent;
8565
+ weight;
8566
+ constructor(value) {
8567
+ this.value = value;
8568
+ this.initWeight();
8569
+ }
8570
+ /**
8571
+ * `getNodeString` returns a string of weight and value of this node.
8572
+ */
8573
+ getNodeString() {
8574
+ return `${this.weight}${this.value}`;
8575
+ }
8576
+ /**
8577
+ * `getValue` returns value of this node.
8578
+ */
8579
+ getValue() {
8580
+ return this.value;
8581
+ }
8582
+ /**
8583
+ * `getLeftWeight` returns left weight of this node.
8584
+ */
8585
+ getLeftWeight() {
8586
+ return !this.hasLeft() ? 0 : this.left.getWeight();
8587
+ }
8588
+ /**
8589
+ * `getRightWeight` returns right weight of this node.
8590
+ */
8591
+ getRightWeight() {
8592
+ return !this.hasRight() ? 0 : this.right.getWeight();
8593
+ }
8594
+ /**
8595
+ * `getWeight` returns weight of this node.
8596
+ */
8597
+ getWeight() {
8598
+ return this.weight;
8599
+ }
8600
+ /**
8601
+ * `getLeft` returns a left node.
8602
+ */
8603
+ getLeft() {
8604
+ return this.left;
8605
+ }
8606
+ /**
8607
+ * `getRight` returns a right node.
8608
+ */
8609
+ getRight() {
8610
+ return this.right;
8611
+ }
8612
+ /**
8613
+ * `getParent` returns parent of this node.
8614
+ */
8615
+ getParent() {
8616
+ return this.parent;
8617
+ }
8618
+ /**
8619
+ * `hasLeft` check if the left node exists
8620
+ */
8621
+ hasLeft() {
8622
+ return !!this.left;
8623
+ }
8624
+ /**
8625
+ * `hasRight` check if the right node exists
8626
+ */
8627
+ hasRight() {
8628
+ return !!this.right;
8629
+ }
8630
+ /**
8631
+ * `hasParent` check if the parent node exists
8632
+ */
8633
+ hasParent() {
8634
+ return !!this.parent;
8635
+ }
8636
+ /**
8637
+ * `setLeft` sets a left node.
8638
+ */
8639
+ setLeft(left) {
8640
+ this.left = left;
8641
+ }
8642
+ /**
8643
+ * `setRight` sets a right node.
8644
+ */
8645
+ setRight(right) {
8646
+ this.right = right;
8647
+ }
8648
+ /**
8649
+ * `setParent` sets a parent node.
8650
+ */
8651
+ setParent(parent) {
8652
+ this.parent = parent;
8653
+ }
8654
+ /**
8655
+ * `unlink` unlink parent, right and left node.
8656
+ */
8657
+ unlink() {
8658
+ this.parent = void 0;
8659
+ this.right = void 0;
8660
+ this.left = void 0;
8661
+ }
8662
+ /**
8663
+ * `hasLinks` checks if parent, right and left node exists.
8664
+ */
8665
+ hasLinks() {
8666
+ return this.hasParent() || this.hasLeft() || this.hasRight();
8667
+ }
8668
+ /**
8669
+ * `increaseWeight` increases weight.
8670
+ */
8671
+ increaseWeight(weight) {
8672
+ this.weight += weight;
8673
+ }
8674
+ /**
8675
+ * `initWeight` sets initial weight of this node.
8676
+ */
8677
+ initWeight() {
8678
+ this.weight = this.getLength();
8679
+ }
8680
+ }
8681
+ class SplayTree {
8682
+ root;
8683
+ constructor(root) {
8684
+ this.root = root;
8685
+ }
8686
+ /**
8687
+ * `length` returns the size of this tree.
8688
+ */
8689
+ get length() {
8690
+ return this.root ? this.root.getWeight() : 0;
8691
+ }
8692
+ /**
8693
+ * `findForText` returns the Node and offset of the given position (cursor).
8694
+ * Used for Text where cursor placed between characters.
8695
+ */
8696
+ findForText(pos) {
8697
+ if (!this.root || pos < 0) {
8698
+ return [void 0, 0];
8699
+ }
8700
+ let node = this.root;
8701
+ for (; ; ) {
8702
+ if (node.hasLeft() && pos <= node.getLeftWeight()) {
8703
+ node = node.getLeft();
8704
+ } else if (node.hasRight() && node.getLeftWeight() + node.getLength() < pos) {
8705
+ pos -= node.getLeftWeight() + node.getLength();
8706
+ node = node.getRight();
8707
+ } else {
8708
+ pos -= node.getLeftWeight();
8709
+ break;
8710
+ }
8711
+ }
8712
+ if (pos > node.getLength()) {
8713
+ throw new YorkieError(
8714
+ Code.ErrInvalidArgument,
8715
+ `out of index range: pos: ${pos} > node.length: ${node.getLength()}`
8716
+ );
8717
+ }
8718
+ this.splayNode(node);
8719
+ return [node, pos];
8720
+ }
8721
+ /**
8722
+ * `findForArray` returns the Node of the given position (index).
8723
+ * Used for Array where index points to the element.
8724
+ */
8725
+ findForArray(idx) {
8726
+ if (!this.root) {
8727
+ return void 0;
8728
+ }
8729
+ if (idx < 0 || idx >= this.length) {
8730
+ throw new YorkieError(
8731
+ Code.ErrInvalidArgument,
8732
+ `out of index range: idx: ${idx}, length: ${this.length}`
8733
+ );
8734
+ }
8735
+ let node = this.root;
8736
+ for (; ; ) {
8737
+ if (node.hasLeft() && idx < node.getLeftWeight()) {
8738
+ node = node.getLeft();
8739
+ } else if (node.hasRight() && node.getLeftWeight() + node.getLength() <= idx) {
8740
+ idx -= node.getLeftWeight() + node.getLength();
8741
+ node = node.getRight();
8742
+ } else {
8743
+ break;
8744
+ }
8745
+ }
8746
+ this.splayNode(node);
8747
+ return node;
8748
+ }
8749
+ /**
8750
+ * Find the index of the given node in BST.
8751
+ *
8752
+ * @param node - the given node
8753
+ * @returns the index of given node
8754
+ */
8755
+ indexOf(node) {
8756
+ if (!node || node !== this.root && !node.hasLinks()) {
8757
+ return -1;
8758
+ }
8759
+ this.splayNode(node);
8760
+ return this.root.getLeftWeight();
8761
+ }
8762
+ /**
8763
+ * `getRoot` returns root of this tree.
8764
+ */
8765
+ getRoot() {
8766
+ return this.root;
8767
+ }
8768
+ /**
8769
+ * `insert` inserts the node at the last.
8770
+ */
8771
+ insert(newNode) {
8772
+ return this.insertAfter(this.root, newNode);
8773
+ }
8774
+ /**
8775
+ * `insertAfter` inserts the node after the given previous node.
8776
+ */
8777
+ insertAfter(target, newNode) {
8778
+ if (!target) {
8779
+ this.root = newNode;
8780
+ return newNode;
8781
+ }
8782
+ this.splayNode(target);
8783
+ this.root = newNode;
8784
+ newNode.setRight(target.getRight());
8785
+ if (target.hasRight()) {
8786
+ target.getRight().setParent(newNode);
8787
+ }
8788
+ newNode.setLeft(target);
8789
+ target.setParent(newNode);
8790
+ target.setRight();
8791
+ this.updateWeight(target);
8792
+ this.updateWeight(newNode);
8793
+ return newNode;
8794
+ }
8795
+ /**
8796
+ * `updateWeight` recalculates the weight of this node with the value and children.
8797
+ */
8798
+ updateWeight(node) {
8799
+ node.initWeight();
8800
+ if (node.hasLeft()) {
8801
+ node.increaseWeight(node.getLeftWeight());
8802
+ }
8803
+ if (node.hasRight()) {
8804
+ node.increaseWeight(node.getRightWeight());
8805
+ }
8806
+ }
8807
+ updateTreeWeight(node) {
8808
+ while (node) {
8809
+ this.updateWeight(node);
8810
+ node = node.getParent();
8811
+ }
8812
+ }
8813
+ /**
8814
+ * `splayNode` moves the given node to the root.
8815
+ */
8816
+ splayNode(node) {
8817
+ if (!node) {
8818
+ return;
8819
+ }
8820
+ for (; ; ) {
8821
+ if (this.isLeftChild(node.getParent()) && this.isRightChild(node)) {
8822
+ this.rotateLeft(node);
8823
+ this.rotateRight(node);
8824
+ } else if (this.isRightChild(node.getParent()) && this.isLeftChild(node)) {
8825
+ this.rotateRight(node);
8826
+ this.rotateLeft(node);
8827
+ } else if (this.isLeftChild(node.getParent()) && this.isLeftChild(node)) {
8828
+ this.rotateRight(node.getParent());
8829
+ this.rotateRight(node);
8830
+ } else if (this.isRightChild(node.getParent()) && this.isRightChild(node)) {
8831
+ this.rotateLeft(node.getParent());
8832
+ this.rotateLeft(node);
8833
+ } else {
8834
+ if (this.isLeftChild(node)) {
8835
+ this.rotateRight(node);
8836
+ } else if (this.isRightChild(node)) {
8837
+ this.rotateLeft(node);
8838
+ }
8839
+ this.updateWeight(node);
8840
+ return;
8841
+ }
8842
+ }
8843
+ }
8844
+ /**
8845
+ * `delete` deletes target node of this tree.
8846
+ */
8847
+ delete(node) {
8848
+ this.splayNode(node);
8849
+ const leftTree = new SplayTree(node.getLeft());
8850
+ if (leftTree.root) {
8851
+ leftTree.root.setParent();
8852
+ }
8853
+ const rightTree = new SplayTree(node.getRight());
8854
+ if (rightTree.root) {
8855
+ rightTree.root.setParent();
8856
+ }
8857
+ if (leftTree.root) {
8858
+ const rightmostNode = leftTree.getRightmost();
8859
+ leftTree.splayNode(rightmostNode);
8860
+ leftTree.root.setRight(rightTree.root);
8861
+ if (rightTree.root) {
8862
+ rightTree.root.setParent(leftTree.root);
8863
+ }
8864
+ this.root = leftTree.root;
8865
+ } else {
8866
+ this.root = rightTree.root;
8867
+ }
8868
+ node.unlink();
8869
+ if (this.root) {
8870
+ this.updateWeight(this.root);
8871
+ }
8872
+ }
8873
+ /**
8874
+ * `deleteRange` separates the range between given 2 boundaries from this Tree.
8875
+ * This function separates the range to delete as a subtree
8876
+ * by splaying outer boundary nodes.
8877
+ * leftBoundary must exist because of 0-indexed initial dummy node of tree,
8878
+ * but rightBoundary can be nil means range to delete includes the end of tree.
8879
+ * Refer to the design document in https://github.com/yorkie-team/yorkie/tree/main/design
8880
+ */
8881
+ deleteRange(leftBoundary, rightBoundary) {
8882
+ if (!rightBoundary) {
8883
+ this.splayNode(leftBoundary);
8884
+ this.cutOffRight(leftBoundary);
8885
+ return;
8886
+ }
8887
+ this.splayNode(leftBoundary);
8888
+ this.splayNode(rightBoundary);
8889
+ if (rightBoundary.getLeft() != leftBoundary) {
8890
+ this.rotateRight(leftBoundary);
8891
+ }
8892
+ this.cutOffRight(leftBoundary);
8893
+ }
8894
+ cutOffRight(root) {
8895
+ const nodesToFreeWeight = [];
8896
+ this.traversePostorder(root.getRight(), nodesToFreeWeight);
8897
+ for (const node of nodesToFreeWeight) {
8898
+ node.initWeight();
8899
+ }
8900
+ this.updateTreeWeight(root);
8901
+ }
8902
+ /**
8903
+ * `toTestString` returns a string containing the meta data of the Node
8904
+ * for debugging purpose.
8905
+ */
8906
+ toTestString() {
8907
+ const metaString = [];
8908
+ this.traverseInorder(this.root, metaString);
8909
+ return metaString.map((n) => `[${n.getWeight()},${n.getLength()}]${n.getValue() || ""}`).join("");
8910
+ }
8911
+ /**
8912
+ * `checkWeight` returns false when there is an incorrect weight node.
8913
+ * for debugging purpose.
8914
+ */
8915
+ checkWeight() {
8916
+ const nodes = [];
8917
+ this.traverseInorder(this.root, nodes);
8918
+ for (const node of nodes) {
8919
+ if (node.getWeight() != node.getLength() + node.getLeftWeight() + node.getRightWeight()) {
8920
+ return false;
8921
+ }
8922
+ }
8923
+ return true;
8924
+ }
8925
+ getRightmost() {
8926
+ let node = this.root;
8927
+ while (node.hasRight()) {
8928
+ node = node.getRight();
8929
+ }
8930
+ return node;
8931
+ }
8932
+ traverseInorder(node, stack) {
8933
+ if (!node) {
8934
+ return;
8935
+ }
8936
+ this.traverseInorder(node.getLeft(), stack);
8937
+ stack.push(node);
8938
+ this.traverseInorder(node.getRight(), stack);
8939
+ }
8940
+ traversePostorder(node, stack) {
8941
+ if (!node) {
8942
+ return;
8943
+ }
8944
+ this.traversePostorder(node.getLeft(), stack);
8945
+ this.traversePostorder(node.getRight(), stack);
8946
+ stack.push(node);
8947
+ }
8948
+ rotateLeft(pivot) {
8949
+ const root = pivot.getParent();
8950
+ if (root.hasParent()) {
8951
+ if (root === root.getParent().getLeft()) {
8952
+ root.getParent().setLeft(pivot);
8953
+ } else {
8954
+ root.getParent().setRight(pivot);
8955
+ }
8956
+ } else {
8957
+ this.root = pivot;
8958
+ }
8959
+ pivot.setParent(root.getParent());
8960
+ root.setRight(pivot.getLeft());
8961
+ if (root.hasRight()) {
8962
+ root.getRight().setParent(root);
8963
+ }
8964
+ pivot.setLeft(root);
8965
+ pivot.getLeft().setParent(pivot);
8966
+ this.updateWeight(root);
8967
+ this.updateWeight(pivot);
8968
+ }
8969
+ rotateRight(pivot) {
8970
+ const root = pivot.getParent();
8971
+ if (root.hasParent()) {
8972
+ if (root === root.getParent().getLeft()) {
8973
+ root.getParent().setLeft(pivot);
8974
+ } else {
8975
+ root.getParent().setRight(pivot);
8976
+ }
8977
+ } else {
8978
+ this.root = pivot;
8979
+ }
8980
+ pivot.setParent(root.getParent());
8981
+ root.setLeft(pivot.getRight());
8982
+ if (root.hasLeft()) {
8983
+ root.getLeft().setParent(root);
8984
+ }
8985
+ pivot.setRight(root);
8986
+ pivot.getRight().setParent(pivot);
8987
+ this.updateWeight(root);
8988
+ this.updateWeight(pivot);
8989
+ }
8990
+ isLeftChild(node) {
8991
+ if (node && node.hasParent()) {
8992
+ return node.getParent().getLeft() === node;
8993
+ }
8994
+ return false;
8995
+ }
8996
+ isRightChild(node) {
8997
+ if (node && node.hasParent()) {
8998
+ return node.getParent().getRight() === node;
8999
+ }
9000
+ return false;
9001
+ }
9002
+ }
8569
9003
  const DefaultComparator = (a, b) => {
8570
9004
  if (a === b) {
8571
9005
  return 0;
@@ -8581,10 +9015,10 @@ class LLRBNode {
8581
9015
  left;
8582
9016
  right;
8583
9017
  isRed;
8584
- constructor(key, value, isRed) {
9018
+ constructor(key, value, isRed2) {
8585
9019
  this.key = key;
8586
9020
  this.value = value;
8587
- this.isRed = isRed;
9021
+ this.isRed = isRed2;
8588
9022
  }
8589
9023
  }
8590
9024
  class SortedMapIterator {
@@ -21016,7 +21450,7 @@ function createAuthInterceptor(apiKey, token) {
21016
21450
  };
21017
21451
  }
21018
21452
  const name$1 = "@yorkie-js/sdk";
21019
- const version$1 = "0.7.11-rc";
21453
+ const version$1 = "0.7.11";
21020
21454
  const pkg$1 = {
21021
21455
  name: name$1,
21022
21456
  version: version$1
@@ -23100,7 +23534,7 @@ if (typeof globalThis !== "undefined") {
23100
23534
  };
23101
23535
  }
23102
23536
  const name = "@yorkie-js/react";
23103
- const version = "0.7.11-rc";
23537
+ const version = "0.7.11";
23104
23538
  const pkg = {
23105
23539
  name,
23106
23540
  version