Fix infinite sequence being terminated prematurely when being iterated without calling hasNext

#KT-16922 Fixed
This commit is contained in:
Ilya Gorbunov
2017-03-17 23:17:28 +03:00
parent f00ab135d6
commit e5a28311bc
2 changed files with 33 additions and 9 deletions
@@ -94,10 +94,11 @@ public abstract class SequenceBuilder<in T> internal constructor() {
private typealias State = Int private typealias State = Int
private const val State_NotReady: State = 0 private const val State_NotReady: State = 0
private const val State_ManyReady: State = 1 private const val State_ManyNotReady: State = 1
private const val State_Ready: State = 2 private const val State_ManyReady: State = 2
private const val State_Done: State = 3 private const val State_Ready: State = 3
private const val State_Failed: State = 4 private const val State_Done: State = 4
private const val State_Failed: State = 5
private class SequenceBuilderIterator<T> : SequenceBuilder<T>(), Iterator<T>, Continuation<Unit> { private class SequenceBuilderIterator<T> : SequenceBuilder<T>(), Iterator<T>, Continuation<Unit> {
private var state = State_NotReady private var state = State_NotReady
@@ -109,10 +110,15 @@ private class SequenceBuilderIterator<T> : SequenceBuilder<T>(), Iterator<T>, Co
while (true) { while (true) {
when (state) { when (state) {
State_NotReady -> {} State_NotReady -> {}
State_ManyReady -> State_ManyNotReady ->
if (nextIterator!!.hasNext()) return true else nextIterator = null if (nextIterator!!.hasNext()) {
state = State_ManyReady
return true
} else {
nextIterator = null
}
State_Done -> return false State_Done -> return false
State_Ready -> return true State_Ready, State_ManyReady -> return true
else -> throw exceptionalState() else -> throw exceptionalState()
} }
@@ -125,8 +131,11 @@ private class SequenceBuilderIterator<T> : SequenceBuilder<T>(), Iterator<T>, Co
override fun next(): T { override fun next(): T {
when (state) { when (state) {
State_NotReady -> return nextNotReady() State_NotReady, State_ManyNotReady -> return nextNotReady()
State_ManyReady -> return nextIterator!!.next() State_ManyReady -> {
state = State_ManyNotReady
return nextIterator!!.next()
}
State_Ready -> { State_Ready -> {
state = State_NotReady state = State_NotReady
val result = nextValue as T val result = nextValue as T
@@ -287,4 +287,19 @@ class SequenceBuilderTest {
effects.toList() effects.toList()
) )
} }
@Test
fun testInfiniteYieldAll() {
val values = buildIterator {
while (true) {
yieldAll((1..5).map { it })
}
}
var sum = 0
repeat(10) {
sum += values.next() //.also(::println)
}
assertEquals(30, sum)
}
} }