summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2012-09-29 18:15:15 +0200
committerJason Zaugg <jzaugg@gmail.com>2012-11-04 21:21:51 +0100
commitbc3dda2b0222d3b7cf3db491728b98f9b6110856 (patch)
treed71d81b7c443e75e12da82e9d6e8c53c84d31f1d /src/library
parent2c6777fd53b93b95a261aadc87a5cbc03c14d503 (diff)
downloadscala-bc3dda2b0222d3b7cf3db491728b98f9b6110856.tar.gz
scala-bc3dda2b0222d3b7cf3db491728b98f9b6110856.tar.bz2
scala-bc3dda2b0222d3b7cf3db491728b98f9b6110856.zip
SI-6448 Collecting the spoils of PartialFun#runWith
Avoids calling both `isDefinedAt` and `apply`. This pathological case that would benefit the most looks like: xs collect { case x if {expensive(); true} => x } The typical change looks like: - for (x <- this) if (pf.isDefinedAt(x)) b += pf(x) + foreach(pf.runWith(b += _)) Incorporates feedback provided by Pavel Pavlov: https://github.com/retronym/scala/commit/ef5430 A few more opportunities for optimization are noted in the `Pending` section of the enclosed test. `Iterator.collect` would be nice, but a solution eludes me. Calling the guard less frequently does change the behaviour of these functions in an obervable way, but not contravene the documented semantics. That said, there is an alternative opinion on the comment of the ticket: https://issues.scala-lang.org/browse/SI-6448
Diffstat (limited to 'src/library')
-rw-r--r--src/library/scala/Option.scala2
-rw-r--r--src/library/scala/collection/TraversableLike.scala2
-rw-r--r--src/library/scala/collection/TraversableOnce.scala6
-rw-r--r--src/library/scala/collection/immutable/Stream.scala13
-rw-r--r--src/library/scala/collection/parallel/RemainsIterator.scala3
-rw-r--r--src/library/scala/collection/parallel/mutable/ParArray.scala3
6 files changed, 17 insertions, 12 deletions
diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala
index 755071a14f..95fddc43f4 100644
--- a/src/library/scala/Option.scala
+++ b/src/library/scala/Option.scala
@@ -256,7 +256,7 @@ sealed abstract class Option[+A] extends Product with Serializable {
* value (if possible), or $none.
*/
@inline final def collect[B](pf: PartialFunction[A, B]): Option[B] =
- if (!isEmpty && pf.isDefinedAt(this.get)) Some(pf(this.get)) else None
+ if (!isEmpty) pf.lift(this.get) else None
/** Returns this $option if it is nonempty,
* otherwise return the result of evaluating `alternative`.
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index 7849f1c544..ad96382d52 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -275,7 +275,7 @@ trait TraversableLike[+A, +Repr] extends Any
def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
- for (x <- this) if (pf.isDefinedAt(x)) b += pf(x)
+ foreach(pf.runWith(b += _))
b.result
}
diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala
index a61d1354dc..569412a441 100644
--- a/src/library/scala/collection/TraversableOnce.scala
+++ b/src/library/scala/collection/TraversableOnce.scala
@@ -128,10 +128,8 @@ trait TraversableOnce[+A] extends Any with GenTraversableOnce[A] {
* @example `Seq("a", 1, 5L).collectFirst({ case x: Int => x*10 }) = Some(10)`
*/
def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = {
- for (x <- self.toIterator) { // make sure to use an iterator or `seq`
- if (pf isDefinedAt x)
- return Some(pf(x))
- }
+ // make sure to use an iterator or `seq`
+ self.toIterator.foreach(pf.runWith(b => return Some(b)))
None
}
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala
index 5566806c55..e6b110131d 100644
--- a/src/library/scala/collection/immutable/Stream.scala
+++ b/src/library/scala/collection/immutable/Stream.scala
@@ -385,12 +385,17 @@ self =>
// 1) stackoverflows (could be achieved with tailrec, too)
// 2) out of memory errors for big streams (`this` reference can be eliminated from the stack)
var rest: Stream[A] = this
- while (rest.nonEmpty && !pf.isDefinedAt(rest.head)) rest = rest.tail
+
+ // Avoids calling both `pf.isDefined` and `pf.apply`.
+ var newHead: B = null.asInstanceOf[B]
+ val runWith = pf.runWith((b: B) => newHead = b)
+
+ while (rest.nonEmpty && !runWith(rest.head)) rest = rest.tail
// without the call to the companion object, a thunk is created for the tail of the new stream,
// and the closure of the thunk will reference `this`
if (rest.isEmpty) Stream.Empty.asInstanceOf[That]
- else Stream.collectedTail(rest, pf, bf).asInstanceOf[That]
+ else Stream.collectedTail(newHead, rest, pf, bf).asInstanceOf[That]
}
}
@@ -1170,8 +1175,8 @@ object Stream extends SeqFactory[Stream] {
cons(stream.head, stream.tail filter p)
}
- private[immutable] def collectedTail[A, B, That](stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = {
- cons(pf(stream.head), stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]])
+ private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = {
+ cons(head, stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]])
}
}
diff --git a/src/library/scala/collection/parallel/RemainsIterator.scala b/src/library/scala/collection/parallel/RemainsIterator.scala
index 9bf287cc39..857d051ded 100644
--- a/src/library/scala/collection/parallel/RemainsIterator.scala
+++ b/src/library/scala/collection/parallel/RemainsIterator.scala
@@ -123,9 +123,10 @@ private[collection] trait AugmentedIterableIterator[+T] extends RemainsIterator[
def collect2combiner[S, That](pf: PartialFunction[T, S], cb: Combiner[S, That]): Combiner[S, That] = {
//val cb = pbf(repr)
+ val runWith = pf.runWith(cb += _)
while (hasNext) {
val curr = next
- if (pf.isDefinedAt(curr)) cb += pf(curr)
+ runWith(curr)
}
cb
}
diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala
index 7527c9a71a..92f0b27568 100644
--- a/src/library/scala/collection/parallel/mutable/ParArray.scala
+++ b/src/library/scala/collection/parallel/mutable/ParArray.scala
@@ -405,9 +405,10 @@ self =>
private def collect2combiner_quick[S, That](pf: PartialFunction[T, S], a: Array[Any], cb: Builder[S, That], ntil: Int, from: Int) {
var j = from
+ val runWith = pf.runWith(b => cb += b)
while (j < ntil) {
val curr = a(j).asInstanceOf[T]
- if (pf.isDefinedAt(curr)) cb += pf(curr)
+ runWith(curr)
j += 1
}
}