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

Commit 4efa362

Browse files
committed
wip
1 parent 021f874 commit 4efa362

File tree

10 files changed

+137
-36
lines changed

10 files changed

+137
-36
lines changed

src/main/scala/strawman/collection/Factories.scala

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,36 @@ import strawman.collection.mutable.Builder
66
import scala.{Any, Int, Nothing, Ordering}
77
import scala.annotation.unchecked.uncheckedVariance
88

9+
trait BuildFrom[-From, -A, +C] extends Any {
10+
def fromSpecificIterable(from: From)(it: Iterable[A]): C
11+
}
12+
13+
trait StrictBuildFrom[-From, -A, +C] extends Any with BuildFrom[From, A, C] {
14+
def newBuilder(from: From): Builder[A, C]
15+
}
16+
17+
object StrictBuildFrom {
18+
/** Build the source collection type from an IterableOps */
19+
implicit def buildFromIterableOps[C[X] <: IterableOps[X, C, _], A, E]: StrictBuildFrom[C[A], E, C[E]] = new StrictBuildFrom[C[A], E, C[E]] {
20+
//TODO: Reuse a prototype instance
21+
def newBuilder(from: C[A]): Builder[E, C[E]] = Builder.surrogateBuilder(from.iterableFactory)
22+
def fromSpecificIterable(from: C[A])(it: Iterable[E]): C[E] = from.iterableFactory.fromIterable(it)
23+
}
24+
25+
/** Build the source collection type from an Iterable with SortedOps */
26+
implicit def buildFromSortedOps[C[X] <: Iterable[X] with SortedOps[X, C[X], C], A, E : Ordering]: StrictBuildFrom[C[A], E, C[E]] = new StrictBuildFrom[C[A], E, C[E]] {
27+
def newBuilder(from: C[A]): Builder[E, C[E]] = Builder.surrogateBuilder(from.sortedIterableFactory)
28+
def fromSpecificIterable(from: C[A])(it: Iterable[E]): C[E] = from.sortedIterableFactory.fromSpecificIterable(it)
29+
}
30+
}
31+
932
/**
1033
* Builds a collection of type `C` from elements of type `A`
1134
* @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
1235
* @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
1336
*/
14-
trait FromSpecificIterable[-A, +C] extends Any {
37+
trait FromSpecificIterable[-A, +C] extends Any with BuildFrom[Any, A, C] {
38+
def fromSpecificIterable(from: Any)(it: Iterable[A]): C = fromSpecificIterable(it)
1539
def fromSpecificIterable(it: Iterable[A]): C
1640
}
1741

@@ -91,6 +115,10 @@ trait SortedIterableFactory[+CC[_]] {
91115
def fill[A : Ordering](n: Int)(elem: => A): CC[A] = sortedFromIterable(View.Fill(n)(elem))
92116
}
93117

118+
trait SortedIterableFactoryWithBuilder[+CC[_]] extends SortedIterableFactory[CC] {
119+
def newBuilder[A : Ordering](): Builder[A, CC[A]]
120+
}
121+
94122
object SortedIterableFactory {
95123
import scala.language.implicitConversions
96124

src/main/scala/strawman/collection/SortedMap.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ trait SortedMap[K, +V]
1212

1313
trait SortedMapOps[K, +V, +CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMap[K, V]]
1414
extends MapOps[K, V, Map, C]
15-
with SortedOps[K, C] {
15+
with SortedOps[K, C, SortedSet] {
16+
17+
def sortedIterableFactory = SortedSet
1618

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

src/main/scala/strawman/collection/SortedOps.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package strawman.collection
33
import scala.{Ordering, Option, Some}
44

55
/** Base trait for sorted collections */
6-
trait SortedOps[A, +C] {
6+
trait SortedOps[A, +C, +CC[_]] {
77

88
implicit def ordering: Ordering[A]
99

10+
def sortedIterableFactory: SortedIterableFactory[CC]
11+
1012
/** Returns the first key of the collection. */
1113
def firstKey: A
1214

src/main/scala/strawman/collection/SortedSet.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ trait SortedSet[A] extends Set[A] with SortedSetOps[A, SortedSet, SortedSet[A]]
99

1010
trait SortedSetOps[A, +CC[X], +C <: SortedSet[A]]
1111
extends SetOps[A, Set, C]
12-
with SortedOps[A, C] {
12+
with SortedOps[A, C, CC] {
1313

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

src/main/scala/strawman/collection/immutable/BitSet.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ sealed abstract class BitSet
2727
def empty: BitSet = BitSet.empty
2828

2929
def iterableFactory = Set
30+
def sortedIterableFactory = SortedSet
3031

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

src/main/scala/strawman/collection/immutable/TreeSet.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package strawman
22
package collection
33
package immutable
44

5-
import mutable.Builder
5+
import mutable.{ArrayBuffer, Builder}
66
import immutable.{RedBlackTree => RB}
77

88
import scala.{Boolean, Int, NullPointerException, Option, Ordering, Some, Unit}
@@ -63,6 +63,8 @@ final class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: O
6363

6464
def iterableFactory = Set
6565

66+
def sortedIterableFactory = TreeSet
67+
6668
protected[this] def fromSpecificIterable(coll: strawman.collection.Iterable[A]): TreeSet[A] =
6769
TreeSet.sortedFromIterable(coll)
6870

@@ -103,7 +105,7 @@ final class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: O
103105
else newSet(RB.delete(tree, elem))
104106
}
105107

106-
object TreeSet extends SortedIterableFactory[TreeSet] {
108+
object TreeSet extends SortedIterableFactoryWithBuilder[TreeSet] {
107109

108110
def empty[A: Ordering]: TreeSet[A] = new TreeSet[A]
109111

@@ -113,4 +115,5 @@ object TreeSet extends SortedIterableFactory[TreeSet] {
113115
case _ => empty[E] ++ it
114116
}
115117

118+
def newBuilder[A : Ordering](): Builder[A, TreeSet[A]] = new ArrayBuffer[A].mapResult(sortedFromIterable[A] _)
116119
}

src/main/scala/strawman/collection/mutable/BitSet.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class BitSet(protected[collection] final var elems: Array[Long])
3636

3737
def iterableFactory = Set
3838

39+
def sortedIterableFactory = SortedSet
40+
3941
protected[this] def sortedFromIterable[B : Ordering](it: collection.Iterable[B]): collection.mutable.SortedSet[B] =
4042
collection.mutable.SortedSet.sortedFromIterable(it)
4143

src/main/scala/strawman/collection/mutable/Builder.scala

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package strawman.collection.mutable
22

3-
import scala.{Boolean, Any, Char, Unit}
3+
import scala.{Any, Boolean, Char, Unit}
44
import java.lang.String
5-
import strawman.collection.IterableOnce
5+
6+
import strawman.collection.{IterableFactory, IterableFactoryWithBuilder, IterableOnce, SortedIterableFactory}
7+
8+
import scala.math.Ordering
69

710
/** Base trait for collection builders */
811
trait Builder[-A, +To] extends Growable[A] { self =>
@@ -24,6 +27,19 @@ trait Builder[-A, +To] extends Growable[A] { self =>
2427
}
2528
}
2629

30+
object Builder {
31+
/** Get a proper builder for an IterableFactoryWithBuilder, otherwise a Builder that uses an intermediate
32+
* ArrayBuffer to store the elements. */
33+
def surrogateBuilder[A, CC[_]](fact: IterableFactory[CC]): Builder[A, CC[A]] = fact match {
34+
case fact: IterableFactoryWithBuilder[CC] => fact.newBuilder[A]()
35+
case fact => new ArrayBuffer[A]().mapResult(fact.fromIterable _)
36+
}
37+
def surrogateBuilder[A : Ordering, CC[_]](fact: SortedIterableFactory[CC]): Builder[A, CC[A]] = fact match {
38+
case fact: IterableFactoryWithBuilder[CC] => fact.newBuilder[A]()
39+
case fact => new ArrayBuffer[A]().mapResult(fact.sortedFromIterable[A] _)
40+
}
41+
}
42+
2743
class StringBuilder extends Builder[Char, String] {
2844
private val sb = new java.lang.StringBuilder
2945

src/main/scala/strawman/collection/mutable/TreeSet.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package strawman
22
package collection.mutable
33

4-
import collection.SortedIterableFactory
4+
import collection.SortedIterableFactoryWithBuilder
55
import collection.mutable.{RedBlackTree => RB}
66

77
import scala.{Boolean, Int, None, Null, NullPointerException, Option, Ordering, Serializable, SerialVersionUID, Some, Unit}
@@ -45,6 +45,8 @@ sealed class TreeSet[A] private (tree: RB.Tree[A, Null])(implicit val ordering:
4545

4646
def iterableFactory = Set
4747

48+
def sortedIterableFactory = TreeSet
49+
4850
def keysIteratorFrom(start: A): collection.Iterator[A] = RB.keysIterator(tree, Some(start))
4951

5052
def empty: TreeSet[A] = TreeSet.empty
@@ -175,10 +177,11 @@ sealed class TreeSet[A] private (tree: RB.Tree[A, Null])(implicit val ordering:
175177
* @author Lucien Pereira
176178
*
177179
*/
178-
object TreeSet extends SortedIterableFactory[TreeSet] {
180+
object TreeSet extends SortedIterableFactoryWithBuilder[TreeSet] {
179181

180182
def empty[A : Ordering]: TreeSet[A] = new TreeSet[A]()
181183

182184
def sortedFromIterable[E : Ordering](it: collection.Iterable[E]): TreeSet[E] = Growable.fromIterable(empty[E], it)
183185

186+
def newBuilder[A : Ordering](): Builder[A, TreeSet[A]] = new ArrayBuffer[A].mapResult(sortedFromIterable[A] _)
184187
}

src/test/scala/strawman/collection/test/TraverseTest.scala

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,95 @@ package strawman
33
package collection.test
44

55
import org.junit.Test
6-
import strawman.collection.Iterable
7-
import strawman.collection.mutable.{ArrayBuffer, Builder, Growable}
86
import strawman.collection._
7+
import strawman.collection.mutable.{ArrayBuffer, Builder, Growable}
98

109
import scala.{Any, Either, Int, Left, None, Option, Right, Some, Unit}
10+
import java.lang.String
1111
import scala.Predef.ArrowAssoc
1212
import scala.math.Ordering
13-
import java.lang.String
1413

1514
class TraverseTest {
1615

17-
def optionSequence[CC[X] <: Iterable[X] with IterableOps[X, CC, _], A](xs: CC[Option[A]]): Option[CC[A]] = {
18-
def folder[F[X] <: Growable[X]]: (Option[F[A]], Option[A]) => Option[F[A]] = { (bo, xo) =>
19-
(bo, xo) match {
20-
case (Some(builder), Some(a)) => Some(builder += a)
21-
case _ => None
22-
}
23-
}
24-
val factory = xs.iterableFactory
25-
factory match {
26-
case iterableBuilder: IterableFactoryWithBuilder[CC] =>
27-
xs.foldLeft[Option[Builder[A, CC[A]]]](
28-
Some(iterableBuilder.newBuilder[A]())
29-
)(
30-
folder[({ type l[X] = Builder[X, CC[X]] })#l]
31-
).map(_.result)
32-
case _ =>
33-
xs.foldLeft[Option[ArrayBuffer[A]]](Some(new ArrayBuffer[A]))(folder).map(_.to(xs.iterableFactory))
34-
}
35-
}
16+
// You can either overload methods for IterableOps and Iterable with SortedOps (if you want to support constrained collection types)
17+
def optionSequence1[C[X] <: IterableOps[X, C, _], A](xs: C[Option[A]]): Option[C[A]] =
18+
xs.foldLeft[Option[Builder[A, C[A]]]](Some(Builder.surrogateBuilder[A, C](xs.iterableFactory))) {
19+
case (Some(builder), Some(a)) => Some(builder += a)
20+
case _ => None
21+
}.map(_.result)
22+
def optionSequence1[C[X] <: Iterable[X] with SortedOps[X, C[X], C], A : Ordering](xs: C[Option[A]]): Option[C[A]] =
23+
xs.foldLeft[Option[Builder[A, C[A]]]](Some(Builder.surrogateBuilder[A, C](xs.sortedIterableFactory))) {
24+
case (Some(builder), Some(a)) => Some(builder += a)
25+
case _ => None
26+
}.map(_.result)
27+
28+
// ...or use BuildFrom to abstract over both and also allow building arbitrary collection types
29+
def optionSequence2[CC[X] <: Iterable[X], A, To](xs: CC[Option[A]])(implicit bf: StrictBuildFrom[CC[Option[A]], A, To]): Option[To] =
30+
xs.foldLeft[Option[Builder[A, To]]](Some(bf.newBuilder(xs))) {
31+
case (Some(builder), Some(a)) => Some(builder += a)
32+
case _ => None
33+
}.map(_.result)
3634

3735
@Test
3836
def optionSequence1Test: Unit = {
3937
val xs1 = immutable.List(Some(1), None, Some(2))
40-
val o1 = optionSequence(xs1)
38+
val o1 = optionSequence1(xs1)
4139
val o1t: Option[immutable.List[Int]] = o1
4240

43-
val xs2: immutable.Set[Option[String]] = immutable.TreeSet(Some("foo"), Some("bar"), None)
44-
val o2 = optionSequence(xs2)
41+
val xs2: immutable.TreeSet[Option[String]] = immutable.TreeSet(Some("foo"), Some("bar"), None)
42+
val o2 = optionSequence1(xs2)
4543
val o2t: Option[immutable.Set[String]] = o2
4644

4745
val xs4 = immutable.List[Option[(Int, String)]](Some((1 -> "a")), Some((2 -> "b")))
48-
val o4 = optionSequence(xs4)
46+
val o4 = optionSequence1(xs4)
4947
val o4t: Option[immutable.List[(Int, String)]] = o4
5048
val o5: Option[immutable.TreeMap[Int, String]] = o4.map(_.to(immutable.TreeMap))
5149
}
5250

51+
def optionSequence2Test: Unit = {
52+
val xs1 = immutable.List(Some(1), None, Some(2))
53+
val o1 = optionSequence2(xs1)
54+
val o1t: Option[immutable.List[Int]] = o1
55+
56+
val xs2 = immutable.TreeSet(Some("foo"), Some("bar"), None)
57+
val o2 = optionSequence2(xs2)
58+
val o2t: Option[immutable.TreeSet[String]] = o2
59+
60+
// Breakout-like use case from https://github.com/scala/scala/pull/5233:
61+
val xs4 = immutable.List[Option[(Int, String)]](Some((1 -> "a")), Some((2 -> "b")))
62+
val o4 = optionSequence2(xs4)(immutable.TreeMap) // same syntax as in `.to`
63+
val o4t: Option[immutable.TreeMap[Int, String]] = o4
64+
}
65+
66+
/*
67+
68+
def eitherSequence[C[X] <: Iterable[X], A, B](xs: C[Either[A, B]])(implicit bf: BuildFrom[xs.type, B]): Either[A, bf.To] =
69+
xs.foldLeft[Either[A, Builder[B, bf.To]]](Right(bf.newBuilder(xs))) {
70+
case (Right(builder), Right(b)) => Right(builder += b)
71+
case (Left(a) , _) => Left(a)
72+
case (_ , Left(a)) => Left(a)
73+
}.map(_.result)
74+
75+
def optionSequenceTest: Unit = {
76+
val xs1 = immutable.List(Some(1), None, Some(2))
77+
val o1 = optionSequence(xs1)
78+
val o1t: Option[immutable.List[Int]] = o1
79+
80+
val xs2 = immutable.TreeSet(Some("foo"), Some("bar"), None)
81+
val o2 = optionSequence(xs2)
82+
val o2t: Option[immutable.TreeSet[String]] = o2
83+
84+
// Breakout-like use case from https://github.com/scala/scala/pull/5233:
85+
val xs4 = immutable.List[Option[(Int, String)]](Some((1 -> "a")), Some((2 -> "b")))
86+
val o4 = optionSequence(xs4)(immutable.TreeMap) // same syntax as in `.to`
87+
val o4t: Option[immutable.TreeMap[Int, String]] = o4
88+
}
89+
90+
def eitherSequenceTest: Unit = {
91+
val xs3 = mutable.ListBuffer(Right("foo"), Left(0), Right("bar"))
92+
val e1 = eitherSequence(xs3)
93+
val e1t: Either[Int, mutable.ListBuffer[String]] = e1
94+
}
95+
*/
96+
5397
}

0 commit comments

Comments
 (0)