Update stdlib and tests (#1194)
This commit is contained in:
committed by
Nikolay Igotti
parent
2e07b3f52f
commit
670d05a4f3
@@ -36,7 +36,7 @@ public class KotlinVersion(val major: Int, val minor: Int, val patch: Int) : Com
|
||||
require(major in 0..MAX_COMPONENT_VALUE && minor in 0..MAX_COMPONENT_VALUE && patch in 0..MAX_COMPONENT_VALUE) {
|
||||
"Version components are out of range: $major.$minor.$patch"
|
||||
}
|
||||
return major shl 16 + minor shl 8 + patch
|
||||
return major.shl(16) + minor.shl(8) + patch
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,6 +84,6 @@ public class KotlinVersion(val major: Int, val minor: Int, val patch: Int) : Com
|
||||
* Returns the current version of the Kotlin standard library.
|
||||
*/
|
||||
// TODO: get from metadata or hardcode automatically during build
|
||||
public val CURRENT: KotlinVersion = KotlinVersion(1, 1, 4)
|
||||
public val CURRENT: KotlinVersion = KotlinVersion(1, 2, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1187,7 +1187,7 @@ public fun <T> List<T>.takeLast(n: Int): List<T> {
|
||||
for (index in size - n .. size - 1)
|
||||
list.add(this[index])
|
||||
} else {
|
||||
for (item in this.listIterator(n))
|
||||
for (item in this.listIterator(size - n))
|
||||
list.add(item)
|
||||
}
|
||||
return list
|
||||
@@ -2257,6 +2257,39 @@ public fun <T : Any> List<T?>.requireNoNulls(): List<T> {
|
||||
return this as List<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this collection into a list of lists each not exceeding the given [size].
|
||||
*
|
||||
* The last list in the resulting list may have less elements than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each list, must be positive and can be greater than the number of elements in this collection.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.chunked
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Iterable<T>.chunked(size: Int): List<List<T>> {
|
||||
return windowed(size, size, partialWindows = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this collection into several lists each not exceeding the given [size]
|
||||
* and applies the given [transform] function to an each.
|
||||
*
|
||||
* @return list of results of the [transform] applied to an each list.
|
||||
*
|
||||
* Note that the list passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* The last list may have less elements than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each list, must be positive and can be greater than the number of elements in this collection.
|
||||
*
|
||||
* @sample samples.text.Strings.chunkedTransform
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Iterable<T>.chunked(size: Int, transform: (List<T>) -> R): List<R> {
|
||||
return windowed(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all elements of the original collection without the first occurrence of the given [element].
|
||||
*/
|
||||
@@ -2426,6 +2459,83 @@ public inline fun <T> Collection<T>.plusElement(element: T): List<T> {
|
||||
return plus(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of snapshots of the window of the given [size]
|
||||
* sliding along this collection with the given [step], where each
|
||||
* snapshot is a list.
|
||||
*
|
||||
* Several last lists may have less elements than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this collection.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Iterable<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): List<List<T>> {
|
||||
checkWindowSizeStep(size, step)
|
||||
if (this is RandomAccess && this is List) {
|
||||
val thisSize = this.size
|
||||
val result = ArrayList<List<T>>((thisSize + step - 1) / step)
|
||||
var index = 0
|
||||
while (index < thisSize) {
|
||||
val windowSize = size.coerceAtMost(thisSize - index)
|
||||
if (windowSize < size && !partialWindows) break
|
||||
result.add(List(windowSize) { this[it + index] })
|
||||
index += step
|
||||
}
|
||||
return result
|
||||
}
|
||||
val result = ArrayList<List<T>>()
|
||||
windowedIterator(iterator(), size, step, partialWindows, reuseBuffer = false).forEach {
|
||||
result.add(it)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of results of applying the given [transform] function to
|
||||
* an each list representing a view over the window of the given [size]
|
||||
* sliding along this collection with the given [step].
|
||||
*
|
||||
* Note that the list passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* Several last lists may have less elements than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this collection.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Iterable<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (List<T>) -> R): List<R> {
|
||||
checkWindowSizeStep(size, step)
|
||||
if (this is RandomAccess && this is List) {
|
||||
val thisSize = this.size
|
||||
val result = ArrayList<R>((thisSize + step - 1) / step)
|
||||
val window = MovingSubList(this)
|
||||
var index = 0
|
||||
while (index < thisSize) {
|
||||
window.move(index, (index + size).coerceAtMost(thisSize))
|
||||
if (!partialWindows && window.size < size) break
|
||||
result.add(transform(window))
|
||||
index += step
|
||||
}
|
||||
return result
|
||||
}
|
||||
val result = ArrayList<R>()
|
||||
windowedIterator(iterator(), size, step, partialWindows, reuseBuffer = true).forEach {
|
||||
result.add(transform(it))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of pairs built from elements of both collections with same indexes. List has length of shortest collection.
|
||||
*/
|
||||
@@ -2470,6 +2580,40 @@ public inline fun <T, R, V> Iterable<T>.zip(other: Iterable<R>, transform: (T, R
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of pairs of each two adjacent elements in this collection.
|
||||
*
|
||||
* The returned list is empty if this collection contains less than two elements.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.zipWithNext
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Iterable<T>.zipWithNext(): List<Pair<T, T>> {
|
||||
return zipWithNext { a, b -> a to b }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing the results of applying the given [transform] function
|
||||
* to an each pair of two adjacent elements in this collection.
|
||||
*
|
||||
* The returned list is empty if this collection contains less than two elements.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.zipWithNextToFindDeltas
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public inline fun <T, R> Iterable<T>.zipWithNext(transform: (a: T, b: T) -> R): List<R> {
|
||||
val iterator = iterator()
|
||||
if (!iterator.hasNext()) return emptyList()
|
||||
val result = mutableListOf<R>()
|
||||
var current = iterator.next()
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
result.add(transform(current, next))
|
||||
current = next
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied.
|
||||
*
|
||||
|
||||
@@ -595,6 +595,81 @@ public inline operator fun <K, V> MutableMap<in K, in V>.plusAssign(map: Map<K,
|
||||
putAll(map)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map containing all entries of the original map except the entry with the given [key].
|
||||
*
|
||||
* The returned map preserves the entry iteration order of the original map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public operator fun <K, V> Map<out K, V>.minus(key: K): Map<K, V>
|
||||
= this.toMutableMap().apply { minusAssign(key) }.optimizeReadOnlyMap()
|
||||
|
||||
/**
|
||||
* Returns a map containing all entries of the original map except those entries
|
||||
* the keys of which are contained in the given [keys] collection.
|
||||
*
|
||||
* The returned map preserves the entry iteration order of the original map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public operator fun <K, V> Map<out K, V>.minus(keys: Iterable<K>): Map<K, V>
|
||||
= this.toMutableMap().apply { minusAssign(keys) }.optimizeReadOnlyMap()
|
||||
|
||||
/**
|
||||
* Returns a map containing all entries of the original map except those entries
|
||||
* the keys of which are contained in the given [keys] array.
|
||||
*
|
||||
* The returned map preserves the entry iteration order of the original map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public operator fun <K, V> Map<out K, V>.minus(keys: Array<out K>): Map<K, V>
|
||||
= this.toMutableMap().apply { minusAssign(keys) }.optimizeReadOnlyMap()
|
||||
|
||||
/**
|
||||
* Returns a map containing all entries of the original map except those entries
|
||||
* the keys of which are contained in the given [keys] sequence.
|
||||
*
|
||||
* The returned map preserves the entry iteration order of the original map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
public operator fun <K, V> Map<out K, V>.minus(keys: Sequence<K>): Map<K, V>
|
||||
= this.toMutableMap().apply { minusAssign(keys) }.optimizeReadOnlyMap()
|
||||
|
||||
/**
|
||||
* Removes the entry with the given [key] from this mutable map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline operator fun <K, V> MutableMap<K, V>.minusAssign(key: K) {
|
||||
remove(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all entries the keys of which are contained in the given [keys] collection from this mutable map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline operator fun <K, V> MutableMap<K, V>.minusAssign(keys: Iterable<K>) {
|
||||
this.keys.removeAll(keys)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all entries the keys of which are contained in the given [keys] array from this mutable map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline operator fun <K, V> MutableMap<K, V>.minusAssign(keys: Array<out K>) {
|
||||
this.keys.removeAll(keys)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all entries from the keys of which are contained in the given [keys] sequence from this mutable map.
|
||||
*/
|
||||
@SinceKotlin("1.1")
|
||||
@kotlin.internal.InlineOnly
|
||||
public inline operator fun <K, V> MutableMap<K, V>.minusAssign(keys: Sequence<K>) {
|
||||
this.keys.removeAll(keys)
|
||||
}
|
||||
|
||||
@kotlin.internal.InlineExposed
|
||||
internal fun <K, V> Map<K, V>.optimizeReadOnlyMap() = when (size) {
|
||||
0 -> emptyMap()
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlin.collections
|
||||
|
||||
import kotlin.coroutines.experimental.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 .. toIndex-1) {
|
||||
this[idx] = element
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package kotlin.sequences
|
||||
|
||||
import kotlin.comparisons.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
|
||||
|
||||
/**
|
||||
@@ -1718,6 +1719,43 @@ public fun <T : Any> Sequence<T?>.requireNoNulls(): Sequence<T> {
|
||||
return map { it ?: throw IllegalArgumentException("null element found in $this.") }
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this sequence into a sequence of lists each not exceeding the given [size].
|
||||
*
|
||||
* The last list in the resulting sequence may have less elements than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each list, must be positive and can be greater than the number of elements in this sequence.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.chunked
|
||||
*
|
||||
* The operation is _intermediate_ and _stateful_.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Sequence<T>.chunked(size: Int): Sequence<List<T>> {
|
||||
return windowed(size, size, partialWindows = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this sequence into several lists each not exceeding the given [size]
|
||||
* and applies the given [transform] function to an each.
|
||||
*
|
||||
* @return sequence of results of the [transform] applied to an each list.
|
||||
*
|
||||
* Note that the list passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* The last list may have less elements than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each list, must be positive and can be greater than the number of elements in this sequence.
|
||||
*
|
||||
* @sample samples.text.Strings.chunkedTransform
|
||||
*
|
||||
* The operation is _intermediate_ and _stateful_.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Sequence<T>.chunked(size: Int, transform: (List<T>) -> R): Sequence<R> {
|
||||
return windowed(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence containing all elements of the original sequence without the first occurrence of the given [element].
|
||||
*/
|
||||
@@ -1853,6 +1891,48 @@ public inline fun <T> Sequence<T>.plusElement(element: T): Sequence<T> {
|
||||
return plus(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of snapshots of the window of the given [size]
|
||||
* sliding along this sequence with the given [step], where each
|
||||
* snapshot is a list.
|
||||
*
|
||||
* Several last lists may have less elements than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Sequence<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): Sequence<List<T>> {
|
||||
return windowedSequence(size, step, partialWindows, reuseBuffer = false)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of results of applying the given [transform] function to
|
||||
* an each list representing a view over the window of the given [size]
|
||||
* sliding along this sequence with the given [step].
|
||||
*
|
||||
* Note that the list passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* Several last lists may have less elements than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Sequence<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (List<T>) -> R): Sequence<R> {
|
||||
return windowedSequence(size, step, partialWindows, reuseBuffer = true).map(transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of pairs built from elements of both sequences with same indexes.
|
||||
* Resulting sequence has length of shortest input sequence.
|
||||
@@ -1868,6 +1948,44 @@ public fun <T, R, V> Sequence<T>.zip(other: Sequence<R>, transform: (T, R) -> V)
|
||||
return MergingSequence(this, other, transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of pairs of each two adjacent elements in this sequence.
|
||||
*
|
||||
* The returned sequence is empty if this sequence contains less than two elements.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.zipWithNext
|
||||
*
|
||||
* The operation is _intermediate_ and _stateless_.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T> Sequence<T>.zipWithNext(): Sequence<Pair<T, T>> {
|
||||
return zipWithNext { a, b -> a to b }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence containing the results of applying the given [transform] function
|
||||
* to an each pair of two adjacent elements in this sequence.
|
||||
*
|
||||
* The returned sequence is empty if this sequence contains less than two elements.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.zipWithNextToFindDeltas
|
||||
*
|
||||
* The operation is _intermediate_ and _stateless_.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <T, R> Sequence<T>.zipWithNext(transform: (a: T, b: T) -> R): Sequence<R> {
|
||||
return buildSequence result@ {
|
||||
val iterator = iterator()
|
||||
if (!iterator.hasNext()) return@result
|
||||
var current = iterator.next()
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
yield(transform(current, next))
|
||||
current = next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the string from all the elements separated using [separator] and using the given [prefix] and [postfix] if supplied.
|
||||
*
|
||||
|
||||
@@ -2288,6 +2288,72 @@ public inline fun CharSequence.sumByDouble(selector: (Char) -> Double): Double {
|
||||
return sum
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this char sequence into a list of strings each not exceeding the given [size].
|
||||
*
|
||||
* The last string in the resulting list may have less characters than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each string, must be positive and can be greater than the number of elements in this char sequence.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.chunked
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.chunked(size: Int): List<String> {
|
||||
return windowed(size, size, partialWindows = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this char sequence into several char sequences each not exceeding the given [size]
|
||||
* and applies the given [transform] function to an each.
|
||||
*
|
||||
* @return list of results of the [transform] applied to an each char sequence.
|
||||
*
|
||||
* Note that the char sequence passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* The last char sequence may have less characters than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each char sequence, must be positive and can be greater than the number of elements in this char sequence.
|
||||
*
|
||||
* @sample samples.text.Strings.chunkedTransform
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.chunked(size: Int, transform: (CharSequence) -> R): List<R> {
|
||||
return windowed(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this char sequence into a sequence of strings each not exceeding the given [size].
|
||||
*
|
||||
* The last string in the resulting sequence may have less characters than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each string, must be positive and can be greater than the number of elements in this char sequence.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.chunked
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.chunkedSequence(size: Int): Sequence<String> {
|
||||
return chunkedSequence(size) { it.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this char sequence into several char sequences each not exceeding the given [size]
|
||||
* and applies the given [transform] function to an each.
|
||||
*
|
||||
* @return sequence of results of the [transform] applied to an each char sequence.
|
||||
*
|
||||
* Note that the char sequence passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* The last char sequence may have less characters than the given [size].
|
||||
*
|
||||
* @param size the number of elements to take in each char sequence, must be positive and can be greater than the number of elements in this char sequence.
|
||||
*
|
||||
* @sample samples.text.Strings.chunkedTransformToSequence
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.chunkedSequence(size: Int, transform: (CharSequence) -> R): Sequence<R> {
|
||||
return windowedSequence(size, size, partialWindows = true, transform = transform)
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the original char sequence into pair of char sequences,
|
||||
* where *first* char sequence contains characters for which [predicate] yielded `true`,
|
||||
@@ -2324,6 +2390,102 @@ public inline fun String.partition(predicate: (Char) -> Boolean): Pair<String, S
|
||||
return Pair(first.toString(), second.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of snapshots of the window of the given [size]
|
||||
* sliding along this char sequence with the given [step], where each
|
||||
* snapshot is a string.
|
||||
*
|
||||
* Several last strings may have less characters than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): List<String> {
|
||||
return windowed(size, step, partialWindows) { it.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of results of applying the given [transform] function to
|
||||
* an each char sequence representing a view over the window of the given [size]
|
||||
* sliding along this char sequence with the given [step].
|
||||
*
|
||||
* Note that the char sequence passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* Several last char sequences may have less characters than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (CharSequence) -> R): List<R> {
|
||||
checkWindowSizeStep(size, step)
|
||||
val thisSize = this.length
|
||||
val result = ArrayList<R>((thisSize + step - 1) / step)
|
||||
var index = 0
|
||||
while (index < thisSize) {
|
||||
val end = index + size
|
||||
val coercedEnd = if (end > thisSize) { if (partialWindows) thisSize else break } else end
|
||||
result.add(transform(subSequence(index, coercedEnd)))
|
||||
index += step
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of snapshots of the window of the given [size]
|
||||
* sliding along this char sequence with the given [step], where each
|
||||
* snapshot is a string.
|
||||
*
|
||||
* Several last strings may have less characters than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.takeWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.windowedSequence(size: Int, step: Int = 1, partialWindows: Boolean = false): Sequence<String> {
|
||||
return windowedSequence(size, step, partialWindows) { it.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of results of applying the given [transform] function to
|
||||
* an each char sequence representing a view over the window of the given [size]
|
||||
* sliding along this char sequence with the given [step].
|
||||
*
|
||||
* Note that the char sequence passed to the [transform] function is ephemeral and is valid only inside that function.
|
||||
* You should not store it or allow it to escape in some way, unless you made a snapshot of it.
|
||||
* Several last char sequences may have less characters than the given [size].
|
||||
*
|
||||
* Both [size] and [step] must be positive and can be greater than the number of elements in this char sequence.
|
||||
* @param size the number of elements to take in each window
|
||||
* @param step the number of elements to move the window forward by on an each step, by default 1
|
||||
* @param partialWindows controls whether or not to keep partial windows in the end if any,
|
||||
* by default `false` which means partial windows won't be preserved
|
||||
*
|
||||
* @sample samples.collections.Sequences.Transformations.averageWindows
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun <R> CharSequence.windowedSequence(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (CharSequence) -> R): Sequence<R> {
|
||||
checkWindowSizeStep(size, step)
|
||||
val windows = (if (partialWindows) indices else 0 until length - size + 1) step step
|
||||
return windows.asSequence().map { index -> transform(subSequence(index, (index + size).coerceAtMost(length))) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of pairs built from characters of both char sequences with same indexes. List has length of shortest char sequence.
|
||||
*/
|
||||
@@ -2343,6 +2505,37 @@ public inline fun <V> CharSequence.zip(other: CharSequence, transform: (a: Char,
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of pairs of each two adjacent characters in this char sequence.
|
||||
*
|
||||
* The returned list is empty if this char sequence contains less than two characters.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.zipWithNext
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public fun CharSequence.zipWithNext(): List<Pair<Char, Char>> {
|
||||
return zipWithNext { a, b -> a to b }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing the results of applying the given [transform] function
|
||||
* to an each pair of two adjacent characters in this char sequence.
|
||||
*
|
||||
* The returned list is empty if this char sequence contains less than two characters.
|
||||
*
|
||||
* @sample samples.collections.Collections.Transformations.zipWithNextToFindDeltas
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
public inline fun <R> CharSequence.zipWithNext(transform: (a: Char, b: Char) -> R): List<R> {
|
||||
val size = length - 1
|
||||
if (size < 1) return emptyList()
|
||||
val result = ArrayList<R>(size)
|
||||
for (index in 0..size - 1) {
|
||||
result.add(transform(this[index], this[index + 1]))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an [Iterable] instance that wraps the original char sequence returning its characters when being iterated.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user