@@ -19,7 +19,7 @@ import java.lang.{StringBuilder => JStringBuilder}
19
19
20
20
import scala .annotation .tailrec
21
21
import scala .collection .generic .SerializeEnd
22
- import scala .collection .mutable .{ArrayBuffer , Builder , StringBuilder }
22
+ import scala .collection .mutable .{ArrayBuffer , Builder , ReusableBuilder , StringBuilder }
23
23
import scala .language .implicitConversions
24
24
25
25
/** The class `LazyList` implements lazy lists where elements
@@ -194,6 +194,10 @@ import scala.language.implicitConversions
194
194
* @define coll lazy list
195
195
* @define orderDependent
196
196
* @define orderDependentFold
197
+ * @define appendStackSafety Note: Repeated chaining of calls to append methods (`appended`,
198
+ * `appendedAll`, `lazyAppendedAll`) without forcing any of the
199
+ * intermediate resulting lazy lists may overflow the stack when
200
+ * the final result is forced.
197
201
*/
198
202
@ SerialVersionUID (3L )
199
203
final class LazyList [+ A ] private (private [this ] var lazyState : () => LazyList .State [A ])
@@ -300,6 +304,8 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta
300
304
override protected [this ] def className = " LazyList"
301
305
302
306
/** The lazy list resulting from the concatenation of this lazy list with the argument lazy list.
307
+ *
308
+ * $appendStackSafety
303
309
*
304
310
* @param suffix The collection that gets appended to this lazy list
305
311
* @return The lazy list containing elements of this lazy list and the iterable object.
@@ -314,10 +320,18 @@ final class LazyList[+A] private(private[this] var lazyState: () => LazyList.Sta
314
320
else sCons(head, tail lazyAppendedAll suffix)
315
321
}
316
322
323
+ /** @inheritdoc
324
+ *
325
+ * $appendStackSafety
326
+ */
317
327
override def appendedAll [B >: A ](suffix : IterableOnce [B ]): LazyList [B ] =
318
328
if (knownIsEmpty) LazyList .from(suffix)
319
329
else lazyAppendedAll(suffix)
320
330
331
+ /** @inheritdoc
332
+ *
333
+ * $appendStackSafety
334
+ */
321
335
override def appended [B >: A ](elem : B ): LazyList [B ] =
322
336
if (knownIsEmpty) newLL(sCons(elem, LazyList .empty))
323
337
else lazyAppendedAll(Iterator .single(elem))
@@ -789,38 +803,6 @@ object LazyList extends SeqFactory[LazyList] {
789
803
final class Cons [A ](val head : A , val tail : LazyList [A ]) extends State [A ]
790
804
}
791
805
792
- private class SlidingIterator [A ](private [this ] var lazyList : LazyList [A ], size : Int , step : Int )
793
- extends AbstractIterator [LazyList [A ]] {
794
- private val minLen = size - step max 0
795
- private var first = true
796
-
797
- def hasNext : Boolean =
798
- if (first) lazyList.nonEmpty
799
- else lazyList.lengthGt(minLen)
800
-
801
- def next (): LazyList [A ] = {
802
- if (! hasNext) Iterator .empty.next()
803
- else {
804
- first = false
805
- val list = lazyList
806
- lazyList = list.drop(step)
807
- list.take(size)
808
- }
809
- }
810
- }
811
-
812
- private class LazyIterator [+ A ](private [this ] var lazyList : LazyList [A ]) extends AbstractIterator [A ] {
813
- override def hasNext : Boolean = lazyList.nonEmpty
814
-
815
- override def next (): A =
816
- if (lazyList.isEmpty) Iterator .empty.next()
817
- else {
818
- val res = lazyList.head
819
- lazyList = lazyList.tail
820
- res
821
- }
822
- }
823
-
824
806
/** Creates a new LazyList. */
825
807
@ inline private def newLL [A ](state : => State [A ]): LazyList [A ] = new LazyList [A ](() => state)
826
808
@@ -886,15 +868,6 @@ object LazyList extends SeqFactory[LazyList] {
886
868
if (! it.hasNext) State .Empty
887
869
else stateFromIteratorConcatSuffix(it.next().iterator)(concatIterator(it))
888
870
889
- private final class WithFilter [A ] private [LazyList ](lazyList : LazyList [A ], p : A => Boolean )
890
- extends collection.WithFilter [A , LazyList ] {
891
- private [this ] val filtered = lazyList.filter(p)
892
- def map [B ](f : A => B ): LazyList [B ] = filtered.map(f)
893
- def flatMap [B ](f : A => IterableOnce [B ]): LazyList [B ] = filtered.flatMap(f)
894
- def foreach [U ](f : A => U ): Unit = filtered.foreach(f)
895
- def withFilter (q : A => Boolean ): collection.WithFilter [A , LazyList ] = new WithFilter (filtered, q)
896
- }
897
-
898
871
/** An infinite LazyList that repeatedly applies a given function to a start value.
899
872
*
900
873
* @param start the start value of the LazyList
@@ -954,7 +927,103 @@ object LazyList extends SeqFactory[LazyList] {
954
927
}
955
928
}
956
929
957
- def newBuilder [A ]: Builder [A , LazyList [A ]] = ArrayBuffer .newBuilder[A ].mapResult(array => from(array))
930
+ def newBuilder [A ]: Builder [A , LazyList [A ]] = new LazyBuilder [A ]
931
+
932
+ private class LazyIterator [+ A ](private [this ] var lazyList : LazyList [A ]) extends AbstractIterator [A ] {
933
+ override def hasNext : Boolean = lazyList.nonEmpty
934
+
935
+ override def next (): A =
936
+ if (lazyList.isEmpty) Iterator .empty.next()
937
+ else {
938
+ val res = lazyList.head
939
+ lazyList = lazyList.tail
940
+ res
941
+ }
942
+ }
943
+
944
+ private class SlidingIterator [A ](private [this ] var lazyList : LazyList [A ], size : Int , step : Int )
945
+ extends AbstractIterator [LazyList [A ]] {
946
+ private val minLen = size - step max 0
947
+ private var first = true
948
+
949
+ def hasNext : Boolean =
950
+ if (first) lazyList.nonEmpty
951
+ else lazyList.lengthGt(minLen)
952
+
953
+ def next (): LazyList [A ] = {
954
+ if (! hasNext) Iterator .empty.next()
955
+ else {
956
+ first = false
957
+ val list = lazyList
958
+ lazyList = list.drop(step)
959
+ list.take(size)
960
+ }
961
+ }
962
+ }
963
+
964
+ private final class WithFilter [A ] private [LazyList ](lazyList : LazyList [A ], p : A => Boolean )
965
+ extends collection.WithFilter [A , LazyList ] {
966
+ private [this ] val filtered = lazyList.filter(p)
967
+ def map [B ](f : A => B ): LazyList [B ] = filtered.map(f)
968
+ def flatMap [B ](f : A => IterableOnce [B ]): LazyList [B ] = filtered.flatMap(f)
969
+ def foreach [U ](f : A => U ): Unit = filtered.foreach(f)
970
+ def withFilter (q : A => Boolean ): collection.WithFilter [A , LazyList ] = new WithFilter (filtered, q)
971
+ }
972
+
973
+ private final class LazyBuilder [A ] extends ReusableBuilder [A , LazyList [A ]] {
974
+ import LazyBuilder ._
975
+
976
+ private [this ] var next : DeferredState [A ] = _
977
+ private [this ] var list : LazyList [A ] = _
978
+
979
+ clear()
980
+
981
+ override def clear (): Unit = {
982
+ val deferred = new DeferredState [A ]
983
+ list = newLL(deferred.eval())
984
+ next = deferred
985
+ }
986
+
987
+ override def result (): LazyList [A ] = {
988
+ next init State .Empty
989
+ list
990
+ }
991
+
992
+ override def addOne (elem : A ): this .type = {
993
+ val deferred = new DeferredState [A ]
994
+ next init sCons(elem, newLL(deferred.eval()))
995
+ next = deferred
996
+ this
997
+ }
998
+
999
+ // lazy implementation which doesn't evaluate the collection being added
1000
+ override def addAll (xs : IterableOnce [A ]): this .type = {
1001
+ if (xs.knownSize != 0 ) {
1002
+ val deferred = new DeferredState [A ]
1003
+ next init stateFromIteratorConcatSuffix(xs.iterator)(deferred.eval())
1004
+ next = deferred
1005
+ }
1006
+ this
1007
+ }
1008
+ }
1009
+
1010
+ private object LazyBuilder {
1011
+ final class DeferredState [A ] {
1012
+ private [this ] var _state : () => State [A ] = _
1013
+
1014
+ def eval (): State [A ] = {
1015
+ val state = _state
1016
+ if (state == null ) throw new IllegalStateException (" uninitialized" )
1017
+ state()
1018
+ }
1019
+
1020
+ // racy
1021
+ def init (state : => State [A ]): Unit = {
1022
+ if (_state != null ) throw new IllegalStateException (" already initialized" )
1023
+ _state = () => state
1024
+ }
1025
+ }
1026
+ }
958
1027
959
1028
/** This serialization proxy is used for LazyLists which start with a sequence of evaluated cons cells.
960
1029
* The forced sequence is serialized in a compact, sequential format, followed by the unevaluated tail, which uses
0 commit comments