From b1fac4e72192f85c31e81c32582eeabe9382816f Mon Sep 17 00:00:00 2001 From: Abduqodiri Qurbonzoda Date: Fri, 6 Mar 2020 13:49:22 +0300 Subject: [PATCH] Implement reduceIndexedOrNull and reduceRightIndexedOrNull #KT-36866 --- .../stdlib/common/src/generated/_Arrays.kt | 369 ++++++++++++++++++ .../common/src/generated/_Collections.kt | 43 ++ .../stdlib/common/src/generated/_Sequences.kt | 23 ++ .../stdlib/common/src/generated/_Strings.kt | 41 ++ .../stdlib/common/src/generated/_UArrays.kt | 180 +++++++++ .../test/samples/collections/collections.kt | 2 + .../stdlib/test/collections/ArraysTest.kt | 28 ++ .../stdlib/test/collections/CollectionTest.kt | 36 ++ .../stdlib/test/collections/SequenceTest.kt | 4 + .../test/collections/UnsignedArraysTest.kt | 20 + libraries/stdlib/test/text/StringTest.kt | 32 ++ .../kotlin-stdlib-runtime-merged.txt | 23 ++ .../src/templates/Aggregates.kt | 163 ++++++++ 13 files changed, 964 insertions(+) diff --git a/libraries/stdlib/common/src/generated/_Arrays.kt b/libraries/stdlib/common/src/generated/_Arrays.kt index 446c788a038..ff68df59a2c 100644 --- a/libraries/stdlib/common/src/generated/_Arrays.kt +++ b/libraries/stdlib/common/src/generated/_Arrays.kt @@ -13562,6 +13562,186 @@ public inline fun CharArray.reduceIndexed(operation: (index: Int, acc: Char, Cha return accumulator } +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun Array.reduceIndexedOrNull(operation: (index: Int, acc: S, T) -> S): S? { + if (isEmpty()) + return null + var accumulator: S = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun ByteArray.reduceIndexedOrNull(operation: (index: Int, acc: Byte, Byte) -> Byte): Byte? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun ShortArray.reduceIndexedOrNull(operation: (index: Int, acc: Short, Short) -> Short): Short? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun IntArray.reduceIndexedOrNull(operation: (index: Int, acc: Int, Int) -> Int): Int? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun LongArray.reduceIndexedOrNull(operation: (index: Int, acc: Long, Long) -> Long): Long? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun FloatArray.reduceIndexedOrNull(operation: (index: Int, acc: Float, Float) -> Float): Float? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun DoubleArray.reduceIndexedOrNull(operation: (index: Int, acc: Double, Double) -> Double): Double? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun BooleanArray.reduceIndexedOrNull(operation: (index: Int, acc: Boolean, Boolean) -> Boolean): Boolean? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun CharArray.reduceIndexedOrNull(operation: (index: Int, acc: Char, Char) -> Char): Char? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + /** * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty. * @@ -14021,6 +14201,195 @@ public inline fun CharArray.reduceRightIndexed(operation: (index: Int, Char, acc return accumulator } +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun Array.reduceRightIndexedOrNull(operation: (index: Int, T, acc: S) -> S): S? { + var index = lastIndex + if (index < 0) return null + var accumulator: S = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun ByteArray.reduceRightIndexedOrNull(operation: (index: Int, Byte, acc: Byte) -> Byte): Byte? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun ShortArray.reduceRightIndexedOrNull(operation: (index: Int, Short, acc: Short) -> Short): Short? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun IntArray.reduceRightIndexedOrNull(operation: (index: Int, Int, acc: Int) -> Int): Int? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun LongArray.reduceRightIndexedOrNull(operation: (index: Int, Long, acc: Long) -> Long): Long? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun FloatArray.reduceRightIndexedOrNull(operation: (index: Int, Float, acc: Float) -> Float): Float? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun DoubleArray.reduceRightIndexedOrNull(operation: (index: Int, Double, acc: Double) -> Double): Double? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun BooleanArray.reduceRightIndexedOrNull(operation: (index: Int, Boolean, acc: Boolean) -> Boolean): Boolean? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun CharArray.reduceRightIndexedOrNull(operation: (index: Int, Char, acc: Char) -> Char): Char? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value. Returns null if the array is empty. * diff --git a/libraries/stdlib/common/src/generated/_Collections.kt b/libraries/stdlib/common/src/generated/_Collections.kt index ae440ab9251..cc682dfb19a 100644 --- a/libraries/stdlib/common/src/generated/_Collections.kt +++ b/libraries/stdlib/common/src/generated/_Collections.kt @@ -1893,6 +1893,27 @@ public inline fun Iterable.reduceIndexed(operation: (index: Int, a return accumulator } +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original collection. + * Returns null if the collection is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun Iterable.reduceIndexedOrNull(operation: (index: Int, acc: S, T) -> S): S? { + val iterator = this.iterator() + if (!iterator.hasNext()) return null + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next()) + } + return accumulator +} + /** * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the collection is empty. * @@ -1946,6 +1967,28 @@ public inline fun List.reduceRightIndexed(operation: (index: Int, return accumulator } +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original list and current accumulator value. + * Returns null if the list is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun List.reduceRightIndexedOrNull(operation: (index: Int, T, acc: S) -> S): S? { + val iterator = listIterator(size) + if (!iterator.hasPrevious()) + return null + var accumulator: S = iterator.previous() + while (iterator.hasPrevious()) { + val index = iterator.previousIndex() + accumulator = operation(index, iterator.previous(), accumulator) + } + return accumulator +} + /** * Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value. Returns null if the list is empty. * diff --git a/libraries/stdlib/common/src/generated/_Sequences.kt b/libraries/stdlib/common/src/generated/_Sequences.kt index 7fdab30e3ec..d0cb2f21515 100644 --- a/libraries/stdlib/common/src/generated/_Sequences.kt +++ b/libraries/stdlib/common/src/generated/_Sequences.kt @@ -1388,6 +1388,29 @@ public inline fun Sequence.reduceIndexed(operation: (index: Int, a return accumulator } +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original sequence. + * Returns null if the sequence is empty. + * @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 _terminal_. + * + * @sample samples.collections.Collections.Aggregates.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun Sequence.reduceIndexedOrNull(operation: (index: Int, acc: S, T) -> S): S? { + val iterator = this.iterator() + if (!iterator.hasNext()) return null + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next()) + } + return accumulator +} + /** * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the sequence is empty. * diff --git a/libraries/stdlib/common/src/generated/_Strings.kt b/libraries/stdlib/common/src/generated/_Strings.kt index cb98b6cfaca..c6694812b64 100644 --- a/libraries/stdlib/common/src/generated/_Strings.kt +++ b/libraries/stdlib/common/src/generated/_Strings.kt @@ -1220,6 +1220,26 @@ public inline fun CharSequence.reduceIndexed(operation: (index: Int, acc: Char, return accumulator } +/** + * Accumulates value starting with the first character and applying [operation] from left to right + * to current accumulator value and each character with its index in the original char sequence. + * Returns null if the char sequence is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +public inline fun CharSequence.reduceIndexedOrNull(operation: (index: Int, acc: Char, Char) -> Char): Char? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + /** * Accumulates value starting with the first character and applying [operation] from left to right to current accumulator value and each character. Returns null if the char sequence is empty. * @@ -1271,6 +1291,27 @@ public inline fun CharSequence.reduceRightIndexed(operation: (index: Int, Char, return accumulator } +/** + * Accumulates value starting with last character and applying [operation] from right to left + * to each character with its index in the original char sequence and current accumulator value. + * Returns null if the char sequence is empty. + * @param [operation] function that takes the index of a character, the character itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +public inline fun CharSequence.reduceRightIndexedOrNull(operation: (index: Int, Char, acc: Char) -> Char): Char? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Accumulates value starting with last character and applying [operation] from right to left to each character and current accumulator value. Returns null if the char sequence is empty. * diff --git a/libraries/stdlib/common/src/generated/_UArrays.kt b/libraries/stdlib/common/src/generated/_UArrays.kt index 9b48d88c280..ed2171352fb 100644 --- a/libraries/stdlib/common/src/generated/_UArrays.kt +++ b/libraries/stdlib/common/src/generated/_UArrays.kt @@ -6002,6 +6002,94 @@ public inline fun UShortArray.reduceIndexed(operation: (index: Int, acc: UShort, return accumulator } +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.reduceIndexedOrNull(operation: (index: Int, acc: UInt, UInt) -> UInt): UInt? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.reduceIndexedOrNull(operation: (index: Int, acc: ULong, ULong) -> ULong): ULong? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.reduceIndexedOrNull(operation: (index: Int, acc: UByte, UByte) -> UByte): UByte? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + +/** + * Accumulates value starting with the first element and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * Returns null if the array is empty. + * @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.reduceOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.reduceIndexedOrNull(operation: (index: Int, acc: UShort, UShort) -> UShort): UShort? { + if (isEmpty()) + return null + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator +} + /** * Accumulates value starting with the first element and applying [operation] from left to right to current accumulator value and each element. Returns null if the array is empty. * @@ -6238,6 +6326,98 @@ public inline fun UShortArray.reduceRightIndexed(operation: (index: Int, UShort, return accumulator } +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.reduceRightIndexedOrNull(operation: (index: Int, UInt, acc: UInt) -> UInt): UInt? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.reduceRightIndexedOrNull(operation: (index: Int, ULong, acc: ULong) -> ULong): ULong? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.reduceRightIndexedOrNull(operation: (index: Int, UByte, acc: UByte) -> UByte): UByte? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with last element and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * Returns null if the array is empty. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + * + * @sample samples.collections.Collections.Aggregates.reduceRightOrNull + */ +@SinceKotlin("1.4") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.reduceRightIndexedOrNull(operation: (index: Int, UShort, acc: UShort) -> UShort): UShort? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Accumulates value starting with last element and applying [operation] from right to left to each element and current accumulator value. Returns null if the array is empty. * diff --git a/libraries/stdlib/samples/test/samples/collections/collections.kt b/libraries/stdlib/samples/test/samples/collections/collections.kt index ce73fb30f51..206c8fb2f2a 100644 --- a/libraries/stdlib/samples/test/samples/collections/collections.kt +++ b/libraries/stdlib/samples/test/samples/collections/collections.kt @@ -698,6 +698,7 @@ class Collections { fun reduceOrNull() { val strings = listOf("a", "b", "c", "d") assertPrints(strings.reduceOrNull { acc, string -> acc + string }, "abcd") + assertPrints(strings.reduceIndexedOrNull { index, acc, string -> acc + string + index }, "ab1c2d3") assertPrints(emptyList().reduceOrNull { _, _ -> "" }, "null") } @@ -706,6 +707,7 @@ class Collections { fun reduceRightOrNull() { val strings = listOf("a", "b", "c", "d") assertPrints(strings.reduceRightOrNull { string, acc -> acc + string }, "dcba") + assertPrints(strings.reduceRightIndexedOrNull { index, string, acc -> acc + string + index }, "dc2b1a0") assertPrints(emptyList().reduceRightOrNull { _, _ -> "" }, "null") } diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 09619196d09..248984e9590 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -1016,6 +1016,20 @@ class ArraysTest { } } + @Test fun reduceIndexedOrNull() { + expect(-1) { intArrayOf(1, 2, 3).reduceIndexedOrNull { index, a, b -> index + a - b } } + expect(-1.toLong()) { longArrayOf(1, 2, 3).reduceIndexedOrNull { index, a, b -> index + a - b } } + expect(-1F) { floatArrayOf(1F, 2F, 3F).reduceIndexedOrNull { index, a, b -> index + a - b } } + expect(-1.0) { doubleArrayOf(1.0, 2.0, 3.0).reduceIndexedOrNull { index, a, b -> index + a - b } } + expect('2') { charArrayOf('1', '3', '2').reduceIndexedOrNull { index, a, b -> if (a > b && index == 1) a else b } } + expect(true) { booleanArrayOf(true, true, false).reduceIndexedOrNull { index, a, b -> a && b || index == 2 } } + expect(false) { booleanArrayOf(true, true).reduceIndexedOrNull { index, a, b -> a && b && index != 1 } } + expect(1.toByte()) { byteArrayOf(3, 2, 1).reduceIndexedOrNull { index, a, b -> if (index != 2) (a - b).toByte() else a.toByte() } } + expect(1.toShort()) { shortArrayOf(3, 2, 1).reduceIndexedOrNull { index, a, b -> if (index != 2) (a - b).toShort() else a.toShort() } } + + expect(null, { intArrayOf().reduceIndexedOrNull { index, a, b -> index + a + b } }) + } + @Test fun reduceRightIndexed() { expect(1) { intArrayOf(1, 2, 3).reduceRightIndexed { index, a, b -> index + a - b } } expect(1.toLong()) { longArrayOf(1, 2, 3).reduceRightIndexed { index, a, b -> index + a - b } } @@ -1032,6 +1046,20 @@ class ArraysTest { } } + @Test fun reduceRightIndexedOrNull() { + expect(1) { intArrayOf(1, 2, 3).reduceRightIndexedOrNull { index, a, b -> index + a - b } } + expect(1.toLong()) { longArrayOf(1, 2, 3).reduceRightIndexedOrNull { index, a, b -> index + a - b } } + expect(1F) { floatArrayOf(1F, 2F, 3F).reduceRightIndexedOrNull { index, a, b -> index + a - b } } + expect(1.0) { doubleArrayOf(1.0, 2.0, 3.0).reduceRightIndexedOrNull { index, a, b -> index + a - b } } + expect('2') { charArrayOf('1', '3', '2').reduceRightIndexedOrNull { index, a, b -> if (a > b && index == 0) a else b } } + expect(true) { booleanArrayOf(true, true, false).reduceRightIndexedOrNull { index, a, b -> a && b || index == 1 } } + expect(false) { booleanArrayOf(true, true).reduceRightIndexedOrNull { index, a, b -> a && b && index != 0 } } + expect(1.toByte()) { byteArrayOf(3, 2, 1).reduceRightIndexedOrNull { index, a, b -> if (index != 1) (a - b).toByte() else a.toByte() } } + expect(1.toShort()) { shortArrayOf(3, 2, 1).reduceRightIndexedOrNull { index, a, b -> if (index != 1) (a - b).toShort() else a.toShort() } } + + expect(null, { intArrayOf().reduceRightIndexedOrNull { index, a, b -> index + a + b } }) + } + @Test fun reduce() { expect(-4) { intArrayOf(1, 2, 3).reduce { a, b -> a - b } } expect(-4.toLong()) { longArrayOf(1, 2, 3).reduce { a, b -> a - b } } diff --git a/libraries/stdlib/test/collections/CollectionTest.kt b/libraries/stdlib/test/collections/CollectionTest.kt index 2501024122a..d19f6635a25 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -296,6 +296,24 @@ class CollectionTest { } } + @Test fun reduceIndexedOrNull() { + expect("123") { + val list = listOf("1", "2", "3", "4") + list.reduceIndexedOrNull { index, a, b -> if (index == 3) a else a + b } + } + + expect(5) { + listOf(2, 3).reduceIndexedOrNull { index, acc: Number, e -> + assertEquals(1, index) + assertEquals(2, acc) + assertEquals(3, e) + acc.toInt() + e + } + } + + expect(null, { arrayListOf().reduceIndexedOrNull { index, a, b -> index + a + b } }) + } + @Test fun reduceRightIndexed() { expect("234") { val list = listOf("1", "2", "3", "4") @@ -316,6 +334,24 @@ class CollectionTest { } } + @Test fun reduceRightIndexedOrNull() { + expect("234") { + val list = listOf("1", "2", "3", "4") + list.reduceRightIndexedOrNull { index, a, b -> if (index == 0) b else a + b } + } + + expect(1) { + listOf(2, 3).reduceRightIndexedOrNull { index, e, acc: Number -> + assertEquals(0, index) + assertEquals(3, acc) + assertEquals(2, e) + acc.toInt() - e + } + } + + expect(null, { arrayListOf().reduceRightIndexedOrNull { index, a, b -> index + a + b } }) + } + @Test fun reduce() { expect("1234") { val list = listOf("1", "2", "3", "4") diff --git a/libraries/stdlib/test/collections/SequenceTest.kt b/libraries/stdlib/test/collections/SequenceTest.kt index 549daa19d02..528d8b08313 100644 --- a/libraries/stdlib/test/collections/SequenceTest.kt +++ b/libraries/stdlib/test/collections/SequenceTest.kt @@ -426,6 +426,10 @@ public class SequenceTest { expect(null, { sequenceOf().reduceOrNull { acc, i -> acc + i } }) } + @Test fun reduceIndexedOrNullOnEmpty() { + expect(null, { sequenceOf().reduceIndexedOrNull { index, acc, i -> acc + i + index } }) + } + @Test fun minusElement() = testMinus(expected = listOf("foo", "bar")) { it - "bar" - "zoo" } @Test fun minusCollection() = testMinus { it - listOf("bar", "zoo") } @Test fun minusArray() = testMinus { it - arrayOf("bar", "zoo") } diff --git a/libraries/stdlib/test/collections/UnsignedArraysTest.kt b/libraries/stdlib/test/collections/UnsignedArraysTest.kt index 846684ee7c0..750ada1279b 100644 --- a/libraries/stdlib/test/collections/UnsignedArraysTest.kt +++ b/libraries/stdlib/test/collections/UnsignedArraysTest.kt @@ -548,6 +548,16 @@ class UnsignedArraysTest { } } + @Test + fun reduceIndexedOrNull() { + expect(1u) { ubyteArrayOf(3, 2, 1).reduceIndexedOrNull { index, acc, e -> if (index != 2) (e - acc).toUByte() else e } } + expect(1u) { ushortArrayOf(3, 2, 1).reduceIndexedOrNull { index, acc, e -> if (index != 2) (e - acc).toUShort() else e } } + expect(UInt.MAX_VALUE) { uintArrayOf(1, 2, 3).reduceIndexedOrNull { index, acc, e -> index.toUInt() + acc - e } } + expect(ULong.MAX_VALUE) { ulongArrayOf(1, 2, 3).reduceIndexedOrNull { index, acc, e -> index.toULong() + acc - e } } + + expect(null, { uintArrayOf().reduceIndexedOrNull { index, acc, e -> index.toUInt() + e + acc } }) + } + @Test fun reduceRight() { expect(2u) { ubyteArrayOf(1, 2, 3).reduceRightOrNull { e, acc -> (e - acc).toUByte() } } @@ -582,6 +592,16 @@ class UnsignedArraysTest { } } + @Test + fun reduceRightIndexedOrNull() { + expect(1u) { ubyteArrayOf(3, 2, 1).reduceRightIndexedOrNull { index, e, acc -> if (index != 1) (e - acc).toUByte() else e } } + expect(1u) { ushortArrayOf(3, 2, 1).reduceRightIndexedOrNull { index, e, acc -> if (index != 1) (e - acc).toUShort() else e } } + expect(1u) { uintArrayOf(1, 2, 3).reduceRightIndexedOrNull { index, e, acc -> index.toUInt() + e - acc } } + expect(1uL) { ulongArrayOf(1, 2, 3).reduceRightIndexedOrNull { index, e, acc -> index.toULong() + e - acc } } + + expect(null, { uintArrayOf().reduceRightIndexedOrNull { index, e, acc -> index.toUInt() + e + acc } }) + } + @Test fun forEach() { var i = 0 diff --git a/libraries/stdlib/test/text/StringTest.kt b/libraries/stdlib/test/text/StringTest.kt index 95161303bfc..957b6fb3f81 100644 --- a/libraries/stdlib/test/text/StringTest.kt +++ b/libraries/stdlib/test/text/StringTest.kt @@ -1268,6 +1268,22 @@ class StringTest { } } + @Test fun reduceIndexedOrNull() = withOneCharSequenceArg { arg1 -> + // get the 3rd character + assertEquals('c', arg1("bacfd").reduceIndexedOrNull { index, v, c -> if (index == 2) c else v }) + + expect('c') { + "ab".reduceIndexedOrNull { index, acc, e -> + assertEquals(1, index) + assertEquals('a', acc) + assertEquals('b', e) + e + (e - acc) + } + } + + expect(null, { arg1("").reduceIndexedOrNull { _, _, _ -> '\n' } }) + } + @Test fun reduceRightIndexed() = withOneCharSequenceArg { arg1 -> // get the 3rd character assertEquals('c', arg1("bacfd").reduceRightIndexed { index, c, v -> if (index == 2) c else v }) @@ -1286,6 +1302,22 @@ class StringTest { } } + @Test fun reduceRightIndexedOrNull() = withOneCharSequenceArg { arg1 -> + // get the 3rd character + assertEquals('c', arg1("bacfd").reduceRightIndexedOrNull { index, c, v -> if (index == 2) c else v }) + + expect('c') { + "ab".reduceRightIndexedOrNull { index, e, acc -> + assertEquals(0, index) + assertEquals('b', acc) + assertEquals('a', e) + acc + (acc - e) + } + } + + expect(null, { arg1("").reduceRightIndexedOrNull { _, _, _ -> '\n' } }) + } + @Test fun reduce() = withOneCharSequenceArg { arg1 -> // get the smallest character(by char value) assertEquals('a', arg1("bacfd").reduce { v, c -> if (v > c) c else v }) 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 a0dcbb081af..b1426a31096 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 @@ -1491,6 +1491,15 @@ public final class kotlin/collections/ArraysKt { public static final fun reduceIndexed ([Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; public static final fun reduceIndexed ([SLkotlin/jvm/functions/Function3;)S public static final fun reduceIndexed ([ZLkotlin/jvm/functions/Function3;)Z + public static final fun reduceIndexedOrNull ([BLkotlin/jvm/functions/Function3;)Ljava/lang/Byte; + public static final fun reduceIndexedOrNull ([CLkotlin/jvm/functions/Function3;)Ljava/lang/Character; + public static final fun reduceIndexedOrNull ([DLkotlin/jvm/functions/Function3;)Ljava/lang/Double; + public static final fun reduceIndexedOrNull ([FLkotlin/jvm/functions/Function3;)Ljava/lang/Float; + public static final fun reduceIndexedOrNull ([ILkotlin/jvm/functions/Function3;)Ljava/lang/Integer; + public static final fun reduceIndexedOrNull ([JLkotlin/jvm/functions/Function3;)Ljava/lang/Long; + public static final fun reduceIndexedOrNull ([Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static final fun reduceIndexedOrNull ([SLkotlin/jvm/functions/Function3;)Ljava/lang/Short; + public static final fun reduceIndexedOrNull ([ZLkotlin/jvm/functions/Function3;)Ljava/lang/Boolean; public static final fun reduceOrNull ([BLkotlin/jvm/functions/Function2;)Ljava/lang/Byte; public static final fun reduceOrNull ([CLkotlin/jvm/functions/Function2;)Ljava/lang/Character; public static final fun reduceOrNull ([DLkotlin/jvm/functions/Function2;)Ljava/lang/Double; @@ -1518,6 +1527,15 @@ public final class kotlin/collections/ArraysKt { public static final fun reduceRightIndexed ([Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; public static final fun reduceRightIndexed ([SLkotlin/jvm/functions/Function3;)S public static final fun reduceRightIndexed ([ZLkotlin/jvm/functions/Function3;)Z + public static final fun reduceRightIndexedOrNull ([BLkotlin/jvm/functions/Function3;)Ljava/lang/Byte; + public static final fun reduceRightIndexedOrNull ([CLkotlin/jvm/functions/Function3;)Ljava/lang/Character; + public static final fun reduceRightIndexedOrNull ([DLkotlin/jvm/functions/Function3;)Ljava/lang/Double; + public static final fun reduceRightIndexedOrNull ([FLkotlin/jvm/functions/Function3;)Ljava/lang/Float; + public static final fun reduceRightIndexedOrNull ([ILkotlin/jvm/functions/Function3;)Ljava/lang/Integer; + public static final fun reduceRightIndexedOrNull ([JLkotlin/jvm/functions/Function3;)Ljava/lang/Long; + public static final fun reduceRightIndexedOrNull ([Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static final fun reduceRightIndexedOrNull ([SLkotlin/jvm/functions/Function3;)Ljava/lang/Short; + public static final fun reduceRightIndexedOrNull ([ZLkotlin/jvm/functions/Function3;)Ljava/lang/Boolean; public static final fun reduceRightOrNull ([BLkotlin/jvm/functions/Function2;)Ljava/lang/Byte; public static final fun reduceRightOrNull ([CLkotlin/jvm/functions/Function2;)Ljava/lang/Character; public static final fun reduceRightOrNull ([DLkotlin/jvm/functions/Function2;)Ljava/lang/Double; @@ -2129,9 +2147,11 @@ public final class kotlin/collections/CollectionsKt { public static final fun randomOrNull (Ljava/util/Collection;Lkotlin/random/Random;)Ljava/lang/Object; public static final fun reduce (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun reduceIndexed (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static final fun reduceIndexedOrNull (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; public static final fun reduceOrNull (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun reduceRight (Ljava/util/List;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun reduceRightIndexed (Ljava/util/List;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static final fun reduceRightIndexedOrNull (Ljava/util/List;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; public static final fun reduceRightOrNull (Ljava/util/List;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun removeAll (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z public static final fun removeAll (Ljava/util/Collection;Ljava/lang/Iterable;)Z @@ -4660,6 +4680,7 @@ public final class kotlin/sequences/SequencesKt { public static final fun plus (Lkotlin/sequences/Sequence;[Ljava/lang/Object;)Lkotlin/sequences/Sequence; public static final fun reduce (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; public static final fun reduceIndexed (Lkotlin/sequences/Sequence;Lkotlin/jvm/functions/Function3;)Ljava/lang/Object; + public static final fun reduceIndexedOrNull (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; @@ -5058,9 +5079,11 @@ public final class kotlin/text/StringsKt { public static final fun randomOrNull (Ljava/lang/CharSequence;Lkotlin/random/Random;)Ljava/lang/Character; public static final fun reduce (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function2;)C public static final fun reduceIndexed (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function3;)C + public static final fun reduceIndexedOrNull (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function3;)Ljava/lang/Character; public static final fun reduceOrNull (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function2;)Ljava/lang/Character; public static final fun reduceRight (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function2;)C public static final fun reduceRightIndexed (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function3;)C + public static final fun reduceRightIndexedOrNull (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function3;)Ljava/lang/Character; public static final fun reduceRightOrNull (Ljava/lang/CharSequence;Lkotlin/jvm/functions/Function2;)Ljava/lang/Character; public static final fun regionMatches (Ljava/lang/CharSequence;ILjava/lang/CharSequence;IIZ)Z public static final fun regionMatches (Ljava/lang/String;ILjava/lang/String;IIZ)Z diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt index e386852a817..92597b97e74 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt @@ -708,6 +708,85 @@ object Aggregates : TemplateGroupBase() { } } + val f_reduceIndexedOrNull = fn("reduceIndexedOrNull(operation: (index: Int, acc: T, T) -> T)") { + include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) + } builder { + since("1.4") + inline() + specialFor(ArraysOfUnsigned) { inlineOnly() } + + doc { + """ + Accumulates value starting with the first ${f.element} and applying [operation] from left to right + to current accumulator value and each ${f.element} with its index in the original ${f.collection}. + Returns null if the ${f.collection} is empty. + @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.reduceOrNull") + returns("T?") + body { + """ + if (isEmpty()) + return null + + var accumulator = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator + """ + } + } + + val f_reduceIndexedOrNullSuper = fn("reduceIndexedOrNull(operation: (index: Int, acc: S, T) -> S)") { + include(ArraysOfObjects, Iterables, Sequences) + } builder { + since("1.4") + inline() + + doc { + """ + Accumulates value starting with the first ${f.element} and applying [operation] from left to right + to current accumulator value and each ${f.element} with its index in the original ${f.collection}. + Returns null if the ${f.collection} is empty. + @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. + """ + } + typeParam("S") + typeParam("T : S") + sample("samples.collections.Collections.Aggregates.reduceOrNull") + returns("S?") + body { + fun checkOverflow(value: String) = if (f == Sequences || f == Iterables) "checkIndexOverflow($value)" else value + """ + val iterator = this.iterator() + if (!iterator.hasNext()) return null + + var index = 1 + var accumulator: S = iterator.next() + while (iterator.hasNext()) { + accumulator = operation(${checkOverflow("index++")}, accumulator, iterator.next()) + } + return accumulator + """ + } + body(ArraysOfObjects) { + """ + if (isEmpty()) + return null + + var accumulator: S = this[0] + for (index in 1..lastIndex) { + accumulator = operation(index, accumulator, this[index]) + } + return accumulator + """ + } + } + val f_reduceRightIndexed = fn("reduceRightIndexed(operation: (index: Int, T, acc: T) -> T)") { include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned) } builder { @@ -788,6 +867,90 @@ object Aggregates : TemplateGroupBase() { } } + val f_reduceRightIndexedOrNull = fn("reduceRightIndexedOrNull(operation: (index: Int, T, acc: T) -> T)") { + include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned) + } builder { + since("1.4") + inline() + specialFor(ArraysOfUnsigned) { inlineOnly() } + + doc { + """ + Accumulates value starting with last ${f.element} and applying [operation] from right to left + to each ${f.element} with its index in the original ${f.collection} and current accumulator value. + Returns null if the ${f.collection} is empty. + @param [operation] function that takes the index of ${f.element.prefixWithArticle()}, the ${f.element} itself + and current accumulator value, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.reduceRightOrNull") + returns("T?") + body { + """ + var index = lastIndex + if (index < 0) return null + + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + + return accumulator + """ + } + } + + val f_reduceRightIndexedOrNullSuper = fn("reduceRightIndexedOrNull(operation: (index: Int, T, acc: S) -> S)") { + include(Lists, ArraysOfObjects) + } builder { + since("1.4") + inline() + + doc { + """ + Accumulates value starting with last ${f.element} and applying [operation] from right to left + to each ${f.element} with its index in the original ${f.collection} and current accumulator value. + Returns null if the ${f.collection} is empty. + @param [operation] function that takes the index of ${f.element.prefixWithArticle()}, the ${f.element} itself + and current accumulator value, and calculates the next accumulator value. + """ + } + sample("samples.collections.Collections.Aggregates.reduceRightOrNull") + typeParam("S") + typeParam("T : S") + returns("S?") + body { + """ + var index = lastIndex + if (index < 0) return null + + var accumulator: S = get(index--) + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + + return accumulator + """ + } + body(Lists) { + """ + val iterator = listIterator(size) + if (!iterator.hasPrevious()) + return null + + var accumulator: S = iterator.previous() + while (iterator.hasPrevious()) { + val index = iterator.previousIndex() + accumulator = operation(index, iterator.previous(), accumulator) + } + + return accumulator + """ + } + } + val f_reduce = fn("reduce(operation: (acc: T, T) -> T)") { include(ArraysOfPrimitives, ArraysOfUnsigned, CharSequences) } builder {