From 06008c40ab7f6a9fdfe55f2632e298b301272b1f Mon Sep 17 00:00:00 2001 From: Alfredo Delli Bovi Date: Fri, 13 Dec 2019 19:06:59 +0100 Subject: [PATCH] KT-33761 Add reduceRightOrNull --- .../stdlib/common/src/generated/_Arrays.kt | 135 ++++++++++++++++++ .../common/src/generated/_Collections.kt | 16 +++ .../stdlib/common/src/generated/_Strings.kt | 15 ++ .../stdlib/common/src/generated/_UArrays.kt | 68 +++++++++ .../stdlib/test/collections/ArraysTest.kt | 14 ++ .../stdlib/test/collections/CollectionTest.kt | 9 ++ .../src/templates/Aggregates.kt | 64 +++++++++ 7 files changed, 321 insertions(+) diff --git a/libraries/stdlib/common/src/generated/_Arrays.kt b/libraries/stdlib/common/src/generated/_Arrays.kt index ace2514434d..faa4606d02f 100644 --- a/libraries/stdlib/common/src/generated/_Arrays.kt +++ b/libraries/stdlib/common/src/generated/_Arrays.kt @@ -13136,6 +13136,141 @@ 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 and current accumulator value. Returns null if the array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun Array.reduceRightOrNull(operation: (T, acc: S) -> S): S? { + var index = lastIndex + if (index < 0) return null + var accumulator: S = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun ByteArray.reduceRightOrNull(operation: (Byte, acc: Byte) -> Byte): Byte? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun ShortArray.reduceRightOrNull(operation: (Short, acc: Short) -> Short): Short? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun IntArray.reduceRightOrNull(operation: (Int, acc: Int) -> Int): Int? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun LongArray.reduceRightOrNull(operation: (Long, acc: Long) -> Long): Long? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun FloatArray.reduceRightOrNull(operation: (Float, acc: Float) -> Float): Float? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun DoubleArray.reduceRightOrNull(operation: (Double, acc: Double) -> Double): Double? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun BooleanArray.reduceRightOrNull(operation: (Boolean, acc: Boolean) -> Boolean): Boolean? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun CharArray.reduceRightOrNull(operation: (Char, acc: Char) -> Char): Char? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator +} + /** * 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 4d53244c2bf..060959fe08e 100644 --- a/libraries/stdlib/common/src/generated/_Collections.kt +++ b/libraries/stdlib/common/src/generated/_Collections.kt @@ -1913,6 +1913,22 @@ 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 and current accumulator value. Returns null if the list is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun List.reduceRightOrNull(operation: (T, acc: S) -> S): S? { + val iterator = listIterator(size) + if (!iterator.hasPrevious()) + return null + var accumulator: S = iterator.previous() + while (iterator.hasPrevious()) { + accumulator = operation(iterator.previous(), accumulator) + } + return accumulator +} + /** * 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/_Strings.kt b/libraries/stdlib/common/src/generated/_Strings.kt index feeddc3917f..076b0e3cb74 100644 --- a/libraries/stdlib/common/src/generated/_Strings.kt +++ b/libraries/stdlib/common/src/generated/_Strings.kt @@ -1240,6 +1240,21 @@ 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 and current accumulator value. Returns null if the char sequence is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +public inline fun CharSequence.reduceRightOrNull(operation: (Char, acc: Char) -> Char): Char? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator +} + /** * 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 52d49a9bda8..6104e9df5ff 100644 --- a/libraries/stdlib/common/src/generated/_UArrays.kt +++ b/libraries/stdlib/common/src/generated/_UArrays.kt @@ -5830,6 +5830,74 @@ 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 and current accumulator value. Returns null if the array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.reduceRightOrNull(operation: (UInt, acc: UInt) -> UInt): UInt? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.reduceRightOrNull(operation: (ULong, acc: ULong) -> ULong): ULong? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.reduceRightOrNull(operation: (UByte, acc: UByte) -> UByte): UByte? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), 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 array is empty. + */ +@SinceKotlin("1.3") +@ExperimentalStdlibApi +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.reduceRightOrNull(operation: (UShort, acc: UShort) -> UShort): UShort? { + var index = lastIndex + if (index < 0) return null + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator +} + /** * Returns the sum of all values produced by [selector] function applied to each element in the array. */ diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 086eb7d0936..f51892f4db9 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -1036,6 +1036,20 @@ class ArraysTest { } } + @Test fun reduceRightOrNull() { + expect(2) { intArrayOf(1, 2, 3).reduceRightOrNull { a, b -> a - b } } + expect(2.toLong()) { longArrayOf(1, 2, 3).reduceRightOrNull { a, b -> a - b } } + expect(2F) { floatArrayOf(1F, 2F, 3F).reduceRightOrNull { a, b -> a - b } } + expect(2.0) { doubleArrayOf(1.0, 2.0, 3.0).reduceRightOrNull { a, b -> a - b } } + expect('3') { charArrayOf('1', '3', '2').reduceRightOrNull { a, b -> if (a > b) a else b } } + expect(false) { booleanArrayOf(true, true, false).reduceRightOrNull { a, b -> a && b } } + expect(true) { booleanArrayOf(true, true).reduceRightOrNull { a, b -> a && b } } + expect(2.toByte()) { byteArrayOf(1, 2, 3).reduceRightOrNull { a, b -> (a - b).toByte() } } + expect(2.toShort()) { shortArrayOf(1, 2, 3).reduceRightOrNull { a, b -> (a - b).toShort() } } + + expect(null, { intArrayOf().reduceRightOrNull { a, b -> a + b } }) + } + @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 c63307f7102..50311ce0540 100644 --- a/libraries/stdlib/test/collections/CollectionTest.kt +++ b/libraries/stdlib/test/collections/CollectionTest.kt @@ -335,6 +335,15 @@ class CollectionTest { } } + @Test fun reduceRightOrNull() { + expect("1234") { + val list = listOf("1", "2", "3", "4") + list.reduceRightOrNull { a, b -> a + b } + } + + expect(null, { arrayListOf().reduceRightOrNull { a, b -> a + b } }) + } + @Test fun groupBy() { val words = listOf("a", "abc", "ab", "def", "abcd") val byLength = words.groupBy { it.length } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt index f0b097fe50b..1daa8b75285 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt @@ -961,6 +961,70 @@ object Aggregates : TemplateGroupBase() { } } + val f_reduceRightOrNull = fn("reduceRightOrNull(operation: (T, acc: T) -> T)") { + include(CharSequences, ArraysOfPrimitives, ArraysOfUnsigned) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + inline() + specialFor(ArraysOfUnsigned) { inlineOnly() } + + doc { "Accumulates value starting with last ${f.element} and applying [operation] from right to left to each ${f.element} and current accumulator value. Returns null if the ${f.collection} is empty." } + returns("T?") + body { + """ + var index = lastIndex + if (index < 0) return null + + var accumulator = get(index--) + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + + return accumulator + """ + } + } + + val f_reduceRightOrNullSuper = fn("reduceRightOrNull(operation: (T, acc: S) -> S)") { + include(Lists, ArraysOfObjects) + } builder { + since("1.3") + annotation("@ExperimentalStdlibApi") + inline() + doc { "Accumulates value starting with last ${f.element} and applying [operation] from right to left to each ${f.element} and current accumulator value. Returns null if the ${f.collection} is empty." } + 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(get(index--), accumulator) + } + + return accumulator + """ + } + body(Lists) { + """ + val iterator = listIterator(size) + if (!iterator.hasPrevious()) + return null + + var accumulator: S = iterator.previous() + while (iterator.hasPrevious()) { + accumulator = operation(iterator.previous(), accumulator) + } + + return accumulator + """ + } + } + val f_onEach = fn("onEach(action: (T) -> Unit)") { include(Iterables, Maps, CharSequences, Sequences) } builder {