@@ -3,8 +3,41 @@ package decorators
33
44import scala .annotation .tailrec
55
6+ /** Enriches Iterator with additional methods.
7+ *
8+ * @define mayNotTerminateInf
9+ * Note: may not terminate for infinite iterators.
10+ * @define doesNotTerminateInf
11+ * Note: does not terminate for infinite iterators.
12+ * @define consumesIterator
13+ * After calling this method, one should discard the iterator it was called
14+ * on. Using it is undefined and subject to change.
15+ * @define consumesAndProducesIterator
16+ * After calling this method, one should discard the iterator it was called
17+ * on, and use only the iterator that was returned. Using the old iterator
18+ * is undefined, subject to change, and may result in changes to the new
19+ * iterator as well.
20+ * @define pseudoCodeExample
21+ * The `===` operator in this pseudo code stands for 'is equivalent to';
22+ * both sides of the `===` give the same result.
23+ */
624class IteratorDecorator [A ](val `this` : Iterator [A ]) extends AnyVal {
725
26+ /**
27+ * Inserts a separator value between each element.
28+ *
29+ * {{{
30+ * Iterator(1, 2, 3).intersperse(0) === Iterator(1, 0, 2, 0, 3)
31+ * Iterator('a', 'b', 'c').intersperse(',') === Iterator('a', ',', 'b', ',', 'c')
32+ * Iterator('a').intersperse(',') === Iterator('a')
33+ * Iterator().intersperse(',') === Iterator()
34+ * }}}
35+ * $pseudoCodeExample
36+ *
37+ * @param sep the separator value.
38+ * @return The resulting iterator contains all elements from the source iterator, separated by the `sep` value.
39+ * @note Reuse: $consumesAndProducesIterator
40+ */
841 def intersperse [B >: A ](sep : B ): Iterator [B ] = new Iterator [B ] {
942 var intersperseNext = false
1043 override def hasNext = intersperseNext || `this`.hasNext
@@ -15,6 +48,27 @@ class IteratorDecorator[A](val `this`: Iterator[A]) extends AnyVal {
1548 }
1649 }
1750
51+ /**
52+ * Inserts a start value at the start of the iterator, a separator value between each element, and
53+ * an end value at the end of the iterator.
54+ *
55+ * {{{
56+ * Iterator(1, 2, 3).intersperse(-1, 0, 99) === Iterator(-1, 1, 0, 2, 0, 3, 99)
57+ * Iterator('a', 'b', 'c').intersperse('[', ',', ']') === Iterator('[', 'a', ',', 'b', ',', 'c', ']')
58+ * Iterator('a').intersperse('[', ',', ']') === Iterator('[', 'a', ']')
59+ * Iterator().intersperse('[', ',', ']') === Iterator('[', ']')
60+ * }}}
61+ * $pseudoCodeExample
62+ *
63+ * @param start the starting value.
64+ * @param sep the separator value.
65+ * @param end the ending value.
66+ * @return The resulting iterator
67+ * begins with the `start` value and ends with the `end` value.
68+ * Inside, are all elements from the source iterator separated by
69+ * the `sep` value.
70+ * @note Reuse: $consumesAndProducesIterator
71+ */
1872 def intersperse [B >: A ](start : B , sep : B , end : B ): Iterator [B ] = new Iterator [B ] {
1973 var started = false
2074 var finished = false
@@ -41,6 +95,27 @@ class IteratorDecorator[A](val `this`: Iterator[A]) extends AnyVal {
4195 }
4296 }
4397
98+ /**
99+ * Folds elements with combination function `op` until
100+ * all elements have been processed, or `op` returns `None`.
101+ * $mayNotTerminateInf
102+ *
103+ * {{{
104+ * def sumOp(acc: Int, e: Int): Option[Int] = if (e == 4) None else Some(acc + e)
105+ * Iterator.empty.foldSomeLeft(0)(sumOp) === 0
106+ * Iterator(1, 2, 3).foldSomeLeft(0)(sumOp) === 6
107+ * Iterator(1, 2, 3, 4, 5).foldSomeLeft(0)(sumOp) === 6
108+ * }}}
109+ * $pseudoCodeExample
110+ *
111+ * @param z the start value
112+ * @param op the binary operator
113+ * @tparam B the result type of the binary operator
114+ * @return the result of evaluating `op` on the previous result of `op` (or `z` for the first time) and
115+ * elements of the source iterator, stopping when all the elements have been
116+ * iterated or earlier when `op` returns `None`
117+ * @note Reuse: $consumesIterator
118+ */
44119 def foldSomeLeft [B ](z : B )(op : (B , A ) => Option [B ]): B = {
45120 var result : B = z
46121 while (`this`.hasNext) {
@@ -52,6 +127,10 @@ class IteratorDecorator[A](val `this`: Iterator[A]) extends AnyVal {
52127 result
53128 }
54129
130+ /**
131+ * $mayNotTerminateInf
132+ * @note Reuse: $consumesIterator
133+ */
55134 def lazyFoldLeft [B ](z : B )(op : (B , => A ) => B ): B = {
56135 var result = z
57136 var finished = false
@@ -66,6 +145,10 @@ class IteratorDecorator[A](val `this`: Iterator[A]) extends AnyVal {
66145 result
67146 }
68147
148+ /**
149+ * $doesNotTerminateInf
150+ * @note Reuse: $consumesIterator
151+ */
69152 def lazyFoldRight [B ](z : B )(op : A => Either [B , B => B ]): B = {
70153
71154 def chainEval (x : B , fs : immutable.List [B => B ]): B =
@@ -87,26 +170,20 @@ class IteratorDecorator[A](val `this`: Iterator[A]) extends AnyVal {
87170 }
88171
89172 /**
90- * Constructs an iterator where consecutive elements are accumulated as
91- * long as the output of f for each element doesn't change.
92- * <pre>
93- * Vector(1,2,2,3,3,3,2,2)
94- * .iterator
95- * .splitBy(identity)
96- * .toList
97- * </pre>
98- * produces
99- * <pre>
100- * List(Seq(1),
101- * Seq(2,2),
102- * Seq(3,3,3),
103- * Seq(2,2))
104- * </pre>
173+ * Constructs an iterator in which each element is a the sequence of accumulated elements
174+ * from the source iterator that have the same key, where the key is calculated by `f`.
175+ *
176+ * {{{
177+ * Iterator(1,2,2,3,3,3,2,2).splitBy(identity) === Iterator(Seq(1), Seq(2,2), Seq(3,3,3), Seq(2,2))
178+ * Iterator((1,1), (1,2), (2, 3)).splitBy(_._1) === Iterator(Seq((1,1), (1,2)), Seq((2,3)))
179+ * }}}
180+ * $pseudoCodeExample
105181 *
106182 * @param f the function to compute a key for an element
107183 * @tparam K the type of the computed key
108184 * @return an iterator of sequences of the consecutive elements with the
109185 * same key in the original iterator
186+ * @note Reuse: $consumesIterator
110187 */
111188 def splitBy [K ](f : A => K ): Iterator [immutable.Seq [A ]] =
112189 new AbstractIterator [immutable.Seq [A ]] {
0 commit comments