Finger Trees

Finger Trees are a efficient, general purpose immutable data structures that use recursive type definitions to enforce the valid state of the tree. The “fingers” of the tree structure forms that vary between one and four entries, which allows some critical slack in the data structure and avoids a lot of expensive updates.

This implementation is updated to the 2.6.1 compiler.

package finger;
 
/** Implements Paterson/Hinze Finger Trees -- a general purpose functional
data structure.  Finger Trees support fast access to the ends of the sequence
and O(log N) splits, seeks, etc...see their pages for more details.
 
Written by Ross Judson
 
This work is in the public domain. You may use it for any purpose.
 
Please send comments to ross at (s)oletta.com.
 
If you study the code you'll find a fair number of Scala programming 
techniques covered, so this serves as reference code.  I make no claim
that this is the <i>best</i> way to use Scala, though!
 
This is a relatively literal implementation at this time --
here and there I've used polymorphism instead of pattern matching, with the 
idea being that a method call in the Java VM is usually pretty fast.
 
The append algorithm is slightly modified to <i>roll</i> a shallow Deep
object to the left, which results in a more balanced tree if creation
is by repeated append.
 
TODO:
 
- sort out the covariant vs. singleton empty object issue
- foldRight
- measure and determine if any additional implementations of Seq methods
  would help 
- see if there's any way to reduce the size of the .class files
- determine if Node2 and Node3 are similar enough to Two and Three that they
  should be merged or have a common base class.
- figure out how to add laziness and zipper effects
 
 
Making this better
 
- get rid of node and digit...just use the tuple classes.
- have a trait Sizer, where sizer can be extended to include
  other things, so carrying is possible (like with the Haskell version)
- One[A] becomes (S >: Sizer, A)
- Two[A] becomes (S >: Sizer, A, A), and so forth
- Can we carry along some notion of dimension, so we don't need to 
  do any nasty instanceof testing or anything like that? Distance can either
  be carried along with function calls, or it can be embedded in the structure.
  It's sort of implicit during traversal -- each time we recurse into Deep, we
  increment the dimension by one.
*/
  
object Finger {
 
  import collection.mutable.{Buffer, ArrayBuffer};
  import xml.{Elem, TopScope, Text, UnprefixedAttribute, Null};
  
  private [finger] val emptyFTSingleton = Empty[Nothing]();
  private [finger] def empty[A] = emptyFTSingleton.asInstanceOf[Empty[A]];
  private val emptySingleton: FingerSeq[Nothing] = new FingerSeq[Nothing](emptyFTSingleton);
  
  /** Builds a finger tree from a single element. */
  def singleton[A](a: A) = new FingerSeq[A](Single(a));
  
  /** Returns an empty finger tree for items of type A. */
  def emptySeq[A]() = emptySingleton.asInstanceOf[FingerSeq[A]];
 
  /** Constructs a finger tree from a sequence of items. */
  def build[A](a: A*): FingerSeq[A] = new FingerSeq(buildFrom(a.length, a.elements))
  
  /** Efficiently construct a finger tree from the elements provided
  by the given iterator. The length must be provided as well, and
  should exactly match the number of items in the iterator. Only
  len items will be taken from the iterator. */
  def buildFrom[A](len: Int, a: Iterator[A]): FingerTree[A] = {
    def one = One(a.next)
    def two = Two(a.next, a.next)
    def three = Three(a.next, a.next, a.next)
    def four = Four(a.next, a.next, a.next, a.next)
    len match {
      case 0 => emptyFTSingleton.asInstanceOf[FingerTree[A]]
      case 1 => Single(a.next)
      case 2 => deep(one, empty[Node[A]], one)
      case 3 => deep(two, empty[Node[A]], one)
      case 4 => deep(two, empty[Node[A]], two)
      case 5 => deep(three, empty[Node[A]], two)
      case 6 => deep(three, empty[Node[A]], three)
      case 7 => deep(four, empty[Node[A]], three)
      case 8 => deep(four, empty[Node[A]], four)
      case _ => buildFrom(8, a) add buildFrom(len - 8, a)
    }
  }
 
  /** Assembles a finger tree from a sequence of items. */
  def apply[A](a: A*) = build(a:_*);
  
  /** Determines the size of the given element. */
  private [finger] def sizeOf(a: Any) = a match {
    case sz: Sized => sz.size;
    case _ => 1
  }
 
  /** A type describing the placement of something, usually
  returned as a result of a find operation. */
  type Place[a] = (int,a); 
  
  def Place[a](x: int, y: a) = (x,y);
 
  private [finger] def deep[A](pr: Digit[A], m: FingerTree[Node[A]], sf: Digit[A]) = 
    Deep(pr.size + m.size + sf.size, pr, m, sf);
  
  private [finger] def node2[A](a: A, b: A) = new Node2(sizeOf(a) + sizeOf(b), a, b);
  private [finger] def node3[A](a: A, b: A, c: A) = new Node3(sizeOf(a) + sizeOf(b) + sizeOf(c), a, b, c);
  
