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
3 changes: 2 additions & 1 deletion src/main/scala/strawman/collection/ArrayOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ class ArrayOps[A](val xs: Array[A])

def elemTag: ClassTag[A] = ClassTag(xs.getClass.getComponentType)

def iterableFactory = immutable.Seq

protected[this] def fromTaggedIterable[B: ClassTag](coll: Iterable[B]): Array[B] = coll.toArray[B]
protected[this] def fromSpecificIterable(coll: Iterable[A]): Array[A] = coll.toArray[A](elemTag)
protected[this] def fromIterable[B](coll: Iterable[B]): immutable.Seq[B] = immutable.Seq.fromIterable(coll)

protected[this] def newBuilder = new ArrayBuffer[A].mapResult(_.toArray(elemTag))

Expand Down
44 changes: 25 additions & 19 deletions src/main/scala/strawman/collection/Factories.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package strawman
package collection

import scala.{Any, Int, Ordering, Nothing}
import strawman.collection.mutable.Builder

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

/**
Expand All @@ -26,6 +28,10 @@ trait IterableFactory[+CC[_]] {

}

trait IterableFactoryWithBuilder[+CC[_]] extends IterableFactory[CC] {
def newBuilder[A](): Builder[A, CC[A]]
}
Copy link
Contributor

@julienrf julienrf May 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As explained in the comment at the bottom of the diff, it would be useful to have more power and also add the following method:

implicit def canBuild[A]: CanBuild[A, CC[A]] = () => newBuilder[A]

Where CanBuild is the type defined in #80. If we add this line and if we also add XxxWithBuilder factories for the other kind of factories (SortedIterable, Map and SortedMap), we would be able to implement the tests given in #80.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented this suggestion in #91.


object IterableFactory {
import scala.language.implicitConversions

Expand Down Expand Up @@ -74,54 +80,54 @@ object MapFactory {
}

/** Base trait for companion objects of collections that require an implicit evidence */
trait OrderedIterableFactory[+CC[_]] {
trait SortedIterableFactory[+CC[_]] {

def orderedFromIterable[E : Ordering](it: Iterable[E]): CC[E]
def sortedFromIterable[E : Ordering](it: Iterable[E]): CC[E]

def empty[A : Ordering]: CC[A]

def apply[A : Ordering](xs: A*): CC[A] = orderedFromIterable(View.Elems(xs: _*))
def apply[A : Ordering](xs: A*): CC[A] = sortedFromIterable(View.Elems(xs: _*))

def fill[A : Ordering](n: Int)(elem: => A): CC[A] = orderedFromIterable(View.Fill(n)(elem))
def fill[A : Ordering](n: Int)(elem: => A): CC[A] = sortedFromIterable(View.Fill(n)(elem))
}

object OrderedIterableFactory {
object SortedIterableFactory {
import scala.language.implicitConversions

implicit def toSpecific[A: Ordering, CC[_]](factory: OrderedIterableFactory[CC]): FromSpecificIterable[A, CC[A]] =
implicit def toSpecific[A: Ordering, CC[_]](factory: SortedIterableFactory[CC]): FromSpecificIterable[A, CC[A]] =
new FromSpecificIterable[A, CC[A]] {
def fromSpecificIterable(it: Iterable[A]): CC[A] = factory.orderedFromIterable[A](it)
def fromSpecificIterable(it: Iterable[A]): CC[A] = factory.sortedFromIterable[A](it)
}

class Delegate[CC[_]](delegate: OrderedIterableFactory[CC]) extends OrderedIterableFactory[CC] {
class Delegate[CC[_]](delegate: SortedIterableFactory[CC]) extends SortedIterableFactory[CC] {
def empty[A : Ordering]: CC[A] = delegate.empty
def orderedFromIterable[E : Ordering](it: Iterable[E]): CC[E] = delegate.orderedFromIterable(it)
def sortedFromIterable[E : Ordering](it: Iterable[E]): CC[E] = delegate.sortedFromIterable(it)
}

}

/** Factory methods for collections of kind `* −> * -> *` which require an implicit evidence value for the key type */
trait OrderedMapFactory[+CC[X, Y]] {
trait SortedMapFactory[+CC[X, Y]] {

def empty[K : Ordering, V]: CC[K, V]

def orderedFromIterable[K : Ordering, V](it: Iterable[(K, V)]): CC[K, V]
def sortedFromIterable[K : Ordering, V](it: Iterable[(K, V)]): CC[K, V]

def apply[K : Ordering, V](elems: (K, V)*): CC[K, V] =
orderedFromIterable(elems.toStrawman)
sortedFromIterable(elems.toStrawman)
}

object OrderedMapFactory {
object SortedMapFactory {
import scala.language.implicitConversions

implicit def toSpecific[K : Ordering, V, CC[_, _]](factory: OrderedMapFactory[CC]): FromSpecificIterable[(K, V), CC[K, V]] =
implicit def toSpecific[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]): FromSpecificIterable[(K, V), CC[K, V]] =
new FromSpecificIterable[(K, V), CC[K, V]] {
def fromSpecificIterable(it: Iterable[(K, V)]): CC[K, V] = factory.orderedFromIterable(it)
def fromSpecificIterable(it: Iterable[(K, V)]): CC[K, V] = factory.sortedFromIterable(it)
}

class Delegate[CC[_, _]](delegate: OrderedMapFactory[CC]) extends OrderedMapFactory[CC] {
class Delegate[CC[_, _]](delegate: SortedMapFactory[CC]) extends SortedMapFactory[CC] {
def empty[K: Ordering, V]: CC[K, V] = delegate.empty[K, V]
def orderedFromIterable[K: Ordering, V](it: Iterable[(K, V)]): CC[K, V] = delegate.orderedFromIterable(it)
def sortedFromIterable[K: Ordering, V](it: Iterable[(K, V)]): CC[K, V] = delegate.sortedFromIterable(it)
}

}
}
6 changes: 5 additions & 1 deletion src/main/scala/strawman/collection/Iterable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterabl
trait IterableOps[+A, +CC[X], +C] extends Any {

protected def coll: Iterable[A]

protected[this] def fromSpecificIterable(coll: Iterable[A]): C
protected[this] def fromIterable[E](it: Iterable[E]): CC[E]

def iterableFactory: IterableFactory[CC]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a tempting design that I considered on several occasions but always backed out because that factory is limited to building unconstrained unary types. It looks promising the way it's used here. I'll have to take a closer look for potential problems I ran into when I tried it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I’d also like to stress that the solution proposed in this PR is very simple but does not support the use cases described in #65 and might require substantial changes to support scala/scala#5233.


protected[this] def fromIterable[E](it: Iterable[E]): CC[E] = iterableFactory.fromIterable(it)

/** Apply `f` to each element for its side effects
* Note: [U] parameter needed to help scalac's type inference.
Expand Down
12 changes: 6 additions & 6 deletions src/main/scala/strawman/collection/SortedMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, C
extends MapOps[K, V, Map, C]
with SortedOps[K, C] {

protected[this] def orderedMapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2]
protected[this] def sortedMapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2]

def firstKey: K = head._1
def lastKey: K = last._1

// And finally, we add new overloads taking an ordering
def map[K2, V2](f: ((K, V)) => (K2, V2))(implicit ordering: Ordering[K2]): CC[K2, V2] =
orderedMapFromIterable(View.Map[(K, V), (K2, V2)](coll, f))
sortedMapFromIterable(View.Map[(K, V), (K2, V2)](coll, f))

def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] =
orderedMapFromIterable(View.FlatMap(coll, f))
sortedMapFromIterable(View.FlatMap(coll, f))

/** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
* right hand operand. The element type of the $coll is the most specific superclass encompassing
Expand All @@ -36,16 +36,16 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, C
* @return a new collection of type `CC[K2, V2]` which contains all elements
* of this $coll followed by all elements of `xs`.
*/
def concat[K2 >: K, V2 >: V](xs: IterableOnce[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = orderedMapFromIterable(View.Concat(coll, xs))
def concat[K2 >: K, V2 >: V](xs: IterableOnce[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = sortedMapFromIterable(View.Concat(coll, xs))

/** Alias for `concat` */
@`inline` final def ++ [K2 >: K, V2 >: V](xs: IterableOnce[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = concat(xs)

// We override these methods to fix their return type (which would be `Map` otherwise)
override def concat[V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = orderedMapFromIterable(View.Concat(coll, xs))
override def concat[V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = sortedMapFromIterable(View.Concat(coll, xs))
override def ++ [V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = concat(xs)
// TODO Also override mapValues

}

object SortedMap extends OrderedMapFactory.Delegate[SortedMap](TreeMap)
object SortedMap extends SortedMapFactory.Delegate[SortedMap](TreeMap)
10 changes: 5 additions & 5 deletions src/main/scala/strawman/collection/SortedSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ trait SortedSetOps[A, +CC[X], +C <: SortedSet[A]]
extends SetOps[A, Set, C]
with SortedOps[A, C] {

protected[this] def orderedFromIterable[B: Ordering](it: Iterable[B]): CC[B]
protected[this] def sortedFromIterable[B: Ordering](it: Iterable[B]): CC[B]

def firstKey: A = head
def lastKey: A = last

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

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

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

def collect[B: Ordering](pf: scala.PartialFunction[A, B]): CC[B] = flatMap(a =>
Expand All @@ -32,4 +32,4 @@ trait SortedSetOps[A, +CC[X], +C <: SortedSet[A]]
)
}

object SortedSet extends OrderedIterableFactory.Delegate[SortedSet](immutable.SortedSet)
object SortedSet extends SortedIterableFactory.Delegate[SortedSet](immutable.SortedSet)
2 changes: 1 addition & 1 deletion src/main/scala/strawman/collection/StringOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class StringOps(val s: String)
sb.result
}

protected[this] def fromIterable[E](coll: Iterable[E]): List[E] = List.fromIterable(coll)
def iterableFactory = List

protected[this] def newBuilder = new StringBuilder

Expand Down
19 changes: 13 additions & 6 deletions src/main/scala/strawman/collection/View.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,30 @@ import scala.Predef.intWrapper
trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] {
override def view = this

/** Avoid copying if source collection is already a view. */
override def fromIterable[B](c: Iterable[B]): View[B] = c match {
case c: View[B] => c
case _ => View.fromIterator(c.iterator())
}
def iterableFactory = View

override protected[this] def fromSpecificIterable(coll: Iterable[A]): View[A] =
fromIterable(coll)

override def className = "View"
}

/** This object reifies operations on views as case classes */
object View {
object View extends IterableFactory[View] {

def fromIterator[A](it: => Iterator[A]): View[A] = new View[A] {
def iterator() = it
}

/** Avoid copying if source collection is already a view. */
def fromIterable[E](it: Iterable[E]): View[E] = it match {
case it: View[E] => it
case _ => View.fromIterator(it.iterator())
}

def empty[A]: View[A] = Empty
override def apply[A](xs: A*): View[A] = Elems(xs: _*)

/** The empty view */
case object Empty extends View[Nothing] {
def iterator() = Iterator.empty
Expand Down
5 changes: 3 additions & 2 deletions src/main/scala/strawman/collection/immutable/BitSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ sealed abstract class BitSet

def empty: BitSet = BitSet.empty

protected[this] def fromIterable[B](coll: collection.Iterable[B]): Set[B] = Set.fromIterable(coll)
def iterableFactory = Set

protected[this] def fromSpecificIterable(coll: collection.Iterable[Int]): BitSet = BitSet.fromSpecificIterable(coll)
protected[this] def orderedFromIterable[B : Ordering](it: collection.Iterable[B]): SortedSet[B] = SortedSet.orderedFromIterable(it)
protected[this] def sortedFromIterable[B : Ordering](it: collection.Iterable[B]): SortedSet[B] = SortedSet.sortedFromIterable(it)


protected[collection] def fromBitMaskNoCopy(elems: Array[Long]): BitSet = BitSet.fromBitMaskNoCopy(elems)
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/strawman/collection/immutable/HashMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ sealed trait HashMap[K, +V]

import HashMap.{bufferSize, liftMerger, Merger, MergeFunction, nullToEmpty}

protected[this] def fromIterable[E](it: collection.Iterable[E]): Iterable[E] = List.fromIterable(it)
def iterableFactory = List

protected[this] def fromSpecificIterable(coll: collection.Iterable[(K, V)]): HashMap[K, V] = HashMap.fromIterable(coll)

Expand Down
5 changes: 3 additions & 2 deletions src/main/scala/strawman/collection/immutable/HashSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ sealed trait HashSet[A]

import HashSet.nullToEmpty

protected[this] def fromIterable[B](coll: collection.Iterable[B]): HashSet[B] = HashSet.fromIterable(coll)
def iterableFactory = HashSet

protected[this] def fromSpecificIterable(coll: collection.Iterable[A]): HashSet[A] = fromIterable(coll)

def contains(elem: A): Boolean = get0(elem, computeHash(elem), 0)
Expand Down Expand Up @@ -59,7 +60,7 @@ object HashSet extends IterableFactory[HashSet] {
case _ => empty ++ it
}

def empty[A <: Any]: HashSet[A] = EmptyHashSet.asInstanceOf[HashSet[A]]
def empty[A]: HashSet[A] = EmptyHashSet.asInstanceOf[HashSet[A]]

private object EmptyHashSet extends HashSet[Any] {

Expand Down
5 changes: 2 additions & 3 deletions src/main/scala/strawman/collection/immutable/LazyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class LazyList[+A](expr: => LazyList.Evaluated[A])

def #:: [B >: A](elem: => B): LazyList[B] = new LazyList(Some((elem, this)))

protected[this] def fromIterable[B](coll: collection.Iterable[B]): LazyList[B] = LazyList.fromIterable(coll)
def iterableFactory = LazyList

protected[this] def fromSpecificIterable(coll: collection.Iterable[A]): LazyList[A] = fromIterable(coll)

override def className = "LazyList"
Expand Down Expand Up @@ -64,7 +65,5 @@ object LazyList extends IterableFactory[LazyList] {
def fromIterator[A](it: Iterator[A]): LazyList[A] =
new LazyList(if (it.hasNext) Some(it.next(), fromIterator(it)) else None)

def newBuilder[A]: Builder[A, LazyList[A]] = ???

def empty[A]: LazyList[A] = new LazyList[A](None)
}
10 changes: 5 additions & 5 deletions src/main/scala/strawman/collection/immutable/List.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ sealed trait List[+A]
with SeqOps[A, List, List[A]]
with Buildable[A, List[A]] {

protected[this] def fromIterable[B](c: collection.Iterable[B]): List[B] = List.fromIterable(c)
def iterableFactory = List

protected[this] def fromSpecificIterable(coll: collection.Iterable[A]): List[A] = fromIterable(coll)

protected[this] def newBuilder = List.newBuilder[A]
Expand Down Expand Up @@ -54,15 +55,14 @@ case object Nil extends List[Nothing] {
override def tail: Nothing = throw new UnsupportedOperationException("tail of empty list")
}

object List extends IterableFactory[List] {
object List extends IterableFactoryWithBuilder[List] {

def fromIterable[B](coll: collection.Iterable[B]): List[B] = coll match {
case coll: List[B] => coll
case _ => ListBuffer.fromIterable(coll).toList
}

def newBuilder[A]: Builder[A, List[A]] = new ListBuffer[A].mapResult(_.toList)

def empty[A <: Any]: List[A] = Nil
def newBuilder[A](): Builder[A, List[A]] = new ListBuffer[A].mapResult(_.toList)

def empty[A]: List[A] = Nil
}
2 changes: 1 addition & 1 deletion src/main/scala/strawman/collection/immutable/ListMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ sealed class ListMap[K, +V]
with MapOps[K, V, ListMap, ListMap[K, V]]
with Serializable {

protected[this] def fromIterable[E](it: collection.Iterable[E]): Iterable[E] = List.fromIterable(it)
def iterableFactory = List

protected[this] def mapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)]): ListMap[K2,V2] = ListMap.fromIterable(it)

Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/strawman/collection/immutable/ListSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ sealed class ListSet[A]

def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]]

protected[this] def fromIterable[B](coll: collection.Iterable[B]): ListSet[B] = ListSet.fromIterable(coll)
def iterableFactory = ListSet
protected[this] def fromSpecificIterable(coll: collection.Iterable[A]): ListSet[A] = fromIterable(coll)

/**
Expand Down Expand Up @@ -122,7 +122,7 @@ object ListSet extends IterableFactory[ListSet] {
private object EmptyListSet extends ListSet[Any]
private[collection] def emptyInstance: ListSet[Any] = EmptyListSet

def empty[A <: Any]: ListSet[A] = EmptyListSet.asInstanceOf[ListSet[A]]
def empty[A]: ListSet[A] = EmptyListSet.asInstanceOf[ListSet[A]]

}

9 changes: 9 additions & 0 deletions src/main/scala/strawman/collection/immutable/SortedMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@ trait SortedMapOps[K, +V, +CC[X, +Y] <: SortedMap[X, Y] with SortedMapOps[X, Y,
extends MapOps[K, V, Map, C]
with collection.SortedMapOps[K, V, CC, C] {

protected[this] def coll: CC[K, V]

protected def mapFromIterable[K2, V2](it: collection.Iterable[(K2, V2)]): Map[K2, V2] =
Map.fromIterable(it)

// We override these methods to fix their return type (which would be `Map` otherwise)
def updated[V1 >: V](key: K, value: V1): CC[K, V1]
override def + [V1 >: V](kv: (K, V1)): CC[K, V1] = updated(kv._1, kv._2)

override def concat[V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = {
var result: CC[K, V2] = coll
val it = xs.iterator()
while (it.hasNext) result = result + it.next()
result
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ trait SortedSetOps[A,
extends SetOps[A, Set, C]
with collection.SortedSetOps[A, CC, C]

object SortedSet extends OrderedIterableFactory.Delegate[SortedSet](TreeSet)
object SortedSet extends SortedIterableFactory.Delegate[SortedSet](TreeSet)
Loading