Create at most one wrapper sequence for adjacent drop/take operations on sequences.

Based on PR #814 by Sargun Vohra
#KT-10821 Fixed
This commit is contained in:
Ilya Gorbunov
2016-02-12 20:37:16 +03:00
parent a663797cb8
commit 24edbc36df
4 changed files with 122 additions and 14 deletions
+10 -2
View File
@@ -289,7 +289,11 @@ public inline fun <T> Sequence<T>.singleOrNull(predicate: (T) -> Boolean): T? {
*/
public fun <T> Sequence<T>.drop(n: Int): Sequence<T> {
require(n >= 0, { "Requested element count $n is less than zero." })
return if (n == 0) this else DropSequence(this, n)
return when {
n == 0 -> this
this is DropTakeSequence -> this.drop(n)
else -> DropSequence(this, n)
}
}
/**
@@ -367,7 +371,11 @@ public inline fun <T, C : MutableCollection<in T>> Sequence<T>.filterTo(destinat
*/
public fun <T> Sequence<T>.take(n: Int): Sequence<T> {
require(n >= 0, { "Requested element count $n is less than zero." })
return if (n == 0) emptySequence() else TakeSequence(this, n)
return when {
n == 0 -> emptySequence()
this is DropTakeSequence -> this.take(n)
else -> TakeSequence(this, n)
}
}
/**
@@ -36,8 +36,10 @@ public fun <T> sequenceOf(vararg elements: T): Sequence<T> = if (elements.isEmpt
*/
public fun <T> emptySequence(): Sequence<T> = EmptySequence
private object EmptySequence : Sequence<Nothing> {
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
}
/**
@@ -247,18 +249,79 @@ internal class FlatteningSequence<T, R, E>
}
}
/**
* 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>
constructor(private val sequence: Sequence<T>,
private val count: Int
) : Sequence<T> {
internal class TakeSequence<T> (
private val sequence: Sequence<T>,
private val count: Int
) : Sequence<T>, DropTakeSequence<T> {
init {
require (count >= 0) { throw IllegalArgumentException("count should be non-negative, but is $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();
@@ -326,14 +389,17 @@ internal class TakeWhileSequence<T>
* A sequence that skips the specified number of values from the underlying [sequence] and returns
* all values after that.
*/
internal class DropSequence<T>
constructor(private val sequence: Sequence<T>,
private val count: Int
) : Sequence<T> {
internal class DropSequence<T> (
private val sequence: Sequence<T>,
private val count: Int
) : Sequence<T>, DropTakeSequence<T> {
init {
require (count >= 0) { throw IllegalArgumentException("count should be non-negative, but is $count") }
}
override fun drop(n: Int): Sequence<T> = DropSequence(sequence, count + n)
override fun take(n: Int): Sequence<T> = SubSequence(sequence, count, count + n)
override fun iterator(): Iterator<T> = object : Iterator<T> {
val iterator = sequence.iterator();
var left = count