  private [finger] def streamOf[A](a: A*) = _streamOn(a, 0)
  private [finger] def streamOn[A](s: Seq[A]) = _streamOn(s, 0)
  private [finger] def _streamOn[A](s: Seq[A], i: Int): Stream[A] = s.isDefinedAt(i) match {
    case true => Stream.cons(s(i), _streamOn(s, i+1))
    case false => Stream.empty
  }
  private [finger] def streamOne[A](a: A) = Stream.cons(a, Stream.empty)
  
  private [finger] final val SSERROR = "Cannot create subsequence";
  
    
  /* 
  def joinIterable[A](pieces: Iterable[A]*): Iterator[A] = pieces.length match {
    case 0 => Iterator.empty;
    case 1 => pieces(0).elements;
    case _ => new Iterator[A] {
      val pieceIter = pieces.elements;
      var iter = pieceIter.next.elements;
      def hasNext: boolean = iter.hasNext || (pieceIter.hasNext && { iter = pieceIter.next.elements; hasNext });
      def next = iter.next;
    }
  }    
 
  def convertToXML(x: Any*): scala.xml.NodeSeq = x.toArray.map(_convertToXML)
  private def _convertToXML(x: Any): xml.Node = x match {
    case fs: FingerSeq[Nothing] => fs.toXML
    case ft: FingerTree[Nothing] => ft.toXML
    case nd: Node[Nothing] => nd.toXML
    case d: Digit[Nothing] => d.toXML
    case _ => xml.Text(x.toString())
  }
*/
  
}
 
import Finger._;
import xml.Elem;
 
class FingerSeq[A](val xs: FingerTree[A]) extends Seq[A] {
  
  //
  // Implementations of Seq[A] methods
  //
  override def stringPrefix = "FingerSeq"; 
  
  /** Return the length of this Finger Sequence. */
  def length = xs.size;
  
  /** Return an iterator over the elements of this Finger Sequence. */
  def elements: Iterator[A] = xs.elements;
  
  /** Concatenate this sequence with another.  If the other is a finger sequence,
  special processing will make the operation more efficient. */
  override def concat[B >: A](that:Iterable[B]) = that match {
    case f: FingerSeq[B] => this ++ f
    case _ => super.concat(that)
  }
    
  /** Concatenates two sequences efficiently. 
    TODO: This is clearly cheating, but I don't want to modify the entire FingerTree area just yet.
    */
  override def ++ [B >: A](that: Iterable[B]) = that match {
    case f: FingerSeq[B] => new FingerSeq[A](xs add f.asInstanceOf[FingerSeq[A]].xs)
    case _ => super.++(that)
  }
  
  def ++ [B >: A](that: FingerSeq[B]): FingerSeq[A] = 
    new FingerSeq[A](xs add that.asInstanceOf[FingerSeq[A]].xs)
  
  /** Returns a subsequence of this finger sequence.  The subsequence will
  share as much structure as possible.*/
  override def slice(from: Int, until: Int): FingerSeq[A] = {
    if (from == 0) {
      if (until < length)
        splitAt(until)._1
      else if (until == length)
        this
      else
        error(SSERROR)
    } else if (from >= length) {
      emptySeq[A]()
    } else if (from > 0) {
      val s = splitAt(from)._2
      val len = until - from
      if (len < s.length)
        s.splitAt(len)._1
      else if (len > s.length)
        error(SSERROR)
      else
        s
    } else {
      error(SSERROR)
    }
  }
  
  /** Determines if the predicate holds true for all elements in this sequence. */
  override def forall(p: A => Boolean) = xs forall p
  
  /** Finds the first element for which the predicate holds true. */
  override def find(p: A => Boolean): Option[A] = xs.find(p) match {
    case Some(x) => Some(x)
    case _ => None
  }
  
   /** Combines the elements of this sequence together using the binary
   *  operator op, from left to right, and starting with
   *  the value z. 
   *  @return op(... (op(op(z,a0),a1) ...), an) if the list
   *  is FingerSeq(a0, a1, ..., an).
   */
  override def foldLeft[B](z: B)(op: (B, A) => B): B = (z /: xs)(op);
  
  // Methods that should probably exist if Scala had an immutable list/queue trait
  /** Push the element on the end of this sequence, returning the new sequence. */
  def push(a: A) = append(a);
  
  /** Returns the last element in the sequence, throwing an error if the sequence is empty. */
  def top = last;
  
  /** Returns the first element in the sequence, throwing an error if the sequence is empty. */
  def first = xs.first;
  
  /** Returns the last element in the sequence, throwing an error if the sequence is empty. */
  override def last = xs.last;
 
  /** Returns a tuple consisting of the first element in this sequence together with a new
  sequence minus the first element. */    
  def dequeue = xs.viewLTree match {
    case Some((a,t)) => (a,new FingerSeq(t))
    case _ => error("empty")
  }
  
