summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/TraversableOnce.scala
diff options
context:
space:
mode:
authorRex Kerr <ichoran@gmail.com>2015-02-13 16:37:19 -0800
committerRex Kerr <ichoran@gmail.com>2015-03-30 16:56:00 -0700
commit56c1af90999f0a9a55a90f3dd3bf6d04ddda5943 (patch)
treef9a5cd4aa1d2b8b84469ea4823be2968e418764f /src/library/scala/collection/TraversableOnce.scala
parent955eb2170e1291500813e6bec76a9f0e1e3bad50 (diff)
downloadscala-56c1af90999f0a9a55a90f3dd3bf6d04ddda5943.tar.gz
scala-56c1af90999f0a9a55a90f3dd3bf6d04ddda5943.tar.bz2
scala-56c1af90999f0a9a55a90f3dd3bf6d04ddda5943.zip
Performance improvement: collectFirst in TraversableOnce
collectFirst was implemented in TraversableOnce by calling toIterator and then using a non-local return to pull out a Some when the partial function succeeded. This had two problems: 1. If the TraversableOnce was Iterator or Iterable, stepping through until pf is happy is much (15x!) faster. 2. If the TraversableOnce was not, creating an Iterator is a waste of time and memory This fixes both of these issues by inspecting the self-type and choosing the appropriate implementation. Further (modest) improvements likely possible in 2.12 by moving specialized implementations to child classes and using `applyOrElse` on the partial function with a package-private object instead of a locally created one.
Diffstat (limited to 'src/library/scala/collection/TraversableOnce.scala')
-rw-r--r--src/library/scala/collection/TraversableOnce.scala17
1 files changed, 15 insertions, 2 deletions
diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala
index 2eab58009c..c5b0d0f085 100644
--- a/src/library/scala/collection/TraversableOnce.scala
+++ b/src/library/scala/collection/TraversableOnce.scala
@@ -128,8 +128,21 @@ 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] = {
- // make sure to use an iterator or `seq`
- self.toIterator.foreach(pf.runWith(b => return Some(b)))
+ // TODO 2.12 -- move out alternate implementations into child classes
+ val i: Iterator[A] = self match {
+ case it: Iterator[A] => it
+ case _: GenIterable[_] => self.toIterator // If it might be parallel, be sure to .seq or use iterator!
+ case _ => // Not parallel, not iterable--just traverse
+ self.foreach(pf.runWith(b => return Some(b)))
+ return None
+ }
+ // Presumably the fastest way to get in and out of a partial function is for a sentinel function to return itself
+ // (Tested to be lower-overhead than runWith. Would be better yet to not need to (formally) allocate it--change in 2.12.)
+ val sentinel: Function1[A, Any] = new scala.runtime.AbstractFunction1[A, Any]{ def apply(a: A) = this }
+ while (i.hasNext) {
+ val x = pf.applyOrElse(i.next, sentinel)
+ if (x.asInstanceOf[AnyRef] ne sentinel) return Some(x.asInstanceOf[B])
+ }
None
}