diff --git a/libraries/stdlib/common/src/generated/_Arrays.kt b/libraries/stdlib/common/src/generated/_Arrays.kt index e9b3cf0a42d..7c67fb2c4bd 100644 --- a/libraries/stdlib/common/src/generated/_Arrays.kt +++ b/libraries/stdlib/common/src/generated/_Arrays.kt @@ -13568,6 +13568,872 @@ public inline fun CharArray.reduceRightOrNull(operation: (Char, acc: Char) -> Ch return accumulator } +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Array.scan(initial: R, operation: (acc: R, T) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ByteArray.scan(initial: R, operation: (acc: R, Byte) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ShortArray.scan(initial: R, operation: (acc: R, Short) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun IntArray.scan(initial: R, operation: (acc: R, Int) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun LongArray.scan(initial: R, operation: (acc: R, Long) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun FloatArray.scan(initial: R, operation: (acc: R, Float) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun DoubleArray.scan(initial: R, operation: (acc: R, Double) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun BooleanArray.scan(initial: R, operation: (acc: R, Boolean) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun CharArray.scan(initial: R, operation: (acc: R, Char) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Array.scanIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ByteArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Byte) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ShortArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Short) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun IntArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Int) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun LongArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Long) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun FloatArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Float) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun DoubleArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Double) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun BooleanArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Boolean) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun CharArray.scanIndexed(initial: R, operation: (index: Int, acc: R, Char) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and the element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Array.scanReduce(operation: (acc: S, T) -> S): List { + if (isEmpty()) return emptyList() + var accumulator: S = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ByteArray.scanReduce(operation: (acc: Byte, Byte) -> Byte): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ShortArray.scanReduce(operation: (acc: Short, Short) -> Short): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun IntArray.scanReduce(operation: (acc: Int, Int) -> Int): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun LongArray.scanReduce(operation: (acc: Long, Long) -> Long): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun FloatArray.scanReduce(operation: (acc: Float, Float) -> Float): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun DoubleArray.scanReduce(operation: (acc: Double, Double) -> Double): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun BooleanArray.scanReduce(operation: (acc: Boolean, Boolean) -> Boolean): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun CharArray.scanReduce(operation: (acc: Char, Char) -> Char): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Array.scanReduceIndexed(operation: (index: Int, acc: S, T) -> S): List { + if (isEmpty()) return emptyList() + var accumulator: S = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ByteArray.scanReduceIndexed(operation: (index: Int, acc: Byte, Byte) -> Byte): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun ShortArray.scanReduceIndexed(operation: (index: Int, acc: Short, Short) -> Short): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun IntArray.scanReduceIndexed(operation: (index: Int, acc: Int, Int) -> Int): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun LongArray.scanReduceIndexed(operation: (index: Int, acc: Long, Long) -> Long): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun FloatArray.scanReduceIndexed(operation: (index: Int, acc: Float, Float) -> Float): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun DoubleArray.scanReduceIndexed(operation: (index: Int, acc: Double, Double) -> Double): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun BooleanArray.scanReduceIndexed(operation: (index: Int, acc: Boolean, Boolean) -> Boolean): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@kotlin.internal.InlineOnly +public inline fun CharArray.scanReduceIndexed(operation: (index: Int, acc: Char, Char) -> Char): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the array. */ diff --git a/libraries/stdlib/common/src/generated/_Collections.kt b/libraries/stdlib/common/src/generated/_Collections.kt index 163cc625697..eeaf04b6eb5 100644 --- a/libraries/stdlib/common/src/generated/_Collections.kt +++ b/libraries/stdlib/common/src/generated/_Collections.kt @@ -1962,6 +1962,110 @@ public inline fun List.reduceRightOrNull(operation: (T, acc: S) -> return accumulator } +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Iterable.scan(initial: R, operation: (acc: R, T) -> R): List { + val estimatedSize = collectionSizeOrDefault(9) + if (estimatedSize == 0) return listOf(initial) + val result = ArrayList(estimatedSize + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original collection and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Iterable.scanIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): List { + val estimatedSize = collectionSizeOrDefault(9) + if (estimatedSize == 0) return listOf(initial) + val result = ArrayList(estimatedSize + 1).apply { add(initial) } + var index = 0 + var accumulator = initial + for (element in this) { + accumulator = operation(index++, accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this collection. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and the element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Iterable.scanReduce(operation: (acc: S, T) -> S): List { + val iterator = this.iterator() + if (!iterator.hasNext()) return emptyList() + var accumulator: S = iterator.next() + val result = ArrayList(collectionSizeOrDefault(10)).apply { add(accumulator) } + while (iterator.hasNext()) { + accumulator = operation(accumulator, iterator.next()) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original collection and current accumulator value that starts with the first element of this collection. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Iterable.scanReduceIndexed(operation: (index: Int, acc: S, T) -> S): List { + val iterator = this.iterator() + if (!iterator.hasNext()) return emptyList() + var accumulator: S = iterator.next() + val result = ArrayList(collectionSizeOrDefault(10)).apply { add(accumulator) } + var index = 1 + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + result.add(accumulator) + } + return result +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the collection. */ diff --git a/libraries/stdlib/common/src/generated/_Sequences.kt b/libraries/stdlib/common/src/generated/_Sequences.kt index 890b6ac8624..db70096dae3 100644 --- a/libraries/stdlib/common/src/generated/_Sequences.kt +++ b/libraries/stdlib/common/src/generated/_Sequences.kt @@ -1405,6 +1405,124 @@ public inline fun Sequence.reduceOrNull(operation: (acc: S, T) -> return accumulator } +/** + * Returns a sequence containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting sequence. + * The [initial] value should also be immutable (or should not be mutated) + * as it may be passed to [operation] function later because of sequence's lazy nature. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * The operation is _intermediate_ and _stateless_. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public fun Sequence.scan(initial: R, operation: (acc: R, T) -> R): Sequence { + return sequence { + yield(initial) + var accumulator = initial + for (element in this@scan) { + accumulator = operation(accumulator, element) + yield(accumulator) + } + } +} + +/** + * Returns a sequence containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original sequence and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting sequence. + * The [initial] value should also be immutable (or should not be mutated) + * as it may be passed to [operation] function later because of sequence's lazy nature. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * The operation is _intermediate_ and _stateless_. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public fun Sequence.scanIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): Sequence { + return sequence { + yield(initial) + var index = 0 + var accumulator = initial + for (element in this@scanIndexed) { + accumulator = operation(checkIndexOverflow(index++), accumulator, element) + yield(accumulator) + } + } +} + +/** + * Returns a sequence containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this sequence. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting sequence. + * + * @param [operation] function that takes current accumulator value and the element, and calculates the next accumulator value. + * + * The operation is _intermediate_ and _stateless_. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public fun Sequence.scanReduce(operation: (acc: S, T) -> S): Sequence { + return sequence { + val iterator = iterator() + if (iterator.hasNext()) { + var accumulator: S = iterator.next() + yield(accumulator) + while (iterator.hasNext()) { + accumulator = operation(accumulator, iterator.next()) + yield(accumulator) + } + } + } +} + +/** + * Returns a sequence containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original sequence and current accumulator value that starts with the first element of this sequence. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting sequence. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * The operation is _intermediate_ and _stateless_. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public fun Sequence.scanReduceIndexed(operation: (index: Int, acc: S, T) -> S): Sequence { + return sequence { + val iterator = iterator() + if (iterator.hasNext()) { + var accumulator: S = iterator.next() + yield(accumulator) + var index = 1 + while (iterator.hasNext()) { + accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next()) + yield(accumulator) + } + } + } +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the sequence. * diff --git a/libraries/stdlib/common/src/generated/_Strings.kt b/libraries/stdlib/common/src/generated/_Strings.kt index 032096c754c..8bba76383bf 100644 --- a/libraries/stdlib/common/src/generated/_Strings.kt +++ b/libraries/stdlib/common/src/generated/_Strings.kt @@ -1288,6 +1288,104 @@ public inline fun CharSequence.reduceRightOrNull(operation: (Char, acc: Char) -> return accumulator } +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each character and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and a character, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun CharSequence.scan(initial: R, operation: (acc: R, Char) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(length + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each character, its index in the original char sequence and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of a character, current accumulator value + * and the character itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun CharSequence.scanIndexed(initial: R, operation: (index: Int, acc: R, Char) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(length + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each character and current accumulator value that starts with the first character of this char sequence. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and a character, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun CharSequence.scanReduce(operation: (acc: Char, Char) -> Char): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(length).apply { add(accumulator) } + for (index in 1 until length) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each character, its index in the original char sequence and current accumulator value that starts with the first character of this char sequence. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of a character, current accumulator value + * and the character itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun CharSequence.scanReduceIndexed(operation: (index: Int, acc: Char, Char) -> Char): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(length).apply { add(accumulator) } + for (index in 1 until length) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + /** * Returns the sum of all values produced by [selector] function applied to each character in the char sequence. */ diff --git a/libraries/stdlib/common/src/generated/_UArrays.kt b/libraries/stdlib/common/src/generated/_UArrays.kt index 399192c9bd4..7ad2c4f028b 100644 --- a/libraries/stdlib/common/src/generated/_UArrays.kt +++ b/libraries/stdlib/common/src/generated/_UArrays.kt @@ -6038,6 +6038,430 @@ public inline fun UShortArray.reduceRightOrNull(operation: (UShort, acc: UShort) return accumulator } +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.scan(initial: R, operation: (acc: R, UInt) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.scan(initial: R, operation: (acc: R, ULong) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.scan(initial: R, operation: (acc: R, UByte) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.scan(initial: R, operation: (acc: R, UShort) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.scanIndexed(initial: R, operation: (index: Int, acc: R, UInt) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.scanIndexed(initial: R, operation: (index: Int, acc: R, ULong) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.scanIndexed(initial: R, operation: (index: Int, acc: R, UByte) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with [initial] value. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scan + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.scanIndexed(initial: R, operation: (index: Int, acc: R, UShort) -> R): List { + if (isEmpty()) return listOf(initial) + val result = ArrayList(size + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.scanReduce(operation: (acc: UInt, UInt) -> UInt): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.scanReduce(operation: (acc: ULong, ULong) -> ULong): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.scanReduce(operation: (acc: UByte, UByte) -> UByte): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes current accumulator value and an element, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.scanReduce(operation: (acc: UShort, UShort) -> UShort): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.scanReduceIndexed(operation: (index: Int, acc: UInt, UInt) -> UInt): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.scanReduceIndexed(operation: (index: Int, acc: ULong, ULong) -> ULong): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.scanReduceIndexed(operation: (index: Int, acc: UByte, UByte) -> UByte): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + +/** + * Returns a list containing successive accumulation values generated by applying [operation] from left to right + * to each element, its index in the original array and current accumulator value that starts with the first element of this array. + * + * Note that `acc` value passed to [operation] function should not be mutated; + * otherwise it would affect the previous value in resulting list. + * + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.scanReduce + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.scanReduceIndexed(operation: (index: Int, acc: UShort, UShort) -> UShort): List { + if (isEmpty()) return emptyList() + var accumulator = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the array. */ diff --git a/libraries/stdlib/jvm/build.gradle b/libraries/stdlib/jvm/build.gradle index b5e6094f126..aeaf214c380 100644 --- a/libraries/stdlib/jvm/build.gradle +++ b/libraries/stdlib/jvm/build.gradle @@ -147,6 +147,10 @@ compileTestKotlin { } } +compileLongRunningTestKotlin { + kotlinOptions.freeCompilerArgs += "-Xuse-experimental=kotlin.ExperimentalStdlibApi" +} + task longRunningTest(type: Test, dependsOn: longRunningTestClasses) { group = "verification" testClassesDirs = sourceSets.longRunningTest.output.classesDirs diff --git a/libraries/stdlib/jvm/testLongRunning/collections/IndexOverflowJVMTest.kt b/libraries/stdlib/jvm/testLongRunning/collections/IndexOverflowJVMTest.kt index f1e3f79af04..eb36138909a 100644 --- a/libraries/stdlib/jvm/testLongRunning/collections/IndexOverflowJVMTest.kt +++ b/libraries/stdlib/jvm/testLongRunning/collections/IndexOverflowJVMTest.kt @@ -139,6 +139,17 @@ class IndexOverflowJVMTest { } + @Test + fun scanIndexedOverflow() { + assertIndexOverflow { maxIndexSequence.scanIndexed("") { index, _, s -> checkIndexPositive(index); s }.forEach { } } + } + + @Test + fun scanReduceIndexedOverflow() { + assertIndexOverflow { maxIndexSequence.scanReduceIndexed { index, _, s -> checkIndexPositive(index); s }.forEach { } } + } + + @Test fun dropTwiceMaxValue() { diff --git a/libraries/stdlib/samples/test/samples/collections/collections.kt b/libraries/stdlib/samples/test/samples/collections/collections.kt index 66166138b95..ddfbc0a1b92 100644 --- a/libraries/stdlib/samples/test/samples/collections/collections.kt +++ b/libraries/stdlib/samples/test/samples/collections/collections.kt @@ -697,6 +697,24 @@ class Collections { assertPrints(emptyList().reduceRightOrNull { _, _ -> "" }, "null") } + + @Sample + fun scan() { + val strings = listOf("a", "b", "c", "d") + assertPrints(strings.scan("s") { acc, string -> acc + string }, "[s, sa, sab, sabc, sabcd]") + assertPrints(strings.scanIndexed("s") { index, acc, string -> acc + string + index }, "[s, sa0, sa0b1, sa0b1c2, sa0b1c2d3]") + + assertPrints(emptyList().scan("s") { _, _ -> "X" }, "[s]") + } + + @Sample + fun scanReduce() { + val strings = listOf("a", "b", "c", "d") + assertPrints(strings.scanReduce { acc, string -> acc + string }, "[a, ab, abc, abcd]") + assertPrints(strings.scanReduceIndexed { index, acc, string -> acc + string + index }, "[a, ab1, ab1c2, ab1c2d3]") + + assertPrints(emptyList().scanReduce { _, _ -> "X" }, "[]") + } } class Elements { diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 6f845ae2c10..b7618a60998 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -11,6 +11,7 @@ import test.assertStaticTypeIs import test.assertTypeEquals import test.collections.behaviors.* import test.comparisons.STRING_CASE_INSENSITIVE_ORDER +import test.text.isAsciiLetter import kotlin.test.* import kotlin.random.Random @@ -1073,6 +1074,161 @@ class ArraysTest { expect(null, { intArrayOf().reduceRightOrNull { a, b -> a + b } }) } + @Test + fun scan() { + for (size in 0 until 4) { + val expected = listOf("", "0", "01", "012", "0123").take(size + 1) + // Array + assertEquals(expected, Array(size) { it }.scan("") { acc, e -> acc + e }) + // Primitive Arrays + assertEquals(expected, ByteArray(size) { it.toByte() }.scan("") { acc, e -> acc + e }) + assertEquals(expected, CharArray(size) { '0' + it }.scan("") { acc, e -> acc + e }) + assertEquals(expected, ShortArray(size) { it.toShort() }.scan("") { acc, e -> acc + e }) + assertEquals(expected, IntArray(size) { it }.scan("") { acc, e -> acc + e }) + assertEquals(expected, LongArray(size) { it.toLong() }.scan("") { acc, e -> acc + e }) + assertEquals(expected, FloatArray(size) { it.toFloat() }.scan("") { acc, e -> acc + e.toInt() }) + assertEquals(expected, DoubleArray(size) { it.toDouble() }.scan("") { acc, e -> acc + e.toInt() }) + assertEquals( + expected.map { it.map { c -> c.toInt() % 2 == 0 }.joinToString(separator = "") }, + BooleanArray(size) { it % 2 == 0 }.scan("") { acc, e -> acc + e } + ) + } + } + + @Test + fun scanIndexed() { + for (size in 0 until 4) { + val expected = listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").take(size + 1) + // Array + assertEquals( + expected, + Array(size) { 'a' + it }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" } + ) + // Primitive Arrays + assertEquals( + expected, + ByteArray(size) { it.toByte() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + CharArray(size) { it.toChar() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + ShortArray(size) { it.toShort() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + IntArray(size) { it }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e}]" } + ) + assertEquals( + expected, + LongArray(size) { it.toLong() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + FloatArray(size) { it.toFloat() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + DoubleArray(size) { it.toDouble() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected.map { it.map { c -> if (c.isAsciiLetter()) c.toInt() % 2 != 0 else c }.joinToString(separator = "") }, + BooleanArray(size) { it % 2 == 0 }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" } + ) + } + } + + @Test + fun scanReduce() { + for (size in 0 until 4) { + val expected = listOf(0, 1, 3, 6).take(size) + // Array + assertEquals( + expected, + Array(size) { it }.scanReduce { acc, e -> acc + e } + ) + // Primitive Arrays + assertEquals( + expected.map { it.toByte() }, + ByteArray(size) { it.toByte() }.scanReduce { acc, e -> (acc + e).toByte() } + ) + assertEquals( + expected.map { it.toChar() }, + CharArray(size) { it.toChar() }.scanReduce { acc, e -> acc + e.toInt() } + ) + assertEquals( + expected.map { it.toShort() }, + ShortArray(size) { it.toShort() }.scanReduce { acc, e -> (acc + e).toShort() } + ) + assertEquals( + expected, + IntArray(size) { it }.scanReduce { acc, e -> acc + e } + ) + assertEquals( + expected.map { it.toLong() }, + LongArray(size) { it.toLong() }.scanReduce { acc, e -> acc + e } + ) + assertEquals( + expected.map { it.toFloat() }, + FloatArray(size) { it.toFloat() }.scanReduce { acc, e -> acc + e.toInt() } + ) + assertEquals( + expected.map { it.toDouble() }, + DoubleArray(size) { it.toDouble() }.scanReduce { acc, e -> acc + e.toInt() } + ) + assertEquals( + expected.indices.map { it % 2 == 0 }, + BooleanArray(size) { true }.scanReduce { acc, e -> acc != e } + ) + } + } + + @Test + fun scanReduceIndexed() { + for (size in 0 until 4) { + val expected = listOf(0, 1, 6, 27).take(size) + // Array + assertEquals( + expected, + Array(size) { it }.scanReduceIndexed { index, acc, e -> index * (acc + e) } + ) + // Primitive Arrays + assertEquals( + expected.map { it.toByte() }, + ByteArray(size) { it.toByte() }.scanReduceIndexed { index, acc, e -> (index * (acc + e)).toByte() }) + assertEquals( + expected.map { it.toChar() }, + CharArray(size) { it.toChar() }.scanReduceIndexed { index, acc, e -> (index * (acc.toInt() + e.toInt())).toChar() } + ) + assertEquals( + expected.map { it.toShort() }, + ShortArray(size) { it.toShort() }.scanReduceIndexed { index, acc, e -> (index * (acc + e)).toShort() } + ) + assertEquals( + expected, + IntArray(size) { it }.scanReduceIndexed { index, acc, e -> index * (acc + e) } + ) + assertEquals( + expected.map { it.toLong() }, + LongArray(size) { it.toLong() }.scanReduceIndexed { index, acc, e -> index * (acc + e) } + ) + assertEquals( + expected.map { it.toFloat() }, + FloatArray(size) { it.toFloat() }.scanReduceIndexed { index, acc, e -> index * (acc + e) } + ) + assertEquals( + expected.map { it.toDouble() }, + DoubleArray(size) { it.toDouble() }.scanReduceIndexed { index, acc, e -> index * (acc + e) } + ) + assertEquals( + expected.indices.map { it % 2 == 0 }, + BooleanArray(size) { true }.scanReduceIndexed { index, acc, e -> acc != e && index % 2 == 0 } + ) + } + } + @Test fun reverseInPlace() { fun doTest(build: Iterable.() -> TArray, reverse: TArray.() -> Unit, snapshot: TArray.() -> List) { diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 3bda9e33de3..68e81c659b3 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -344,6 +344,38 @@ class CollectionTest { expect(null, { arrayListOf().reduceRightOrNull { a, b -> a + b } }) } + @Test + fun scan() { + for (size in 0 until 4) { + val expected = listOf("", "0", "01", "012", "0123").take(size + 1) + assertEquals(expected, List(size) { it }.scan("") { acc, e -> acc + e }) + } + } + + @Test + fun scanIndexed() { + for (size in 0 until 4) { + val expected = listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").take(size + 1) + assertEquals(expected, List(size) { 'a' + it }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" }) + } + } + + @Test + fun scanReduce() { + for (size in 0 until 4) { + val expected = listOf(0, 1, 3, 6).take(size) + assertEquals(expected, List(size) { it }.scanReduce { acc, e -> acc + e }) + } + } + + @Test + fun scanReduceIndexed() { + for (size in 0 until 4) { + val expected = listOf(0, 1, 6, 27).take(size) + assertEquals(expected, List(size) { it }.scanReduceIndexed { index, acc, e -> index * (acc + e) }) + } + } + @Test fun groupBy() { val words = listOf("a", "abc", "ab", "def", "abcd") val byLength = words.groupBy { it.length } diff --git a/libraries/stdlib/test/collections/IterableTests.kt b/libraries/stdlib/test/collections/IterableTests.kt index e9b97920220..9be58dbaac1 100644 --- a/libraries/stdlib/test/collections/IterableTests.kt +++ b/libraries/stdlib/test/collections/IterableTests.kt @@ -438,6 +438,40 @@ abstract class IterableTests>(val createFrom: (Array acc + e } + assertEquals(3, accumulators.size) + assertEquals("baz", accumulators.first()) + assertTrue(accumulators.elementAt(1) in listOf("bazfoo", "bazbar")) + assertTrue(accumulators.last() in listOf("bazfoobar", "bazbarfoo")) + } + + @Test + fun scanIndexed() { + val accumulators = data.scanIndexed("baz") { i, acc, e -> acc + i + e } + assertEquals(3, accumulators.size) + assertEquals("baz", accumulators.first()) + assertTrue(accumulators.elementAt(1) in listOf("baz0foo", "baz0bar")) + assertTrue(accumulators.last() in listOf("baz0foo1bar", "baz0bar1foo")) + } + + @Test + fun scanReduce() { + val accumulators = data.scanReduce { acc, e -> acc + e } + assertEquals(2, accumulators.size) + assertTrue(accumulators.first() in listOf("foo", "bar")) + assertTrue(accumulators.last() in listOf("foobar", "barfoo")) + } + + @Test + fun scanReduceIndexed() { + val accumulators = data.scanReduceIndexed { i, acc, e -> acc + i + e } + assertEquals(2, accumulators.size) + assertTrue(accumulators.first() in listOf("foo", "bar")) + assertTrue(accumulators.last() in listOf("foo1bar", "bar1foo")) + } + @Test fun mapAndJoinToString() { val result = data.joinToString(separator = "-") { it.toUpperCase() } diff --git a/libraries/stdlib/test/collections/SequenceTest.kt b/libraries/stdlib/test/collections/SequenceTest.kt index 8f22aaa9e3f..549daa19d02 100644 --- a/libraries/stdlib/test/collections/SequenceTest.kt +++ b/libraries/stdlib/test/collections/SequenceTest.kt @@ -13,6 +13,8 @@ fun fibonacci(): Sequence { return generateSequence(Pair(0, 1), { Pair(it.second, it.first + it.second) }).map { it.first * 1 } } +fun indexSequence(): Sequence = generateSequence(0) { it + 1 } + public class SequenceTest { private class TriggerSequence(val source: Sequence) : Sequence { @@ -145,6 +147,47 @@ public class SequenceTest { assertEquals("13, 21, 34, 55, 89, ...", fibonacci().filter { it > 10 }.joinToString(separator = ", ", limit = 5)) } + @Test + fun scan() { + for (size in 0 until 4) { + assertEquals( + sequenceOf("", "0", "01", "012").take(size).toList(), + indexSequence().scan("") { acc, e -> acc + e }.take(size).toList() + ) + } + } + + @Test + fun scanIndexed() { + for (size in 0 until 4) { + assertEquals( + sequenceOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]").take(size).toList(), + indexSequence().map { 'a' + it }.scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" }.take(size).toList() + ) + } + } + + @Test + fun scanReduce() { + for (size in 0 until 4) { + val expected = listOf(0, 1, 3, 6).subList(0, size) + assertEquals( + sequenceOf(0, 1, 3, 6).take(size).toList(), + indexSequence().scanReduce { acc, e -> acc + e }.take(size).toList() + ) + } + } + + @Test + fun scanReduceIndexed() { + for (size in 0 until 4) { + assertEquals( + sequenceOf(0, 1, 6, 27).take(size).toList(), + indexSequence().scanReduceIndexed { index, acc, e -> index * (acc + e) }.take(size).toList() + ) + } + } + @Test fun drop() { assertEquals(emptyList(), emptySequence().drop(1).toList()) listOf(2, 3, 4, 5).let { assertEquals(it, it.asSequence().drop(0).toList()) } diff --git a/libraries/stdlib/test/collections/UnsignedArraysTest.kt b/libraries/stdlib/test/collections/UnsignedArraysTest.kt index db3f56d2d21..bb4c254f9eb 100644 --- a/libraries/stdlib/test/collections/UnsignedArraysTest.kt +++ b/libraries/stdlib/test/collections/UnsignedArraysTest.kt @@ -635,6 +635,86 @@ class UnsignedArraysTest { expect(" 2-3 1-2 0-1") { ulongArrayOf(1, 2, 3).foldRightIndexed("") { i, e, acc -> "$acc $i-$e" } } } + @Test + fun scan() { + for (size in 0 until 4) { + val expected = listOf("", "0", "01", "012", "0123").subList(0, size + 1) + assertEquals(expected, UByteArray(size) { it.toUByte() }.scan("") { acc, e -> acc + e }) + assertEquals(expected, UShortArray(size) { it.toUShort() }.scan("") { acc, e -> acc + e }) + assertEquals(expected, UIntArray(size) { it.toUInt() }.scan("") { acc, e -> acc + e }) + assertEquals(expected, ULongArray(size) { it.toULong() }.scan("") { acc, e -> acc + e }) + } + } + + @Test + fun scanIndexed() { + for (size in 0 until 4) { + val expected = listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").subList(0, size + 1) + assertEquals( + expected, + UByteArray(size) { it.toUByte() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + UShortArray(size) { it.toUShort() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + UIntArray(size) { it.toUInt() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + assertEquals( + expected, + ULongArray(size) { it.toULong() }.scanIndexed("+") { index, acc, e -> "$acc[$index: ${'a' + e.toInt()}]" } + ) + } + } + + @Test + fun scanReduce() { + for (size in 0 until 4) { + val expected = listOf(0, 1, 3, 6).subList(0, size) + assertEquals( + expected.map { it.toUByte() }, + UByteArray(size) { it.toUByte() }.scanReduce { acc, e -> (acc + e).toUByte() } + ) + assertEquals( + expected.map { it.toUShort() }, + UShortArray(size) { it.toUShort() }.scanReduce { acc, e -> (acc + e).toUShort() } + ) + assertEquals( + expected.map { it.toUInt() }, + UIntArray(size) { it.toUInt() }.scanReduce { acc, e -> acc + e } + ) + assertEquals( + expected.map { it.toULong() }, + ULongArray(size) { it.toULong() }.scanReduce { acc, e -> acc + e } + ) + } + } + + @Test + fun scanReduceIndexed() { + for (size in 0 until 4) { + val expected = listOf(0, 1, 6, 27).subList(0, size) + assertEquals( + expected.map { it.toUByte() }, + UByteArray(size) { it.toUByte() }.scanReduceIndexed { index, acc, e -> (index.toUInt() * (acc + e)).toUByte() } + ) + assertEquals( + expected.map { it.toUShort() }, + UShortArray(size) { it.toUShort() }.scanReduceIndexed { index, acc, e -> (index.toUInt() * (acc + e)).toUShort() } + ) + assertEquals( + expected.map { it.toUInt() }, + UIntArray(size) { it.toUInt() }.scanReduceIndexed { index, acc, e -> index.toUInt() * (acc + e) } + ) + assertEquals( + expected.map { it.toULong() }, + ULongArray(size) { it.toULong() }.scanReduceIndexed { index, acc, e -> index.toULong() * (acc + e) } + ) + } + } + @Test fun elementAt() { expect(0u) { ubyteArrayOf(0, 1, 2).elementAt(0) } diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index 64f6ad0496f..95161303bfc 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -1311,6 +1311,47 @@ class StringTest { expect(null, { arg1("").reduceOrNull { _, _ -> '\n' } }) } + + @Test + fun scan() = withOneCharSequenceArg { arg1 -> + for (size in 0 until 4) { + assertEquals( + listOf("", "0", "01", "012", "0123").take(size + 1), + arg1((0 until size).joinToString(separator = "")).scan("") { acc, e -> acc + e } + ) + } + } + + @Test + fun scanIndexed() = withOneCharSequenceArg { arg1 -> + for (size in 0 until 4) { + assertEquals( + listOf("+", "+[0: a]", "+[0: a][1: b]", "+[0: a][1: b][2: c]", "+[0: a][1: b][2: c][3: d]").take(size + 1), + arg1(('a' until 'a' + size).joinToString(separator = "")).scanIndexed("+") { index, acc, e -> "$acc[$index: $e]" } + ) + } + } + + @Test + fun scanReduce() = withOneCharSequenceArg { arg1 -> + for (size in 0 until 4) { + assertEquals( + listOf(0, 1, 3, 6).take(size).map { it.toChar() }, + arg1((0.toChar() until size.toChar()).joinToString(separator = "")).scanReduce { acc, e -> acc + e.toInt() } + ) + } + } + + @Test + fun scanReduceIndexed() = withOneCharSequenceArg { arg1 -> + for (size in 0 until 4) { + assertEquals( + listOf(0, 1, 6, 27).take(size).map { it.toChar() }, + arg1((0.toChar() until size.toChar()).joinToString(separator = "")).scanReduceIndexed { index, acc, e -> (index * (acc.toInt() + e.toInt())).toChar() } + ) + } + } + @Test fun groupBy() = withOneCharSequenceArg("abAbaABcD") { data -> // group characters by their case val result = data.groupBy { it.isAsciiUpperCase() } diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 07cf4f61b8a..08d7d36b582 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -1553,6 +1553,10 @@ public final class kotlin/collections/ArraysKt { public static final fun reversedArray ([Ljava/lang/Object;)[Ljava/lang/Object; public static final fun reversedArray ([S)[S public static final fun reversedArray ([Z)[Z + public static final fun scan ([Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static final fun scanIndexed ([Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/util/List; + public static final fun scanReduce ([Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static final fun scanReduceIndexed ([Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/util/List; public static final fun single ([B)B public static final fun single ([BLkotlin/jvm/functions/Function1;)B public static final fun single ([C)C @@ -2145,6 +2149,10 @@ public final class kotlin/collections/CollectionsKt { public static final fun retainAll (Ljava/util/List;Lkotlin/jvm/functions/Function1;)Z public static final fun reverse (Ljava/util/List;)V public static final fun reversed (Ljava/lang/Iterable;)Ljava/util/List; + public static final fun scan (Ljava/lang/Iterable;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static final fun scanIndexed (Ljava/lang/Iterable;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/util/List; + public static final fun scanReduce (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static final fun scanReduceIndexed (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function3;)Ljava/util/List; public static final fun shuffle (Ljava/util/List;Lkotlin/random/Random;)V public static final fun shuffled (Ljava/lang/Iterable;)Ljava/util/List; public static final fun shuffled (Ljava/lang/Iterable;Ljava/util/Random;)Ljava/util/List; @@ -4605,6 +4613,10 @@ public final class kotlin/sequences/SequencesKt { public static final fun reduceIndexed (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; public static final fun reduceOrNull (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun requireNoNulls (Lkotlin/sequences/Sequence;)Lkotlin/sequences/Sequence; + public static final fun scan (Lkotlin/sequences/Sequence;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; + public static final fun scanIndexed (Lkotlin/sequences/Sequence;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lkotlin/sequences/Sequence; + public static final fun scanReduce (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; + public static final fun scanReduceIndexed (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function3;)Lkotlin/sequences/Sequence; public static final fun sequence (Lkotlin/jvm/functions/Function2;)Lkotlin/sequences/Sequence; public static final fun sequenceOf ([Ljava/lang/Object;)Lkotlin/sequences/Sequence; public static final fun single (Lkotlin/sequences/Sequence;)Ljava/lang/Object; @@ -5047,6 +5059,10 @@ public final class kotlin/text/StringsKt { public static final fun replaceRange (Ljava/lang/CharSequence;IILjava/lang/CharSequence;)Ljava/lang/CharSequence; public static final fun replaceRange (Ljava/lang/CharSequence;Lkotlin/ranges/IntRange;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; public static final fun reversed (Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + public static final fun scan (Ljava/lang/CharSequence;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static final fun scanIndexed (Ljava/lang/CharSequence;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/util/List; + public static final fun scanReduce (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function2;)Ljava/util/List; + public static final fun scanReduceIndexed (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function3;)Ljava/util/List; public static final fun single (Ljava/lang/CharSequence;)C public static final fun single (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function1;)C public static final fun singleOrNull (Ljava/lang/CharSequence;)Ljava/lang/Character; diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt index de93db67d48..e386852a817 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt @@ -5,6 +5,7 @@ package templates +import templates.DocExtensions.mapResult import templates.Family.* import templates.SequenceClass.* @@ -1037,6 +1038,371 @@ object Aggregates : TemplateGroupBase() { } } + private fun scanAccMutationNote(hasInitial: Boolean, f: Family): String { + if (!hasInitial && f.isPrimitiveSpecialization) return "" + + val initialValueRequirement = if (hasInitial && f == Sequences) + """The [initial] value should also be immutable (or should not be mutated) + as it may be passed to [operation] function later because of sequence's lazy nature. + """ else + "" + return """ + Note that `acc` value passed to [operation] function should not be mutated; + otherwise it would affect the previous value in resulting ${f.mapResult}. + $initialValueRequirement""" + } + + val f_scan = fn("scan(initial: R, operation: (acc: R, T) -> R)") { + includeDefault() + include(CharSequences, ArraysOfUnsigned) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + + specialFor(Iterables, ArraysOfObjects, CharSequences) { inline() } + specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() } + + typeParam("R") + + returns("List") + specialFor(Sequences) { returns("Sequence") } + + doc { + """ + Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right + to each ${f.element} and current accumulator value that starts with [initial] value. + ${scanAccMutationNote(true, f)} + @param [operation] function that takes current accumulator value and ${f.element.prefixWithArticle()}, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.scan") + sequenceClassification(intermediate, stateless) + + body(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) { + """ + if (isEmpty()) return listOf(initial) + + val result = ArrayList(${f.code.size} + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result + """ + } + body(Iterables) { + """ + val estimatedSize = collectionSizeOrDefault(9) + if (estimatedSize == 0) return listOf(initial) + + val result = ArrayList(estimatedSize + 1).apply { add(initial) } + var accumulator = initial + for (element in this) { + accumulator = operation(accumulator, element) + result.add(accumulator) + } + return result + """ + } + body(Sequences) { + """ + return sequence { + yield(initial) + var accumulator = initial + for (element in this@scan) { + accumulator = operation(accumulator, element) + yield(accumulator) + } + } + """ + } + } + + val f_scanIndexed = fn("scanIndexed(initial: R, operation: (index: Int, acc: R, T) -> R)") { + includeDefault() + include(CharSequences, ArraysOfUnsigned) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + + specialFor(Iterables, ArraysOfObjects, CharSequences) { inline() } + specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() } + + typeParam("R") + + returns("List") + specialFor(Sequences) { returns("Sequence") } + + doc { + """ + Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right + to each ${f.element}, its index in the original ${f.collection} and current accumulator value that starts with [initial] value. + ${scanAccMutationNote(true, f)} + @param [operation] function that takes the index of ${f.element.prefixWithArticle()}, current accumulator value + and the ${f.element} itself, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.scan") + sequenceClassification(intermediate, stateless) + + body(ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) { + """ + if (isEmpty()) return listOf(initial) + + val result = ArrayList(${f.code.size} + 1).apply { add(initial) } + var accumulator = initial + for (index in indices) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result + """ + } + body(Iterables) { + """ + val estimatedSize = collectionSizeOrDefault(9) + if (estimatedSize == 0) return listOf(initial) + + val result = ArrayList(estimatedSize + 1).apply { add(initial) } + var index = 0 + var accumulator = initial + for (element in this) { + accumulator = operation(index++, accumulator, element) + result.add(accumulator) + } + return result + """ + } + body(Sequences) { + """ + return sequence { + yield(initial) + var index = 0 + var accumulator = initial + for (element in this@scanIndexed) { + accumulator = operation(checkIndexOverflow(index++), accumulator, element) + yield(accumulator) + } + } + """ + } + } + + val f_scanReduce = fn("scanReduce(operation: (acc: T, T) -> T)") { + include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + + specialFor(CharSequences) { inline() } + specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() } + + returns("List") + + doc { + """ + Returns a list containing successive accumulation values generated by applying [operation] from left to right + to each ${f.element} and current accumulator value that starts with the first ${f.element} of this ${f.collection}. + ${scanAccMutationNote(false, f)} + @param [operation] function that takes current accumulator value and ${f.element.prefixWithArticle()}, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.scanReduce") + + body { + """ + if (isEmpty()) return emptyList() + + var accumulator = this[0] + val result = ArrayList(${f.code.size}).apply { add(accumulator) } + for (index in 1 until ${f.code.size}) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result + """ + } + } + + val f_scanReduceIndexed = fn("scanReduceIndexed(operation: (index: Int, acc: T, T) -> T)") { + include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + + specialFor(CharSequences) { inline() } + specialFor(ArraysOfPrimitives, ArraysOfUnsigned) { inlineOnly() } + + returns("List") + + doc { + """ + Returns a list containing successive accumulation values generated by applying [operation] from left to right + to each ${f.element}, its index in the original ${f.collection} and current accumulator value that starts with the first ${f.element} of this ${f.collection}. + ${scanAccMutationNote(false, f)} + @param [operation] function that takes the index of ${f.element.prefixWithArticle()}, current accumulator value + and the ${f.element} itself, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.scanReduce") + + body { + """ + if (isEmpty()) return emptyList() + + var accumulator = this[0] + val result = ArrayList(${f.code.size}).apply { add(accumulator) } + for (index in 1 until ${f.code.size}) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result + """ + } + } + + val f_scanReduceSuper = fn("scanReduce(operation: (acc: S, T) -> S)") { + include(ArraysOfObjects, Iterables, Sequences) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + + specialFor(ArraysOfObjects, Iterables) { inline() } + + typeParam("S") + typeParam("T : S") + + returns("List") + specialFor(Sequences) { returns("Sequence") } + + doc { + """ + Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right + to each ${f.element} and current accumulator value that starts with the first ${f.element} of this ${f.collection}. + ${scanAccMutationNote(false, f)} + @param [operation] function that takes current accumulator value and the ${f.element}, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.scanReduce") + sequenceClassification(intermediate, stateless) + + body(ArraysOfObjects) { + """ + if (isEmpty()) return emptyList() + + var accumulator: S = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(accumulator, this[index]) + result.add(accumulator) + } + return result + """ + } + body(Iterables) { + """ + val iterator = this.iterator() + if (!iterator.hasNext()) return emptyList() + + var accumulator: S = iterator.next() + val result = ArrayList(collectionSizeOrDefault(10)).apply { add(accumulator) } + while (iterator.hasNext()) { + accumulator = operation(accumulator, iterator.next()) + result.add(accumulator) + } + return result + """ + } + body(Sequences) { + """ + return sequence { + val iterator = iterator() + if (iterator.hasNext()) { + var accumulator: S = iterator.next() + yield(accumulator) + while (iterator.hasNext()) { + accumulator = operation(accumulator, iterator.next()) + yield(accumulator) + } + } + } + """ + } + } + + val f_scanReduceIndexedSuper = fn("scanReduceIndexed(operation: (index: Int, acc: S, T) -> S)") { + include(ArraysOfObjects, Iterables, Sequences) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + + specialFor(ArraysOfObjects, Iterables) { inline() } + + typeParam("S") + typeParam("T : S") + + returns("List") + specialFor(Sequences) { returns("Sequence") } + + doc { + """ + Returns a ${f.mapResult} containing successive accumulation values generated by applying [operation] from left to right + to each ${f.element}, its index in the original ${f.collection} and current accumulator value that starts with the first ${f.element} of this ${f.collection}. + ${scanAccMutationNote(false, f)} + @param [operation] function that takes the index of ${f.element.prefixWithArticle()}, current accumulator value + and the ${f.element} itself, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.scanReduce") + sequenceClassification(intermediate, stateless) + + body(ArraysOfObjects) { + """ + if (isEmpty()) return emptyList() + + var accumulator: S = this[0] + val result = ArrayList(size).apply { add(accumulator) } + for (index in 1 until size) { + accumulator = operation(index, accumulator, this[index]) + result.add(accumulator) + } + return result + """ + } + body(Iterables) { + """ + val iterator = this.iterator() + if (!iterator.hasNext()) return emptyList() + + var accumulator: S = iterator.next() + val result = ArrayList(collectionSizeOrDefault(10)).apply { add(accumulator) } + var index = 1 + while (iterator.hasNext()) { + accumulator = operation(index++, accumulator, iterator.next()) + result.add(accumulator) + } + return result + """ + } + body(Sequences) { + """ + return sequence { + val iterator = iterator() + if (iterator.hasNext()) { + var accumulator: S = iterator.next() + yield(accumulator) + var index = 1 + while (iterator.hasNext()) { + accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next()) + yield(accumulator) + } + } + } + """ + } + } + val f_onEach = fn("onEach(action: (T) -> Unit)") { include(Iterables, Maps, CharSequences, Sequences) } builder {