  /** Returns a new sequence with the specified element appended to it. */
  def enqueue(a: A) = append(a);
  
  /** Returns the first element in the sequence, throwing an error if the sequence is empty. */
  def front = first;
  
  /** Returns a new sequence with the element in the given position altered to x. */
  def update(i: int, x: A) = adjust(i, x);
  
  // Finger Sequence external methods.
 
  /** Creates a stream on the elements in this sequence. */    
  def stream: Stream[A] = xs.stream;
  
  /** Creates a stream on the elements in this sequence, starting from a specified
  position.  NOTE: Not functional yet. */
  def streamFrom(i: int): Stream[A] = xs.streamFrom(-i)._2;
  
  /** Returns a new sequence with the element at the given position altered. */
  def adjust(i: int, x: A) = new FingerSeq(xs.adjust((pos, item) => item, -i));
 
  /** Splits this sequence at the given position.  The returned sequences are balanced
  and contain as much shared structure from this sequence as is possible. */    
  def splitAt(i: int): (FingerSeq[A], FingerSeq[A]) = {
    if (length == 0)
      (this, this)
    else if (length <= i)
      (this, emptySeq[A]())
    else {
      val ftpair = xs.split(-i, true, true);
      (new FingerSeq(ftpair.left), new FingerSeq(ftpair.right \+ ftpair.pivot))
    }
  }
  
  /** Appends the specified item to this sequence, returning the new sequence
      that results. */
  def append(a: A) = new FingerSeq(xs append a);
  
  /** Prepends the specified item to this sequence, returning the new sequence
  that results. */
  def prepend(a: A) = new FingerSeq(xs \+ a);
  
  /** Converts the internal structure of this sequence to XML nodes, for easy
  examination. */
  // def toXML = <FingerSeq size={length.toString()}>{xs.toXML}</FingerSeq> ;
  
  /** Returns the element at the specified position, throwing an error if
  the position is out of bounds. */
  def apply(i: int) =
    if (i >= 0 && i < length) 
      xs.lookup(-i)._2;
    else 
      error("Index out of bounds") ;
 
  /** Returns a new sequence consisting of this one with the given element appended
  to the end. */
  def +(a: A) = append(a);
  
  /** Returns a string showing the internal structure of this sequence. */
  def structure = xs.toString();
  
}
 
abstract sealed private[finger] class Sized {
  def size: int;
}
 
