From 78ae055e5231d5a9ef3aae6228863cc3ddcf963e Mon Sep 17 00:00:00 2001 From: Aleksandar Pokopec Date: Fri, 19 Nov 2010 12:38:14 +0000 Subject: Fixes #3686 by special casing Stream transforme... Fixes #3686 by special casing Stream transformers depending on target type. Review by extempore. --- .../scala/collection/immutable/Stream.scala | 55 +++++++++++++++------- 1 file changed, 39 insertions(+), 16 deletions(-) (limited to 'src/library') diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 02a17427ef..6a7d0535fc 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -120,6 +120,10 @@ self => */ @inline private def asThat[That](x: AnyRef): That = x.asInstanceOf[That] @inline private def asStream[B](x: AnyRef): Stream[B] = x.asInstanceOf[Stream[B]] + @inline private def buildsThis[B, That](bf: CanBuildFrom[Stream[A], B, That]) = bf.isInstanceOf[Stream.StreamCanBuildFrom[_]] + @inline private def ifTargetThis[B, That](bf: CanBuildFrom[Stream[A], B, That])(ifIs: => Stream[B])(ifNot: => That): That = + if (buildsThis(bf)) ifIs.asInstanceOf[That] + else ifNot // Overridden methods from Traversable @@ -139,10 +143,12 @@ self => */ override def ++[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = // we assume there is no other builder factory on streams and therefore know that That = Stream[A] - asThat[That]( + ifTargetThis[B, That](bf) { if (isEmpty) that.toStream else new Stream.Cons(head, asStream[A](tail ++ that)) - ) + } { + super.++(that)(bf) + } /** * Create a new stream which contains all intermediate results of applying the operator @@ -150,10 +156,12 @@ self => * @note This works because the target type of the Builder That is a Stream. */ override final def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = - asThat[That]( + ifTargetThis[B, That](bf) { if (isEmpty) Stream(z) else new Stream.Cons(z, asStream[B](tail.scanLeft(op(z, head))(op))) - ) + } { + super.scanLeft(z)(op)(bf) + } /** Returns the stream resulting from applying the given function * `f` to each element of this stream. @@ -162,11 +170,14 @@ self => * @return f(a0), ..., f(an) if this * sequence is a0, ..., an. */ - override final def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = - asThat[That]( + override final def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { + ifTargetThis[B, That](bf) { if (isEmpty) Stream.Empty else new Stream.Cons(f(head), asStream[B](tail map f)) - ) + } { + super.map(f)(bf) + } + } /** Applies the given function `f` to each element of * this stream, then concatenates the results. @@ -180,7 +191,7 @@ self => // we assume there is no other builder factory on streams and therefore know that That = Stream[B] // optimisations are not for speed, but for functionality // see tickets #153, #498, #2147, and corresponding tests in run/ (as well as run/stream_flatmap_odds.scala) - asThat[That]( + ifTargetThis[B, That](bf) { if (isEmpty) Stream.Empty else { // establish !prefix.isEmpty || nonEmptyPrefix.isEmpty @@ -195,7 +206,9 @@ self => if (nonEmptyPrefix.isEmpty) Stream.empty else prefix append asStream[B](nonEmptyPrefix.tail flatMap f) } - ) + } { + super.flatMap(f)(bf) + } /** Returns all the elements of this stream that satisfy the * predicate p. The order of the elements is preserved. @@ -221,20 +234,24 @@ self => override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { def tailMap = asStream[B](tail withFilter p map f) - asThat[That]( + ifTargetThis[B, That](bf) { if (isEmpty) Stream.Empty else if (p(head)) new Stream.Cons(f(head), tailMap) else tailMap - ) + } { + super.map(f)(bf) + } } override def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { def tailFlatMap = asStream[B](tail withFilter p flatMap f) - asThat[That]( + ifTargetThis[B, That](bf) { if (isEmpty) Stream.Empty else if (p(head)) f(head).toStream append tailFlatMap else tailFlatMap - ) + } { + super.flatMap(f)(bf) + } } override def foreach[B](f: A => B) = @@ -319,10 +336,12 @@ self => */ override final def zip[A1 >: A, B, That](that: Iterable[B])(implicit bf: CanBuildFrom[Stream[A], (A1, B), That]): That = // we assume there is no other builder factory on streams and therefore know that That = Stream[(A1, B)] - asThat[That]( + ifTargetThis[(A1, B), That](bf) { if (this.isEmpty || that.isEmpty) Stream.Empty else new Stream.Cons((this.head, that.head), asStream[(A1, B)](this.tail zip that.tail)) - ) + } { + super.zip(that)(bf) + } /** Zips this iterable with its indices. `s.zipWithIndex` is equivalent to * `s zip s.indices` @@ -456,7 +475,11 @@ self => if (these.isEmpty) Stream.fill(len)(elem) else new Stream.Cons(these.head, loop(len - 1, these.tail)) - asThat[That](loop(len, this)) + ifTargetThis[B, That](bf) { + loop(len, this) + } { + super.padTo(len, elem)(bf) + } // was: if (bf.isInstanceOf[Stream.StreamCanBuildFrom[_]]) loop(len, this).asInstanceOf[That] // else super.padTo(len, elem) } -- cgit v1.2.3