From 120e7811527ec61a4484e9d12f7294a5d3bb987e Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 5 Oct 2015 21:02:51 +0200 Subject: [PATCH 1/6] Add CollectionStrawman2. --- .../collections/CollectionStrawMan2.scala | 406 ++++++++++++++++++ 1 file changed, 406 insertions(+) create mode 100644 src/strawman/collections/CollectionStrawMan2.scala diff --git a/src/strawman/collections/CollectionStrawMan2.scala b/src/strawman/collections/CollectionStrawMan2.scala new file mode 100644 index 000000000000..7774a41e47d9 --- /dev/null +++ b/src/strawman/collections/CollectionStrawMan2.scala @@ -0,0 +1,406 @@ +package strawman.collections + +import Predef.{augmentString => _, wrapString => _, _} +import scala.reflect.ClassTag + +/** 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] + } + + /** 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[+A] extends CanIterate[A] with FromIterator[Iterable] + + /** Base trait for sequence collections */ + trait Seq[+A] extends Iterable[A] with FromIterator[Seq] { + def apply(i: Int): A + def length: Int + } + + /* ------------ Operations ----------------------------------- */ + + /** Operations returning types unrelated to current collection */ + trait Ops[A] extends Any { + def iterator: Iterator[A] + def foreach(f: A => Unit): Unit = iterator.foreach(f) + def foldLeft[B](z: B)(op: (B, A) => B): B = iterator.foldLeft(z)(op) + def foldRight[B](z: B)(op: (A, B) => B): B = iterator.foldRight(z)(op) + def indexWhere(p: A => Boolean): Int = iterator.indexWhere(p) + def isEmpty: Boolean = !iterator.hasNext + def head: A = iterator.next + def view: View[A] = new View(iterator) + def collectAs[C[X] <: Iterable[X]](fi: FromIterator[C]): C[A] = fi.fromIterator(iterator) + } + + /** Transforms returning same collection type */ + trait MonoTransforms[A, Repr] extends Any { + protected def iter: Iterator[A] + protected def fromIter(it: => Iterator[A]): Repr + def partition(p: A => Boolean): (Repr, Repr) = { + val (xs, ys) = iter.partition(p) + (fromIter(xs), fromIter(ys)) + } + def drop(n: Int): Repr = fromIter(iter.drop(n)) + } + + /** Transforms returning same collection type constructor */ + trait PolyTransforms[A, C[X]] extends Any { + protected def iter: Iterator[A] + protected def fromIter[B](it: => Iterator[B]): C[B] + def map[B](f: A => B): C[B] = fromIter(iter.map(f)) + def flatMap[B](f: A => CanIterate[B]): C[B] = fromIter(iter.flatMap(f(_))) + def ++[B >: A](xs: CanIterate[B]): C[B] = fromIter(iter ++ xs) + def zip[B](xs: CanIterate[B]): C[(A, B)] = fromIter(iter.zip(xs.iterator)) + } + + /** Transforms that only apply to Seq */ + trait MonoTransformsOfSeqs[A, Repr] extends Any with MonoTransforms[A, Repr] { + def reverse: Repr = fromIter(iter.reverse) + } + + /** Implementation of Ops for all generic collections */ + implicit class IterableOps[A](val c: Iterable[A]) + extends AnyVal with Ops[A] { + def iterator = 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]] { + protected def iter = c.iterator + protected def fromIter(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] { + protected def iter = c.iterator + protected def fromIter[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]] { + protected def iter = c.iterator + protected def fromIter(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 Nil extends List[Nothing] { + def isEmpty = true + def head = ??? + def tail = ??? + } + + 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 + } + + /** Concrete collection type: ArrayBuffer */ + class ArrayBuffer[A] private (initElems: Array[AnyRef], initLength: Int) extends Seq[A] with FromIterator[ArrayBuffer] { + def this() = this(new Array[AnyRef](16), 0) + private var elems: Array[AnyRef] = initElems + private var start = 0 + private var limit = initLength + def apply(i: Int) = elems(start + i).asInstanceOf[A] + def length = limit - start + def iterator = new ArrayBufferIterator[A](elems, start, length) + def fromIterator[B](it: Iterator[B]): ArrayBuffer[B] = + ArrayBuffer.fromIterator(it) + def +=(elem: A): this.type = { + if (limit == elems.length) { + if (start > 0) { + Array.copy(elems, start, elems, 0, length) + limit -= start + start = 0 + } + else { + val newelems = new Array[AnyRef](limit * 2) + Array.copy(elems, 0, newelems, 0, limit) + elems = newelems + } + } + elems(limit) = elem.asInstanceOf[AnyRef] + limit += 1 + this + } + def trimStart(n: Int): Unit = start += (n max 0) + override def toString = s"ArrayBuffer(${elems.slice(start, limit).mkString(", ")})" + } + + object ArrayBuffer extends IterableFactory[ArrayBuffer] { + def fromIterator[B](it: Iterator[B]): ArrayBuffer[B] = it match { + case Iterator.Concat(fst: ArrayBufferIterator[_], snd: ArrayBufferIterator[_]) => + val elems = new Array[AnyRef](fst.remaining + snd.remaining) + Array.copy(fst.elems, fst.start, elems, 0, fst.remaining) + Array.copy(snd.elems, snd.start, elems, fst.remaining, snd.remaining) + new ArrayBuffer(elems, elems.length) + case it @ Iterator.Partition(underlying, _, buf, _) => + while (underlying.hasNext) it.distribute() + buf.asInstanceOf[ArrayBuffer[B]] + case it if it.remaining >= 0 => + val elems = new Array[AnyRef](it.remaining) + for (i <- 0 until elems.length) elems(i) = it.next.asInstanceOf[AnyRef] + new ArrayBuffer[B](elems, elems.length) + case _ => + val buf = new ArrayBuffer[B] + while (it.hasNext) buf += it.next + buf + } + } + + class ArrayBufferIterator[A](val elems: Array[AnyRef], initStart: Int, length: Int) extends RandomAccessIterator[A] { + val limit = length + def apply(n: Int) = elems(initStart + n).asInstanceOf[A] + } + + /** Concrete collection type: View */ + class View[+A](it: => Iterator[A]) extends CanIterate[A] { + def iterator = it + } + + implicit class ViewOps[A](val v: View[A]) extends AnyVal with Ops[A] { + def iterator = v.iterator + def cache = collectAs(ArrayBuffer).view + } + + implicit class ViewMonoTransforms[A](val v: View[A]) + extends AnyVal with MonoTransforms[A, View[A]] { + protected def iter = v.iterator + protected def fromIter(it: => Iterator[A]): View[A] = new View(it) + } + + implicit class ViewPolyTransforms[A](val v: View[A]) + extends AnyVal with PolyTransforms[A, View] { + protected def iter = v.iterator + protected def fromIter[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] { + override val limit = s.length + def apply(n: Int) = s.charAt(n) + } + } + + implicit class StringMonoTransforms(val s: String) + extends AnyVal with MonoTransformsOfSeqs[Char, String] { + protected def iter = StringOps(s).iterator + protected def fromIter(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] { + protected def iter = StringOps(s).iterator + protected def fromIter[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] = Iterator.Map(this, f) + def flatMap[B](f: A => CanIterate[B]): Iterator[B] = Iterator.FlatMap(this, f) + def ++[B >: A](xs: CanIterate[B]): Iterator[B] = Iterator.Concat(this, xs.iterator) + def partition(p: A => Boolean): (Iterator[A], Iterator[A]) = { + val lookaheadTrue, lookaheadFalse = new ArrayBuffer[A] + (Iterator.Partition(this, p, lookaheadTrue, lookaheadFalse), + Iterator.Partition[A](this, !p(_), lookaheadFalse, lookaheadTrue)) + } + def drop(n: Int): Iterator[A] = Iterator.Drop(this, n) + def zip[B](that: CanIterate[B]): Iterator[(A, B)] = Iterator.Zip(this, that.iterator) + def reverse: Iterator[A] = { + var elems: List[A] = Nil + while (hasNext) elems = Cons(next, elems) + elems.iterator + } + + /** If this iterator results from applying a transfomation to another iterator, + * that other iterator, otherwise the iterator itself. + */ + def underlying: Iterator[_] = this + + /** If the number of elements still to be returned by this iterator is known, + * that number, otherwise -1. + */ + def remaining = -1 + } + + object Iterator { + val empty: Iterator[Nothing] = new Iterator[Nothing] { + def hasNext = false + def next = ??? + override def remaining = 0 + } + def apply[A](xs: A*): Iterator[A] = new RandomAccessIterator[A] { + override val limit = xs.length + def apply(n: Int) = xs(n) + } + def nextOnEmpty = throw new NoSuchElementException("next on empty iterator") + + case class Map[A, B](override val underlying: Iterator[A], f: A => B) extends Iterator[B] { + def hasNext = underlying.hasNext + def next = f(underlying.next) + override def remaining = underlying.remaining + } + case class FlatMap[A, B](override val underlying: Iterator[A], f: A => CanIterate[B]) extends Iterator[B] { + private var myCurrent: Iterator[B] = Iterator.empty + private def current = { + while (!myCurrent.hasNext && underlying.hasNext) + myCurrent = f(underlying.next).iterator + myCurrent + } + def hasNext = current.hasNext + def next = current.next + } + case class Concat[A](override val underlying: Iterator[A], other: Iterator[A]) extends Iterator[A] { + private var myCurrent = underlying + private def current = { + if (!myCurrent.hasNext && myCurrent.eq(underlying)) myCurrent = other + myCurrent + } + def hasNext = current.hasNext + def next = current.next + override def remaining = + if (underlying.remaining >= 0 && other.remaining >= 0) + underlying.remaining + other.remaining + else -1 + } + case class Partition[A](override val underlying: Iterator[A], p: A => Boolean, lookahead: ArrayBuffer[A], dual: ArrayBuffer[A]) extends Iterator[A] { + def distribute() = { + val elem = underlying.next + (if (p(elem)) lookahead else dual) += elem + } + final def hasNext: Boolean = + !lookahead.isEmpty || underlying.hasNext && { distribute(); hasNext } + final def next = + if (hasNext) { + val r = lookahead.head + lookahead.trimStart(1) + r + } else Iterator.nextOnEmpty + } + case class Drop[A](override val underlying: Iterator[A], n: Int) extends Iterator[A] { + var toSkip = n + def hasNext: Boolean = underlying.hasNext && ( + toSkip == 0 || { underlying.next; toSkip -= 1; hasNext }) + def next = if (hasNext) underlying.next else nextOnEmpty + override def remaining = (underlying.remaining - toSkip) max -1 + } + case class Zip[A, B](override val underlying: Iterator[A], other: Iterator[B]) extends Iterator[(A, B)] { + def hasNext = underlying.hasNext && other.hasNext + def next = (underlying.next, other.next) + override def remaining = underlying.remaining min other.remaining + } + case class Reverse[A](override val underlying: RandomAccessIterator[A]) extends RandomAccessIterator[A] { + def apply(n: Int) = underlying.apply(underlying.limit - 1 - n) + def limit = underlying.remaining + } + } + + trait RandomAccessIterator[+A] extends Iterator[A] { self => + def apply(n: Int): A + def limit: Int + var start = 0 + override def remaining = (limit - start) max 0 + def hasNext = start < limit + def next: A = { val r = this(start); start += 1; r } + override def drop(n: Int): Iterator[A] = { start += (n max 0); this } + override def reverse: Iterator[A] = new Iterator.Reverse(this) + } +} + + From 48afa750b803eca44eb295c8889c2c3612c29529 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 5 Oct 2015 21:15:50 +0200 Subject: [PATCH 2/6] Get rid of view. Replace it by type alias, One class less in hierarchy. --- src/strawman/collections/CollectionStrawMan2.scala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/strawman/collections/CollectionStrawMan2.scala b/src/strawman/collections/CollectionStrawMan2.scala index 7774a41e47d9..8eb08d884f0b 100644 --- a/src/strawman/collections/CollectionStrawMan2.scala +++ b/src/strawman/collections/CollectionStrawMan2.scala @@ -40,6 +40,8 @@ object CollectionStrawMan1 { def length: Int } + type View[A] = () => Iterator[A] + /* ------------ Operations ----------------------------------- */ /** Operations returning types unrelated to current collection */ @@ -51,7 +53,7 @@ object CollectionStrawMan1 { def indexWhere(p: A => Boolean): Int = iterator.indexWhere(p) def isEmpty: Boolean = !iterator.hasNext def head: A = iterator.next - def view: View[A] = new View(iterator) + def view: View[A] = iterator _ def collectAs[C[X] <: Iterable[X]](fi: FromIterator[C]): C[A] = fi.fromIterator(iterator) } @@ -210,9 +212,6 @@ object CollectionStrawMan1 { } /** Concrete collection type: View */ - class View[+A](it: => Iterator[A]) extends CanIterate[A] { - def iterator = it - } implicit class ViewOps[A](val v: View[A]) extends AnyVal with Ops[A] { def iterator = v.iterator @@ -222,13 +221,13 @@ object CollectionStrawMan1 { implicit class ViewMonoTransforms[A](val v: View[A]) extends AnyVal with MonoTransforms[A, View[A]] { protected def iter = v.iterator - protected def fromIter(it: => Iterator[A]): View[A] = new View(it) + protected def fromIter(it: => Iterator[A]): View[A] = it } implicit class ViewPolyTransforms[A](val v: View[A]) extends AnyVal with PolyTransforms[A, View] { protected def iter = v.iterator - protected def fromIter[B](it: => Iterator[B]) = new View(it) + protected def fromIter[B](it: => Iterator[B]) = it } /** Concrete collection type: String */ From 52816883cd6a86a59cd92efdc482cf441aecd8aa Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 5 Oct 2015 21:25:14 +0200 Subject: [PATCH 3/6] Decouple views from collections. Same should be done for parallel collections. --- src/strawman/collections/CollectionStrawMan2.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/strawman/collections/CollectionStrawMan2.scala b/src/strawman/collections/CollectionStrawMan2.scala index 8eb08d884f0b..c0d59c9b990d 100644 --- a/src/strawman/collections/CollectionStrawMan2.scala +++ b/src/strawman/collections/CollectionStrawMan2.scala @@ -53,10 +53,13 @@ object CollectionStrawMan1 { def indexWhere(p: A => Boolean): Int = iterator.indexWhere(p) def isEmpty: Boolean = !iterator.hasNext def head: A = iterator.next - def view: View[A] = iterator _ def collectAs[C[X] <: Iterable[X]](fi: FromIterator[C]): C[A] = fi.fromIterator(iterator) } + trait Viewable[A] extends Any { + def view: View[A] + } + /** Transforms returning same collection type */ trait MonoTransforms[A, Repr] extends Any { protected def iter: Iterator[A] @@ -89,6 +92,11 @@ object CollectionStrawMan1 { def iterator = c.iterator } + implicit class IterableIsViewable[A](val c: Iterable[A]) extends Viewable[A]{ + def iterator: Iterator[A] = c.iterator + def view: View[A] = 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]] { From b77ab7c7a9f42df8996a3e3d814abc0406b2cca6 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 5 Oct 2015 21:48:43 +0200 Subject: [PATCH 4/6] Remove operations from iterators. They are on views. I've seen many projects, including Dotty itself where there is code similar to ```scala def average(xs: Iterator[Int]) = xs.sum/xs.size ``` It simply should not compile. --- .../collections/CollectionStrawMan2.scala | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/src/strawman/collections/CollectionStrawMan2.scala b/src/strawman/collections/CollectionStrawMan2.scala index c0d59c9b990d..7fcea0d0fc49 100644 --- a/src/strawman/collections/CollectionStrawMan2.scala +++ b/src/strawman/collections/CollectionStrawMan2.scala @@ -65,20 +65,22 @@ object CollectionStrawMan1 { protected def iter: Iterator[A] protected def fromIter(it: => Iterator[A]): Repr def partition(p: A => Boolean): (Repr, Repr) = { - val (xs, ys) = iter.partition(p) + val lookaheadTrue, lookaheadFalse = new ArrayBuffer[A] + val xs = Iterator.Partition[A](this, p, lookaheadTrue, lookaheadFalse) + val ys = Iterator.Partition[A](this, !p(_), lookaheadFalse, lookaheadTrue) (fromIter(xs), fromIter(ys)) } - def drop(n: Int): Repr = fromIter(iter.drop(n)) + def drop(n: Int): Repr = fromIter(Iterator.Drop(iter, n)) } /** Transforms returning same collection type constructor */ trait PolyTransforms[A, C[X]] extends Any { protected def iter: Iterator[A] protected def fromIter[B](it: => Iterator[B]): C[B] - def map[B](f: A => B): C[B] = fromIter(iter.map(f)) - def flatMap[B](f: A => CanIterate[B]): C[B] = fromIter(iter.flatMap(f(_))) - def ++[B >: A](xs: CanIterate[B]): C[B] = fromIter(iter ++ xs) - def zip[B](xs: CanIterate[B]): C[(A, B)] = fromIter(iter.zip(xs.iterator)) + def map[B](f: A => B): C[B] = fromIter(Iterator.Map(iter, f)) + def flatMap[B](f: A => CanIterate[B]): C[B] = fromIter(Iterator.FlatMap(iter, f)) + def ++[B >: A](xs: CanIterate[B]): C[B] = fromIter(Iterator.Concat(iter, xs)) + def zip[B](xs: CanIterate[B]): C[(A, B)] = fromIter(Iterator.Zip(iter, xs.iterator)) } /** Transforms that only apply to Seq */ @@ -285,30 +287,6 @@ object CollectionStrawMan1 { 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] = Iterator.Map(this, f) - def flatMap[B](f: A => CanIterate[B]): Iterator[B] = Iterator.FlatMap(this, f) - def ++[B >: A](xs: CanIterate[B]): Iterator[B] = Iterator.Concat(this, xs.iterator) - def partition(p: A => Boolean): (Iterator[A], Iterator[A]) = { - val lookaheadTrue, lookaheadFalse = new ArrayBuffer[A] - (Iterator.Partition(this, p, lookaheadTrue, lookaheadFalse), - Iterator.Partition[A](this, !p(_), lookaheadFalse, lookaheadTrue)) - } - def drop(n: Int): Iterator[A] = Iterator.Drop(this, n) - def zip[B](that: CanIterate[B]): Iterator[(A, B)] = Iterator.Zip(this, that.iterator) def reverse: Iterator[A] = { var elems: List[A] = Nil while (hasNext) elems = Cons(next, elems) From 5244c5cf1f3d2ff2917a09e9760f9ad887ca4ce0 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Tue, 6 Oct 2015 15:54:40 +0200 Subject: [PATCH 5/6] Abstract over LegthType and make it be Long. --- .../collections/CollectionStrawMan2.scala | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/strawman/collections/CollectionStrawMan2.scala b/src/strawman/collections/CollectionStrawMan2.scala index 7fcea0d0fc49..07edbd28d38c 100644 --- a/src/strawman/collections/CollectionStrawMan2.scala +++ b/src/strawman/collections/CollectionStrawMan2.scala @@ -13,6 +13,8 @@ import scala.reflect.ClassTag */ object CollectionStrawMan1 { + type LengthType = Long + /* ------------ Base Traits -------------------------------- */ /** Replaces TraversableOnce */ @@ -36,8 +38,8 @@ object CollectionStrawMan1 { /** Base trait for sequence collections */ trait Seq[+A] extends Iterable[A] with FromIterator[Seq] { - def apply(i: Int): A - def length: Int + def apply(i: LengthType): A + def length: LengthType } type View[A] = () => Iterator[A] @@ -50,7 +52,7 @@ object CollectionStrawMan1 { def foreach(f: A => Unit): Unit = iterator.foreach(f) def foldLeft[B](z: B)(op: (B, A) => B): B = iterator.foldLeft(z)(op) def foldRight[B](z: B)(op: (A, B) => B): B = iterator.foldRight(z)(op) - def indexWhere(p: A => Boolean): Int = iterator.indexWhere(p) + def indexWhere(p: A => Boolean): LengthType = iterator.indexWhere(p) def isEmpty: Boolean = !iterator.hasNext def head: A = iterator.next def collectAs[C[X] <: Iterable[X]](fi: FromIterator[C]): C[A] = fi.fromIterator(iterator) @@ -70,7 +72,7 @@ object CollectionStrawMan1 { val ys = Iterator.Partition[A](this, !p(_), lookaheadFalse, lookaheadTrue) (fromIter(xs), fromIter(ys)) } - def drop(n: Int): Repr = fromIter(Iterator.Drop(iter, n)) + def drop(n: LengthType): Repr = fromIter(Iterator.Drop(iter, n)) } /** Transforms returning same collection type constructor */ @@ -129,11 +131,11 @@ object CollectionStrawMan1 { 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 = { + def apply(i: LengthType): A = { require(!isEmpty) if (i == 0) head else tail.apply(i - 1) } - def length: Int = + def length: LengthType = if (isEmpty) 0 else 1 + tail.length } @@ -164,12 +166,12 @@ object CollectionStrawMan1 { } /** Concrete collection type: ArrayBuffer */ - class ArrayBuffer[A] private (initElems: Array[AnyRef], initLength: Int) extends Seq[A] with FromIterator[ArrayBuffer] { + class ArrayBuffer[A] private (initElems: Array[AnyRef], initLength: LengthType) extends Seq[A] with FromIterator[ArrayBuffer] { def this() = this(new Array[AnyRef](16), 0) private var elems: Array[AnyRef] = initElems - private var start = 0 - private var limit = initLength - def apply(i: Int) = elems(start + i).asInstanceOf[A] + private var start: LengthType = 0 + private var limit: LengthType = initLength + def apply(i: LengthType) = elems(start + i).asInstanceOf[A] def length = limit - start def iterator = new ArrayBufferIterator[A](elems, start, length) def fromIterator[B](it: Iterator[B]): ArrayBuffer[B] = @@ -191,7 +193,7 @@ object CollectionStrawMan1 { limit += 1 this } - def trimStart(n: Int): Unit = start += (n max 0) + def trimStart(n: LengthType): Unit = start += (n max 0) override def toString = s"ArrayBuffer(${elems.slice(start, limit).mkString(", ")})" } @@ -216,9 +218,9 @@ object CollectionStrawMan1 { } } - class ArrayBufferIterator[A](val elems: Array[AnyRef], initStart: Int, length: Int) extends RandomAccessIterator[A] { - val limit = length - def apply(n: Int) = elems(initStart + n).asInstanceOf[A] + class ArrayBufferIterator[A](val elems: Array[AnyRef], initStart: LengthType, length: LengthType) extends RandomAccessIterator[A] { + val limit: LengthType = length + def apply(n: LengthType) = elems(initStart + n).asInstanceOf[A] } /** Concrete collection type: View */ @@ -244,7 +246,7 @@ object CollectionStrawMan1 { implicit class StringOps(val s: String) extends AnyVal with Ops[Char] { def iterator: Iterator[Char] = new RandomAccessIterator[Char] { override val limit = s.length - def apply(n: Int) = s.charAt(n) + def apply(n: LengthType) = s.charAt(n) } } @@ -312,7 +314,7 @@ object CollectionStrawMan1 { } def apply[A](xs: A*): Iterator[A] = new RandomAccessIterator[A] { override val limit = xs.length - def apply(n: Int) = xs(n) + def apply(n: LengthType) = xs(n) } def nextOnEmpty = throw new NoSuchElementException("next on empty iterator") @@ -358,7 +360,7 @@ object CollectionStrawMan1 { r } else Iterator.nextOnEmpty } - case class Drop[A](override val underlying: Iterator[A], n: Int) extends Iterator[A] { + case class Drop[A](override val underlying: Iterator[A], n: LengthType) extends Iterator[A] { var toSkip = n def hasNext: Boolean = underlying.hasNext && ( toSkip == 0 || { underlying.next; toSkip -= 1; hasNext }) @@ -371,19 +373,19 @@ object CollectionStrawMan1 { override def remaining = underlying.remaining min other.remaining } case class Reverse[A](override val underlying: RandomAccessIterator[A]) extends RandomAccessIterator[A] { - def apply(n: Int) = underlying.apply(underlying.limit - 1 - n) + def apply(n: LengthType) = underlying.apply(underlying.limit - 1 - n) def limit = underlying.remaining } } trait RandomAccessIterator[+A] extends Iterator[A] { self => - def apply(n: Int): A - def limit: Int + def apply(n: LengthType): A + def limit: LengthType var start = 0 override def remaining = (limit - start) max 0 def hasNext = start < limit def next: A = { val r = this(start); start += 1; r } - override def drop(n: Int): Iterator[A] = { start += (n max 0); this } + override def drop(n: LengthType): Iterator[A] = { start += (n max 0); this } override def reverse: Iterator[A] = new Iterator.Reverse(this) } } From 22ca08d28895e6829d9cee58f0262228c11f3a75 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Wed, 7 Oct 2015 17:52:06 +0200 Subject: [PATCH 6/6] LengthType: make it be a custom value class. --- .../collections/CollectionStrawMan2.scala | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/strawman/collections/CollectionStrawMan2.scala b/src/strawman/collections/CollectionStrawMan2.scala index 07edbd28d38c..6f8854064e65 100644 --- a/src/strawman/collections/CollectionStrawMan2.scala +++ b/src/strawman/collections/CollectionStrawMan2.scala @@ -1,6 +1,7 @@ package strawman.collections import Predef.{augmentString => _, wrapString => _, _} +import scala.language.implicitConversions import scala.reflect.ClassTag /** A strawman architecture for new collections. It contains some @@ -13,7 +14,21 @@ import scala.reflect.ClassTag */ object CollectionStrawMan1 { - type LengthType = Long + type LengthTypeUnderlying = Long + + final case class LengthType(u: LengthTypeUnderlying) extends AnyVal { + def +(other: LengthType) = LengthType(u + other.u) + def -(other: LengthType) = LengthType(u - other.u) + def /(other: LengthType) = LengthType(u / other.u) + def *(other: LengthType) = LengthType(u * other.u) + def <(other: LengthType) = u < other.u + def >(other: LengthType) = u > other.u + def <=(other: LengthType) = u <= other.u + def >=(other: LengthType) = u >= other.u + } + + implicit def intToLengthType(x: Int): LengthType = LengthType(x) + implicit def lengthTypeToLong(x: LengthType): Long = x.u.toLong /* ------------ Base Traits -------------------------------- */