abstract sealed private[finger] class FingerTree[A] extends Sized {
  
    type FTSplit = Split[FingerTree[A], A]
    type NodeTree = FingerTree[Node[A]]
    type ADigit = Digit[A]
    type ATree = FingerTree[A]
    type LeftView = Option[(A, FingerTree[A])]
    type RightView = Option[(FingerTree[A], A)]
                            
    def fmap[B <: Sized](func: A => B): FingerTree[B];
 
    def find(p: A => boolean): Option[A] = ffind(a => if (p(a)) Some(a) else None);
    def ffind[B](p: A => Option[B]): Option[B];
    def foldLeft[B](z: B)(op: (B, A) => B): B;
    final def /:[B](z: B)(op: (B, A) => B) = foldLeft(z)(op);
    def forall(p: A => Boolean): Boolean;      
    def prepend(x: A): ATree;
    final def \+(x: A) = prepend(x);
    def append(x: A): ATree;
    final def +(x: A) = append(x);
    // def toXML: Elem;
    def lookup(i: int): Place[A];
    def adjust(f: (int, A) => A, i: int): ATree;
    def elements: Iterator[A];
    def stream: Stream[A];
    def streamFrom(i: int): Place[Stream[A]];
    def split(i: int, left: boolean, right: boolean): FTSplit;
    def first: A;
    def last: A;
    
    def viewLTree: LeftView;
    def viewRTree: RightView;
    
    // def reverse: ATree;
    
    // def appendTree(x: ATree) = appendTree0(x);
      
    def add(right: ATree): ATree;
    def add1(n: A, right: ATree): ATree;
    def add2(n1: A, n2: A, right: ATree): ATree;
    def add3(n1: A, n2: A, n3: A, right: ATree): ATree;
    def add4(n1: A, n2: A, n3: A, n4: A, right: ATree): ATree;
    
    def addDigits0(m1: NodeTree, dig1: ADigit, dig2: ADigit, m2: NodeTree): NodeTree = dig1 match {
      case One(a) => dig2 match {
        case One(b) => m1.add1( node2(a, b), m2)
        case Two(b,c) => m1.add1( node3(a,b,c), m2)
        case Three(b,c,d) => m1.add2( node2(a,b), node2(c,d),m2)
        case Four(b,c,d,e) => m1.add2( node3(a,b,c), node2(d,e), m2)
      }
      case Two(a,b) => dig2 match {
        case One(c) => m1.add1( node3(a,b,c), m2)
        case Two(c,d) => m1.add2( node2(a,b), node2(c,d), m2)
        case Three(c,d,e) => m1.add2( node3(a,b,c), node2(d,e), m2)
        case Four(c,d,e,f) => m1.add2( node3(a,b,c), node3(d,e,f), m2)
      }
      case Three(a,b,c) => dig2 match {
        case One(d) => m1.add2( node2(a,b), node2(c,d), m2)
        case Two(d,e) => m1.add2( node3(a,b,c), node2(d,e), m2)
        case Three(d,e,f) => m1.add2( node3(a,b,c), node3(d,e,f), m2)
        case Four(d,e,f,g) => m1.add3( node3(a,b,c), node2(d,e), node2(f,g), m2)
      }
      case Four(a,b,c,d) => dig2 match {
        case One(e) => m1.add2( node3(a,b,c), node2(d,e), m2)
        case Two(e,f) => m1.add2( node3(a,b,c), node3(d,e,f), m2)
        case Three(e,f,g) => m1.add3( node3(a,b,c), node2(d,e), node2(f,g), m2)
        case Four(e,f,g,h) => m1.add3( node3(a,b,c), node3(d,e,f), node2(g,h), m2)
      }
    }
    
    def addDigits1(m1: NodeTree, d1: ADigit, x: A, d2: ADigit, m2: NodeTree): NodeTree = d1 match {
      case One(a) => d2 match {
        case One(b) => m1.add1(node3(a,x,b), m2)
        case Two(b,c) => m1.add2(node2(a,x), node2(b,c), m2)
        case Three(b,c,d) => m1.add2(node3(a,x,b), node2(c,d), m2)
        case Four(b,c,d,e) => m1.add2(node3(a,x,b), node3(c,d,e), m2)
      }
      case Two(a,b) => d2 match {
        case One(c) => m1.add2(node2(a,b), node2(x,c), m2)
        case Two(c,d) => m1.add2(node3(a,b,x), node2(c,d), m2)
        case Three(c,d,e) => m1.add2(node3(a,b,x), node3(c,d,e), m2)
        case Four(c,d,e,f) => m1.add3(node3(a,b,x), node2(c,d), node2(e,f), m2)
      }
      case Three(a,b,c) => d2 match {
        case One(d) => m1.add2(node3(a,b,c), node2(x,d), m2)
        case Two(d,e) => m1.add2(node3(a,b,c), node3(x,d,e), m2)
        case Three(d,e,f) => m1.add3(node3(a,b,c), node2(x,d), node2(e,f), m2)
        case Four(d,e,f,g) => m1.add3(node3(a,b,c), node3(x,d,e), node2(f,g), m2)
      }
      case Four(a,b,c,d) => d2 match {
        case One(e) => m1.add2(node3(a,b,c), node3(d,x,e), m2)
        case Two(e,f) => m1.add3(node3(a,b,c), node2(d,x), node2(e,f), m2)
        case Three(e,f,g) => m1.add3(node3(a,b,c), node3(d,x,e), node2(f,g), m2)
        case Four(e,f,g,h) => m1.add3(node3(a,b,c), node3(d,x,e), node3(f,g,h), m2)
      }
    }
    
    def addDigits2(m1: NodeTree, d1: ADigit, x: A, y: A, d2: ADigit, m2: NodeTree): NodeTree = d1 match {
      case One(a) => d2 match {
        case One(b) => m1.add2(node2(a,x), node2(y,b), m2)
        case Two(b,c) => m1.add2(node3(a,x,y), node2(b,c), m2)
        case Three(b,c,d) => m1.add2(node3(a,x,y), node3(b,c,d), m2)
        case Four(b,c,d,e) => m1.add3(node3(a,x,y), node2(b,c), node2(d,e), m2)
      }
      case Two(a,b) => d2 match {
        case One(c) => m1.add2(node3(a,b,x), node2(y,c), m2)
        case Two(c,d) => m1.add2(node3(a,b,x), node3(y,c,d), m2)
        case Three(c,d,e) => m1.add3(node3(a,b,x), node2(y,c), node2(d,e), m2)
        case Four(c,d,e,f) => m1.add3(node3(a,b,x), node3(y,c,d), node2(e,f), m2)
      }
      case Three(a,b,c) => d2 match {
        case One(d) => m1.add2(node3(a,b,c), node3(x,y,d), m2)
        case Two(d,e) => m1.add3(node3(a,b,c), node2(x,y), node2(d,e), m2)
        case Three(d,e,f) => m1.add3(node3(a,b,c), node3(x,y,d), node2(e,f), m2)
        case Four(d,e,f,g) => m1.add3(node3(a,b,c), node3(x,y,d), node3(e,f,g), m2)
      }
      case Four(a,b,c,d) => d2 match {
        case One(e) => m1.add3(node3(a,b,c), node2(d,x), node2(y,e), m2)
        case Two(e,f) => m1.add3(node3(a,b,c), node3(d,x,y), node2(e,f), m2)
        case Three(e,f,g) => m1.add3(node3(a,b,c), node3(d,x,y), node3(e,f,g), m2)
        case Four(e,f,g,h) => m1.add4(node3(a,b,c), node3(d,x,y), node2(e,f), node2(g,h), m2)
      }
    }
 
    def addDigits3(m1: NodeTree, d1: ADigit, x: A, y: A, z: A, d2: ADigit, m2: NodeTree): NodeTree = d1 match {
      case One(a) => d2 match {
        case One(b) => m1.add2(node3(a,x,y), node2(z,b), m2)
        case Two(b,c) => m1.add2(node3(a,x,y), node3(z,b,c), m2)
        case Three(b,c,d) => m1.add3(node3(a,x,y), node2(z,b), node2(c,d), m2)
        case Four(b,c,d,e) => m1.add3(node3(a,x,y), node3(z,b,c), node2(d,e), m2)
      }
      case Two(a,b) => d2 match {
        case One(c) => m1.add2(node3(a,b,x), node3(y,z,c), m2)
        case Two(c,d) => m1.add3(node3(a,b,x), node2(y,z), node2(c,d), m2)
        case Three(c,d,e) => m1.add3(node3(a,b,x), node3(y,z,c), node2(d,e), m2)
        case Four(c,d,e,f) => m1.add3(node3(a,b,x), node3(y,z,c), node3(d,e,f),m2)
      }
      case Three(a,b,c) => d2 match {
        case One(d) => m1.add3(node3(a,b,c), node2(x,y), node2(z,d), m2)
        case Two(d,e) => m1.add3(node3(a,b,c), node3(x,y,z), node2(d,e), m2)
        case Three(d,e,f) => m1.add3(node3(a,b,c), node3(x,y,z), node3(d,e,f), m2)
        case Four(d,e,f,g) => m1.add4(node3(a,b,c), node3(x,y,z), node2(d,e), node2(f,g), m2)
      }
      case Four(a,b,c,d) => d2 match {
        case One(e) => m1.add3(node3(a,b,c), node3(d,x,y), node2(z,e), m2)
        case Two(e,f) => m1.add3(node3(a,b,c), node3(d,x,y), node3(z,e,f), m2)
        case Three(e,f,g) => m1.add4(node3(a,b,c), node3(d,x,y), node2(z,e),node2(f,g), m2)
        case Four(e,f,g,h) => m1.add4(node3(a,b,c), node3(d,x,y), node3(z,e,f), node2(g,h), m2)
      }
    }
    
    def addDigits4(m1: NodeTree, d1: ADigit, x: A, y: A, z: A, w: A, d2: ADigit, m2: NodeTree): NodeTree = d1 match {
      case One(a) => d2 match {
        case One(b) => m1.add2(node3(a,x,y), node3(z,w,b), m2)
        case Two(b,c) => m1.add3(node3(a,x,y), node2(z,w), node2(b,c), m2)
        case Three(b,c,d) => m1.add3(node3(a,x,y), node3(z,w,b), node2(c,d), m2)
        case Four(b,c,d,e) => m1.add3(node3(a,x,y), node3(z,w,b), node3(c,d,e), m2)
      }
      case Two(a,b) => d2 match {
        case One(c) => m1.add3(node3(a,b,x), node2(y,z), node2(w,c), m2)
        case Two(c,d) => m1.add3(node3(a,b,x), node3(y,z,w), node2(c,d), m2)
        case Three(c,d,e) => m1.add3(node3(a,b,x), node3(y,z,w), node3(c,d,e), m2)
        case Four(c,d,e,f) => m1.add4(node3(a,b,x), node3(y,z,w), node2(c,d), node2(e,f),m2)
      }
      case Three(a,b,c) => d2 match {
        case One(d) => m1.add3(node3(a,b,c), node3(x,y,z), node2(w,d), m2)
        case Two(d,e) => m1.add3(node3(a,b,c), node3(x,y,z), node3(w,d,e), m2)
        case Three(d,e,f) => m1.add4(node3(a,b,c), node3(x,y,z), node2(w,d),node2(e,f), m2)
        case Four(d,e,f,g) => m1.add4(node3(a,b,c), node3(x,y,z), node3(w,d,e), node2(f,g), m2)
      }
      case Four(a,b,c,d) => d2 match {
        case One(e) => m1.add3(node3(a,b,c), node3(d,x,y), node3(z,w,e), m2)
        case Two(e,f) => m1.add4(node3(a,b,c), node3(d,x,y), node2(z,w), node2(e,f), m2)
        case Three(e,f,g) => m1.add4(node3(a,b,c), node3(d,x,y), node3(z,w,e),node2(f,g), m2)
        case Four(e,f,g,h) => m1.add4(node3(a,b,c), node3(d,x,y), node3(z,w,e), node3(f,g,h), m2)
      }
    }
}
 
