Patch common stdlib to prevent it from using experimental coroutines
This commit is contained in:
committed by
SvyatoslavScherbina
parent
9972a57af6
commit
d424a1f1ce
@@ -150,6 +150,9 @@ def commonSrc = file('build/stdlib')
|
||||
|
||||
task unzipStdlibSources(type: Copy) {
|
||||
from (zipTree(configurations.kotlin_common_stdlib_src.singleFile)) {
|
||||
exclude 'generated/_Sequences.kt'
|
||||
exclude 'kotlin/collections/Sequences.kt'
|
||||
exclude 'kotlin/collections/SlidingWindow.kt'
|
||||
include 'generated/**/*.kt'
|
||||
include 'kotlin/**/*.kt'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.collections
|
||||
|
||||
import kotlin.*
|
||||
import kotlin.sequences.buildIterator
|
||||
|
||||
internal fun checkWindowSizeStep(size: Int, step: Int) {
|
||||
require(size > 0 && step > 0) {
|
||||
if (size != step)
|
||||
"Both size $size and step $step must be greater than zero."
|
||||
else
|
||||
"size $size must be greater than zero."
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> Sequence<T>.windowedSequence(size: Int, step: Int, partialWindows: Boolean, reuseBuffer: Boolean): Sequence<List<T>> {
|
||||
checkWindowSizeStep(size, step)
|
||||
return Sequence { windowedIterator(iterator(), size, step, partialWindows, reuseBuffer) }
|
||||
}
|
||||
|
||||
internal fun <T> windowedIterator(iterator: Iterator<T>, size: Int, step: Int, partialWindows: Boolean, reuseBuffer: Boolean): Iterator<List<T>> {
|
||||
if (!iterator.hasNext()) return EmptyIterator
|
||||
return buildIterator<List<T>> {
|
||||
val gap = step - size
|
||||
if (gap >= 0) {
|
||||
var buffer = ArrayList<T>(size)
|
||||
var skip = 0
|
||||
for (e in iterator) {
|
||||
if (skip > 0) { skip -= 1; continue }
|
||||
buffer.add(e)
|
||||
if (buffer.size == size) {
|
||||
yield(buffer)
|
||||
if (reuseBuffer) buffer.clear() else buffer = ArrayList(size)
|
||||
skip = gap
|
||||
}
|
||||
}
|
||||
if (buffer.isNotEmpty()) {
|
||||
if (partialWindows || buffer.size == size) yield(buffer)
|
||||
}
|
||||
} else {
|
||||
val buffer = RingBuffer<T>(size)
|
||||
for (e in iterator) {
|
||||
buffer.add(e)
|
||||
if (buffer.isFull()) {
|
||||
yield(if (reuseBuffer) buffer else ArrayList(buffer))
|
||||
buffer.removeFirst(step)
|
||||
}
|
||||
}
|
||||
if (partialWindows) {
|
||||
while (buffer.size > step) {
|
||||
yield(if (reuseBuffer) buffer else ArrayList(buffer))
|
||||
buffer.removeFirst(step)
|
||||
}
|
||||
if (buffer.isNotEmpty()) yield(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MovingSubList<out E>(private val list: List<E>) : AbstractList<E>(), RandomAccess {
|
||||
private var fromIndex: Int = 0
|
||||
private var _size: Int = 0
|
||||
|
||||
fun move(fromIndex: Int, toIndex: Int) {
|
||||
checkRangeIndexes(fromIndex, toIndex, list.size)
|
||||
this.fromIndex = fromIndex
|
||||
this._size = toIndex - fromIndex
|
||||
}
|
||||
|
||||
override fun get(index: Int): E {
|
||||
checkElementIndex(index, _size)
|
||||
|
||||
return list[fromIndex + index]
|
||||
}
|
||||
|
||||
override val size: Int get() = _size
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides ring buffer implementation.
|
||||
*
|
||||
* Buffer overflow is not allowed so [add] doesn't overwrite tail but raises an exception.
|
||||
*/
|
||||
private class RingBuffer<T>(val capacity: Int) : AbstractList<T>(), RandomAccess {
|
||||
init {
|
||||
require(capacity >= 0) { "ring buffer capacity should not be negative but it is $capacity" }
|
||||
}
|
||||
|
||||
private val buffer = arrayOfNulls<Any?>(capacity)
|
||||
private var startIndex: Int = 0
|
||||
|
||||
override var size: Int = 0
|
||||
private set
|
||||
|
||||
override fun get(index: Int): T {
|
||||
checkElementIndex(index, size)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return buffer[startIndex.forward(index)] as T
|
||||
}
|
||||
|
||||
fun isFull() = size == capacity
|
||||
|
||||
override fun iterator(): Iterator<T> = object : AbstractIterator<T>() {
|
||||
private var count = size
|
||||
private var index = startIndex
|
||||
|
||||
override fun computeNext() {
|
||||
if (count == 0) {
|
||||
done()
|
||||
} else {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
setNext(buffer[index] as T)
|
||||
index = index.forward(1)
|
||||
count--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T> toArray(array: Array<T>): Array<T> {
|
||||
val result: Array<T?> =
|
||||
if (array.size < this.size) array.copyOf(this.size) else array as Array<T?>
|
||||
|
||||
val size = this.size
|
||||
|
||||
var widx = 0
|
||||
var idx = startIndex
|
||||
|
||||
while (widx < size && idx < capacity) {
|
||||
result[widx] = buffer[idx] as T
|
||||
widx++
|
||||
idx++
|
||||
}
|
||||
|
||||
idx = 0
|
||||
while (widx < size) {
|
||||
result[widx] = buffer[idx] as T
|
||||
widx++
|
||||
idx++
|
||||
}
|
||||
if (result.size > this.size) result[this.size] = null
|
||||
|
||||
return result as Array<T>
|
||||
}
|
||||
|
||||
override fun toArray(): Array<Any?> {
|
||||
return toArray(arrayOfNulls(size))
|
||||
}
|
||||
|
||||
/**
|
||||
* Add [element] to the buffer or fail with [IllegalStateException] if no free space available in the buffer
|
||||
*/
|
||||
fun add(element: T) {
|
||||
if (isFull()) {
|
||||
throw IllegalStateException("ring buffer is full")
|
||||
}
|
||||
|
||||
buffer[startIndex.forward(size)] = element
|
||||
size++
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes [n] first elements from the buffer or fails with [IllegalArgumentException] if not enough elements in the buffer to remove
|
||||
*/
|
||||
fun removeFirst(n: Int) {
|
||||
require(n >= 0) { "n shouldn't be negative but it is $n" }
|
||||
require(n <= size) { "n shouldn't be greater than the buffer size: n = $n, size = $size" }
|
||||
|
||||
if (n > 0) {
|
||||
val start = startIndex
|
||||
val end = start.forward(n)
|
||||
|
||||
if (start > end) {
|
||||
buffer.fill(null, start, capacity)
|
||||
buffer.fill(null, 0, end)
|
||||
} else {
|
||||
buffer.fill(null, start, end)
|
||||
}
|
||||
|
||||
startIndex = end
|
||||
size -= n
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun Int.forward(n: Int): Int = (this + n) % capacity
|
||||
|
||||
// TODO: replace with Array.fill from stdlib when available in common
|
||||
private fun <T> Array<T>.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit {
|
||||
for (idx in fromIndex until toIndex) {
|
||||
this[idx] = element
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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")
|
||||
|
||||
package kotlin.sequences
|
||||
|
||||
import kotlin.*
|
||||
|
||||
/**
|
||||
* Given an [iterator] function constructs a [Sequence] that returns values through the [Iterator]
|
||||
* provided by that function.
|
||||
* The values are evaluated lazily, and the sequence is potentially infinite.
|
||||
*
|
||||
* @sample samples.collections.Sequences.Building.sequenceFromIterator
|
||||
*/
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun <T> Sequence(crossinline iterator: () -> Iterator<T>): Sequence<T> = object : Sequence<T> {
|
||||
override fun iterator(): Iterator<T> = iterator()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sequence that returns all elements from this iterator. The sequence is constrained to be iterated only once.
|
||||
*
|
||||
* @sample samples.collections.Sequences.Building.sequenceFromIterator
|
||||
*/
|
||||
public fun <T> Iterator<T>.asSequence(): Sequence<T> = Sequence { this }.constrainOnce()
|
||||
|
||||
/**
|
||||
* Creates a sequence that returns the specified values.
|
||||
*
|
||||
* @sample samples.collections.Sequences.Building.sequenceOfValues
|
||||
*/
|
||||
public fun <T> sequenceOf(vararg elements: T): Sequence<T> = if (elements.isEmpty()) emptySequence() else elements.asSequence()
|
||||
|
||||
/**
|
||||
* Returns an empty sequence.
|
||||
*/
|
||||
public fun <T> emptySequence(): Sequence<T> = EmptySequence
|
||||
|
||||
private object EmptySequence : Sequence<Nothing>, DropTakeSequence<Nothing> {
|
||||
override fun iterator(): Iterator<Nothing> = EmptyIterator
|
||||
override fun drop(n: Int) = EmptySequence
|
||||
override fun take(n: Int) = EmptySequence
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this sequence if it's not `null` and the empty sequence otherwise.
|
||||
* @sample samples.collections.Sequences.Usage.sequenceOrEmpty
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline fun <T> Sequence<T>?.orEmpty(): Sequence<T> = this ?: emptySequence()
|
||||
|
||||
|
||||
/**
|
||||
* Returns a sequence that iterates through the elements either of this sequence
|
||||
* or, if this sequence turns out to be empty, of the sequence returned by [defaultValue] function.
|
||||
*
|
||||
* @sample samples.collections.Sequences.Usage.sequenceIfEmpty
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
public fun <T> Sequence<T>.ifEmpty(defaultValue: () -> Sequence<T>): Sequence<T> = buildSequence {
|
||||
val iterator = this@ifEmpty.iterator()
|
||||
if (iterator.hasNext()) {
|
||||
yieldAll(iterator)
|
||||
} else {
|
||||
yieldAll(defaultValue())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of all elements from all sequences in this sequence.
|
||||
*
|
||||
* The operation is _intermediate_ and _stateless_.
|
||||
*/
|
||||
public fun <T> Sequence<Sequence<T>>.flatten(): Sequence<T> = flatten { it.iterator() }
|
||||
|
||||
/**
|
||||
* Returns a sequence of all elements from all iterables in this sequence.
|
||||
*
|
||||
* The operation is _intermediate_ and _stateless_.
|
||||
*/
|
||||
@kotlin.jvm.JvmName("flattenSequenceOfIterable")
|
||||
public fun <T> Sequence<Iterable<T>>.flatten(): Sequence<T> = flatten { it.iterator() }
|
||||
|
||||
private fun <T, R> Sequence<T>.flatten(iterator: (T) -> Iterator<R>): Sequence<R> {
|
||||
if (this is TransformingSequence<*, *>) {
|
||||
return (this as TransformingSequence<*, T>).flatten(iterator)
|
||||
}
|
||||
return FlatteningSequence(this, { it }, iterator)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pair of lists, where
|
||||
* *first* list is built from the first values of each pair from this sequence,
|
||||
* *second* list is built from the second values of each pair from this sequence.
|
||||
*
|
||||
* The operation is _terminal_.
|
||||
*/
|
||||
public fun <T, R> Sequence<Pair<T, R>>.unzip(): Pair<List<T>, List<R>> {
|
||||
val listT = ArrayList<T>()
|
||||
val listR = ArrayList<R>()
|
||||
for (pair in this) {
|
||||
listT.add(pair.first)
|
||||
listR.add(pair.second)
|
||||
}
|
||||
return listT to listR
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence that returns the values from the underlying [sequence] that either match or do not match
|
||||
* the specified [predicate].
|
||||
*
|
||||
* @param sendWhen If `true`, values for which the predicate returns `true` are returned. Otherwise,
|
||||
* values for which the predicate returns `false` are returned
|
||||
*/
|
||||
internal class FilteringSequence<T>(
|
||||
private val sequence: Sequence<T>,
|
||||
private val sendWhen: Boolean = true,
|
||||
private val predicate: (T) -> Boolean
|
||||
) : Sequence<T> {
|
||||
|
||||
override fun iterator(): Iterator<T> = object : Iterator<T> {
|
||||
val iterator = sequence.iterator()
|
||||
var nextState: Int = -1 // -1 for unknown, 0 for done, 1 for continue
|
||||
var nextItem: T? = null
|
||||
|
||||
private fun calcNext() {
|
||||
while (iterator.hasNext()) {
|
||||
val item = iterator.next()
|
||||
if (predicate(item) == sendWhen) {
|
||||
nextItem = item
|
||||
nextState = 1
|
||||
return
|
||||
}
|
||||
}
|
||||
nextState = 0
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
if (nextState == -1)
|
||||
calcNext()
|
||||
if (nextState == 0)
|
||||
throw NoSuchElementException()
|
||||
val result = nextItem
|
||||
nextItem = null
|
||||
nextState = -1
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return result as T
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (nextState == -1)
|
||||
calcNext()
|
||||
return nextState == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence which returns the results of applying the given [transformer] function to the values
|
||||
* in the underlying [sequence].
|
||||
*/
|
||||
|
||||
internal class TransformingSequence<T, R>
|
||||
constructor(private val sequence: Sequence<T>, private val transformer: (T) -> R) : Sequence<R> {
|
||||
override fun iterator(): Iterator<R> = object : Iterator<R> {
|
||||
val iterator = sequence.iterator()
|
||||
override fun next(): R {
|
||||
return transformer(iterator.next())
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return iterator.hasNext()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <E> flatten(iterator: (R) -> Iterator<E>): Sequence<E> {
|
||||
return FlatteningSequence<T, R, E>(sequence, transformer, iterator)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence which returns the results of applying the given [transformer] function to the values
|
||||
* in the underlying [sequence], where the transformer function takes the index of the value in the underlying
|
||||
* sequence along with the value itself.
|
||||
*/
|
||||
internal class TransformingIndexedSequence<T, R>
|
||||
constructor(private val sequence: Sequence<T>, private val transformer: (Int, T) -> R) : Sequence<R> {
|
||||
override fun iterator(): Iterator<R> = object : Iterator<R> {
|
||||
val iterator = sequence.iterator()
|
||||
var index = 0
|
||||
override fun next(): R {
|
||||
return transformer(checkIndexOverflow(index++), iterator.next())
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return iterator.hasNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence which combines values from the underlying [sequence] with their indices and returns them as
|
||||
* [IndexedValue] objects.
|
||||
*/
|
||||
internal class IndexingSequence<T>
|
||||
constructor(private val sequence: Sequence<T>) : Sequence<IndexedValue<T>> {
|
||||
override fun iterator(): Iterator<IndexedValue<T>> = object : Iterator<IndexedValue<T>> {
|
||||
val iterator = sequence.iterator()
|
||||
var index = 0
|
||||
override fun next(): IndexedValue<T> {
|
||||
return IndexedValue(checkIndexOverflow(index++), iterator.next())
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return iterator.hasNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence which takes the values from two parallel underlying sequences, passes them to the given
|
||||
* [transform] function and returns the values returned by that function. The sequence stops returning
|
||||
* values as soon as one of the underlying sequences stops returning values.
|
||||
*/
|
||||
internal class MergingSequence<T1, T2, V>
|
||||
constructor(
|
||||
private val sequence1: Sequence<T1>,
|
||||
private val sequence2: Sequence<T2>,
|
||||
private val transform: (T1, T2) -> V
|
||||
) : Sequence<V> {
|
||||
override fun iterator(): Iterator<V> = object : Iterator<V> {
|
||||
val iterator1 = sequence1.iterator()
|
||||
val iterator2 = sequence2.iterator()
|
||||
override fun next(): V {
|
||||
return transform(iterator1.next(), iterator2.next())
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return iterator1.hasNext() && iterator2.hasNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class FlatteningSequence<T, R, E>
|
||||
constructor(
|
||||
private val sequence: Sequence<T>,
|
||||
private val transformer: (T) -> R,
|
||||
private val iterator: (R) -> Iterator<E>
|
||||
) : Sequence<E> {
|
||||
override fun iterator(): Iterator<E> = object : Iterator<E> {
|
||||
val iterator = sequence.iterator()
|
||||
var itemIterator: Iterator<E>? = null
|
||||
|
||||
override fun next(): E {
|
||||
if (!ensureItemIterator())
|
||||
throw NoSuchElementException()
|
||||
return itemIterator!!.next()
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return ensureItemIterator()
|
||||
}
|
||||
|
||||
private fun ensureItemIterator(): Boolean {
|
||||
if (itemIterator?.hasNext() == false)
|
||||
itemIterator = null
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence that supports drop(n) and take(n) operations
|
||||
*/
|
||||
internal interface DropTakeSequence<T> : Sequence<T> {
|
||||
fun drop(n: Int): Sequence<T>
|
||||
fun take(n: Int): Sequence<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence that skips [startIndex] values from the underlying [sequence]
|
||||
* and stops returning values right before [endIndex], i.e. stops at `endIndex - 1`
|
||||
*/
|
||||
internal class SubSequence<T>(
|
||||
private val sequence: Sequence<T>,
|
||||
private val startIndex: Int,
|
||||
private val endIndex: Int
|
||||
) : Sequence<T>, DropTakeSequence<T> {
|
||||
|
||||
init {
|
||||
require(startIndex >= 0) { "startIndex should be non-negative, but is $startIndex" }
|
||||
require(endIndex >= 0) { "endIndex should be non-negative, but is $endIndex" }
|
||||
require(endIndex >= startIndex) { "endIndex should be not less than startIndex, but was $endIndex < $startIndex" }
|
||||
}
|
||||
|
||||
private val count: Int get() = endIndex - startIndex
|
||||
|
||||
override fun drop(n: Int): Sequence<T> = if (n >= count) emptySequence() else SubSequence(sequence, startIndex + n, endIndex)
|
||||
override fun take(n: Int): Sequence<T> = if (n >= count) this else SubSequence(sequence, startIndex, startIndex + n)
|
||||
|
||||
override fun iterator() = object : Iterator<T> {
|
||||
|
||||
val iterator = sequence.iterator()
|
||||
var position = 0
|
||||
|
||||
// Shouldn't be called from constructor to avoid premature iteration
|
||||
private fun drop() {
|
||||
while (position < startIndex && iterator.hasNext()) {
|
||||
iterator.next()
|
||||
position++
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
drop()
|
||||
return (position < endIndex) && iterator.hasNext()
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
drop()
|
||||
if (position >= endIndex)
|
||||
throw NoSuchElementException()
|
||||
position++
|
||||
return iterator.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence that returns at most [count] values from the underlying [sequence], and stops returning values
|
||||
* as soon as that count is reached.
|
||||
*/
|
||||
internal class TakeSequence<T>(
|
||||
private val sequence: Sequence<T>,
|
||||
private val count: Int
|
||||
) : Sequence<T>, DropTakeSequence<T> {
|
||||
|
||||
init {
|
||||
require(count >= 0) { "count must be non-negative, but was $count." }
|
||||
}
|
||||
|
||||
override fun drop(n: Int): Sequence<T> = if (n >= count) emptySequence() else SubSequence(sequence, n, count)
|
||||
override fun take(n: Int): Sequence<T> = if (n >= count) this else TakeSequence(sequence, n)
|
||||
|
||||
override fun iterator(): Iterator<T> = object : Iterator<T> {
|
||||
var left = count
|
||||
val iterator = sequence.iterator()
|
||||
|
||||
override fun next(): T {
|
||||
if (left == 0)
|
||||
throw NoSuchElementException()
|
||||
left--
|
||||
return iterator.next()
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return left > 0 && iterator.hasNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence that returns values from the underlying [sequence] while the [predicate] function returns
|
||||
* `true`, and stops returning values once the function returns `false` for the next element.
|
||||
*/
|
||||
internal class TakeWhileSequence<T>
|
||||
constructor(
|
||||
private val sequence: Sequence<T>,
|
||||
private val predicate: (T) -> Boolean
|
||||
) : Sequence<T> {
|
||||
override fun iterator(): Iterator<T> = object : Iterator<T> {
|
||||
val iterator = sequence.iterator()
|
||||
var nextState: Int = -1 // -1 for unknown, 0 for done, 1 for continue
|
||||
var nextItem: T? = null
|
||||
|
||||
private fun calcNext() {
|
||||
if (iterator.hasNext()) {
|
||||
val item = iterator.next()
|
||||
if (predicate(item)) {
|
||||
nextState = 1
|
||||
nextItem = item
|
||||
return
|
||||
}
|
||||
}
|
||||
nextState = 0
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
if (nextState == -1)
|
||||
calcNext() // will change nextState
|
||||
if (nextState == 0)
|
||||
throw NoSuchElementException()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val result = nextItem as T
|
||||
|
||||
// Clean next to avoid keeping reference on yielded instance
|
||||
nextItem = null
|
||||
nextState = -1
|
||||
return result
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (nextState == -1)
|
||||
calcNext() // will change nextState
|
||||
return nextState == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence that skips the specified number of values from the underlying [sequence] and returns
|
||||
* all values after that.
|
||||
*/
|
||||
internal class DropSequence<T>(
|
||||
private val sequence: Sequence<T>,
|
||||
private val count: Int
|
||||
) : Sequence<T>, DropTakeSequence<T> {
|
||||
init {
|
||||
require(count >= 0) { "count must be non-negative, but was $count." }
|
||||
}
|
||||
|
||||
override fun drop(n: Int): Sequence<T> = (count + n).let { n1 -> if (n1 < 0) DropSequence(this, n) else DropSequence(sequence, n1) }
|
||||
override fun take(n: Int): Sequence<T> = (count + n).let { n1 -> if (n1 < 0) TakeSequence(this, n) else SubSequence(sequence, count, n1) }
|
||||
|
||||
override fun iterator(): Iterator<T> = object : Iterator<T> {
|
||||
val iterator = sequence.iterator()
|
||||
var left = count
|
||||
|
||||
// Shouldn't be called from constructor to avoid premature iteration
|
||||
private fun drop() {
|
||||
while (left > 0 && iterator.hasNext()) {
|
||||
iterator.next()
|
||||
left--
|
||||
}
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
drop()
|
||||
return iterator.next()
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
drop()
|
||||
return iterator.hasNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sequence that skips the values from the underlying [sequence] while the given [predicate] returns `true` and returns
|
||||
* all values after that.
|
||||
*/
|
||||
internal class DropWhileSequence<T>
|
||||
constructor(
|
||||
private val sequence: Sequence<T>,
|
||||
private val predicate: (T) -> Boolean
|
||||
) : Sequence<T> {
|
||||
|
||||
override fun iterator(): Iterator<T> = object : Iterator<T> {
|
||||
val iterator = sequence.iterator()
|
||||
var dropState: Int = -1 // -1 for not dropping, 1 for nextItem, 0 for normal iteration
|
||||
var nextItem: T? = null
|
||||
|
||||
private fun drop() {
|
||||
while (iterator.hasNext()) {
|
||||
val item = iterator.next()
|
||||
if (!predicate(item)) {
|
||||
nextItem = item
|
||||
dropState = 1
|
||||
return
|
||||
}
|
||||
}
|
||||
dropState = 0
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
if (dropState == -1)
|
||||
drop()
|
||||
|
||||
if (dropState == 1) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val result = nextItem as T
|
||||
nextItem = null
|
||||
dropState = 0
|
||||
return result
|
||||
}
|
||||
return iterator.next()
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (dropState == -1)
|
||||
drop()
|
||||
return dropState == 1 || iterator.hasNext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class DistinctSequence<T, K>(private val source: Sequence<T>, private val keySelector: (T) -> K) : Sequence<T> {
|
||||
override fun iterator(): Iterator<T> = DistinctIterator(source.iterator(), keySelector)
|
||||
}
|
||||
|
||||
private class DistinctIterator<T, K>(private val source: Iterator<T>, private val keySelector: (T) -> K) : AbstractIterator<T>() {
|
||||
private val observed = HashSet<K>()
|
||||
|
||||
override fun computeNext() {
|
||||
while (source.hasNext()) {
|
||||
val next = source.next()
|
||||
val key = keySelector(next)
|
||||
|
||||
if (observed.add(key)) {
|
||||
setNext(next)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
done()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class GeneratorSequence<T : Any>(private val getInitialValue: () -> T?, private val getNextValue: (T) -> T?) : Sequence<T> {
|
||||
override fun iterator(): Iterator<T> = object : Iterator<T> {
|
||||
var nextItem: T? = null
|
||||
var nextState: Int = -2 // -2 for initial unknown, -1 for next unknown, 0 for done, 1 for continue
|
||||
|
||||
private fun calcNext() {
|
||||
nextItem = if (nextState == -2) getInitialValue() else getNextValue(nextItem!!)
|
||||
nextState = if (nextItem == null) 0 else 1
|
||||
}
|
||||
|
||||
override fun next(): T {
|
||||
if (nextState < 0)
|
||||
calcNext()
|
||||
|
||||
if (nextState == 0)
|
||||
throw NoSuchElementException()
|
||||
val result = nextItem as T
|
||||
// Do not clean nextItem (to avoid keeping reference on yielded instance) -- need to keep state for getNextValue
|
||||
nextState = -1
|
||||
return result
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (nextState < 0)
|
||||
calcNext()
|
||||
return nextState == 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a wrapper sequence that provides values of this sequence, but ensures it can be iterated only one time.
|
||||
*
|
||||
* The operation is _intermediate_ and _stateless_.
|
||||
*
|
||||
* [IllegalStateException] is thrown on iterating the returned sequence from the second time.
|
||||
*
|
||||
*/
|
||||
public fun <T> Sequence<T>.constrainOnce(): Sequence<T> {
|
||||
// as? does not work in js
|
||||
//return this as? ConstrainedOnceSequence<T> ?: ConstrainedOnceSequence(this)
|
||||
return if (this is ConstrainedOnceSequence<T>) this else ConstrainedOnceSequence(this)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a sequence which invokes the function to calculate the next value on each iteration until the function returns `null`.
|
||||
*
|
||||
* The returned sequence is constrained to be iterated only once.
|
||||
*
|
||||
* @see constrainOnce
|
||||
* @see buildSequence
|
||||
*
|
||||
* @sample samples.collections.Sequences.Building.generateSequence
|
||||
*/
|
||||
public fun <T : Any> generateSequence(nextFunction: () -> T?): Sequence<T> {
|
||||
return GeneratorSequence(nextFunction, { nextFunction() }).constrainOnce()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence defined by the starting value [seed] and the function [nextFunction],
|
||||
* which is invoked to calculate the next value based on the previous one on each iteration.
|
||||
*
|
||||
* The sequence produces values until it encounters first `null` value.
|
||||
* If [seed] is `null`, an empty sequence is produced.
|
||||
*
|
||||
* The sequence can be iterated multiple times, each time starting with [seed].
|
||||
*
|
||||
* @see buildSequence
|
||||
*
|
||||
* @sample samples.collections.Sequences.Building.generateSequenceWithSeed
|
||||
*/
|
||||
@kotlin.internal.LowPriorityInOverloadResolution
|
||||
public fun <T : Any> generateSequence(seed: T?, nextFunction: (T) -> T?): Sequence<T> =
|
||||
if (seed == null)
|
||||
EmptySequence
|
||||
else
|
||||
GeneratorSequence({ seed }, nextFunction)
|
||||
|
||||
/**
|
||||
* Returns a sequence defined by the function [seedFunction], which is invoked to produce the starting value,
|
||||
* and the [nextFunction], which is invoked to calculate the next value based on the previous one on each iteration.
|
||||
*
|
||||
* The sequence produces values until it encounters first `null` value.
|
||||
* If [seedFunction] returns `null`, an empty sequence is produced.
|
||||
*
|
||||
* The sequence can be iterated multiple times.
|
||||
*
|
||||
* @see buildSequence
|
||||
*
|
||||
* @sample samples.collections.Sequences.Building.generateSequenceWithLazySeed
|
||||
*/
|
||||
public fun <T : Any> generateSequence(seedFunction: () -> T?, nextFunction: (T) -> T?): Sequence<T> =
|
||||
GeneratorSequence(seedFunction, nextFunction)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user