Skip to content

Commit

Permalink
Merge pull request scala#273 from scala/wip/compat-methods
Browse files Browse the repository at this point in the history
A collection of smaller changes from my integration branch
  • Loading branch information
julienrf committed Oct 24, 2017
2 parents 70bfcb9 + 909d28a commit 75d09da
Show file tree
Hide file tree
Showing 44 changed files with 1,178 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ArrayOps[A](val xs: Array[A])

def toIterable = ArrayView(xs)
protected[this] def coll: Array[A] = xs
def toSeq: Seq[A] = fromIterable(toIterable)
override def toSeq: immutable.Seq[A] = fromIterable(toIterable)

def length = xs.length
@throws[ArrayIndexOutOfBoundsException]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package strawman.collection

import scala.{Option, Some, None}

/** Buffered iterators are iterators which provide a method `head`
* that inspects the next element without discarding it.
*
* @author Martin Odersky
* @version 2.8
* @since 2.8
*/
trait BufferedIterator[+A] extends Iterator[A] {

/** Returns next element of iterator without advancing beyond it.
*/
def head: A

/** Returns an option of the next element of an iterator without advancing beyond it.
* @return the next element of this iterator if it has a next element
* `None` if it does not
*/
def headOption : Option[A] = if (hasNext) Some(head) else None

override def buffered: this.type = this
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package strawman.collection

import scala.{Any, Ordering}
import scala.{Any, Ordering, deprecated, `inline`}

import strawman.collection.mutable.Builder

Expand All @@ -17,6 +17,9 @@ trait BuildFrom[-From, -A, +C] extends Any {
/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
* Building collections with `fromSpecificIterable` is preferred because it can be lazy for lazy collections. */
def newBuilder(from: From): Builder[A, C]

@deprecated("Use newBuilder() instead of apply()", "2.13.0")
@`inline` def apply(from: From): Builder[A, C] = newBuilder(from)
}

object BuildFrom extends BuildFromLowPriority {
Expand Down
6 changes: 4 additions & 2 deletions collections/src/main/scala/strawman/collection/Factory.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import strawman.collection.immutable.NumericRange
import scala.language.implicitConversions
import strawman.collection.mutable.Builder

import scala.{Any, Int, Integral, Nothing, Ordering}
import scala.{Any, Int, Integral, Nothing, Ordering, Some}
import scala.Predef.implicitly
import scala.annotation.unchecked.uncheckedVariance

Expand All @@ -29,7 +29,8 @@ trait Factory[-A, +C] extends Any {
*/
def fromSpecific(it: IterableOnce[A]): C

/** A strict builder that eventually produces a `C` */
/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
* Building collections with `fromSpecific` is preferred because it can be lazy for lazy collections. */
def newBuilder(): Builder[A, C]
}

Expand Down Expand Up @@ -150,6 +151,7 @@ object IterableFactory {
* @tparam CC Collection type constructor (e.g. `List`)
*/
trait SeqFactory[+CC[_]] extends IterableFactory[CC] {
def unapplySeq[A](x: CC[A] @uncheckedVariance): Some[CC[A]] = Some(x) //TODO is uncheckedVariance sound here?

/** Produces a $coll containing the results of some element computation a number of times.
* @param n the number of elements contained in the $coll.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ trait IndexedSeqOps[+A, +CC[X] <: IndexedSeq[X], +C] extends Any with SeqOps[A,
* linear, immutable collections this should avoid making a copy. */
override def dropRight(n: Int): C = fromSpecificIterable(view.dropRight(n))

override def lengthCompare(len: Int): Int = length - len

}
112 changes: 106 additions & 6 deletions collections/src/main/scala/strawman/collection/Iterable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ package collection

import scala.annotation.unchecked.uncheckedVariance
import scala.reflect.ClassTag
import scala.{Any, AnyRef, Array, Boolean, `inline`, Int, None, Numeric, Option, Ordering, PartialFunction, StringContext, Some, Unit}
import scala.{Any, Array, Boolean, `inline`, Int, None, Numeric, Option, Ordering, PartialFunction, StringContext, Some, Unit, deprecated, IllegalArgumentException, Function1, AnyRef}
import java.lang.{String, UnsupportedOperationException}
import scala.Predef.<:<

import strawman.collection.mutable.{ArrayBuffer, Builder, StringBuilder}
import java.lang.String

/** Base trait for generic collections */
trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterable[A]] {
trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterable[A]] with Traversable[A] {

/** The collection itself */
final def toIterable: this.type = this

//TODO scalac generates an override for this in AbstractMap; Making it final leads to a VerifyError
protected[this] def coll: this.type = this

}

/** Base trait for Iterable operations
Expand All @@ -33,7 +36,7 @@ trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterabl
* @tparam C type of the collection (e.g. `List[Int]`, `String`, `BitSet`). Operations returning a collection
* with the same type of element (e.g. `drop`, `filter`) return a `C`.
*/
trait IterableOps[+A, +CC[X], +C] extends Any {
trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] {

/**
* @return This collection as an `Iterable[A]`. No new collection will be built if `this` is already an `Iterable[A]`.
Expand Down Expand Up @@ -117,6 +120,12 @@ trait IterableOps[+A, +CC[X], +C] extends Any {
/** Fold right */
def foldRight[B](z: B)(op: (A, B) => B): B = toIterable.iterator().foldRight(z)(op)

@deprecated("Use foldLeft instead of /:", "2.13.0")
@`inline` final def /: [B](z: B)(op: (B, A) => B): B = foldLeft[B](z)(op)

@deprecated("Use foldRight instead of :\\", "2.13.0")
@`inline` final def :\ [B](z: B)(op: (A, B) => B): B = foldRight[B](z)(op)

/** Reduces the elements of this $coll using the specified associative binary operator.
*
* $undefinedorder
Expand Down Expand Up @@ -225,6 +234,12 @@ trait IterableOps[+A, +CC[X], +C] extends Any {
/** The first element of the collection. */
def head: A = toIterable.iterator().next()

/** The first element of the collection. */
def headOption: Option[A] = {
val it = toIterable.iterator()
if(it.hasNext) Some(it.next()) else None
}

/** Selects the last element.
* $orderDependent
* @return The last element of this $coll.
Expand All @@ -249,6 +264,9 @@ trait IterableOps[+A, +CC[X], +C] extends Any {
*/
def knownSize: Int = -1

@deprecated("Use .knownSize >=0 instead of .hasDefiniteSize", "2.13.0")
@`inline` final def hasDefiniteSize = knownSize >= 0

/** The number of elements in this collection. Does not terminate for
* infinite collections.
*/
Expand All @@ -266,6 +284,19 @@ trait IterableOps[+A, +CC[X], +C] extends Any {
*/
def to[C1](factory: Factory[A, C1]): C1 = factory.fromSpecific(toIterable)

def toList: immutable.List[A] = immutable.List.from(toIterable)

def toVector: immutable.Vector[A] = immutable.Vector.from(toIterable)

def toMap[K, V](implicit ev: A <:< (K, V)): immutable.Map[K, V] =
immutable.Map.from(toIterable.asInstanceOf[Iterable[(K, V)]])

def toSet[B >: A]: immutable.Set[B] = immutable.Set.from(toIterable)

def toSeq: immutable.Seq[A] = immutable.Seq.from(toIterable)

def toIndexedSeq: immutable.IndexedSeq[A] = immutable.IndexedSeq.from(toIterable)

/** Convert collection to array. */
def toArray[B >: A: ClassTag]: Array[B] =
if (knownSize >= 0) copyToArray(new Array[B](knownSize), 0)
Expand All @@ -286,8 +317,22 @@ trait IterableOps[+A, +CC[X], +C] extends Any {
* Collections generally print like this:
*
* <className>(elem_1, ..., elem_n)
*/
def className = getClass.getName
*
* @return a string representation which starts the result of `toString`
* applied to this $coll. By default the string prefix is the
* simple name of the collection class $coll.
*/
def className: String = {
var string = toIterable.getClass.getName
val idx1 = string.lastIndexOf('.' : Int)
if (idx1 != -1) string = string.substring(idx1 + 1)
val idx2 = string.indexOf('$')
if (idx2 != -1) string = string.substring(0, idx2)
string
}

@deprecated("Use className instead of stringPrefix", "2.13.0")
@`inline` final def stringPrefix: String = className

/** A string showing all elements of this collection, separated by string `sep`. */
def mkString(start: String, sep: String, end: String): String = {
Expand All @@ -307,8 +352,61 @@ trait IterableOps[+A, +CC[X], +C] extends Any {

def mkString: String = mkString("")

override def toString = s"$className(${mkString(", ")})"
override def toString = mkString(className + "(", ", ", ")")

//TODO Can there be a useful lazy implementation of this method? Otherwise mark it as being always strict
/** Transposes this $coll of iterable collections into
* a $coll of ${coll}s.
*
* The resulting collection's type will be guided by the
* static type of $coll. For example:
*
* {{{
* val xs = List(
* Set(1, 2, 3),
* Set(4, 5, 6)).transpose
* // xs == List(
* // List(1, 4),
* // List(2, 5),
* // List(3, 6))
*
* val ys = Vector(
* List(1, 2, 3),
* List(4, 5, 6)).transpose
* // ys == Vector(
* // Vector(1, 4),
* // Vector(2, 5),
* // Vector(3, 6))
* }}}
*
* @tparam B the type of the elements of each iterable collection.
* @param asIterable an implicit conversion which asserts that the
* element type of this $coll is an `Iterable`.
* @return a two-dimensional $coll of ${coll}s which has as ''n''th row
* the ''n''th column of this $coll.
* @throws IllegalArgumentException if all collections in this $coll
* are not of the same size.
*/
def transpose[B](implicit asIterable: A => /*<:<!!!*/ Iterable[B]): CC[CC[B] @uncheckedVariance] = {
if (isEmpty)
return iterableFactory.empty[CC[B]]

def fail = throw new IllegalArgumentException("transpose requires all collections have the same size")

val headSize = asIterable(head).size
val bs: strawman.collection.immutable.IndexedSeq[Builder[B, CC[B]]] = strawman.collection.immutable.IndexedSeq.fill(headSize)(iterableFactory.newBuilder[B]())
for (xs <- iterator()) {
var i = 0
for (x <- asIterable(xs)) {
if (i >= headSize) fail
bs(i) += x
i += 1
}
if (i != headSize)
fail
}
fromIterable(bs.map(_.result()))
}

/** Sums up the elements of this collection.
*
Expand Down Expand Up @@ -882,3 +980,5 @@ trait IterableOps[+A, +CC[X], +C] extends Any {
}

object Iterable extends IterableFactory.Delegate[Iterable](immutable.Iterable)

abstract class AbstractIterable[+A] extends Iterable[A]
Original file line number Diff line number Diff line change
@@ -1,11 +1,72 @@
package strawman
package collection

import scala.{Any, Int}
import scala.{Any, Int, Unit, deprecated, `inline`, AnyVal, Boolean, Array, Option}
import scala.Predef.String
import scala.language.implicitConversions
import scala.reflect.ClassTag

trait IterableOnce[+A] extends Any {
/** Iterator can be used only once */
def iterator(): Iterator[A]

def knownSize: Int
}

final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) extends AnyVal {
@deprecated("Use .iterator().foreach(...) instead of .foreach(...) on IterableOnce", "2.13.0")
@`inline` def foreach[U](f: A => U): Unit = it match {
case it: Iterable[_] => it.asInstanceOf[Iterable[A]].foreach(f)
case _ => it.iterator().foreach(f)
}

@deprecated("Use ArrayBuffer.fromIterable(it) instead of it.toBuffer on Iterable (wrap Iterators with View.fromIterator first)", "2.13.0")
def toBuffer[B >: A]: mutable.Buffer[B] = it match {
case it: Iterable[_] => mutable.ArrayBuffer.from(it)
case _ => mutable.ArrayBuffer.from(View.fromIteratorProvider(() => it.iterator()))
}

@deprecated("Use ArrayBuffer.fromIterable(it).toArray instead of it.toArray on Iterable (wrap Iterators with View.fromIterator first)", "2.13.0")
def toArray[B >: A: ClassTag]: Array[B] = it match {
case it: Iterable[_] => it.asInstanceOf[Iterable[B]].toArray[B]
case _ => mutable.ArrayBuffer.from(View.fromIteratorProvider(() => it.iterator())).toArray
}

@deprecated("Use List.fromIterable(it) instead of it.toList on Iterable (wrap Iterators with View.fromIterator first)", "2.13.0")
def toList[B >: A]: immutable.List[B] = it match {
case it: Iterable[_] => immutable.List.from(it.asInstanceOf[Iterable[B]])
case _ => immutable.List.from(View.fromIteratorProvider(() => it.iterator()))
}

@deprecated("Use .iterator().isEmpty instead of .isEmpty on IterableOnce", "2.13.0")
def isEmpty: Boolean = it match {
case it: Iterable[_] => it.isEmpty
case _ => it.iterator().isEmpty
}

@deprecated("Use .iterator().mkString instead of .mkString on IterableOnce", "2.13.0")
def mkString(start: String, sep: String, end: String): String = it match {
case it: Iterable[_] => it.mkString(start, sep, end)
case _ => it.iterator().mkString(start, sep, end)
}

@deprecated("Use .iterator().mkString instead of .mkString on IterableOnce", "2.13.0")
def mkString(sep: String): String = it match {
case it: Iterable[_] => it.mkString(sep)
case _ => it.iterator().mkString(sep)
}

@deprecated("Use .iterator().mkString instead of .mkString on IterableOnce", "2.13.0")
def mkString: String = it match {
case it: Iterable[_] => it.mkString
case _ => it.iterator().mkString
}

@deprecated("Use .iterator().find instead of .find on IterableOnce", "2.13.0")
def find(p: A => Boolean): Option[A] = it.iterator().find(p)
}

object IterableOnce {
@`inline` implicit def iterableOnceExtensionMethods[A](it: IterableOnce[A]): IterableOnceExtensionMethods[A] =
new IterableOnceExtensionMethods[A](it)
}

0 comments on commit 75d09da

Please sign in to comment.