final private[finger] case class Empty[A]() extends FingerTree[A] {
  def size = 0;
  def fmap[B <: Sized](func: A => B) = Empty[B]();
  def ffind[B](p: A => Option[B]): Option[B] = None;
  def foldLeft[B](z: B)(op: (B, A) => B) = z;
  def forall(p: A => Boolean) = true;     
  def apply(i: int): Nothing = error("cannot apply empty");
  def prepend(x: A) = Single(x);
  def append(x: A) = Single(x);
  // def toXML = <Empty/> ;
  def lookup(i: int) = error("Index out of bounds");
  def adjust(f: (int, A) => A, i: int) = error("Index out of bounds");
  def elements = Iterator.empty;
  def stream: Stream[A] = Stream.empty;
  def streamFrom(i: int) = error("Index out of bounds");
  def split(i: int, left: boolean, right: boolean) = error("Cannot split empty");
  def first: A = error("Empty");
  def last: A = first;
  
  def viewLTree = None;
  def viewRTree = None;
  
  def add(right: ATree): ATree = right;
  def add1(n: A, right: ATree): ATree = right \+ n;
  def add2(n1: A, n2: A, right: ATree): ATree = right \+ n2 \+ n1;
  def add3(n1: A, n2: A, n3: A, right: ATree): ATree = right \+ n3 \+ n2 \+ n1;
  def add4(n1: A, n2: A, n3: A, n4: A, right: ATree): ATree = right \+ n4 \+ n3 \+ n2 \+ n1;
}
 
