More Scala coolness
The problem: given a java.util.Iterator<E> (which may be non-strict and infinite), create a new scala.collection.Seq[E] which fulfills the contract of Seq but does not violate the laziness of the underlying Iterator.
Scala is perfect for this - a combination of anonymous classes and closures, along with using implicits to perform the conversion automatically, allow us to use any Java iterator with all the rich Scala collection functionality we want.
implicit def iterator2LazySeq[E](coll: Iterator[E]): Seq[E] = new Seq[E] {
self =>
// use an indexed seq to memoize because most of our operations depend
// heavily on indexing
var memoizedSeq: IndexedSeq[E] = IndexedSeq()
// what's the position of the cursor?
var cursorIndex = -1
def length = throw new UnsupportedOperationException("Length not supported on LazySeqs")
def apply(i: Int): E = {
// fast forward, loading elements and memoizing them as we go
while (i >= memoizedSeq.length) {
cursorIndex = cursorIndex + 1;
memoizedSeq = memoizedSeq :+ coll.next
}
memoizedSeq(i)
}
// anonymous iterator class required by Seq
def iterator = new Iterator[E] {
// just keep an index, use it to index into self
var iteratorIndex = -1
def next: E = {
iteratorIndex += 1
self(iteratorIndex)
}
def hasNext = {
// we only need to check the underlying collection if we haven't
// already memoized the next element
if (iteratorIndex < cursorIndex)
true
else
coll.hasNext
}
}
}
If you find any bugs, please let me know!