@@ -91,6 +91,11 @@ trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self =>
9191
9292 override def slice (from : Int , until : Int ): C = fromSpecific(new IndexedSeqView .Slice (this , from, until))
9393
94+ override def sliding (size : Int , step : Int ): Iterator [C ] = {
95+ require(size >= 1 && step >= 1 , f " size= $size%d and step= $step%d, but both must be positive " )
96+ new IndexedSeqSlidingIterator [A , CC , C ](this , size, step)
97+ }
98+
9499 override def head : A =
95100 if (! isEmpty) apply(0 )
96101 else throw new NoSuchElementException (s " head of empty ${
@@ -145,3 +150,26 @@ trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self =>
145150 }
146151 }
147152}
153+
154+ /** A fast sliding iterator for IndexedSeqs which uses the underlying `slice` operation. */
155+ private final class IndexedSeqSlidingIterator [A , CC [_], C ](s : IndexedSeqOps [A , CC , C ], size : Int , step : Int )
156+ extends AbstractIterator [C ] {
157+
158+ private [this ] val len = s.length
159+ private [this ] var pos = 0
160+ private def chklen : Boolean = len == s.length || {
161+ throw new java.util.ConcurrentModificationException (" collection size changed during iteration" )
162+ false
163+ }
164+
165+ def hasNext : Boolean = chklen && pos < len
166+
167+ def next (): C = if (! chklen || ! hasNext) Iterator .empty.next() else {
168+ val end = { val x = pos + size; if (x < 0 || x > len) len else x } // (pos.toLong + size).min(len).toInt
169+ val slice = s.slice(pos, end)
170+ pos =
171+ if (end >= len) len
172+ else { val x = pos + step; if (x < 0 || x > len) len else x } // (pos.toLong + step).min(len).toInt
173+ slice
174+ }
175+ }
0 commit comments