Skip to content

Commit ffde0e8

Browse files
authored
Merge pull request scala/scala#8311 from Jasper-M/SliceIterator-knownSize
add knownSize to appropriate Iterators
2 parents 2d19a08 + abab089 commit ffde0e8

File tree

1 file changed

+63
-13
lines changed

1 file changed

+63
-13
lines changed

library/src/scala/collection/Iterator.scala

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
129129
hd
130130
}
131131

132+
override def knownSize = {
133+
val thisSize = self.knownSize
134+
if (thisSize >= 0 && hdDefined) thisSize + 1
135+
else thisSize
136+
}
137+
132138
def hasNext =
133139
hdDefined || self.hasNext
134140

@@ -278,22 +284,25 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
278284
* all elements of this $coll followed by the minimal number of occurrences of `elem` so
279285
* that the resulting collection has a length of at least `len`.
280286
*/
281-
def padTo[B >: A](len: Int, elem: B): Iterator[B] = {
282-
val it = this
283-
new AbstractIterator[B] {
284-
private[this] var i = 0
287+
def padTo[B >: A](len: Int, elem: B): Iterator[B] = new AbstractIterator[B] {
288+
private[this] var i = 0
285289

286-
def next(): B = {
287-
val b =
288-
if (it.hasNext) it.next()
289-
else if (i < len) elem
290-
else Iterator.empty.next()
291-
i += 1
292-
b
293-
}
290+
override def knownSize: Int = {
291+
val thisSize = self.knownSize
292+
if (thisSize < 0) -1
293+
else thisSize max (len - i)
294+
}
294295

295-
def hasNext: Boolean = it.hasNext || i < len
296+
def next(): B = {
297+
val b =
298+
if (self.hasNext) self.next()
299+
else if (i < len) elem
300+
else Iterator.empty.next()
301+
i += 1
302+
b
296303
}
304+
305+
def hasNext: Boolean = self.hasNext || i < len
297306
}
298307

299308
/** Partitions this iterator in two iterators according to a predicate.
@@ -369,6 +378,12 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
369378
// and then that will be modified to iterate through the collection
370379
private[this] var current: Iterator[B] =
371380
new AbstractIterator[B] {
381+
override def knownSize = {
382+
val thisSize = self.knownSize
383+
384+
if (thisSize < 0) -1
385+
else thisSize + 1
386+
}
372387
def hasNext: Boolean = true
373388
def next(): B = {
374389
// Here we change our self-reference to a new iterator that iterates through `self`
@@ -379,10 +394,12 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
379394
acc
380395
}
381396
def hasNext: Boolean = self.hasNext
397+
override def knownSize = self.knownSize
382398
}
383399
z
384400
}
385401
}
402+
override def knownSize = current.knownSize
386403
def next(): B = current.next()
387404
def hasNext: Boolean = current.hasNext
388405
}
@@ -551,6 +568,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
551568
}
552569

553570
def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {
571+
override def knownSize = self.knownSize
554572
def hasNext = self.hasNext
555573
def next() = f(self.next())
556574
}
@@ -773,12 +791,19 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
773791

774792
def zip[B](that: IterableOnce[B]): Iterator[(A, B)] = new AbstractIterator[(A, B)] {
775793
val thatIterator = that.iterator
794+
override def knownSize = self.knownSize min thatIterator.knownSize
776795
def hasNext = self.hasNext && thatIterator.hasNext
777796
def next() = (self.next(), thatIterator.next())
778797
}
779798

780799
def zipAll[A1 >: A, B](that: IterableOnce[B], thisElem: A1, thatElem: B): Iterator[(A1, B)] = new AbstractIterator[(A1, B)] {
781800
val thatIterator = that.iterator
801+
override def knownSize = {
802+
val thisSize = self.knownSize
803+
val thatSize = thatIterator.knownSize
804+
if (thisSize < 0 || thatSize < 0) -1
805+
else thisSize max thatSize
806+
}
782807
def hasNext = self.hasNext || thatIterator.hasNext
783808
def next(): (A1, B) = {
784809
val next1 = self.hasNext
@@ -790,6 +815,7 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
790815

791816
def zipWithIndex: Iterator[(A, Int)] = new AbstractIterator[(A, Int)] {
792817
var idx = 0
818+
override def knownSize = self.knownSize
793819
def hasNext = self.hasNext
794820
def next() = {
795821
val ret = (self.next(), idx)
@@ -825,6 +851,13 @@ trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Ite
825851
val gap = new scala.collection.mutable.Queue[A]
826852
var ahead: Iterator[A] = null
827853
class Partner extends AbstractIterator[A] {
854+
override def knownSize: Int = self.synchronized {
855+
val thisSize = self.knownSize
856+
857+
if (this eq ahead) thisSize
858+
else if (thisSize < 0 || gap.knownSize < 0) -1
859+
else thisSize + gap.knownSize
860+
}
828861
def hasNext: Boolean = self.synchronized {
829862
(this ne ahead) && !gap.isEmpty || self.hasNext
830863
}
@@ -958,6 +991,7 @@ object Iterator extends IterableFactory[Iterator] {
958991
*/
959992
override def fill[A](len: Int)(elem: => A): Iterator[A] = new AbstractIterator[A] {
960993
private[this] var i = 0
994+
override def knownSize: Int = (len - i) max 0
961995
def hasNext: Boolean = i < len
962996
def next(): A =
963997
if (hasNext) { i += 1; elem }
@@ -972,6 +1006,7 @@ object Iterator extends IterableFactory[Iterator] {
9721006
*/
9731007
override def tabulate[A](end: Int)(f: Int => A): Iterator[A] = new AbstractIterator[A] {
9741008
private[this] var i = 0
1009+
override def knownSize: Int = (end - i) max 0
9751010
def hasNext: Boolean = i < end
9761011
def next(): A =
9771012
if (hasNext) { val result = f(i); i += 1; result }
@@ -1016,6 +1051,12 @@ object Iterator extends IterableFactory[Iterator] {
10161051
if (step == 0) throw new IllegalArgumentException("zero step")
10171052
private[this] var i = start
10181053
private[this] var hasOverflowed = false
1054+
override def knownSize: Int = {
1055+
val size = math.ceil((end.toLong - i.toLong) / step.toDouble)
1056+
if (size < 0) 0
1057+
else if (size > Int.MaxValue) -1
1058+
else size.toInt
1059+
}
10191060
def hasNext: Boolean = {
10201061
(step <= 0 || i < end) && (step >= 0 || i > end) && !hasOverflowed
10211062
}
@@ -1161,6 +1202,15 @@ object Iterator extends IterableFactory[Iterator] {
11611202
} else
11621203
dropping = 0
11631204
}
1205+
override def knownSize: Int = {
1206+
val size = underlying.knownSize
1207+
if (size < 0) -1
1208+
else {
1209+
val dropSize = 0 max (size - dropping)
1210+
if (unbounded) dropSize
1211+
else remaining min dropSize
1212+
}
1213+
}
11641214
def hasNext = { skip(); remaining != 0 && underlying.hasNext }
11651215
def next() = {
11661216
skip()

0 commit comments

Comments
 (0)