summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-06-13 20:51:39 +0000
committerPaul Phillips <paulp@improving.org>2011-06-13 20:51:39 +0000
commit32d2b15d5db3e9e582632cc8f995dcc362751d6a (patch)
treef55d67b49b8faf1d9fceca9228caaefeebebf3ab
parent21584ed38ea6cbb8932206608ce47d975a127d8d (diff)
downloadscala-32d2b15d5db3e9e582632cc8f995dcc362751d6a.tar.gz
scala-32d2b15d5db3e9e582632cc8f995dcc362751d6a.tar.bz2
scala-32d2b15d5db3e9e582632cc8f995dcc362751d6a.zip
Views using methods implemented in terms of isE...
Views using methods implemented in terms of isEmpty (in particular, headOption and lastOption) were traversing the collection twice up to the nonEmpty element, because "if (isEmpty) None else Some(head)" means calling isEmpty separately from head. I overrode those methods in TraversableViewLike to avoid the second traversal. This leaves at least init and tail still in that boat, but they were getting too involved. How do I say "review by pool of reviewers", who can help set that up? In the meantime no review.
-rw-r--r--src/library/scala/collection/TraversableViewLike.scala21
-rw-r--r--test/files/run/view-headoption.check28
-rw-r--r--test/files/run/view-headoption.scala18
3 files changed, 67 insertions, 0 deletions
diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala
index 36fe6251df..03286fef67 100644
--- a/src/library/scala/collection/TraversableViewLike.scala
+++ b/src/library/scala/collection/TraversableViewLike.scala
@@ -82,6 +82,27 @@ trait TraversableViewLike[+A,
trait Transformed[+B] extends TraversableView[B, Coll] with super.Transformed[B] {
def foreach[U](f: B => U): Unit
+ // Methods whose standard implementations use "isEmpty" need to be rewritten
+ // for views, else they will end up traversing twice in a situation like:
+ // xs.view.flatMap(f).headOption
+ override def headOption: Option[B] = {
+ for (x <- this)
+ return Some(x)
+
+ None
+ }
+ override def lastOption: Option[B] = {
+ // (Should be) better than allocating a Some for every element.
+ var empty = true
+ var result: B = null.asInstanceOf[B]
+ for (x <- this) {
+ empty = false
+ result = x
+ }
+ if (empty) None else Some(result)
+ }
+
+ // XXX: As yet not dealt with, tail and init both call isEmpty.
override def stringPrefix = self.stringPrefix
override def toString = viewToString
}
diff --git a/test/files/run/view-headoption.check b/test/files/run/view-headoption.check
new file mode 100644
index 0000000000..5c98b54b46
--- /dev/null
+++ b/test/files/run/view-headoption.check
@@ -0,0 +1,28 @@
+fail
+success
+f1: Some(5)
+fail
+success
+f2: 5
+fail
+success
+fail
+fail
+success
+fail
+fail
+fail
+success
+f3: Some(5)
+fail
+success
+fail
+success
+fail
+fail
+success
+fail
+fail
+fail
+success
+f4: 5
diff --git a/test/files/run/view-headoption.scala b/test/files/run/view-headoption.scala
new file mode 100644
index 0000000000..659c7e6b82
--- /dev/null
+++ b/test/files/run/view-headoption.scala
@@ -0,0 +1,18 @@
+object Test {
+ val failer = () => { println("fail") ; None }
+ val succeeder = () => { println("success") ; Some(5) }
+ val fs = List(failer, succeeder, failer, failer, succeeder, failer, failer, failer, succeeder)
+
+ def f0 = fs.view flatMap (f => f())
+ def f1 = f0.headOption
+ def f2 = f0.head
+ def f3 = f0.lastOption
+ def f4 = f0.last
+
+ def main(args: Array[String]): Unit = {
+ println("f1: " + f1)
+ println("f2: " + f2)
+ println("f3: " + f3)
+ println("f4: " + f4)
+ }
+}