diff --git a/libraries/stdlib/src/kotlin/collections/Sequences.kt b/libraries/stdlib/src/kotlin/collections/Sequences.kt index 0b50d93818a..7cdcf47af62 100644 --- a/libraries/stdlib/src/kotlin/collections/Sequences.kt +++ b/libraries/stdlib/src/kotlin/collections/Sequences.kt @@ -289,37 +289,55 @@ constructor( private val transformer: (T) -> R, private val iterator: (R) -> Iterator ) : Sequence { + private object State { + const val UNDEFINED = 0 + const val READY = 1 + const val DONE = 2 + } + override fun iterator(): Iterator = object : Iterator { val iterator = sequence.iterator() var itemIterator: Iterator? = null + // Use state to avoid excessive ensureItemIterator calls. + // The state is represented by the integer to avoid an overhead associated with the enum. + var state = State.UNDEFINED + override fun next(): E { - if (!ensureItemIterator()) + if (state == State.DONE) throw NoSuchElementException() + if (state == State.UNDEFINED && !ensureItemIterator()) { throw NoSuchElementException() + } + state = State.UNDEFINED return itemIterator!!.next() } override fun hasNext(): Boolean { + if (state == State.READY) return true + if (state == State.DONE) return false return ensureItemIterator() } private fun ensureItemIterator(): Boolean { - if (itemIterator?.hasNext() == false) - itemIterator = null + val itemIterator = itemIterator + if (itemIterator != null && itemIterator.hasNext()) { + state = State.READY + return true + } - while (itemIterator == null) { - if (!iterator.hasNext()) { - return false - } else { - val element = iterator.next() - val nextItemIterator = iterator(transformer(element)) - if (nextItemIterator.hasNext()) { - itemIterator = nextItemIterator - return true - } + while (iterator.hasNext()) { + val element = iterator.next() + val nextItemIterator = iterator(transformer(element)) + if (nextItemIterator.hasNext()) { + this.itemIterator = nextItemIterator + state = State.READY + return true } } - return true + + state = State.DONE + this.itemIterator = null + return false } } }