Skip to content

Commit 4eac431

Browse files
committed
IterableOnce.isEmpty uses knownSize
Also sum and product intercept BigDecimal identity ops that change the math context. This is a workaround restricted to just these methods.
1 parent 45f005a commit 4eac431

File tree

1 file changed

+34
-5
lines changed

1 file changed

+34
-5
lines changed

library/src/scala/collection/IterableOnce.scala

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,12 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
843843
*
844844
* @return `true` if the $coll contains no elements, `false` otherwise.
845845
*/
846-
def isEmpty: Boolean = !iterator.hasNext
846+
def isEmpty: Boolean =
847+
knownSize match {
848+
case -1 => !iterator.hasNext
849+
case 0 => true
850+
case _ => false
851+
}
847852

848853
/** Tests whether the $coll is not empty.
849854
*
@@ -929,7 +934,13 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
929934
i - start
930935
}
931936

932-
/** Sums up the elements of this collection.
937+
/** Sums the elements of this collection.
938+
*
939+
* The default implementation uses `reduce` for a known non-empty collection,
940+
* `foldLeft` otherwise.
941+
*
942+
* If `foldLeft` is used, this implementation works around pollution of the math context
943+
* by ignoring the identity element.
933944
*
934945
* $willNotTerminateInf
935946
*
@@ -940,12 +951,24 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
940951
*/
941952
def sum[B >: A](implicit num: Numeric[B]): B =
942953
knownSize match {
943-
case -1 => reduceLeftIterator[B](num.zero)(num.plus)
954+
case -1 =>
955+
val z = num.zero
956+
if ((num eq Numeric.BigDecimalIsFractional) || (num eq Numeric.BigDecimalAsIfIntegral)) {
957+
def nonPollutingPlus(x: B, y: B): B = if (x.asInstanceOf[AnyRef] eq z.asInstanceOf[AnyRef]) y else num.plus(x, y)
958+
foldLeft(z)(nonPollutingPlus)
959+
}
960+
else foldLeft(z)(num.plus)
944961
case 0 => num.zero
945962
case _ => reduce(num.plus)
946963
}
947964

948-
/** Multiplies up the elements of this collection.
965+
/** Multiplies together the elements of this collection.
966+
*
967+
* The default implementation uses `reduce` for a known non-empty collection,
968+
* `foldLeft` otherwise.
969+
*
970+
* If `foldLeft` is used, this implementation works around pollution of the math context
971+
* by ignoring the identity element.
949972
*
950973
* $willNotTerminateInf
951974
*
@@ -956,7 +979,13 @@ trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
956979
*/
957980
def product[B >: A](implicit num: Numeric[B]): B =
958981
knownSize match {
959-
case -1 => reduceLeftIterator[B](num.one)(num.times)
982+
case -1 =>
983+
val u = num.one
984+
if ((num eq Numeric.BigDecimalIsFractional) || (num eq Numeric.BigDecimalAsIfIntegral)) {
985+
def nonPollutingProd(x: B, y: B): B = if (x.asInstanceOf[AnyRef] eq u.asInstanceOf[AnyRef]) y else num.times(x, y)
986+
foldLeft(u)(nonPollutingProd)
987+
}
988+
else foldLeft(u)(num.times)
960989
case 0 => num.one
961990
case _ => reduce(num.times)
962991
}

0 commit comments

Comments
 (0)