aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/collections/CollectionStrawMan1.scala
blob: 211c8d7daaf99accb6db835617ee99381cdfc81b (plain) (tree)









































































































































































































































































































































                                                                                                        
package strawman.collections

import Predef.{augmentString => _, wrapString => _, _}
import scala.reflect.ClassTag
import collection.mutable.ListBuffer

/** A strawman architecture for new collections. It contains some
 *  example collection classes and methods with the intent to expose
 *  some key issues. It would be good to compare this to other
 *  implementations of the same functionality, to get an idea of the
 *  strengths and weaknesses of different collection architectures.
 *
 *  For a test file, see tests/run/CollectionTests.scala.
 */
object CollectionStrawMan1 {

  /* ------------ Base Traits -------------------------------- */

  /** Replaces TraversableOnce */
  trait CanIterate[+A] {
    def iterator: Iterator[A]
  }

  /** Iterator guaranteed to be usable multiple times */
  trait HasIterator[+A] extends CanIterate[A]

  /** Base trait for instances that can construct a collection from an iterator */
  trait FromIterator[+C[X] <: Iterable[X]] {
    def fromIterator[B](it: Iterator[B]): C[B]
  }

  /** Base trait for companion objects of collections */
  trait IterableFactory[+C[X] <: Iterable[X]] extends FromIterator[C] {
    def empty[X]: C[X] = fromIterator(Iterator.empty)
    def apply[A](xs: A*): C[A] = fromIterator(Iterator(xs: _*))
  }

  /** Base trait for generic collections */
  trait Iterable[+IA] extends HasIterator[IA] with FromIterator[Iterable] {
    def buildIterator: Iterator[IA] = iterator
  }

  /** Base trait for sequence collections */
  trait Seq[+AA] extends Iterable[AA] with FromIterator[Seq] {
    def apply(i: Int): AA
    def length: Int
  }

  /* ------------ Operations ----------------------------------- */

  /** Operations returning types unrelated to current collection */
  trait Ops[A] extends Any {
    def toIterator: Iterator[A]
    def foreach(f: A => Unit): Unit = toIterator.foreach(f)
    def foldLeft[B](z: B)(op: (B, A) => B): B = toIterator.foldLeft(z)(op)
    def foldRight[B](z: B)(op: (A, B) => B): B = toIterator.foldRight(z)(op)
    def indexWhere(p: A => Boolean): Int = toIterator.indexWhere(p)
    def head: A = toIterator.next
    def view: View[A] = new View(toIterator)
    def collect[C[X] <: Iterable[X]](fi: FromIterator[C]): C[A] = fi.fromIterator(toIterator)
  }

  /** Transforms returning same collection type */
  trait MonoTransforms[A, Repr] extends Any {
    def toIterator: Iterator[A]
    def fromIterator(it: => Iterator[A]): Repr
    def partition(p: A => Boolean): (Repr, Repr) = {
      val (xs, ys) = toIterator.partition(p)
      (fromIterator(xs), fromIterator(ys))
    }
    def drop(n: Int): Repr = fromIterator(toIterator.drop(n))
  }

  /** Transforms returning same collection type constructor */
  trait PolyTransforms[A, C[X]] extends Any {
    def toIterator: Iterator[A]
    def fromIterator[B](it: => Iterator[B]): C[B]
    def map[B](f: A => B): C[B] = fromIterator(toIterator.map(f))
    def flatMap[B](f: A => CanIterate[B]): C[B] = fromIterator(toIterator.flatMap(f(_)))
    def ++[B >: A](xs: CanIterate[B]): C[B] = fromIterator(toIterator ++ xs)
    def zip[B](xs: CanIterate[B]): C[(A, B)] = fromIterator(toIterator.zip(xs.iterator))
  }

  /** Transforms that only apply to Seq */
  trait MonoTransformsOfSeqs[A, Repr] extends Any with MonoTransforms[A, Repr] {
    def reverse: Repr = fromIterator(toIterator.reverse)
  }

  /** Implementation of Ops for all generic collections */
  implicit class IterableOps[A](val c: Iterable[A])
  extends AnyVal with Ops[A] {
    def toIterator = c.iterator
  }

