KT-58588 Optimize Sequence::flatten

Rewrite FlatteningSequence to use
the same optimization technique as AbstractIterator.
Didn't extend AbstractIterator as storing and reloading a value
from a field is slightly slower compared to the implemented approach.
This commit is contained in:
Filipp Zhinkin
2023-09-20 10:36:04 +02:00
committed by Space Team
parent 7ca506870a
commit e803977924
@@ -289,37 +289,55 @@ constructor(
private val transformer: (T) -> R, private val transformer: (T) -> R,
private val iterator: (R) -> Iterator<E> private val iterator: (R) -> Iterator<E>
) : Sequence<E> { ) : Sequence<E> {
private object State {
const val UNDEFINED = 0
const val READY = 1
const val DONE = 2
}
override fun iterator(): Iterator<E> = object : Iterator<E> { override fun iterator(): Iterator<E> = object : Iterator<E> {
val iterator = sequence.iterator() val iterator = sequence.iterator()
var itemIterator: Iterator<E>? = null var itemIterator: Iterator<E>? = 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 { override fun next(): E {
if (!ensureItemIterator()) if (state == State.DONE) throw NoSuchElementException()
if (state == State.UNDEFINED && !ensureItemIterator()) {
throw NoSuchElementException() throw NoSuchElementException()
}
state = State.UNDEFINED
return itemIterator!!.next() return itemIterator!!.next()
} }
override fun hasNext(): Boolean { override fun hasNext(): Boolean {
if (state == State.READY) return true
if (state == State.DONE) return false
return ensureItemIterator() return ensureItemIterator()
} }
private fun ensureItemIterator(): Boolean { private fun ensureItemIterator(): Boolean {
if (itemIterator?.hasNext() == false) val itemIterator = itemIterator
itemIterator = null if (itemIterator != null && itemIterator.hasNext()) {
state = State.READY
return true
}
while (itemIterator == null) { while (iterator.hasNext()) {
if (!iterator.hasNext()) { val element = iterator.next()
return false val nextItemIterator = iterator(transformer(element))
} else { if (nextItemIterator.hasNext()) {
val element = iterator.next() this.itemIterator = nextItemIterator
val nextItemIterator = iterator(transformer(element)) state = State.READY
if (nextItemIterator.hasNext()) { return true
itemIterator = nextItemIterator
return true
}
} }
} }
return true
state = State.DONE
this.itemIterator = null
return false
} }
} }
} }