|
15 | 15 |
|
16 | 16 | import java.lang.reflect.Array;
|
17 | 17 | import java.util.Arrays;
|
| 18 | +import java.util.Iterator; |
18 | 19 | import java.util.List;
|
| 20 | +import java.util.Stack; |
19 | 21 |
|
20 | 22 | import org.organicdesign.fp.collections.ImList;
|
21 | 23 | import org.organicdesign.fp.collections.MutableList;
|
22 | 24 | import org.organicdesign.fp.collections.UnmodIterable;
|
23 | 25 | import org.organicdesign.fp.collections.UnmodSortedIterable;
|
| 26 | +import org.organicdesign.fp.collections.UnmodSortedIterator; |
24 | 27 | import org.organicdesign.fp.tuple.Tuple2;
|
25 | 28 | import org.organicdesign.fp.tuple.Tuple4;
|
26 | 29 |
|
@@ -336,7 +339,26 @@ private RrbTree1(E[] f, int fi, Node<E> r, int s) {
|
336 | 339 | focus = f; focusStartIndex = fi; root = r; size = s;
|
337 | 340 | }
|
338 | 341 |
|
339 |
| - @Override public int size() { return size; } |
| 342 | + /** |
| 343 | + Adds an item at the end of this structure. This is the most efficient way to build an |
| 344 | + RRB Tree as it conforms to the Clojure PersistentVector and all of its optimizations. |
| 345 | + @param t the item to append |
| 346 | + @return a new RRB-Tree with the item appended. |
| 347 | + */ |
| 348 | + @Override public RrbTree1<E> append(E t) { |
| 349 | +// System.out.println("=== append(" + t + ") ==="); |
| 350 | + // If our focus isn't set up for appends or if it's full, insert it into the data structure |
| 351 | + // where it belongs. Then make a new focus |
| 352 | + if (((focusStartIndex < root.size()) && (focus.length > 0) ) || |
| 353 | + (focus.length >= STRICT_NODE_LENGTH) ) { |
| 354 | + Node<E> newRoot = root.pushFocus(focusStartIndex, focus); |
| 355 | + E[] newFocus = singleElementArray(t); |
| 356 | + return new RrbTree1<>(newFocus, size, newRoot, size + 1); |
| 357 | + } |
| 358 | + |
| 359 | + E[] newFocus = insertIntoArrayAt(t, focus, focus.length); |
| 360 | + return new RrbTree1<>(newFocus, focusStartIndex, root, size + 1); |
| 361 | + } |
340 | 362 |
|
341 | 363 | @SuppressWarnings("unchecked")
|
342 | 364 | @Override public boolean equals(Object other) {
|
@@ -385,27 +407,6 @@ private RrbTree1(E[] f, int fi, Node<E> r, int s) {
|
385 | 407 | return root.get(i);
|
386 | 408 | }
|
387 | 409 |
|
388 |
| - /** |
389 |
| - Adds an item at the end of this structure. This is the most efficient way to build an |
390 |
| - RRB Tree as it conforms to the Clojure PersistentVector and all of its optimizations. |
391 |
| - @param t the item to append |
392 |
| - @return a new RRB-Tree with the item appended. |
393 |
| - */ |
394 |
| - @Override public RrbTree1<E> append(E t) { |
395 |
| -// System.out.println("=== append(" + t + ") ==="); |
396 |
| - // If our focus isn't set up for appends or if it's full, insert it into the data structure |
397 |
| - // where it belongs. Then make a new focus |
398 |
| - if (((focusStartIndex < root.size()) && (focus.length > 0) ) || |
399 |
| - (focus.length >= STRICT_NODE_LENGTH) ) { |
400 |
| - Node<E> newRoot = root.pushFocus(focusStartIndex, focus); |
401 |
| - E[] newFocus = singleElementArray(t); |
402 |
| - return new RrbTree1<>(newFocus, size, newRoot, size + 1); |
403 |
| - } |
404 |
| - |
405 |
| - E[] newFocus = insertIntoArrayAt(t, focus, focus.length); |
406 |
| - return new RrbTree1<>(newFocus, focusStartIndex, root, size + 1); |
407 |
| - } |
408 |
| - |
409 | 410 | @Override public RrbTree1<E> immutable() { return this; }
|
410 | 411 |
|
411 | 412 | /**
|
@@ -445,6 +446,76 @@ public RrbTree1<E> insert(int idx, E element) {
|
445 | 446 | return new RrbTree1<>(newFocus, idx, newRoot, size + 1);
|
446 | 447 | }
|
447 | 448 |
|
| 449 | + private final class IdxNode { |
| 450 | + int idx = 0; |
| 451 | + final Node<E> node; |
| 452 | + IdxNode(Node<E> n) { node = n; } |
| 453 | + } |
| 454 | + |
| 455 | + private final class Iter implements UnmodSortedIterator<E> { |
| 456 | + // We want this iterator to walk the tree. You MUST |
| 457 | + private int childIndex = 0; |
| 458 | + private final Stack<IdxNode> stack = new Stack<>(); |
| 459 | + private Node<E> n; |
| 460 | + private Iter() { |
| 461 | + // TODO: Handle case where focus and/or root are null. |
| 462 | + // Push the focus so we don't have to ever check the index. |
| 463 | + Node<E> n = ((focus != null) && focus.length > 0) ? root.pushFocus(focusStartIndex, focus) |
| 464 | + : root; |
| 465 | + if (n instanceof Leaf) { |
| 466 | + stack.add(new IdxNode(n)); |
| 467 | + } else { |
| 468 | + // Descent to left-most bottom node. |
| 469 | + while (!(n instanceof Leaf)) { |
| 470 | + stack.add(new IdxNode(n)); |
| 471 | + n = n.firstChild(); |
| 472 | + } |
| 473 | + } |
| 474 | + } |
| 475 | + |
| 476 | + @Override public boolean hasNext() { return stack.peek() != null; } |
| 477 | + |
| 478 | + @Override public E next() { |
| 479 | + E ret = n.get(childIndex); |
| 480 | + childIndex = childIndex + 1; |
| 481 | + |
| 482 | + // Leaf node has been exhausted, find a new one. |
| 483 | + if (childIndex >= n.size()) { |
| 484 | + // Start the next leaf node at zero. |
| 485 | + childIndex = 0; |
| 486 | + |
| 487 | + // Get the immediate parent and increment it's child pointer. |
| 488 | + IdxNode parent = stack.peek(); |
| 489 | + parent.idx = parent.idx + 1; |
| 490 | + |
| 491 | + // Keep walking up the ancestors until one hasn't been exhausted (or we're done). |
| 492 | + while (parent.idx >= parent.node.size()) { |
| 493 | + stack.pop(); |
| 494 | + parent = stack.peek(); |
| 495 | + if (parent == null) { |
| 496 | + return ret; // This is the end of the tree - all done! |
| 497 | + } |
| 498 | + parent.idx = parent.idx + 1; |
| 499 | + } |
| 500 | + // TODO: We want the node at the index stored with the parent in the IdxNode. |
| 501 | + // Now, walk down to the first child. |
| 502 | + n = parent.node; |
| 503 | + while ( true ) { |
| 504 | + n = n.firstChild(); |
| 505 | + if (n instanceof Leaf) { |
| 506 | + break; |
| 507 | + } |
| 508 | + stack.add(new IdxNode(n)); |
| 509 | + } |
| 510 | + } |
| 511 | + return ret; |
| 512 | + } |
| 513 | + } |
| 514 | + |
| 515 | + @Override public UnmodSortedIterator<E> iterator() { |
| 516 | + return new Iter(); |
| 517 | + } |
| 518 | + |
448 | 519 | @Override public MutableList<E> mutable() {
|
449 | 520 | // TODO: Implement or change interfaces.
|
450 | 521 | throw new UnsupportedOperationException("No mutable version (yet)");
|
@@ -478,6 +549,8 @@ public RrbTree1<E> replace(int index, E item) {
|
478 | 549 | return new RrbTree1<>(focus, focusStartIndex, root.replace(index, item), size);
|
479 | 550 | }
|
480 | 551 |
|
| 552 | + @Override public int size() { return size; } |
| 553 | + |
481 | 554 | /**
|
482 | 555 | Divides this RRB-Tree such that every index less-than the given index ends up in the left-hand tree
|
483 | 556 | and the indexed item and all subsequent ones end up in the right-hand tree.
|
@@ -547,12 +620,16 @@ private interface Node<T> extends Indented {
|
547 | 620 | // So this needs to only be implemented on Relaxed for now.
|
548 | 621 | // Relaxed<T>[] split();
|
549 | 622 |
|
| 623 | + int numChildren(); |
| 624 | + |
550 | 625 | // Because we want to append/insert into the focus as much as possible, we will treat
|
551 | 626 | // the insert or append of a single item as a degenerate case. Instead, the primary way
|
552 | 627 | // to add to the internal data structure will be to push the entire focus array into it
|
553 | 628 | Node<T> pushFocus(int index, T[] oldFocus);
|
554 | 629 |
|
555 | 630 | Node<T> replace(int idx, T t);
|
| 631 | + |
| 632 | + Node<T> firstChild(); |
556 | 633 | }
|
557 | 634 |
|
558 | 635 | private static class SplitNode<T> extends Tuple4<Node<T>,T[],Node<T>,T[]> implements Indented {
|
@@ -584,6 +661,11 @@ private static class Leaf<T> implements Node<T> {
|
584 | 661 | // are strict.
|
585 | 662 | // boolean isStrict;
|
586 | 663 | Leaf(T[] ts) { items = ts; }
|
| 664 | + |
| 665 | + @Override public Node<T> firstChild() { |
| 666 | + throw new UnsupportedOperationException("Don't call this on a leaf"); |
| 667 | + } |
| 668 | + |
587 | 669 | @Override public T get(int i) { return items[i]; }
|
588 | 670 | @Override public int size() { return items.length; }
|
589 | 671 | // If we want to add one more to an existing leaf node, it must already be part of a
|
@@ -636,6 +718,8 @@ private Leaf<T>[] spliceAndSplit(T[] oldFocus, int splitIndex) {
|
636 | 718 | return new Leaf[] {new Leaf<>(split._1()), new Leaf<>(split._2())};
|
637 | 719 | }
|
638 | 720 |
|
| 721 | + @Override public int numChildren() { return size(); } |
| 722 | + |
639 | 723 | // I think this can only be called when the root node is a leaf.
|
640 | 724 | @SuppressWarnings("unchecked")
|
641 | 725 | @Override public Node<T> pushFocus(int index, T[] oldFocus) {
|
@@ -713,6 +797,8 @@ private static class Strict<T> implements Node<T> {
|
713 | 797 | // System.out.println(" new Strict" + shift + arrayString(ns));
|
714 | 798 | }
|
715 | 799 |
|
| 800 | + @Override public Node<T> firstChild() { return nodes[0]; } |
| 801 | + |
716 | 802 | /**
|
717 | 803 | Returns the high bits which we use to index into our array. This is the simplicity (and
|
718 | 804 | speed) of Strict indexing. When everything works, this can be inlined for performance.
|
@@ -904,6 +990,8 @@ Relaxed<T> relax() {
|
904 | 990 | return new Relaxed<>(newCumSizes, nodes);
|
905 | 991 | }
|
906 | 992 |
|
| 993 | + @Override public int numChildren() { return nodes.length; } |
| 994 | + |
907 | 995 | @SuppressWarnings("unchecked")
|
908 | 996 | @Override
|
909 | 997 | public Node<T> pushFocus(int index, T[] oldFocus) {
|
@@ -1129,6 +1217,8 @@ public static <T> Node<T> fixRight(Node<T>[] origNodes, Node<T> splitRight, int
|
1129 | 1217 | }
|
1130 | 1218 | }
|
1131 | 1219 |
|
| 1220 | + @Override public Node<T> firstChild() { return nodes[0]; } |
| 1221 | + |
1132 | 1222 | @Override public int size() {
|
1133 | 1223 | return cumulativeSizes[cumulativeSizes.length - 1];
|
1134 | 1224 | }
|
@@ -1396,6 +1486,8 @@ public SplitNode<T> splitAt(int splitIndex) {
|
1396 | 1486 | return ret;
|
1397 | 1487 | }
|
1398 | 1488 |
|
| 1489 | + @Override public int numChildren() { return nodes.length; } |
| 1490 | + |
1399 | 1491 | @SuppressWarnings("unchecked")
|
1400 | 1492 | @Override public Node<T> pushFocus(int index, T[] oldFocus) {
|
1401 | 1493 | // TODO: Review this entire method.
|
|
0 commit comments