final private[finger] case class Single[A](a: A) extends FingerTree[A] {
  def elements = Iterator.single(a);
  val size = sizeOf(a);
  def fmap[B <: Sized](func: A => B) = Single(func(a));
  def ffind[B](p: A => Option[B]): Option[B] = p(a);
  def foldLeft[B](z: B)(op: (B, A) => B) = op(z, a);
  def forall(p: A => Boolean) = p(a);     
  
  def apply(i: int) = a;
  def prepend(x: A) = deep(One(x), Empty[Node[A]](), One(a));
  def append(x: A) = deep(One(a), Empty[Node[A]](), One(x));
  // def toXML = <Single>{convertToXML(a)}</Single>  ;
  def lookup(i: int) = Place(i, a);
  def adjust(f: (int, A) => A, i: int) = Single(f(i, a));  
  def streamFrom(i: int) = Place(i, stream);
  def split(i: int, left: boolean, right: boolean): FTSplit = new Split(Empty[A](), a, Empty[A]());
  
  def stream: Stream[A] = streamOne(a);
    
  def first: A = a;
  def last: A = a;
  
  def viewLTree = Some((a, Empty[A]()));
  def viewRTree = Some((Empty[A](), a)); 
  
  def reverse: ATree = this;
  
  def add(right: ATree) = right match {
    case Empty() => this
    case _ => right \+ a
  }
  def add1(n: A, right: ATree): ATree = right \+ n \+ a;
  def add2(n1: A, n2: A, right: ATree): ATree = right \+ n2 \+ n1 \+ a;
  def add3(n1: A, n2: A, n3: A, right: ATree): ATree = 
    right prepend n3 prepend n2 prepend n1 prepend a;
  def add4(n1: A, n2: A, n3: A, n4: A, right: ATree): ATree = 
    right \+ n4 \+ n3 \+ n2 \+ n1 \+ a;
}
 
