Implement folding extension functions for UArrays

This commit is contained in:
Abduqodiri Qurbonzoda
2019-01-28 14:27:51 +03:00
committed by Ilya Gorbunov
parent 7695b5e575
commit 503264b996
3 changed files with 406 additions and 2 deletions
@@ -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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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 <R> 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.
*/
@@ -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<IndexOutOfBoundsException> { uintArrayOf().elementAt(0) }
// assertFailsWith<IndexOutOfBoundsException> { 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<NoSuchElementException> { uintArrayOf().first() }
assertFailsWith<NoSuchElementException> { 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<NoSuchElementException> { uintArrayOf().last() }
assertFailsWith<NoSuchElementException> { 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<NoSuchElementException> { uintArrayOf().single() }
assertFailsWith<NoSuchElementException> { ulongArrayOf(0, 1, 2).single { it == 3uL } }
assertFailsWith<IllegalArgumentException> { 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 } }
}
}