|
| 1 | +package scala.collection |
| 2 | + |
| 3 | +import org.junit.Test |
| 4 | + |
| 5 | +import scala.collection.mutable.{ArrayBuffer, Builder, ListBuffer} |
| 6 | +import scala.collection.immutable.{HashMap, List, TreeMap, TreeSet} |
| 7 | +import scala.collection.compat._ |
| 8 | + |
| 9 | +// Tests copied from the 2.13 scala-library |
| 10 | +class BuildFromTest { |
| 11 | + |
| 12 | + // Using BuildFrom to abstract over both and also allow building arbitrary collection types |
| 13 | + def optionSequence2[CC[X] <: Iterable[X], A, To](xs: CC[Option[A]])(implicit bf: BuildFrom[CC[Option[A]], A, To]): Option[To] = |
| 14 | + xs.foldLeft[Option[Builder[A, To]]](Some(bf.newBuilder(xs))) { |
| 15 | + case (Some(builder), Some(a)) => Some(builder += a) |
| 16 | + case _ => None |
| 17 | + }.map(_.result()) |
| 18 | + |
| 19 | + // Using dependent types: |
| 20 | + def optionSequence3[A, To](xs: Iterable[Option[A]])(implicit bf: BuildFrom[xs.type, A, To]): Option[To] = |
| 21 | + xs.foldLeft[Option[Builder[A, To]]](Some(bf.newBuilder(xs))) { |
| 22 | + case (Some(builder), Some(a)) => Some(builder += a) |
| 23 | + case _ => None |
| 24 | + }.map(_.result()) |
| 25 | + |
| 26 | + def eitherSequence[A, B, To](xs: Iterable[Either[A, B]])(implicit bf: BuildFrom[xs.type, B, To]): Either[A, To] = |
| 27 | + xs.foldLeft[Either[A, Builder[B, To]]](Right(bf.newBuilder(xs))) { |
| 28 | + case (Right(builder), Right(b)) => Right(builder += b) |
| 29 | + case (Left(a) , _) => Left(a) |
| 30 | + case (_ , Left(a)) => Left(a) |
| 31 | + }.right.map(_.result()) |
| 32 | + |
| 33 | + @Test |
| 34 | + def optionSequence2Test: Unit = { |
| 35 | + val xs1 = List(Some(1), None, Some(2)) |
| 36 | + val o1 = optionSequence2(xs1) |
| 37 | + val o1t: Option[List[Int]] = o1 |
| 38 | + |
| 39 | + val xs2 = TreeSet(Some("foo"), Some("bar"), None) |
| 40 | + val o2 = optionSequence2(xs2) |
| 41 | + // Not working: the resolved implicit BuildFrom results in a SortedSet instead of a TreeSet |
| 42 | + // val o2t: Option[TreeSet[String]] = o2 |
| 43 | + val o2t: Option[SortedSet[String]] = o2 |
| 44 | + |
| 45 | + // Breakout-like use case from https://github.com/scala/scala/pull/5233: |
| 46 | + val xs4 = List[Option[(Int, String)]](Some((1 -> "a")), Some((2 -> "b"))) |
| 47 | + val o4 = optionSequence2(xs4)(TreeMap) |
| 48 | + val o4t: Option[TreeMap[Int, String]] = o4 |
| 49 | + } |
| 50 | + |
| 51 | + @Test |
| 52 | + def optionSequence3Test: Unit = { |
| 53 | + val xs1 = List(Some(1), None, Some(2)) |
| 54 | + val o1 = optionSequence3(xs1) |
| 55 | + val o1t: Option[List[Int]] = o1 |
| 56 | + |
| 57 | + val xs2 = TreeSet(Some("foo"), Some("bar"), None) |
| 58 | + val o2 = optionSequence3(xs2) |
| 59 | + // Not working: the resolved implicit BuildFrom results in a SortedSet instead of a TreeSet |
| 60 | + // val o2t: Option[TreeSet[String]] = o2 |
| 61 | + val o2t: Option[SortedSet[String]] = o2 |
| 62 | + |
| 63 | + // Breakout-like use case from https://github.com/scala/scala/pull/5233: |
| 64 | + val xs4 = List[Option[(Int, String)]](Some((1 -> "a")), Some((2 -> "b"))) |
| 65 | + val o4 = optionSequence3(xs4)(TreeMap) // same syntax as in `.to` |
| 66 | + val o4t: Option[TreeMap[Int, String]] = o4 |
| 67 | + } |
| 68 | + |
| 69 | + @Test |
| 70 | + def eitherSequenceTest: Unit = { |
| 71 | + val xs3 = ListBuffer(Right("foo"), Left(0), Right("bar")) |
| 72 | + val e1 = eitherSequence(xs3) |
| 73 | + val e1t: Either[Int, ListBuffer[String]] = e1 |
| 74 | + } |
| 75 | + |
| 76 | + // From https://github.com/scala/collection-strawman/issues/44 |
| 77 | + def flatCollect[A, B, To](coll: Iterable[A])(f: PartialFunction[A, IterableOnce[B]]) |
| 78 | + (implicit bf: BuildFrom[coll.type, B, To]): To = { |
| 79 | + val builder = bf.newBuilder(coll) |
| 80 | + for (a <- coll) { |
| 81 | + if (f.isDefinedAt(a)) builder ++= f(a) |
| 82 | + } |
| 83 | + builder.result() |
| 84 | + } |
| 85 | + |
| 86 | + def mapSplit[A, B, C, ToL, ToR](coll: Iterable[A])(f: A => Either[B, C]) |
| 87 | + (implicit bfLeft: BuildFrom[coll.type, B, ToL], bfRight: BuildFrom[coll.type, C, ToR]): (ToL, ToR) = { |
| 88 | + val left = bfLeft.newBuilder(coll) |
| 89 | + val right = bfRight.newBuilder(coll) |
| 90 | + for (a <- coll) |
| 91 | + f(a).fold(left.+=, right.+=) |
| 92 | + (left.result(), right.result()) |
| 93 | + } |
| 94 | + |
| 95 | + @Test |
| 96 | + def flatCollectTest: Unit = { |
| 97 | + val xs1 = List(1, 2, 3) |
| 98 | + val xs2 = flatCollect(xs1) { case 2 => ArrayBuffer("foo", "bar") } |
| 99 | + val xs3: List[String] = xs2 |
| 100 | + |
| 101 | + val xs4 = TreeMap((1, "1"), (2, "2")) |
| 102 | + val xs5 = flatCollect(xs4) { case (2, v) => List((v, v)) } |
| 103 | + val xs6: TreeMap[String, String] = xs5 |
| 104 | + |
| 105 | + val xs7 = HashMap((1, "1"), (2, "2")) |
| 106 | + val xs8 = flatCollect(xs7) { case (2, v) => List((v, v)) } |
| 107 | + val xs9: HashMap[String, String] = xs8 |
| 108 | + |
| 109 | + val xs10 = TreeSet(1, 2, 3) |
| 110 | + val xs11 = flatCollect(xs10) { case 2 => List("foo", "bar") } |
| 111 | + // Not working: the resolved implicit BuildFrom results in a SortedSet instead of a TreeSet |
| 112 | + // val xs12: TreeSet[String] = xs11 |
| 113 | + val xs12: SortedSet[String] = xs11 |
| 114 | + } |
| 115 | + |
| 116 | + @Test |
| 117 | + def mapSplitTest: Unit = { |
| 118 | + val xs1 = List(1, 2, 3) |
| 119 | + val (xs2, xs3) = mapSplit(xs1)(x => if (x % 2 == 0) Left(x) else Right(x.toString)) |
| 120 | + val xs4: List[Int] = xs2 |
| 121 | + val xs5: List[String] = xs3 |
| 122 | + |
| 123 | + val xs6 = TreeMap((1, "1"), (2, "2")) |
| 124 | + val (xs7, xs8) = mapSplit(xs6) { case (k, v) => Left[(String, Int), (Int, Boolean)]((v, k)) } |
| 125 | + val xs9: TreeMap[String, Int] = xs7 |
| 126 | + val xs10: TreeMap[Int, Boolean] = xs8 |
| 127 | + } |
| 128 | + |
| 129 | + implicitly[BuildFrom[String, Char, String]] |
| 130 | + implicitly[BuildFrom[Array[Int], Char, Array[Char]]] |
| 131 | + implicitly[BuildFrom[BitSet, Int, BitSet]] |
| 132 | + implicitly[BuildFrom[immutable.BitSet, Int, immutable.BitSet]] |
| 133 | + implicitly[BuildFrom[mutable.BitSet, Int, mutable.BitSet]] |
| 134 | + |
| 135 | + // Check that collection companions can implicitly be converted to a `BuildFrom` instance |
| 136 | + Iterable: BuildFrom[_, Int, Iterable[Int]] |
| 137 | + Map: BuildFrom[_, (Int, String), Map[Int, String]] |
| 138 | + SortedSet: BuildFrom[_, Int, SortedSet[Int]] |
| 139 | + SortedMap: BuildFrom[_, (Int, String), SortedMap[Int, String]] |
| 140 | +} |
0 commit comments