final private[finger] case class Deep[A](size: int, pr: Digit[A], m: FingerTree[Node[A]], sf: Digit[A]) extends FingerTree[A] {
  
  def elements = stream.elements;
  def stream: Stream[A] = pr.stream.append(m.stream.flatMap(na => na.stream).append(sf.stream));
  def fmap[B <: Sized](func: A => B) = 
    Deep(size, pr fmap func, m fmap (f => f fmap func), sf fmap func);
  def forall(p: A => Boolean) = 
    pr.forall(p) && sf.forall(p) && m.forall(na => na forall p);
  def ffind[B](p: A => Option[B]): Option[B] = 
    pr.ffind(p) match {
      case None => m.ffind(na => na ffind p) match {
        case None => sf ffind p
        case s: Some[B] => s
      }
      case s: Some[B] => s
    };
    
  def foldLeft[B](z: B)(op: (B, A) => B) = 
    ((((z/:pr)(op)/:m)((b,na)=>(b/:na)(op)))/:sf)(op);
    
  def first: A = pr.first;
  def last: A = sf.last;
    
  def viewLTree = pr match {
    case One(a) =>
      Some((a, m.viewLTree match {
        case None => sf.toTree
        case Some((b,m)) => Deep(size - sizeOf(a), b.toDigit, m, sf)
      }))
    case Two(a,b) => Some((a, Deep(size - sizeOf(a), One(b), m, sf)))
    case Three(a,b,c) => Some((a, Deep(size - sizeOf(a), Two(b,c), m, sf)))
    case Four(a,b,c,d) => Some((a, Deep(size - sizeOf(a), Three(b,c,d), m, sf)))
  }
  def viewRTree = sf match {
    case One(z) =>
      Some((m.viewRTree match {
        case None => pr.toTree
        case Some((m,y)) => Deep(size - sizeOf(z), pr, m, y.toDigit)  
      }, z))
    case Two(y,z) => Some((Deep(size - sizeOf(z), pr, m, One(y)), z))
    case Three(x,y,z) => Some((Deep(size - sizeOf(z), pr, m, Two(x,y)), z))
    case Four(w,x,y,z) => Some((Deep(size - sizeOf(z), pr, m, Three(w,x,y)), z))
  }
  
  def prepend(a: A) = pr match {
    case Four(b,c,d,e) =>
      Deep(sizeOf(a) + size, Two(a,b), m \+ node3(c,d,e),sf)
    case Three(b,c,d) =>
      Deep(sizeOf(a) + size, Four(a,b,c,d), m, sf)
    case Two(b,c) =>
      Deep(sizeOf(a) + size, Three(a,b,c), m, sf)
    case One(b) =>
      Deep(sizeOf(a) + size, Two(a,b), m, sf)
  }
  def append(x: A) = this match {
    case Deep(_, One(q), Empty(), Four(a,b,c,d)) =>
      Deep[A](sizeOf(x) + size, Three(q,a,b), Empty(), Three(c,d,x))
    case Deep(_, One(q), Single(Node3(_, a,b,c)), Four(d,e,f,g)) =>
      Deep[A](sizeOf(x) + size, Three(q,a,b), Single(node3(c,d,e)), Three(f,g,x))
    case _ => sf match {
      case Four(a,b,c,d) =>
        Deep(sizeOf(x) + size, pr, m.append(node3(a,b,c)), Two(d, x))
      case Three(a,b,c) =>
        Deep(sizeOf(x) + size, pr, m, Four(a,b,c,x))
      case Two(a,b) =>
        Deep(sizeOf(x) + size, pr, m, Three(a,b,x))
      case One(a) =>
        Deep(sizeOf(x) + size, pr, m, Two(a,x))
    }
  }
  // def toXML = <Deep size={v.toString()}>{List(pr.toXML, m.toXML, sf.toXML)}</Deep>  ;
  def split(i: int, left: boolean, right: boolean): FTSplit = {
    val vpr = i + pr.size;
    if (vpr > 0) {
      val ds = pr.split(i, left, right);
      new Split(ds.left match {
          case None => Empty[A]()
          case Some(d) => d.toTree },
        ds.pivot, deepL(ds.right, m, sf)) 
    } else {
      val vm = vpr + m.size;
      if (vm > 0) {
        val ts = m.split(vpr, left, right);
        val ts2 = ts.pivot.split(vpr + ts.left.size, left, right);
        new Split(deepR(pr, ts.left, ts2.left), ts2.pivot, deepL(ts2.right, ts.right, sf)) 
      } else {
        val rs = sf.split(vm, left, right);
        new Split(deepR(pr, m, rs.left), rs.pivot, rs.right match {
          case None => Empty[A]()
          case Some(d) => d.toTree})
      }
    }
  }
  
  def adjust(f: (int, A) => A, i: int) = {
    val vpr = i + pr.size;
    if (vpr > 0) {
      Deep(size, pr.adjust(f, i), m, sf)
    } else {
      val vm = vpr + m.size;
      if (vm > 0) {
        Deep(size, pr, m.adjust((ni, na) => na.adjust(f, ni), vpr), sf) 
      } else {
        Deep(size, pr, m, sf.adjust(f, vm))
      }
    }
  }
  def lookup(i: int): Place[A] = {
    // remember that i is negative
    val vpr = i + pr.size;
    if (vpr > 0) pr.lookup(i)
    else {
      val vm = vpr + m.size;
      if (vm > 0) {
        val mp = m.lookup(vpr);
        mp._2.lookup(mp._1);
      } else sf.lookup(vm)
    }
  }
  def streamFrom(i: int) = {
    // remember that i is negative!
    val vpr = i + pr.size;
    if (vpr > 0) pr.streamFrom(i)
    else {
      val vm = vpr + m.size;
      if (vm > 0) {
        val mp = m.streamFrom(vpr);
        mp._2.head.streamFrom(mp._1);
      } else sf.streamFrom(vm)
    }
  }
 
  def add(right: ATree) = right match {
    case Empty() => this
    case Single(x) => this+x
    case Deep(v2, pr2, m2, sf2) =>
      Deep(size+v2, pr, addDigits0(m, sf, pr2, m2), sf2)
  }
  
  def add1(n: A, right: ATree) = right match {
    case Empty() => this+n
    case Single(x) => this+n+x
    case Deep(v2, pr2, m2, sf2) =>
      Deep(size + v2 + sizeOf(n), pr, addDigits1(m, sf, n, pr2, m2), sf2)
  }
      
  def add2(n1: A, n2: A, right: ATree) = right match {
    case Empty() => this+n1+n2
    case Single(x) => this+n1+n2+x
    case Deep(v2, pr2, m2, sf2) =>
      Deep(v2 + sizeOf(n1) + sizeOf(n2) + size, pr, addDigits2(m, sf, n1, n2, pr2, m2), sf2) 
  }
      
   def add3(n1: A, n2: A, n3: A, right: ATree) = right match {
     case Empty() => this+n1+n2+n3
     case Single(x) => this+n1+n2+n3+x
     case Deep(v2, pr2, m2, sf2) =>
       Deep(v2 + sizeOf(n1) + sizeOf(n2) + sizeOf(n3) + size, 
         pr, addDigits3(m, sf, n1, n2, n3, pr2, m2), sf2)
   }
      
   def add4(n1: A, n2: A, n3: A, n4: A, right: ATree) = right match { 
     case Empty() => this+n1+n2+n3+n4
     case Single(x) => this+n1+n2+n3+n4+x
     case Deep(v2, pr2, m2, sf2) =>
      Deep(v2 + sizeOf(n1) + sizeOf(n2) + sizeOf(n3) + sizeOf(n4) + size, 
        pr, addDigits4(m, sf, n1, n2, n3, n4, pr2, m2), sf2)
  }
  
  def deepL(l: Option[ADigit], c: NodeTree, r: ADigit): ATree = l match {
    case None => c.viewLTree match {
      case None => sf.toTree
      case Some((a,m)) => deep(a.toDigit, m, sf)
    }
    case Some(x) => deep(x, c, r)
  }
  
  def deepR(l: ADigit, c: NodeTree, r: Option[ADigit]) = r match {
    case None => c.viewRTree match {
      case None => pr.toTree
      case Some((m,a)) => deep(pr, m, a.toDigit)
    }
    case Some(x) => deep(l, c, x)
  }
}
 
 
/*
final case class StreamSingleton[A](h: A) extends Stream[A] {
  import scala.compat.{StringBuilder => SB}
  override def isEmpty = false
  def head = h
  def tail = Stream.empty
  def printElems(buf: SB, prefix: String) = buf.append(prefix).append(h)
}
*/
  
