Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.
Merged
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
8 changes: 5 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ organization in ThisBuild := "ch.epfl.scala"

version in ThisBuild := "0.2.0-SNAPSHOT"

scalaVersion in ThisBuild := "2.12.1"
resolvers in ThisBuild += "scala-pr" at "https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots"
scalaVersion in ThisBuild := "2.12.2-ebe1180-SNAPSHOT" // from https://github.com/scala/scala/pull/5742
scalaBinaryVersion in ThisBuild := "2.12"

scalacOptions in ThisBuild ++=
Seq("-deprecation", "-unchecked", "-Yno-imports", "-language:higherKinds")
Expand All @@ -26,7 +28,7 @@ val collections =
<developer><id>ichoran</id><name>Rex Kerr</name></developer>
<developer><id>odersky</id><name>Martin Odersky</name></developer>
<developer><id>julienrf</id><name>Julien Richard-Foy</name></developer>
<developer><id>szeiger</id><name>Stefan Szeiger</name></developer>
<developer><id>szeiger</id><name>Stefan Zeiger</name></developer>
</developers>,
homepage := Some(url("https://github.com/scala/collection-strawman")),
licenses := Seq("BSD 3-clause" -> url("http://opensource.org/licenses/BSD-3-Clause")),
Expand Down Expand Up @@ -80,4 +82,4 @@ val memoryBenchmark =
}.evaluated
)

lazy val charts = inputKey[File]("Runs the benchmarks and produce charts")
lazy val charts = inputKey[File]("Runs the benchmarks and produce charts")
13 changes: 0 additions & 13 deletions src/main/scala/strawman/collection/BitSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,3 @@ trait BitSetMonoTransforms[+C <: BitSet]
def map(f: Int => Int): C

}

/** Factory methods for unconstrained collections of kind `*` */
trait BitSetFactories[+C] {

def newBuilder: Builder[Int, C]

final def empty: C = newBuilder.result

final def apply(elems: Int*): C = newBuilder.++=(elems.toStrawman).result

implicit val canBuild: () => Builder[Int, C] = () => newBuilder

}
68 changes: 68 additions & 0 deletions src/main/scala/strawman/collection/BuildFrom.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package strawman.collection

import scala.Any
import scala.annotation.implicitNotFound
import mutable.Builder

/** BuildFrom can be used by methods outside the collections framework to build collections of various types without
* having to define overloaded methods for unconstrained / constrained / map-like / etc. collections like we do in
* the collections framework.
*/
@implicitNotFound(msg = "Cannot construct a collection with elements of type ${Elem} based on a collection of type ${From}.")
trait BuildFrom[-From, -Elem] {
type To

/** Creates a new builder on request of a collection.
* @param from the collection requesting the builder to be created.
* @return a builder for collections of type `To` with element type `Elem`.
*/
def newBuilder(from: From): Builder[Elem, To]

def fromIterable(from: From)(it: Iterable[Elem]): To
}

