Ejemplo n.º 1
0
  /**
   * Creates a tree slice from a digit.
   *
   * @param <N> node type
   * @param <E> element type
   * @param nodes the digit
   * @param from element offset
   * @param len number of elements
   * @param buffer buffer to insert the node slice into
   * @param inBuffer initial number of nodes in the buffer
   * @return the slice
   */
  private static <N, E> int splitDigit(
      final Node<N, E>[] nodes,
      final long from,
      final long len,
      final NodeLike<N, E>[] buffer,
      final int inBuffer) {
    if (len <= 0) return inBuffer;

    // find the first sub-node containing used elements
    int firstPos = 0;
    long firstOff = from;
    Node<N, E> first = nodes[0];
    long firstSize = first.size();
    while (firstOff >= firstSize) {
      firstOff -= firstSize;
      first = nodes[++firstPos];
      firstSize = first.size();
    }

    // firstOff < firstSize
    final long inFirst = firstSize - firstOff;
    if (inFirst >= len) {
      // everything in first sub-node
      final NodeLike<N, E> part = len == firstSize ? first : first.slice(firstOff, len);
      return part.append(buffer, inBuffer);
    }

    final NodeLike<N, E> firstSlice = firstOff == 0 ? first : first.slice(firstOff, inFirst);
    int numMerged = firstSlice.append(buffer, inBuffer);

    int pos = firstPos;
    long remaining = len - inFirst;
    while (remaining > 0) {
      final Node<N, E> curr = nodes[++pos];
      final long currSize = curr.size();
      final NodeLike<N, E> slice = remaining >= currSize ? curr : curr.slice(0, remaining);
      numMerged = slice.append(buffer, numMerged);
      remaining -= currSize;
    }

    return numMerged;
  }
Ejemplo n.º 2
0
  @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));
  }