  /** Implementation of MonoTransforms for all generic collections */
  implicit class IterableMonoTransforms[A, C[X] <: Iterable[X]](val c: Iterable[A] with FromIterator[C])
  extends AnyVal with MonoTransforms[A, C[A]] {
    def toIterator = c.buildIterator
    def fromIterator(it: => Iterator[A]): C[A] = c.fromIterator(it)
  }

  /** Implementation of PolyTransforms for all generic collections */
  implicit class IterablePolyTransforms[A, C[X] <: Iterable[X]](val c: Iterable[A] with FromIterator[C])
  extends AnyVal with PolyTransforms[A, C] {
    def toIterator = c.buildIterator
    def fromIterator[B](it: => Iterator[B]) = c.fromIterator(it)
  }

  /** Implementation of MonoTransformsForSeqs for all generic collections */
  implicit class SeqMonoTransforms[A, C[X] <: Seq[X]](val c: Seq[A] with FromIterator[C])
  extends AnyVal with MonoTransformsOfSeqs[A, C[A]] {
    def toIterator = c.buildIterator
    def fromIterator(it: => Iterator[A]) = c.fromIterator(it)
  }

  /* --------- Concrete collection types ------------------------------- */

  /** Concrete collection type: List */
  sealed trait List[+A] extends Seq[A] with FromIterator[List] {
    def isEmpty: Boolean
    def head: A
    def tail: List[A]
    def iterator = new ListIterator[A](this)
    def fromIterator[B](it: Iterator[B]): List[B] = List.fromIterator(it)
    def apply(i: Int): A = {
      require(!isEmpty)
      if (i == 0) head else tail.apply(i - 1)
    }
    def length: Int =
      if (isEmpty) 0 else 1 + tail.length
  }

  case class Cons[+A](x: A, xs: List[A]) extends List[A] {
    def isEmpty = false
    def head = x
    def tail = xs
  }

  case object List extends IterableFactory[List] {
    def fromIterator[B](it: Iterator[B]): List[B] = it match {
      case it: ListIterator[B] => it.toList
      case _ => if (it.hasNext) Cons(it.next, fromIterator(it)) else Nil
    }
  }

  class ListIterator[+A](xs: List[A]) extends Iterator[A] {
    private[this] var current = xs
    def hasNext = !current.isEmpty
    def next = { val r = current.head; current = current.tail; r }
    def toList = current
  }

  case object Nil extends List[Nothing] {
    def isEmpty = true
    def head = ???
    def tail = ???
  }

  /** Concrete collection type: View */
  class View[+A](it: => Iterator[A]) extends HasIterator[A] {
    def iterator = it
  }

  implicit class ViewOps[A](val v: View[A]) extends AnyVal with Ops[A] {
    def toIterator = v.iterator
    def cache = collect(List).view
  }

  implicit class ViewMonoTransforms[A](val v: View[A])
  extends AnyVal with MonoTransforms[A, View[A]] {
    def toIterator = v.iterator
    def fromIterator(it: => Iterator[A]): View[A] = new View(it)
  }

  implicit class ViewPolyTransforms[A](val v: View[A])
  extends AnyVal with PolyTransforms[A, View] {
    def toIterator = v.iterator
    def fromIterator[B](it: => Iterator[B]) = new View(it)
  }

  /** Concrete collection type: String */
  implicit class StringOps(val s: String) extends AnyVal with Ops[Char] {
    def iterator: Iterator[Char] = new RandomAccessIterator[Char] {
      def length = s.length
      def apply(n: Int) = s.charAt(n)
    }
    def toIterator = iterator
  }

  implicit class StringMonoTransforms(val s: String)
  extends AnyVal with MonoTransformsOfSeqs[Char, String] {
    def toIterator = s.iterator
    def fromIterator(it: => Iterator[Char]) = {
      val sb = new StringBuilder
      for (ch <- it) sb.append(ch)
      sb.toString
    }
  }

