Skip to content

Commit 9e11c6a

Browse files
committed
Add BuildFrom.scala to stdlib
1 parent db21d64 commit 9e11c6a

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala.collection
14+
15+
import scala.annotation.implicitNotFound
16+
import scala.collection.mutable.Builder
17+
import scala.collection.immutable.WrappedString
18+
import scala.reflect.ClassTag
19+
20+
/** Builds a collection of type `C` from elements of type `A` when a source collection of type `From` is available.
21+
* Implicit instances of `BuildFrom` are available for all collection types.
22+
*
23+
* @tparam From Type of source collection
24+
* @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
25+
* @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
26+
*/
27+
@implicitNotFound(msg = "Cannot construct a collection of type ${C} with elements of type ${A} based on a collection of type ${From}.")
28+
trait BuildFrom[-From, -A, +C] extends Any { self =>
29+
def fromSpecific(from: From)(it: IterableOnce[A]): C
30+
31+
/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
32+
* Building collections with `fromSpecific` is preferred because it can be lazy for lazy collections. */
33+
def newBuilder(from: From): Builder[A, C]
34+
35+
@deprecated("Use newBuilder() instead of apply()", "2.13.0")
36+
@`inline` def apply(from: From): Builder[A, C] = newBuilder(from)
37+
38+
/** Partially apply a BuildFrom to a Factory */
39+
def toFactory(from: From): Factory[A, C] = new Factory[A, C] {
40+
def fromSpecific(it: IterableOnce[A]): C = self.fromSpecific(from)(it)
41+
def newBuilder: Builder[A, C] = self.newBuilder(from)
42+
}
43+
}
44+
45+
object BuildFrom extends BuildFromLowPriority1 {
46+
47+
/** Build the source collection type from a MapOps */
48+
implicit def buildFromMapOps[CC[X, Y] <: Map[X, Y] with MapOps[X, Y, CC, _], K0, V0, K, V]: BuildFrom[CC[K0, V0] with Map[K0, V0], (K, V), CC[K, V] with Map[K, V]] = new BuildFrom[CC[K0, V0], (K, V), CC[K, V]] {
49+
//TODO: Reuse a prototype instance
50+
def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: MapOps[K0, V0, CC, _]).mapFactory.newBuilder[K, V]
51+
def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: MapOps[K0, V0, CC, _]).mapFactory.from(it)
52+
}
53+
54+
/** Build the source collection type from a SortedMapOps */
55+
implicit def buildFromSortedMapOps[CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, CC, _], K0, V0, K : Ordering, V]: BuildFrom[CC[K0, V0] with SortedMap[K0, V0], (K, V), CC[K, V] with SortedMap[K, V]] = new BuildFrom[CC[K0, V0], (K, V), CC[K, V]] {
56+
def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.newBuilder[K, V]
57+
def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.from(it)
58+
}
59+
60+
implicit def buildFromBitSet[C <: BitSet with BitSetOps[C]]: BuildFrom[C, Int, C] =
61+
new BuildFrom[C, Int, C] {
62+
def fromSpecific(from: C)(it: IterableOnce[Int]): C = from.bitSetFactory.fromSpecific(it)
63+
def newBuilder(from: C): Builder[Int, C] = from.bitSetFactory.newBuilder
64+
}
65+
66+
implicit val buildFromString: BuildFrom[String, Char, String] =
67+
new BuildFrom[String, Char, String] {
68+
def fromSpecific(from: String)(it: IterableOnce[Char]): String = Factory.stringFactory.fromSpecific(it)
69+
def newBuilder(from: String): Builder[Char, String] = Factory.stringFactory.newBuilder
70+
}
71+
72+
implicit val buildFromWrappedString: BuildFrom[WrappedString, Char, WrappedString] =
73+
new BuildFrom[WrappedString, Char, WrappedString] {
74+
def fromSpecific(from: WrappedString)(it: IterableOnce[Char]): WrappedString = WrappedString.fromSpecific(it)
75+
def newBuilder(from: WrappedString): mutable.Builder[Char, WrappedString] = WrappedString.newBuilder
76+
}
77+
78+
implicit def buildFromArray[A : ClassTag]: BuildFrom[Array[_], A, Array[A]] =
79+
new BuildFrom[Array[_], A, Array[A]] {
80+
def fromSpecific(from: Array[_])(it: IterableOnce[A]): Array[A] = Factory.arrayFactory[A].fromSpecific(it)
81+
def newBuilder(from: Array[_]): Builder[A, Array[A]] = Factory.arrayFactory[A].newBuilder
82+
}
83+
84+
implicit def buildFromView[A, B]: BuildFrom[View[A], B, View[B]] =
85+
new BuildFrom[View[A], B, View[B]] {
86+
def fromSpecific(from: View[A])(it: IterableOnce[B]): View[B] = View.from(it)
87+
def newBuilder(from: View[A]): Builder[B, View[B]] = View.newBuilder
88+
}
89+
90+
}
91+
92+
trait BuildFromLowPriority1 extends BuildFromLowPriority2 {
93+
94+
/** Build the source collection type from an Iterable with SortedOps */
95+
// Restating the upper bound of CC in the result type seems redundant, but it serves to prune the
96+
// implicit search space for faster compilation and reduced change of divergence. See the compilation
97+
// test in test/junit/scala/collection/BuildFromTest.scala and discussion in https://github.com/scala/scala/pull/10209
98+
implicit def buildFromSortedSetOps[CC[X] <: SortedSet[X] with SortedSetOps[X, CC, _], A0, A : Ordering]: BuildFrom[CC[A0] with SortedSet[A0], A, CC[A] with SortedSet[A]] = new BuildFrom[CC[A0], A, CC[A]] {
99+
def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.newBuilder[A]
100+
def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.from(it)
101+
}
102+
103+
implicit def fallbackStringCanBuildFrom[A]: BuildFrom[String, A, immutable.IndexedSeq[A]] =
104+
new BuildFrom[String, A, immutable.IndexedSeq[A]] {
105+
def fromSpecific(from: String)(it: IterableOnce[A]): immutable.IndexedSeq[A] = immutable.IndexedSeq.from(it)
106+
def newBuilder(from: String): Builder[A, immutable.IndexedSeq[A]] = immutable.IndexedSeq.newBuilder[A]
107+
}
108+
}
109+
110+
trait BuildFromLowPriority2 {
111+
/** Build the source collection type from an IterableOps */
112+
implicit def buildFromIterableOps[CC[X] <: Iterable[X] with IterableOps[X, CC, _], A0, A]: BuildFrom[CC[A0], A, CC[A]] = new BuildFrom[CC[A0], A, CC[A]] {
113+
//TODO: Reuse a prototype instance
114+
def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: IterableOps[A0, CC, _]).iterableFactory.newBuilder[A]
115+
def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: IterableOps[A0, CC, _]).iterableFactory.from(it)
116+
}
117+
118+
implicit def buildFromIterator[A]: BuildFrom[Iterator[_], A, Iterator[A]] = new BuildFrom[Iterator[_], A, Iterator[A]] {
119+
def newBuilder(from: Iterator[_]): mutable.Builder[A, Iterator[A]] = Iterator.newBuilder
120+
def fromSpecific(from: Iterator[_])(it: IterableOnce[A]): Iterator[A] = Iterator.from(it)
121+
}
122+
}

0 commit comments

Comments
 (0)