diff options
-rw-r--r-- | src/library/scala/collection/immutable/Stream.scala | 35 | ||||
-rw-r--r-- | test/files/run/stream-stack-overflow-filter-map.check | 2 | ||||
-rw-r--r-- | test/files/run/stream-stack-overflow-filter-map.scala | 14 |
3 files changed, 51 insertions, 0 deletions
diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 1bf1e20694..c8e7e7547f 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -479,22 +479,57 @@ self => final class StreamWithFilter(p: A => Boolean) extends WithFilter(p) { override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { + def tailMap(coll: Stream[A]): Stream[B] = { + var head: A = null.asInstanceOf[A] + var tail: Stream[A] = coll + while (true) { + if (tail.isEmpty) + return Stream.Empty + head = tail.head + tail = tail.tail + if (p(head)) + return cons(f(head), tailMap(tail)) + } + throw new RuntimeException() + } + + /* def tailMap = asStream[B](tail withFilter p map f) if (isStreamBuilder(bf)) asThat( if (isEmpty) Stream.Empty else if (p(head)) cons(f(head), tailMap) else tailMap + //XXX Alternative: what about having a Stream.step constructor? ) + */ + if (isStreamBuilder(bf)) asThat(tailMap(Stream.this)) else super.map(f)(bf) } override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { + def tailFlatMap(coll: Stream[A]): Stream[B] = { + var head: A = null.asInstanceOf[A] + var tail: Stream[A] = coll + while (true) { + if (tail.isEmpty) + return Stream.Empty + head = tail.head + tail = tail.tail + if (p(head)) + return f(head).toStream append tailFlatMap(tail) + } + throw new RuntimeException() + } + + /* def tailFlatMap = asStream[B](tail withFilter p flatMap f) if (isStreamBuilder(bf)) asThat( if (isEmpty) Stream.Empty else if (p(head)) f(head).toStream append tailFlatMap else tailFlatMap ) + */ + if (isStreamBuilder(bf)) asThat(tailFlatMap(Stream.this)) else super.flatMap(f)(bf) } diff --git a/test/files/run/stream-stack-overflow-filter-map.check b/test/files/run/stream-stack-overflow-filter-map.check new file mode 100644 index 0000000000..dbf856668b --- /dev/null +++ b/test/files/run/stream-stack-overflow-filter-map.check @@ -0,0 +1,2 @@ +Stream() +Stream() diff --git a/test/files/run/stream-stack-overflow-filter-map.scala b/test/files/run/stream-stack-overflow-filter-map.scala new file mode 100644 index 0000000000..e2bd47bfca --- /dev/null +++ b/test/files/run/stream-stack-overflow-filter-map.scala @@ -0,0 +1,14 @@ +object Test extends App { + //This runs fine. + val resFMap1 = (1 to 10000).toStream filter (_ => false) flatMap (Seq(_)) + val resMap1 = (1 to 10000).toStream filter (_ => false) map (_ + 1) + assert(resMap1.isEmpty) + assert(resFMap1.isEmpty) + println(resMap1) + println(resFMap1) + //This will cause a stack overflow + val resFMap2 = (1 to 10000).toStream withFilter (_ => false) flatMap (Seq(_)) + val resMap2 = (1 to 10000).toStream withFilter (_ => false) map (_ + 1) + assert(resMap1 == resMap2) + assert(resFMap1 == resFMap2) +} |