@Override
  public int append(final NodeLike<Node<N, E>, E>[] out, final int pos) {
    if(pos == 0) {
      out[0] = this;
      return 1;
    }

    @SuppressWarnings("unchecked")
    final NodeLike<N, E>[] buffer = (NodeLike<N, E>[]) out;
    final NodeLike<Node<N, E>, E> left = out[pos - 1];
    if(left instanceof PartialInnerNode) {
      buffer[pos - 1] = ((PartialInnerNode<N, E>) left).sub;
      if(sub.append(buffer, pos) == pos) {
        out[pos - 1] = new PartialInnerNode<>(buffer[pos - 1]);
      } else {
        @SuppressWarnings("unchecked")
        final Node<N, E>[] ch = new Node[2];
        ch[0] = (Node<N, E>) buffer[pos - 1];
        ch[1] = (Node<N, E>) buffer[pos];
        out[pos - 1] = new InnerNode<>(ch);
        out[pos] = null;
      }
      return pos;
    }

    final Node<N, E>[] children = ((InnerNode<N, E>) left).children;
    final int n = children.length;
    final Node<N, E> a, b;
    if(sub instanceof Node) {
      a = children[n - 1];
      b = (Node<N, E>) sub;
    } else {
      buffer[pos - 1] = children[n - 1];
      if(sub.append(buffer, pos) == pos) {
        final Node<N, E>[] ch = children.clone();
        ch[n - 1] = (Node<N, E>) buffer[pos - 1];
        out[pos - 1] = new InnerNode<>(ch);
        return pos;
      }
      a = (Node<N, E>) buffer[pos - 1];
      b = (Node<N, E>) buffer[pos];
    }

    if(n < FingerTree.MAX_ARITY) {
      @SuppressWarnings("unchecked")
      final Node<N, E>[] ch = new Node[n + 1];
      System.arraycopy(children, 0, ch, 0, n - 1);
      ch[n - 1] = a;
      ch[n] = b;
      out[pos - 1] = new InnerNode<>(ch);
      out[pos] = null;
      return pos;
    }

    final int ll = (n + 1) / 2, rl = n + 1 - ll;
    @SuppressWarnings("unchecked")
    final Node<N, E>[] ls = new Node[ll], rs = new Node[rl];
    System.arraycopy(children, 0, ls, 0, ll);
    System.arraycopy(children, ll, rs, 0, rl - 2);
    rs[rl - 2] = a;
    rs[rl - 1] = b;
    out[pos - 1] = new InnerNode<>(ls);
    out[pos] = new InnerNode<>(rs);
    return pos + 1;
  }