kotlin.collections.SequenceBuilder.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:kotlin.jvm.JvmMultifileClass
@file:kotlin.jvm.JvmName("SequencesKt")
@file:OptIn(ExperimentalTypeInference::class)
package kotlin.sequences
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
import kotlin.experimental.ExperimentalTypeInference
/**
* Builds a [Sequence] lazily yielding values one by one.
*
* @see kotlin.sequences.generateSequence
*
* @sample samples.collections.Sequences.Building.buildSequenceYieldAll
* @sample samples.collections.Sequences.Building.buildFibonacciSequence
*/
@SinceKotlin("1.3")
public fun sequence(@BuilderInference block: suspend SequenceScope.() -> Unit): Sequence = Sequence { iterator(block) }
@SinceKotlin("1.3")
@Deprecated("Use 'sequence { }' function instead.", ReplaceWith("sequence(builderAction)"), level = DeprecationLevel.ERROR)
@kotlin.internal.InlineOnly
public inline fun buildSequence(@BuilderInference noinline builderAction: suspend SequenceScope.() -> Unit): Sequence = Sequence { iterator(builderAction) }
/**
* Builds an [Iterator] lazily yielding values one by one.
*
* @sample samples.collections.Sequences.Building.buildIterator
* @sample samples.collections.Iterables.Building.iterable
*/
@SinceKotlin("1.3")
public fun iterator(@BuilderInference block: suspend SequenceScope.() -> Unit): Iterator {
val iterator = SequenceBuilderIterator()
iterator.nextStep = block.createCoroutineUnintercepted(receiver = iterator, completion = iterator)
return iterator
}
@SinceKotlin("1.3")
@Deprecated("Use 'iterator { }' function instead.", ReplaceWith("iterator(builderAction)"), level = DeprecationLevel.ERROR)
@kotlin.internal.InlineOnly
public inline fun buildIterator(@BuilderInference noinline builderAction: suspend SequenceScope.() -> Unit): Iterator = iterator(builderAction)
/**
* The scope for yielding values of a [Sequence] or an [Iterator], provides [yield] and [yieldAll] suspension functions.
*
* @see sequence
* @see iterator
*
* @sample samples.collections.Sequences.Building.buildSequenceYieldAll
* @sample samples.collections.Sequences.Building.buildFibonacciSequence
*/
@RestrictsSuspension
@SinceKotlin("1.3")
public abstract class SequenceScope internal constructor() {
/**
* Yields a value to the [Iterator] being built and suspends
* until the next value is requested.
*
* @sample samples.collections.Sequences.Building.buildSequenceYieldAll
* @sample samples.collections.Sequences.Building.buildFibonacciSequence
*/
public abstract suspend fun yield(value: T)
/**
* Yields all values from the `iterator` to the [Iterator] being built
* and suspends until all these values are iterated and the next one is requested.
*
* The sequence of values returned by the given iterator can be potentially infinite.
*
* @sample samples.collections.Sequences.Building.buildSequenceYieldAll
*/
public abstract suspend fun yieldAll(iterator: Iterator)
/**
* Yields a collections of values to the [Iterator] being built
* and suspends until all these values are iterated and the next one is requested.
*
* @sample samples.collections.Sequences.Building.buildSequenceYieldAll
*/
public suspend fun yieldAll(elements: Iterable) {
if (elements is Collection && elements.isEmpty()) return
return yieldAll(elements.iterator())
}
/**
* Yields potentially infinite sequence of values to the [Iterator] being built
* and suspends until all these values are iterated and the next one is requested.
*
* The sequence can be potentially infinite.
*
* @sample samples.collections.Sequences.Building.buildSequenceYieldAll
*/
public suspend fun yieldAll(sequence: Sequence) = yieldAll(sequence.iterator())
}
@Deprecated("Use SequenceScope class instead.", ReplaceWith("SequenceScope"), level = DeprecationLevel.ERROR)
public typealias SequenceBuilder = SequenceScope
private typealias State = Int
private const val State_NotReady: State = 0
private const val State_ManyNotReady: State = 1
private const val State_ManyReady: State = 2
private const val State_Ready: State = 3
private const val State_Done: State = 4
private const val State_Failed: State = 5
private class SequenceBuilderIterator : SequenceScope(), Iterator, Continuation {
private var state = State_NotReady
private var nextValue: T? = null
private var nextIterator: Iterator? = null
var nextStep: Continuation? = null
override fun hasNext(): Boolean {
while (true) {
when (state) {
State_NotReady -> {}
State_ManyNotReady ->
if (nextIterator!!.hasNext()) {
state = State_ManyReady
return true
} else {
nextIterator = null
}
State_Done -> return false
State_Ready, State_ManyReady -> return true
else -> throw exceptionalState()
}
state = State_Failed
val step = nextStep!!
nextStep = null
step.resume(Unit)
}
}
override fun next(): T {
when (state) {
State_NotReady, State_ManyNotReady -> return nextNotReady()
State_ManyReady -> {
state = State_ManyNotReady
return nextIterator!!.next()
}
State_Ready -> {
state = State_NotReady
@Suppress("UNCHECKED_CAST")
val result = nextValue as T
nextValue = null
return result
}
else -> throw exceptionalState()
}
}
private fun nextNotReady(): T {
if (!hasNext()) throw NoSuchElementException() else return next()
}
private fun exceptionalState(): Throwable = when (state) {
State_Done -> NoSuchElementException()
State_Failed -> IllegalStateException("Iterator has failed.")
else -> IllegalStateException("Unexpected state of the iterator: $state")
}
override suspend fun yield(value: T) {
nextValue = value
state = State_Ready
return suspendCoroutineUninterceptedOrReturn { c ->
nextStep = c
COROUTINE_SUSPENDED
}
}
override suspend fun yieldAll(iterator: Iterator) {
if (!iterator.hasNext()) return
nextIterator = iterator
state = State_ManyReady
return suspendCoroutineUninterceptedOrReturn { c ->
nextStep = c
COROUTINE_SUSPENDED
}
}
// Completion continuation implementation
override fun resumeWith(result: Result) {
result.getOrThrow() // just rethrow exception if it is there
state = State_Done
}
override val context: CoroutineContext
get() = EmptyCoroutineContext
}