diff options
author | Aleksandar Pokopec <aleksandar.prokopec@epfl.ch> | 2010-11-19 12:38:14 +0000 |
---|---|---|
committer | Aleksandar Pokopec <aleksandar.prokopec@epfl.ch> | 2010-11-19 12:38:14 +0000 |
commit | 78ae055e5231d5a9ef3aae6228863cc3ddcf963e (patch) | |
tree | 9cd101df8f5c9c89ff123c224599233a9fe2dc57 | |
parent | a01f074d3e3229db905e21e78469ab02dc6ca0cf (diff) | |
download | scala-78ae055e5231d5a9ef3aae6228863cc3ddcf963e.tar.gz scala-78ae055e5231d5a9ef3aae6228863cc3ddcf963e.tar.bz2 scala-78ae055e5231d5a9ef3aae6228863cc3ddcf963e.zip |
Fixes #3686 by special casing Stream transforme...
Fixes #3686 by special casing Stream transformers depending on target
type.
Review by extempore.
-rw-r--r-- | src/library/scala/collection/immutable/Stream.scala | 55 |
1 files changed, 39 insertions, 16 deletions
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 <code>f(a<sub>0</sub>), ..., f(a<sub>n</sub>)</code> if this * sequence is <code>a<sub>0</sub>, ..., a<sub>n</sub></code>. */ - 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 <code>p</code>. 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) } |