object BuildFrom {
/** Build the source collection type from a PolyBuildable */
implicit def buildFromPolyBuildable[C[X] <: PolyBuildable[X, C], A, E]: BuildFrom[C[A], E] { type To = C[E] } = new BuildFrom[C[A], E] {
//TODO: Reuse a prototype instance
type To = C[E]
def newBuilder(from: C[A]): Builder[E, To] = from.newBuilder[E]
def fromIterable(from: C[A])(it: Iterable[E]): To = from.fromIterable(it)
}

/** Build the source collection type from a ConstrainedPolyBuildable */
implicit def buildFromConstrainedPolyBuildable[Ev[_], Impl[_], CC[_], A, E : Ev]: BuildFrom[ConstrainedPolyBuildable[A, CC, Ev], E] { type To = CC[E] } = new BuildFrom[ConstrainedPolyBuildable[A, CC, Ev], E] {
//TODO: Reuse a prototype instance
type To = CC[E]
def newBuilder(from: ConstrainedPolyBuildable[A, CC, Ev]): Builder[E, To] = from.newConstrainedBuilder[E]
def fromIterable(from: ConstrainedPolyBuildable[A, CC, Ev])(it: Iterable[E]): To = from.constrainedFromIterable(it)
}

/** Convert an IterableFactory to a BuildFrom */
implicit def buildBoundedIterableFactory[E, B >: E](fact: BoundedIterableFactory[B]): BuildFrom[Any, E] { type To = fact.To[E] } = new BuildFrom[Any, E] {
type To = fact.To[E]
def newBuilder(from: Any): Builder[E, To] = fact.newBuilder
def fromIterable(from: Any)(it: Iterable[E]): To = fact.fromIterable(it)
}

/** Convert a ConstrainedIterableFactory to a BuildFrom */
implicit def buildConstrainedIterableFactory[CC[_], Ev[_], E : Ev](fact: ConstrainedIterableFactory[CC, Ev]): BuildFrom[Any, E] { type To = CC[E] } = new BuildFrom[Any, E] {
type To = CC[E]
def newBuilder(from: Any): Builder[E, To] = fact.constrainedNewBuilder
def fromIterable(from: Any)(it: Iterable[E]): To = fact.constrainedFromIterable(it)
}

/** Convert a MapFactory to a BuildFrom */
implicit def buildMapFactory[C[_, _], K, V](fact: MapFactory[C]): BuildFrom[Any, (K, V)] { type To = C[K, V] } = new BuildFrom[Any, (K, V)] {
type To = C[K, V]
def newBuilder(from: Any): Builder[(K, V), To] = fact.newBuilder
def fromIterable(from: Any)(it: Iterable[(K, V)]): To = fact.fromIterable(it)
}

/** Convert a ConstrainedMapFactory to a BuildFrom */
implicit def buildConstrainedMapFactory[CC[_, _], Ev[_], K : Ev, V](fact: ConstrainedMapFactory[CC, Ev]): BuildFrom[Any, (K, V)] { type To = CC[K, V] } = new BuildFrom[Any, (K, V)] {
type To = CC[K, V]
def newBuilder(from: Any): Builder[(K, V), To] = fact.constrainedNewBuilder
def fromIterable(from: Any)(it: Iterable[(K, V)]): To = fact.constrainedFromIterable(it)
}
}
96 changes: 88 additions & 8 deletions src/main/scala/strawman/collection/Iterable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import scala.reflect.ClassTag
import scala.{Any, Array, Boolean, Int, StringContext, Unit}
import java.lang.{String, UnsupportedOperationException}

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