final private[finger] class Split[T,A](val left: T, val pivot: A, val right: T);
 
abstract private[finger] sealed class Node[A] extends Sized {
  
  type Splitting = Split[Option[Digit[A]],A]
  
  val size: Int;
  val a, b: A;
  def stream: Stream[A];
  def forall(p: A => Boolean) = p(a) && p(b); 
  def fmap[B <: Sized](func: A => B): Node[B]; 
  def toDigit: Digit[A];
  // def toXML: Elem;
  def lookup(i: int): Place[A];
  def adjust(f: (int, A) => A, i: int): Node[A];
  def streamFrom(i: int): Place[Stream[A]];
  def split(i: int, left: boolean, right: boolean): Splitting;
  def ffind[B](p: A => Option[B]): Option[B] = p(a) match {
    case None => p(b)
    case x @ _ => x
  };
  def foldLeft[B](z: B)(op: (B, A) => B): B;
  final def /:[B](z: B)(op: (B, A) => B) = foldLeft(z)(op);
  //def reverse: Node[A];
}     
 
final private[finger] class Node2[A](val size: int, val a: A, val b: A) extends Node[A] {
  
  def stream = streamOf(a,b);
  def fmap[B <: Sized](func: A => B) = new Node2(size, func(a), func(b));
  def foldLeft[B](z: B)(op: (B, A) => B) = op(op(z,a),b);     
  def toDigit = Two(a,b);
  // def toXML = <Node2 size={v.toString()}>{ convertToXML(a,b) }</Node2> ;
  
  def split(i: int, left: boolean, right: boolean): Splitting = {
    val va = i + sizeOf(a);
    if (va > 0) 
      new Split(None, a, Some(One(b)))
    else 
      new Split(Some(One(a)), b, None)
  }
  def lookup(i: int) = {
    val va = i + sizeOf(a);
    if (va > 0) {
      Place(i, a)
    } else {
      Place(va, b)
    }
  }
  def adjust(f: (int, A) => A, i: int) = {
    val va = i + sizeOf(a);
    if (va > 0) 
      new Node2(size, f(i, a), b)
    else 
      new Node2(size, a, f(va, b))
  }
  def streamFrom(i: int) = {
    val va = i + sizeOf(a);
    if (va > 0) {
      Place(i, stream)
    } else {
      Place(va, streamOne(b))
    }
  }
}
  
final private[finger] case class Node3[A](size: int, a: A, b: A, c: A) extends Node[A] {
  def stream = streamOf(a,b,c);
  def fmap[B <: Sized](func: A => B) = Node3(size, func(a), func(b), func(c)<