diff --git a/libraries/stdlib/common/src/generated/_UArrays.kt b/libraries/stdlib/common/src/generated/_UArrays.kt index 04967534502..4c133d31ccc 100644 --- a/libraries/stdlib/common/src/generated/_UArrays.kt +++ b/libraries/stdlib/common/src/generated/_UArrays.kt @@ -2723,6 +2723,254 @@ public inline fun UShortArray.count(predicate: (UShort) -> Boolean): Int { return count } +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.fold(initial: R, operation: (acc: R, UInt) -> R): R { + var accumulator = initial + for (element in this) accumulator = operation(accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.fold(initial: R, operation: (acc: R, ULong) -> R): R { + var accumulator = initial + for (element in this) accumulator = operation(accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.fold(initial: R, operation: (acc: R, UByte) -> R): R { + var accumulator = initial + for (element in this) accumulator = operation(accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each element. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.fold(initial: R, operation: (acc: R, UShort) -> R): R { + var accumulator = initial + for (element in this) accumulator = operation(accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.foldIndexed(initial: R, operation: (index: Int, acc: R, UInt) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.foldIndexed(initial: R, operation: (index: Int, acc: R, ULong) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.foldIndexed(initial: R, operation: (index: Int, acc: R, UByte) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from left to right + * to current accumulator value and each element with its index in the original array. + * @param [operation] function that takes the index of an element, current accumulator value + * and the element itself, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.foldIndexed(initial: R, operation: (index: Int, acc: R, UShort) -> R): R { + var index = 0 + var accumulator = initial + for (element in this) accumulator = operation(index++, accumulator, element) + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left to each element and current accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.foldRight(initial: R, operation: (UInt, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left to each element and current accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.foldRight(initial: R, operation: (ULong, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left to each element and current accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.foldRight(initial: R, operation: (UByte, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left to each element and current accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.foldRight(initial: R, operation: (UShort, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(get(index--), accumulator) + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UIntArray.foldRightIndexed(initial: R, operation: (index: Int, UInt, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun ULongArray.foldRightIndexed(initial: R, operation: (index: Int, ULong, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UByteArray.foldRightIndexed(initial: R, operation: (index: Int, UByte, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + +/** + * Accumulates value starting with [initial] value and applying [operation] from right to left + * to each element with its index in the original array and current accumulator value. + * @param [operation] function that takes the index of an element, the element itself + * and current accumulator value, and calculates the next accumulator value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@kotlin.internal.InlineOnly +public inline fun UShortArray.foldRightIndexed(initial: R, operation: (index: Int, UShort, acc: R) -> R): R { + var index = lastIndex + var accumulator = initial + while (index >= 0) { + accumulator = operation(index, get(index), accumulator) + --index + } + return accumulator +} + /** * Performs the given [action] on each element. */ diff --git a/libraries/stdlib/test/collections/UnsignedArraysTest.kt b/libraries/stdlib/test/collections/UnsignedArraysTest.kt index e4505619306..8fbad81875a 100644 --- a/libraries/stdlib/test/collections/UnsignedArraysTest.kt +++ b/libraries/stdlib/test/collections/UnsignedArraysTest.kt @@ -584,4 +584,151 @@ class UnsignedArraysTest { expect(50000u) { ushortArrayOf(20000u, 30000u).sum() } expect(12_000_000_000_000_000_000uL) { ulongArrayOf(10_000_000_000_000_000_000uL, 2_000_000_000_000_000_000uL).sum() } } + + @Test + fun fold() { + expect(6u) { ubyteArrayOf(1, 2, 3).fold(0u) { acc, e -> acc + e } } + expect(13u) { ushortArrayOf(1, 2, 3).fold(1u) { acc, e -> acc + 2u * e } } + expect(6u) { uintArrayOf(1, 2, 3).fold(1u) { acc, e -> acc * e } } + expect("0123") { ulongArrayOf(1, 2, 3).fold("0") { acc, e -> "$acc$e" } } + } + + @Test + fun foldIndexed() { + expect(8u) { ubyteArrayOf(1, 2, 3).foldIndexed(0u) { i, acc, e -> acc + i.toUByte() * e } } + expect(10) { ushortArrayOf(1, 2, 3).foldIndexed(1) { i, acc, e -> acc + i + e.toInt() } } + expect(15u) { uintArrayOf(1, 2, 3).foldIndexed(1u) { i, acc, e -> acc * (i.toUInt() + e) } } + expect(" 0-1 1-2 2-3") { ulongArrayOf(1, 2, 3).foldIndexed("") { i, acc, e -> "$acc $i-$e" } } + } + + @Test + fun foldRight() { + expect(6u) { ubyteArrayOf(1, 2, 3).foldRight(0u) { e, acc -> acc + e } } + expect(13u) { ushortArrayOf(1, 2, 3).foldRight(1u) { e, acc -> acc + 2u * e } } + expect(6u) { uintArrayOf(1, 2, 3).foldRight(1u) { e, acc -> acc * e } } + expect("0321") { ulongArrayOf(1, 2, 3).foldRight("0") { e, acc -> "$acc$e" } } + } + + @Test + fun foldRightIndexed() { + expect(8u) { ubyteArrayOf(1, 2, 3).foldRightIndexed(0u) { i, e, acc -> acc + i.toUByte() * e } } + expect(10) { ushortArrayOf(1, 2, 3).foldRightIndexed(1) { i, e, acc -> acc + i + e.toInt() } } + expect(15u) { uintArrayOf(1, 2, 3).foldRightIndexed(1u) { i, e, acc -> acc * (i.toUInt() + e) } } + expect(" 2-3 1-2 0-1") { ulongArrayOf(1, 2, 3).foldRightIndexed("") { i, e, acc -> "$acc $i-$e" } } + } + + @Test + fun elementAt() { + expect(0u) { ubyteArrayOf(0, 1, 2).elementAt(0) } + expect(1u) { ushortArrayOf(0, 1, 2).elementAt(1) } + expect(2u) { uintArrayOf(0, 1, 2).elementAt(2) } + + // TODO: Uncomment these tests after KT-30051 gets fixed. + // Currently JS does not throw exception on incorrect index. +// assertFailsWith { uintArrayOf().elementAt(0) } +// assertFailsWith { ulongArrayOf(0, 1, 2).elementAt(-1) } + } + + @Test + fun elementAtOrElse() { + expect(0u) { ubyteArrayOf(0, 1, 2).elementAtOrElse(0) { UByte.MAX_VALUE } } + expect(UShort.MAX_VALUE) { ushortArrayOf(0, 1, 2).elementAtOrElse(-1) { UShort.MAX_VALUE } } + expect(UInt.MAX_VALUE) { uintArrayOf(0, 1, 2).elementAtOrElse(3) { UInt.MAX_VALUE } } + expect(ULong.MAX_VALUE) { ulongArrayOf(0, 1, 2).elementAtOrElse(100) { ULong.MAX_VALUE } } + } + + @Test + fun elementAtOrNull() { + expect(0u) { ubyteArrayOf(0, 1, 2).elementAtOrNull(0) } + expect(null) { ushortArrayOf(0, 1, 2).elementAtOrNull(-1) } + expect(null) { uintArrayOf(0, 1, 2).elementAtOrNull(3) } + expect(null) { ulongArrayOf(0, 1, 2).elementAtOrNull(100) } + } + + @Test + fun find() { + expect(0u) { ubyteArrayOf(0, 1, 2).find { it == 0.toUByte() } } + expect(0u) { ushortArrayOf(0, 1, 2).find { it % 2u == 0u } } + expect(1u) { uintArrayOf(0, 1, 2).find { it % 2u == 1u } } + expect(null) { ulongArrayOf(0, 1, 2).find { it == 3uL } } + } + + @Test + fun findLast() { + expect(0u) { ubyteArrayOf(0, 1, 2).findLast { it == 0.toUByte() } } + expect(2u) { ushortArrayOf(0, 1, 2).findLast { it % 2u == 0u } } + expect(1u) { uintArrayOf(0, 1, 2).findLast { it % 2u == 1u } } + expect(null) { ulongArrayOf(0, 1, 2).findLast { it == 3uL } } + } + + @Test + fun first() { + expect(0u) { ubyteArrayOf(0, 1, 2).first() } + expect(0u) { ushortArrayOf(0, 1, 2).first { it % 2u == 0u } } + expect(1u) { uintArrayOf(0, 1, 2).first { it % 2u == 1u } } + assertFailsWith { uintArrayOf().first() } + assertFailsWith { ulongArrayOf(0, 1, 2).first { it == 3uL } } + } + + @Test + fun firstOrNull() { + expect(0u) { ubyteArrayOf(0, 1, 2).firstOrNull() } + expect(0u) { ushortArrayOf(0, 1, 2).firstOrNull { it % 2u == 0u } } + expect(1u) { uintArrayOf(0, 1, 2).firstOrNull { it % 2u == 1u } } + expect(null) { uintArrayOf().firstOrNull() } + expect(null) { ulongArrayOf(0, 1, 2).firstOrNull { it == 3uL } } + } + + @Test + fun getOrElse() { + expect(0u) { ubyteArrayOf(0, 1, 2).getOrElse(0) { UByte.MAX_VALUE } } + expect(UShort.MAX_VALUE) { ushortArrayOf(0, 1, 2).getOrElse(-1) { UShort.MAX_VALUE } } + expect(UInt.MAX_VALUE) { uintArrayOf(0, 1, 2).getOrElse(3) { UInt.MAX_VALUE } } + expect(ULong.MAX_VALUE) { ulongArrayOf(0, 1, 2).getOrElse(100) { ULong.MAX_VALUE } } + } + + @Test + fun getOrNull() { + expect(0u) { ubyteArrayOf(0, 1, 2).getOrNull(0) } + expect(null) { ushortArrayOf(0, 1, 2).getOrNull(-1) } + expect(null) { uintArrayOf(0, 1, 2).getOrNull(3) } + expect(null) { ulongArrayOf(0, 1, 2).getOrNull(100) } + } + + @Test + fun last() { + expect(2u) { ubyteArrayOf(0, 1, 2).last() } + expect(2u) { ushortArrayOf(0, 1, 2).last { it % 2u == 0u } } + expect(1u) { uintArrayOf(0, 1, 2).last { it % 2u == 1u } } + assertFailsWith { uintArrayOf().last() } + assertFailsWith { ulongArrayOf(0, 1, 2).last { it == 3uL } } + } + + @Test + fun lastOrNull() { + expect(2u) { ubyteArrayOf(0, 1, 2).lastOrNull() } + expect(2u) { ushortArrayOf(0, 1, 2).lastOrNull { it % 2u == 0u } } + expect(1u) { uintArrayOf(0, 1, 2).lastOrNull { it % 2u == 1u } } + expect(null) { uintArrayOf().lastOrNull() } + expect(null) { ulongArrayOf(0, 1, 2).lastOrNull { it == 3uL } } + } + + @Test + fun single() { + expect(0u) { ubyteArrayOf(0).single() } + expect(2u) { ushortArrayOf(0, 1, 2).single { it == 2.toUShort() } } + expect(1u) { uintArrayOf(0, 1, 2).single { it % 2u == 1u } } + assertFailsWith { uintArrayOf().single() } + assertFailsWith { ulongArrayOf(0, 1, 2).single { it == 3uL } } + assertFailsWith { ulongArrayOf(0, 1, 2).single { it % 2uL == 0uL } } + } + + @Test + fun singleOrNull() { + expect(0u) { ubyteArrayOf(0).singleOrNull() } + expect(2u) { ushortArrayOf(0, 1, 2).singleOrNull { it == 2.toUShort() } } + expect(1u) { uintArrayOf(0, 1, 2).singleOrNull { it % 2u == 1u } } + expect(null) { uintArrayOf().singleOrNull() } + expect(null) { ulongArrayOf(0, 1, 2).singleOrNull() { it % 2uL == 0uL } } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt index 2931291430a..9e02d23e6b4 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Aggregates.kt @@ -505,8 +505,11 @@ object Aggregates : TemplateGroupBase() { val f_foldIndexed = fn("foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R)") { includeDefault() include(CharSequences) + include(ArraysOfUnsigned) } builder { inline() + specialFor(ArraysOfUnsigned) { inlineOnly() } + doc { """ Accumulates value starting with [initial] value and applying [operation] from left to right @@ -529,9 +532,11 @@ object Aggregates : TemplateGroupBase() { } val f_foldRightIndexed = fn("foldRightIndexed(initial: R, operation: (index: Int, T, acc: R) -> R)") { - include(CharSequences, Lists, ArraysOfObjects, ArraysOfPrimitives) + include(CharSequences, Lists, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) } builder { inline() + specialFor(ArraysOfUnsigned) { inlineOnly() } + doc { """ Accumulates value starting with [initial] value and applying [operation] from right to left @@ -571,8 +576,11 @@ object Aggregates : TemplateGroupBase() { val f_fold = fn("fold(initial: R, operation: (acc: R, T) -> R)") { includeDefault() include(CharSequences) + include(ArraysOfUnsigned) } builder { inline() + specialFor(ArraysOfUnsigned) { inlineOnly() } + doc { "Accumulates value starting with [initial] value and applying [operation] from left to right to current accumulator value and each ${f.element}." } typeParam("R") returns("R") @@ -586,9 +594,10 @@ object Aggregates : TemplateGroupBase() { } val f_foldRight = fn("foldRight(initial: R, operation: (T, acc: R) -> R)") { - include(CharSequences, Lists, ArraysOfObjects, ArraysOfPrimitives) + include(CharSequences, Lists, ArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) } builder { inline() + specialFor(ArraysOfUnsigned) { inlineOnly() } doc { "Accumulates value starting with [initial] value and applying [operation] from right to left to each ${f.element} and current accumulator value." } typeParam("R")