  implicit class StringPolyTransforms(val s: String)
  extends AnyVal with PolyTransforms[Char, Seq] {
    def toIterator = s.iterator
    def fromIterator[B](it: => Iterator[B]) = List.fromIterator(it)
    def map(f: Char => Char): String = {
      val sb = new StringBuilder
      for (ch <- s) sb.append(f(ch))
      sb.toString
    }
    def flatMap(f: Char => String) = {
      val sb = new StringBuilder
      for (ch <- s) sb.append(f(ch))
      sb.toString
    }
    def ++(xs: CanIterate[Char]): String = {
      val sb = new StringBuilder(s)
      for (ch <- xs.iterator) sb.append(ch)
      sb.toString
    }
    def ++(xs: String): String = s + xs
  }

/* ---------- Iterators --------------------------------------------------- */

  /** A core Iterator class */
  trait Iterator[+A] extends CanIterate[A] { self =>
    def hasNext: Boolean
    def next: A
    def iterator = this
    def foldLeft[B](z: B)(op: (B, A) => B): B =
      if (hasNext) foldLeft(op(z, next))(op) else z
    def foldRight[B](z: B)(op: (A, B) => B): B =
      if (hasNext) op(next, foldRight(z)(op)) else z
    def foreach(f: A => Unit): Unit =
      while (hasNext) f(next)
    def indexWhere(p: A => Boolean): Int = {
      var i = 0
      while (hasNext) {
        if (p(next)) return i
        i += 1
      }
      -1
    }
    def map[B](f: A => B): Iterator[B] = new Iterator[B] {
      def hasNext = self.hasNext
      def next = f(self.next)
    }
    def flatMap[B](f: A => CanIterate[B]): Iterator[B] = new Iterator[B] {
      private var myCurrent: Iterator[B] = Iterator.empty
      private def current = {
        while (!myCurrent.hasNext && self.hasNext) myCurrent = f(self.next).iterator
        myCurrent
      }
      def hasNext = current.hasNext
      def next = current.next
    }
    def ++[B >: A](xs: CanIterate[B]): Iterator[B] = new Iterator[B] {
      private var myCurrent: Iterator[B] = self
      private def current = {
        if (!myCurrent.hasNext && myCurrent.eq(self)) myCurrent = xs.iterator
        myCurrent
      }
      def hasNext = current.hasNext
      def next = current.next
    }
    def partition(p: A => Boolean): (Iterator[A], Iterator[A]) = {
      val lookaheadTrue, lookaheadFalse = new ListBuffer[A]
      class PartIterator[+A](buf: ListBuffer[A]) extends Iterator[A] {
        final def hasNext: Boolean =
          buf.nonEmpty ||
            self.hasNext && {
              val elem = self.next
              (if (p(elem)) lookaheadTrue else lookaheadFalse) += elem
              hasNext
            }
        final def next =
          if (hasNext) {
            val r = buf.head
            buf.trimStart(1)
            r
          }
          else Iterator.nextOnEmpty
      }
      (new PartIterator(lookaheadTrue), new PartIterator(lookaheadFalse))
    }
    def drop(n: Int): Iterator[A] = {
      if (n <= 0) this
      else {
        next
        drop(n - 1)
      }
    }
    def zip[B](that: CanIterate[B]): Iterator[(A, B)] = new Iterator[(A, B)] {
      val ti = that.iterator
      def hasNext = self.hasNext && ti.hasNext
      def next = (self.next, ti.next)
    }
    def reverse: Iterator[A] = {
      var elems: List[A] = Nil
      while (hasNext) elems = Cons(next, elems)
      elems.iterator
    }
  }

  object Iterator {
    val empty: Iterator[Nothing] = new Iterator[Nothing] {
      def hasNext = false
      def next = ???
    }
    def apply[A](xs: A*): Iterator[A] = new RandomAccessIterator[A] {
      def length = xs.length
      def apply(n: Int) = xs(n)
    }
    def nextOnEmpty = throw new NoSuchElementException("next on empty iterator")
  }

  trait RandomAccessIterator[+A] extends Iterator[A] { self =>
    def apply(n: Int): A
    def length: Int
    protected val len = length
    private var cur = 0
    def hasNext = cur < len
    def next: A = { val r = this(cur); cur += 1; r }
    override def drop(n: Int): Iterator[A] = { cur += (n max 0); this }
    override def reverse = new RandomAccessIterator[A] {
      def length = self.length
      def apply(n: Int) = apply(len - 1 - n)
    }
  }
}