|
| 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