Update stdlib and tests (#1194)

This commit is contained in:
Pavel Punegov
2018-01-09 13:17:55 +03:00
committed by Nikolay Igotti
parent 2e07b3f52f
commit 670d05a4f3
582 changed files with 14933 additions and 14639 deletions
@@ -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.
*/