/** * Remove an element from the right digit. * * @param pos position inside the right digit * @return resulting tree */ private FingerTree<N, E> removeRight(final long pos) { if (right.length > 1) { // right digit cannot underflow, just delete the element return new DeepTree<>(left, leftSize, middle, remove(right, pos), size - 1); } // singleton digit might underflow final Node<N, E> node = right[0]; if (!middle.isEmpty()) { // potentially balance with middle tree final InnerNode<N, E> last = (InnerNode<N, E>) middle.last(); final Node<N, E> lastSub = last.getSub(last.arity() - 1); final NodeLike<N, E>[] rem = node.remove(lastSub, null, pos); final Node<N, E> newLastSub = (Node<N, E>) rem[0], newNode = (Node<N, E>) rem[1]; if (newNode == null) { // nodes were merged final Node<N, E>[] newRight = last.children.clone(); newRight[newRight.length - 1] = newLastSub; return new DeepTree<>(left, leftSize, middle.init(), newRight, size - 1); } @SuppressWarnings("unchecked") final Node<N, E>[] newRight = new Node[] {newNode}; // replace last node in middle tree final Node<Node<N, E>, E> newLast = last.replaceLast(newLastSub); return new DeepTree<>(left, leftSize, middle.replaceLast(newLast), newRight, size - 1); } // balance with left digit final Node<N, E> lastLeft = left[left.length - 1]; final NodeLike<N, E>[] rem = node.remove(lastLeft, null, pos); final Node<N, E> newLastLeft = (Node<N, E>) rem[0], newNode = (Node<N, E>) rem[1]; if (newNode == null) { // nodes were merged if (left.length == 1) { // only one node left return new SingletonTree<>(newLastLeft); } @SuppressWarnings("unchecked") final Node<N, E>[] newRight = new Node[] {newLastLeft}; return get(slice(left, 0, left.length - 1), newRight, size - 1); } @SuppressWarnings("unchecked") final Node<N, E>[] newRight = new Node[] {newNode}; if (newLastLeft == lastLeft) { // deletion could be absorbed return get(left, leftSize, newRight, size - 1); } // adapt the left digit final Node<N, E>[] newLeft = left.clone(); newLeft[newLeft.length - 1] = newLastLeft; return get(newLeft, newRight, size - 1); }
@Override public TreeSlice<N, E> slice(final long from, final long len) { if (from == 0 && len == size) return new TreeSlice<>(this); final long midSize = middle.size(), rightOff = leftSize + midSize; final long inLeft = from + len <= leftSize ? len : from < leftSize ? leftSize - from : 0; final long inRight = from >= rightOff ? len : from + len > rightOff ? from + len - rightOff : 0; @SuppressWarnings("unchecked") final NodeLike<N, E>[] buffer = new NodeLike[2 * MAX_DIGIT + 1]; int inBuffer = splitDigit(left, from, inLeft, buffer, 0); if (inLeft == len) { if (inBuffer == 1) return new TreeSlice<>(buffer[0]); final int mid1 = inBuffer / 2; final Node<N, E>[] ls = slice(buffer, 0, mid1), rs = slice(buffer, mid1, inBuffer); return new TreeSlice<>(get(ls, rs, len)); } final long inMiddle = len - inLeft - inRight; final FingerTree<Node<N, E>, E> mid; final TreeSlice<Node<N, E>, E> slice; if (inMiddle == 0) { mid = EmptyTree.getInstance(); slice = new TreeSlice<>(mid); } else { final long midOff = from <= leftSize ? 0 : from - leftSize; slice = middle.slice(midOff, inMiddle); if (slice.isTree()) { mid = slice.getTree(); } else { final NodeLike<N, E> sub = ((PartialInnerNode<N, E>) slice.getPartial()).sub; inBuffer = sub.append(buffer, inBuffer); mid = EmptyTree.getInstance(); } } final long rightFrom = from < rightOff ? 0 : from - rightOff; if (mid.isEmpty()) { inBuffer = splitDigit(right, rightFrom, inRight, buffer, inBuffer); return slice.setNodes(buffer, inBuffer, len); } final FingerTree<Node<N, E>, E> mid2; if (inBuffer > 1 || buffer[0] instanceof Node) { mid2 = mid; } else { final InnerNode<N, E> head = (InnerNode<N, E>) mid.head(); final int k = head.arity(); inBuffer = head.getSub(0).append(buffer, inBuffer); for (int i = 1; i < k; i++) buffer[inBuffer++] = head.getSub(i); mid2 = mid.tail(); } if (mid2.isEmpty()) { inBuffer = splitDigit(right, rightFrom, inRight, buffer, inBuffer); return slice.setNodes(buffer, inBuffer, len); } final Node<N, E>[] newLeft = slice(buffer, 0, inBuffer); inBuffer = splitDigit(right, rightFrom, inRight, buffer, 0); final FingerTree<Node<N, E>, E> mid3; final Node<N, E>[] newRight; if (inBuffer == 0) { mid3 = mid2.init(); newRight = ((InnerNode<N, E>) mid2.last()).children; } else if (inBuffer > 1 || buffer[0] instanceof Node) { mid3 = mid2; newRight = slice(buffer, 0, inBuffer); } else { final NodeLike<N, E> partial = buffer[0]; final InnerNode<N, E> last = (InnerNode<N, E>) mid2.last(); final int k = last.arity(); for (int i = 0; i < k; i++) buffer[i] = last.getSub(i); inBuffer = partial.append(buffer, k); mid3 = mid2.init(); newRight = slice(buffer, 0, inBuffer); } return slice.setTree(get(newLeft, mid3, newRight, len)); }
/** * Remove an element from the left digit. * * @param pos position inside the left digit * @return resulting tree */ private FingerTree<N, E> removeLeft(final long pos) { if (left.length > 1) { // left digit cannot underflow, just delete the element return new DeepTree<>(remove(left, pos), leftSize - 1, middle, right, size - 1); } // singleton digit might underflow final Node<N, E> node = left[0]; if (!middle.isEmpty()) { // next node for balancing is in middle tree final InnerNode<N, E> head = (InnerNode<N, E>) middle.head(); final Node<N, E> first = head.getSub(0); final NodeLike<N, E>[] rem = node.remove(null, first, pos); final Node<N, E> newNode = (Node<N, E>) rem[1], newFirst = (Node<N, E>) rem[2]; if (newNode == null) { // nodes were merged final Node<N, E>[] newLeft = head.children.clone(); newLeft[0] = newFirst; return get(newLeft, middle.tail(), right, size - 1); } @SuppressWarnings("unchecked") final Node<N, E>[] newLeft = new Node[] {newNode}; if (newFirst != first) { // nodes were balanced final FingerTree<Node<N, E>, E> newMid = middle.replaceHead(head.replaceFirst(newFirst)); return new DeepTree<>(newLeft, newNode.size(), newMid, right, size - 1); } // no changes to this tree's structure return new DeepTree<>(newLeft, newNode.size(), middle, right, size - 1); } // potentially balance with right digit final NodeLike<N, E>[] rem = node.remove(null, right[0], pos); final Node<N, E> newNode = (Node<N, E>) rem[1], newFirstRight = (Node<N, E>) rem[2]; if (newNode == null) { // nodes were merged if (right.length == 1) return new SingletonTree<>(newFirstRight); final int mid = right.length / 2; final Node<N, E>[] newLeft = slice(right, 0, mid); newLeft[0] = newFirstRight; return get(newLeft, middle, slice(right, mid, right.length), size - 1); } // structure does not change @SuppressWarnings("unchecked") final Node<N, E>[] newLeft = new Node[] {newNode}; if (newFirstRight == right[0]) { // right digit stays the same return new DeepTree<>(newLeft, newLeft[0].size(), middle, right, size - 1); } // adapt the right digit final Node<N, E>[] newRight = right.clone(); newRight[0] = newFirstRight; return new DeepTree<>(newLeft, newNode.size(), middle, newRight, size - 1); }