Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Remove operations of Iterator #7

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 157 additions & 12 deletions src/main/scala/strawman/collection/Iterable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,160 @@ package strawman.collection

import scala.annotation.unchecked.uncheckedVariance
import scala.reflect.ClassTag
import scala.{Int, Boolean, Array, Any, Unit, StringContext}
import scala.{Any, AnyVal, Array, Boolean, Int, StringContext, Unit}
import java.lang.String

import strawman.collection.mutable.{ArrayBuffer, StringBuilder}
import strawman.collection.mutable.{ArrayBuffer, Iterator, StringBuilder}

/** Base trait for generic collections */
trait Iterable[+A] extends IterableOnce[A] with IterableLike[A, Iterable] {
trait Iterable[+A] extends IterableLike[A, Iterable] {
/** The collection itself */
protected def coll: this.type = this

/** Iterator can be used only once */
def iterator(): Iterator[A]

/** Operations based on the underlying `Iterator` */
final def iterating: Iterating[A] = new Iterating(this)

}

/** Low-level operations based on the underlying `Iterator` of an `Iterable` */
class Iterating[+A](val iterable: Iterable[A]) extends AnyVal {

def foldLeft[B](z: B)(op: (B, A) => B): B = {
val it = iterable.iterator()
var b = z
while (it.hasNext) {
b = op(b, it.next())
}
b
}

def foldRight[B](z: B)(op: (A, B) => B): B = {
val it = iterable.iterator()
def loop(): B = if (it.hasNext) op(it.next(), loop()) else z
loop()
}

def foreach(f: A => Unit): Unit = {
val it = iterable.iterator()
while (it.hasNext) f(it.next())
}

def indexWhere(p: A => Boolean): Int = {
val it = iterable.iterator()
var i = 0
while (it.hasNext) {
if (p(it.next())) return i
i += 1
}
-1
}

def length: Int = {
val it = iterable.iterator()
var len = 0
while (it.hasNext) { len += 1; it.next() }
len
}

def filter(p: A => Boolean): Iterator[A] = {
val it = iterable.iterator()
new Iterator[A] {
private var hd: A = _
private var hdDefined: Boolean = false

def hasNext: Boolean = hdDefined || {
do {
if (!it.hasNext) return false
hd = it.next()
} while (!p(hd))
hdDefined = true
true
}

def next() =
if (hasNext) {
hdDefined = false
hd
}
else Iterator.empty.next()
}
}

def map[B](f: A => B): Iterator[B] = {
val it = iterable.iterator()
new Iterator[B] {
def hasNext = it.hasNext
def next() = f(it.next())
}
}

def flatMap[B](f: A => Iterable[B]): Iterator[B] = {
val it = iterable.iterator()
new Iterator[B] {
private var myCurrent: Iterator[B] = Iterator.empty
private def current = {
while (!myCurrent.hasNext && it.hasNext)
myCurrent = f(it.next()).iterator()
myCurrent
}
def hasNext = current.hasNext
def next() = current.next()
}
}

def ++ [B >: A](bs: Iterable[B]): Iterator[B] = {
val it = iterable.iterator()
new Iterator[B] {
private var myCurrent: Iterator[B] = it
private var first = true
private def current = {
if (!myCurrent.hasNext && first) {
myCurrent = bs.iterator()
first = false
}
myCurrent
}
def hasNext = current.hasNext
def next() = current.next()
}
}

def take(n: Int): Iterator[A] = {
val it = iterable.iterator()
new Iterator[A] {
private var i = 0
def hasNext = it.hasNext && i < n
def next() =
if (hasNext) {
i += 1
it.next()
}
else Iterator.empty.next()
}
}

def drop(n: Int): Iterator[A] = {
val it = iterable.iterator()
var i = 0
while (i < n && it.hasNext) {
it.next()
i += 1
}
it
}

def zip[B](that: Iterable[B]): Iterator[(A, B)] = {
val it = iterable.iterator()
new Iterator[(A, B)] {
val thatIterator = that.iterator()
def hasNext = it.hasNext && thatIterator.hasNext
def next() = (it.next(), thatIterator.next())
}
}

}

/** Base trait for Iterable operations
Expand Down Expand Up @@ -52,19 +197,19 @@ trait IterableFactory[+C[X] <: Iterable[X]] extends FromIterable[C] {
*/
trait IterableOps[+A] extends Any {
protected def coll: Iterable[A]
private def iterator() = coll.iterator()
private def iterator(): Iterator[A] = coll.iterator()

/** Apply `f` to each element for tis side effects */
def foreach(f: A => Unit): Unit = iterator().foreach(f)
def foreach(f: A => Unit): Unit = coll.iterating.foreach(f)

/** Fold left */
def foldLeft[B](z: B)(op: (B, A) => B): B = iterator().foldLeft(z)(op)
def foldLeft[B](z: B)(op: (B, A) => B): B = coll.iterating.foldLeft(z)(op)

/** Fold right */
def foldRight[B](z: B)(op: (A, B) => B): B = iterator().foldRight(z)(op)
def foldRight[B](z: B)(op: (A, B) => B): B = coll.iterating.foldRight(z)(op)

/** The index of the first element in this collection for which `p` holds. */
def indexWhere(p: A => Boolean): Int = iterator().indexWhere(p)
def indexWhere(p: A => Boolean): Int = coll.iterating.indexWhere(p)

/** Is the collection empty? */
def isEmpty: Boolean = !iterator().hasNext
Expand All @@ -80,7 +225,7 @@ trait IterableOps[+A] extends Any {
/** The number of elements in this collection. Does not terminate for
* infinite collections.
*/
def size: Int = if (knownSize >= 0) knownSize else iterator().length
def size: Int = if (knownSize >= 0) knownSize else coll.iterating.length

/** A view representing the elements of this collection. */
def view: View[A] = View.fromIterator(iterator())
Expand Down Expand Up @@ -179,12 +324,12 @@ trait IterablePolyTransforms[+A, +C[A]] extends Any {
def map[B](f: A => B): C[B] = fromIterable(View.Map(coll, f))

/** Flatmap */
def flatMap[B](f: A => IterableOnce[B]): C[B] = fromIterable(View.FlatMap(coll, f))
def flatMap[B](f: A => Iterable[B]): C[B] = fromIterable(View.FlatMap(coll, f))

/** Concatenation */
def ++[B >: A](xs: IterableOnce[B]): C[B] = fromIterable(View.Concat(coll, xs))
def ++[B >: A](xs: Iterable[B]): C[B] = fromIterable(View.Concat(coll, xs))

/** Zip. Interesting because it requires to align to source collections. */
def zip[B](xs: IterableOnce[B]): C[(A @uncheckedVariance, B)] = fromIterable(View.Zip(coll, xs))
def zip[B](xs: Iterable[B]): C[(A @uncheckedVariance, B)] = fromIterable(View.Zip(coll, xs))
// sound bcs of VarianceNote
}
8 changes: 0 additions & 8 deletions src/main/scala/strawman/collection/IterableOnce.scala

This file was deleted.

2 changes: 1 addition & 1 deletion src/main/scala/strawman/collection/Seq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ trait LinearSeq[+A] extends Seq[A] with LinearSeqLike[A, LinearSeq] { self =>
}

/** `length` is defined in terms of `iterator` */
def length: Int = iterator().length
def length: Int = iterating.length

/** `apply` is defined in terms of `drop`, which is in turn defined in
* terms of `tail`.
Expand Down
22 changes: 11 additions & 11 deletions src/main/scala/strawman/collection/View.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ object View {

/** A view that filters an underlying collection. */
case class Filter[A](underlying: Iterable[A], p: A => Boolean) extends View[A] {
def iterator() = underlying.iterator().filter(p)
def iterator() = underlying.iterating.filter(p)
}

/** A view that partitions an underlying collection into two views */
Expand All @@ -55,41 +55,41 @@ object View {

/** A view representing one half of a partition. */
case class Partitioned[A](partition: Partition[A], cond: Boolean) extends View[A] {
def iterator() = partition.underlying.iterator().filter(x => partition.p(x) == cond)
def iterator() = partition.underlying.iterating.filter(x => partition.p(x) == cond)
}

/** A view that drops leading elements of the underlying collection. */
case class Drop[A](underlying: Iterable[A], n: Int) extends View[A] {
def iterator() = underlying.iterator().drop(n)
def iterator() = underlying.iterating.drop(n)
protected val normN = n max 0
override def knownSize =
if (underlying.knownSize >= 0) (underlying.knownSize - normN) max 0 else -1
}

/** A view that takes leading elements of the underlying collection. */
case class Take[A](underlying: Iterable[A], n: Int) extends View[A] {
def iterator() = underlying.iterator().take(n)
def iterator() = underlying.iterating.take(n)
protected val normN = n max 0
override def knownSize =
if (underlying.knownSize >= 0) underlying.knownSize min normN else -1
}

/** A view that maps elements of the underlying collection. */
case class Map[A, B](underlying: Iterable[A], f: A => B) extends View[B] {
def iterator() = underlying.iterator().map(f)
def iterator() = underlying.iterating.map(f)
override def knownSize = underlying.knownSize
}

/** A view that flatmaps elements of the underlying collection. */
case class FlatMap[A, B](underlying: Iterable[A], f: A => IterableOnce[B]) extends View[B] {
def iterator() = underlying.iterator().flatMap(f)
case class FlatMap[A, B](underlying: Iterable[A], f: A => Iterable[B]) extends View[B] {
def iterator() = underlying.iterating.flatMap(f)
}

/** A view that concatenates elements of the underlying collection with the elements
* of another collection or iterator.
*/
case class Concat[A](underlying: Iterable[A], other: IterableOnce[A]) extends View[A] {
def iterator() = underlying.iterator() ++ other
case class Concat[A](underlying: Iterable[A], other: Iterable[A]) extends View[A] {
def iterator() = underlying.iterating ++ other
override def knownSize = other match {
case other: Iterable[_] if underlying.knownSize >= 0 && other.knownSize >= 0 =>
underlying.knownSize + other.knownSize
Expand All @@ -101,8 +101,8 @@ object View {
/** A view that zips elements of the underlying collection with the elements
* of another collection or iterator.
*/
case class Zip[A, B](underlying: Iterable[A], other: IterableOnce[B]) extends View[(A, B)] {
def iterator() = underlying.iterator().zip(other)
case class Zip[A, B](underlying: Iterable[A], other: Iterable[B]) extends View[(A, B)] {
def iterator() = underlying.iterating.zip(other)
override def knownSize = other match {
case other: Iterable[_] => underlying.knownSize min other.knownSize
case _ => -1
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/strawman/collection/immutable/List.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package strawman.collection.immutable
import scala.annotation.unchecked.uncheckedVariance
import scala.Nothing
import scala.Predef.???
import strawman.collection.{Iterable, IterableFactory, IterableOnce, LinearSeq, SeqLike}
import strawman.collection.{Iterable, IterableFactory, LinearSeq, SeqLike}
import strawman.collection.mutable.{Buildable, ListBuffer}


Expand All @@ -26,7 +26,7 @@ sealed trait List[+A]
else prefix.head :: prefix.tail ++: this

/** When concatenating with another list `xs`, avoid copying `xs` */
override def ++[B >: A](xs: IterableOnce[B]): List[B] = xs match {
override def ++[B >: A](xs: Iterable[B]): List[B] = xs match {
case xs: List[B] => this ++: xs
case _ => super.++(xs)
}
Expand Down
10 changes: 5 additions & 5 deletions src/main/scala/strawman/collection/javaSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ class StringOps(val s: String)
/** Overloaded version of `++` that gives back a string, where the inherited
* version gives back a sequence.
*/
def ++(xs: IterableOnce[Char]): String = {
def ++(xs: Iterable[Char]): String = {
val sb = new StringBuilder() ++= s
for (ch <- xs.iterator()) sb += ch
for (ch <- xs.iterating) sb += ch
sb.result
}

Expand Down Expand Up @@ -100,9 +100,9 @@ class ArrayOps[A](val xs: Array[A])
override def className = "Array"

def map[B: ClassTag](f: A => B): Array[B] = fromIterable(View.Map(coll, f))
def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = fromIterable(View.FlatMap(coll, f))
def ++[B >: A : ClassTag](xs: IterableOnce[B]): Array[B] = fromIterable(View.Concat(coll, xs))
def zip[B: ClassTag](xs: IterableOnce[B]): Array[(A, B)] = fromIterable(View.Zip(coll, xs))
def flatMap[B: ClassTag](f: A => Iterable[B]): Array[B] = fromIterable(View.FlatMap(coll, f))
def ++[B >: A : ClassTag](xs: Iterable[B]): Array[B] = fromIterable(View.Concat(coll, xs))
def zip[B: ClassTag](xs: Iterable[B]): Array[(A, B)] = fromIterable(View.Zip(coll, xs))
}

case class ArrayView[A](xs: Array[A]) extends IndexedView[A] {
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/strawman/collection/mutable/ArrayBuffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package strawman.collection.mutable

import scala.{Array, Int, Boolean, Unit, AnyRef}
import scala.Predef.intWrapper
import strawman.collection.{IndexedView, Iterable, IterableFactory, IterableOnce, Seq, SeqLike}
import strawman.collection.{IndexedView, Iterable, IterableFactory, Seq, SeqLike}

/** Concrete collection type: ArrayBuffer */
class ArrayBuffer[A] private (initElems: Array[AnyRef], initLength: Int)
Expand Down Expand Up @@ -55,7 +55,7 @@ class ArrayBuffer[A] private (initElems: Array[AnyRef], initLength: Int)
def trimStart(n: Int): Unit = start += (n max 0)

/** Overridden to use array copying for efficiency where possible. */
override def ++[B >: A](xs: IterableOnce[B]): ArrayBuffer[B] = xs match {
override def ++[B >: A](xs: Iterable[B]): ArrayBuffer[B] = xs match {
case xs: ArrayBuffer[B] =>
val elems = new Array[AnyRef](length + xs.length)
Array.copy(this.elems, this.start, elems, 0, this.length)
Expand Down
Loading