/** Base trait for generic collections */
Expand Down Expand Up @@ -81,16 +81,19 @@ trait IterableOps[+A] extends Any {
/** A view representing the elements of this collection. */
def view: View[A] = View.fromIterator(iterator())

/** Given a collection factory `fi` for collections of type constructor `C`,
* convert this collection to one of type `C[A]`. Example uses:
/** Given a collection factory `fi`, convert this collection to the appropriate
* representation for the current element type `A`. Example uses:
*
* xs.to(List)
* xs.to(ArrayBuffer)
* xs.to(BitSet) // for xs: Iterable[Int]
*/
def to[C[X] <: Iterable[X]](fi: FromIterable[C]): C[A @uncheckedVariance] =
// variance seems sound because `to` could just as well have been added
// as a decorator. We should investigate this further to be sure.
fi.fromIterable(coll)
def to(bf: BuildFrom[Iterable[A], A]): bf.To = bf.fromIterable(coll)(coll)
// Note that `bf` is not implicit. We never want it to be inferred (because a collection could only rebuild itself
// that way) but we do rely on the implicit conversions from the various factory types to BuildFrom.

/** Optimized version of `to(BuildFrom)` */
def to(fi: BoundedIterableFactory[A]): fi.To[A @uncheckedVariance] = fi.fromIterable(coll)

/** Convert collection to array. */
def toArray[B >: A: ClassTag]: Array[B] =
Expand Down Expand Up @@ -172,7 +175,7 @@ trait IterableMonoTransforms[+A, +Repr] extends Any {

/** Transforms over iterables that can return collections of different element types.
*/
trait IterablePolyTransforms[+A, +C[A]] extends Any {
trait IterablePolyTransforms[+A, +C[_]] extends Any {
protected def coll: Iterable[A]
def fromIterable[B](coll: Iterable[B]): C[B]

Expand All @@ -189,3 +192,80 @@ trait IterablePolyTransforms[+A, +C[A]] extends Any {
def zip[B](xs: IterableOnce[B]): C[(A @uncheckedVariance, B)] = fromIterable(View.Zip(coll, xs))
// sound bcs of VarianceNote
}

/** Transforms over iterables that can return collections of different element types for which an implicit
* evidence is required. Every constrained collection type `CC` extends an unconstrained collection type `C`
* (e.g. `SortedSet[X] extends Set[X]`) so it inherits methods from `IterablePolyTransforms` that do not require
* the implicit evidence. These methods can only build a default representation of `C` (e.g. a `HashSet` in the
* case of `Set`). The methods in this trait are the same as the ones in `IterablePolyTransforms` but they do
* require the implicit evidence, so they can build a new instance of `CC`.
*/
trait ConstrainedIterablePolyTransforms[+A, +C[_], +CC[X] <: C[X]] extends Any with IterablePolyTransforms[A, C] {
type Ev[_]

protected def coll: Iterable[A]
protected def constrainedFromIterable[B: Ev](it: Iterable[B]): CC[B]

/** Map */
def map[B : Ev](f: A => B): CC[B] = constrainedFromIterable(View.Map(coll, f))

/** Flatmap */
def flatMap[B : Ev](f: A => IterableOnce[B]): CC[B] = constrainedFromIterable(View.FlatMap(coll, f))

/** Concatenation */
def ++[B >: A : Ev](xs: IterableOnce[B]): CC[B] = constrainedFromIterable(View.Concat(coll, xs))

/** Zip. Interesting because it requires to align to source collections. */
def zip[B](xs: IterableOnce[B])(implicit ev: Ev[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] = constrainedFromIterable(View.Zip(coll, xs))
// sound bcs of VarianceNote

def collect[B: Ev](pf: scala.PartialFunction[A, B]): CC[B] = flatMap(a =>
if (pf.isDefinedAt(a)) View.Elems(pf(a))
else View.Empty
)

/** Widen this collection to the most specific unconstrained collection type. This is required in order to
* call methods from `IterablePolyTransforms` to build a new unconstrained collection when no implicit evidence
* is available. */
def unconstrained: C[A @uncheckedVariance]
}

/** Base trait for strict collections that can be built using a builder.
* @tparam A the element type of the collection
* @tparam Repr the type of the underlying collection
*/
trait MonoBuildable[+A, +Repr] extends Any with IterableMonoTransforms[A, Repr] {

/** Creates a new builder. */
protected[this] def newBuilderWithSameElemType: Builder[A, Repr]

/** Optimized, push-based version of `partition`. */
override def partition(p: A => Boolean): (Repr, Repr) = {
val l, r = newBuilderWithSameElemType
coll.iterator().foreach(x => (if (p(x)) l else r) += x)
(l.result, r.result)
}

// one might also override other transforms here to avoid generating
// iterators if it helps efficiency.
}

/** Base trait for strict collections that can be built for arbitrary element types using a builder.
* @tparam A the element type of the collection
* @tparam C the type constructor of the underlying collection
*/
trait PolyBuildable[+A, +C[_]] extends Any with FromIterable[C] {

/** Creates a new builder. */
def newBuilder[E]: Builder[E, C[E]]
}

/** Base trait for strict collections that can be built using a builder for element types with an implicit evidence.
* @tparam A the element type of the collection
* @tparam C the type constructor of the underlying collection
*/
trait ConstrainedPolyBuildable[+A, +CC[_], Ev[_]] extends Any with ConstrainedFromIterable[CC, Ev] {

/** Creates a new builder. */
def newConstrainedBuilder[E : Ev]: Builder[E, CC[E]]
}
48 changes: 37 additions & 11 deletions src/main/scala/strawman/collection/IterableFactories.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,50 @@ package collection

import strawman.collection.mutable.Builder

import scala.Int
import scala.{Any, Int, Nothing}
import scala.annotation.unchecked.uncheckedVariance

/** Base trait for instances that can construct a collection from an iterable */
trait FromIterable[+C[X] <: Iterable[X]] {
def fromIterable[B](it: Iterable[B]): C[B]
/** Base trait for instances that can construct an unconstrained collection from an iterable */
trait FromIterable[+C[_]] extends Any {
def fromIterable[E](it: Iterable[E]): C[E]
}

/** Base trait for companion objects of collections */
trait IterableFactories[+C[X] <: Iterable[X]] extends FromIterable[C] {
/** Base trait for instances that can construct a collection from an iterable by using an implicit evidence
* for the element type. */
trait ConstrainedFromIterable[+CC[_], Ev[_]] extends Any {
def constrainedFromIterable[E : Ev](it: Iterable[E]): CC[E]
}

/** Base trait for companion objects of collection types that may require an upper bound but no implicit evidence */
trait BoundedIterableFactory[-B] { self =>
/** The result type to build for an element type. This is a type member instead of a type parameter because
* it doesn't have to be a proper type constructor (e.g. in `BitSet` we have `type To[_] = BitSet`). */
type To[_]

def fromIterable[E <: B](it: Iterable[E]): To[E]

def empty[A <: B]: To[A] = fromIterable(View.Empty)

def apply[A <: B](xs: A*): To[A] = fromIterable(View.Elems(xs: _*))

def empty[A]: C[A] = fromIterable(View.Empty)
def fill[A <: B](n: Int)(elem: => A): To[A] = fromIterable(View.Fill(n)(elem))

def newBuilder[A <: B]: Builder[A, To[A]]
}

/** Base trait for companion objects of unconstrained collection types */
trait IterableFactory[+C[_]] extends BoundedIterableFactory[Any] with FromIterable[C] {
type To[X] = C[X] @uncheckedVariance
}

def apply[A](xs: A*): C[A] = fromIterable(View.Elems(xs: _*))
/** Base trait for companion objects of collections that require an implicit evidence */
trait ConstrainedIterableFactory[+CC[X], Ev[_]] extends ConstrainedFromIterable[CC, Ev] {

def fill[A](n: Int)(elem: => A): C[A] = fromIterable(View.Fill(n)(elem))
def empty[A : Ev]: CC[A] = constrainedFromIterable(View.Empty)

def newBuilder[A]: Builder[A, C[A]]
def apply[A : Ev](xs: A*): CC[A] = constrainedFromIterable(View.Elems(xs: _*))

implicit def canBuild[A]: () => Builder[A, C[A]] = () => newBuilder[A] // TODO Reuse the same instance
def fill[A : Ev](n: Int)(elem: => A): CC[A] = constrainedFromIterable(View.Fill(n)(elem))

def constrainedNewBuilder[A : Ev]: Builder[A, CC[A]]
}
24 changes: 19 additions & 5 deletions src/main/scala/strawman/collection/Map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package strawman.collection

import strawman.collection.mutable.Builder

import scala.Option
import scala.{Option, Any, Nothing}
import scala.annotation.unchecked.uncheckedVariance
import scala.Predef.???

Expand Down Expand Up @@ -31,16 +31,30 @@ trait MapPolyTransforms[K, +V, +C[X, Y] <: Map[X, Y]] extends IterablePolyTransf
}

/** Factory methods for collections of kind `* −> * -> *` */
trait MapFactories[C[_, _]] {

trait MapFactory[+C[_, _]] { self =>
def newBuilder[K, V]: Builder[(K, V), C[K, V]]

def fromIterable[K, V](it: Iterable[(K, V)]): C[K, V] =
newBuilder[K, V].++=(it).result

def empty[K, V]: C[K, V] =
newBuilder[K, V].result

def apply[K, V](elems: (K, V)*): C[K, V] =
newBuilder[K, V].++=(elems.toStrawman).result
}

/** Factory methods for collections of kind `* −> * -> *` which require an implicit evidence value for the key type */
trait ConstrainedMapFactory[+C[_, _], Ev[_]] { self =>

implicit def canBuild[K, V]: () => Builder[(K, V), C[K, V]] = () => newBuilder[K, V]
def constrainedNewBuilder[K : Ev, V]: Builder[(K, V), C[K, V]]

}
def constrainedFromIterable[K : Ev, V](it: Iterable[(K, V)]): C[K, V] =
constrainedNewBuilder[K, V].++=(it).result

def empty[K : Ev, V]: C[K, V] =
constrainedNewBuilder[K, V].result

def apply[K : Ev, V](elems: (K, V)*): C[K, V] =
constrainedNewBuilder[K, V].++=(elems.toStrawman).result
}
26 changes: 0 additions & 26 deletions src/main/scala/strawman/collection/Sorted.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package strawman.collection

import strawman.collection.mutable.Builder

import scala.Ordering

/** Base trait for sorted collections */
Expand All @@ -12,28 +10,4 @@ trait SortedLike[A, +Repr] {
def ordering: Ordering[A]

def range(from: A, until: A): Repr

}

/** Polymorphic transformation methods on sorted collections */
trait SortedPolyTransforms[A, +C[X] <: Sorted[X]]
extends IterablePolyTransforms[A, Iterable] {

def map[B](f: A => B)(implicit ordering: Ordering[B]): C[B]

}

/**
* Factories for collections whose elements require an ordering
*/
trait OrderingGuidedFactories[C[_]] {

def newBuilder[A](implicit ordering: Ordering[A]): Builder[A, C[A]]

def empty[A : Ordering]: C[A] = newBuilder[A].result

def apply[A : Ordering](as: A*): C[A] = (newBuilder[A] ++= as.toStrawman).result

implicit def canBuild[A : Ordering]: () => Builder[A, C[A]] = () => newBuilder[A]

}
Loading