From 1a6069382ecafc4c6d79bc109c83f67f0aca6188 Mon Sep 17 00:00:00 2001 From: Jake Wharton Date: Fri, 19 Jul 2019 10:09:48 -0400 Subject: [PATCH] Provide Array.fill in common stdlib KT-32359 --- .../stdlib/common/src/generated/_Arrays.kt | 45 ++++++ .../stdlib/common/src/generated/_UArrays.kt | 28 ++++ .../stdlib/js-ir/src/generated/_ArraysJs.kt | 135 ++++++++++++++++++ .../stdlib/js-ir/src/generated/_UArraysJs.kt | 40 ++++++ libraries/stdlib/js-v1/src/js/polyfills.js | 46 ++++++ .../stdlib/js/src/generated/_ArraysJs.kt | 135 ++++++++++++++++++ .../stdlib/js/src/generated/_UArraysJs.kt | 40 ++++++ .../stdlib/jvm/src/generated/_ArraysJvm.kt | 27 ++-- .../stdlib/jvm/src/generated/_UArraysJvm.kt | 12 +- .../jvm/test/collections/UArrayJVMTest.kt | 63 +------- .../src/kotlin/collections/SlidingWindow.kt | 7 - .../stdlib/test/collections/ArraysTest.kt | 75 ++++++++++ .../test/collections/UnsignedArraysTest.kt | 70 ++++++++- .../kotlin-stdlib-gen/src/templates/Arrays.kt | 38 ++++- 14 files changed, 677 insertions(+), 84 deletions(-) diff --git a/libraries/stdlib/common/src/generated/_Arrays.kt b/libraries/stdlib/common/src/generated/_Arrays.kt index 4bc0ec13d8d..905b65a5176 100644 --- a/libraries/stdlib/common/src/generated/_Arrays.kt +++ b/libraries/stdlib/common/src/generated/_Arrays.kt @@ -6338,6 +6338,51 @@ public expect fun BooleanArray.copyOfRange(fromIndex: Int, toIndex: Int): Boolea */ public expect fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray +/** + * Fills original array with the provided value. + */ +public expect fun Array.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +public expect fun CharArray.fill(element: Char, fromIndex: Int = 0, toIndex: Int = size): Unit + /** * Returns the range of valid indices for the array. */ diff --git a/libraries/stdlib/common/src/generated/_UArrays.kt b/libraries/stdlib/common/src/generated/_UArrays.kt index e12c98456b5..fe0d0186ed4 100644 --- a/libraries/stdlib/common/src/generated/_UArrays.kt +++ b/libraries/stdlib/common/src/generated/_UArrays.kt @@ -3230,6 +3230,34 @@ public inline fun UShortArray.copyOfRange(fromIndex: Int, toIndex: Int): UShortA return UShortArray(storage.copyOfRange(fromIndex, toIndex)) } +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public expect fun UIntArray.fill(element: UInt, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public expect fun ULongArray.fill(element: ULong, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public expect fun UByteArray.fill(element: UByte, fromIndex: Int = 0, toIndex: Int = size): Unit + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +public expect fun UShortArray.fill(element: UShort, fromIndex: Int = 0, toIndex: Int = size): Unit + /** * Returns the range of valid indices for the array. */ diff --git a/libraries/stdlib/js-ir/src/generated/_ArraysJs.kt b/libraries/stdlib/js-ir/src/generated/_ArraysJs.kt index 77810754cff..af1f91fb7cd 100644 --- a/libraries/stdlib/js-ir/src/generated/_ArraysJs.kt +++ b/libraries/stdlib/js-ir/src/generated/_ArraysJs.kt @@ -1023,6 +1023,141 @@ public actual fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray return withType("CharArray", this.asDynamic().slice(fromIndex, toIndex)) } +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun Array.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun CharArray.fill(element: Char, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + /** * Returns an array containing all elements of the original array and then the given [element]. */ diff --git a/libraries/stdlib/js-ir/src/generated/_UArraysJs.kt b/libraries/stdlib/js-ir/src/generated/_UArraysJs.kt index 0260b62541d..ebdf41a5445 100644 --- a/libraries/stdlib/js-ir/src/generated/_UArraysJs.kt +++ b/libraries/stdlib/js-ir/src/generated/_UArraysJs.kt @@ -158,3 +158,43 @@ public actual fun UShortArray.asList(): List { } } +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UIntArray.fill(element: UInt, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toInt(), fromIndex, toIndex) +} + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ULongArray.fill(element: ULong, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toLong(), fromIndex, toIndex) +} + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UByteArray.fill(element: UByte, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toByte(), fromIndex, toIndex) +} + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UShortArray.fill(element: UShort, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toShort(), fromIndex, toIndex) +} + diff --git a/libraries/stdlib/js-v1/src/js/polyfills.js b/libraries/stdlib/js-v1/src/js/polyfills.js index f2e119914ba..b1b01e380e7 100644 --- a/libraries/stdlib/js-v1/src/js/polyfills.js +++ b/libraries/stdlib/js-v1/src/js/polyfills.js @@ -249,6 +249,49 @@ if (typeof ArrayBuffer.isView === "undefined") { }; } +if (typeof Array.prototype.fill === "undefined") { + // Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill#Polyfill + Array.prototype.fill = function() { + // Steps 1-2. + if (this == null) { + throw new TypeError('this is null or not defined'); + } + + var O = Object(this); + + // Steps 3-5. + var len = O.length >>> 0; + + // Steps 6-7. + var start = arguments[1]; + var relativeStart = start >> 0; + + // Step 8. + var k = relativeStart < 0 ? + Math.max(len + relativeStart, 0) : + Math.min(relativeStart, len); + + // Steps 9-10. + var end = arguments[2]; + var relativeEnd = end === undefined ? + len : end >> 0; + + // Step 11. + var final = relativeEnd < 0 ? + Math.max(len + relativeEnd, 0) : + Math.min(relativeEnd, len); + + // Step 12. + while (k < final) { + O[k] = value; + k++; + } + + // Step 13. + return O; + }; +} + (function() { function normalizeOffset(offset, length) { if (offset < 0) return Math.max(0, offset + length); @@ -266,6 +309,9 @@ if (typeof ArrayBuffer.isView === "undefined") { var arrays = [Int8Array, Int16Array, Uint16Array, Int32Array, Float32Array, Float64Array]; for (var i = 0; i < arrays.length; ++i) { var TypedArray = arrays[i]; + if (typeof TypedArray.prototype.fill === "undefined") { + TypedArray.prototype.fill = Array.prototype.fill; + } if (typeof TypedArray.prototype.slice === "undefined") { Object.defineProperty(TypedArray.prototype, 'slice', { value: typedArraySlice diff --git a/libraries/stdlib/js/src/generated/_ArraysJs.kt b/libraries/stdlib/js/src/generated/_ArraysJs.kt index 0c7fd962f3e..4e3ea15c2ef 100644 --- a/libraries/stdlib/js/src/generated/_ArraysJs.kt +++ b/libraries/stdlib/js/src/generated/_ArraysJs.kt @@ -1053,6 +1053,141 @@ public actual fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray return withType("CharArray", this.asDynamic().slice(fromIndex, toIndex)) } +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun Array.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + +/** + * Fills original array with the provided value. + */ +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun CharArray.fill(element: Char, fromIndex: Int = 0, toIndex: Int = size): Unit { + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex $fromIndex out of range [0, $size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex $toIndex out of range [$fromIndex, $size]") + } + require(fromIndex <= toIndex) { "fromIndex($fromIndex) > toIndex($toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); +} + /** * Returns an array containing all elements of the original array and then the given [element]. */ diff --git a/libraries/stdlib/js/src/generated/_UArraysJs.kt b/libraries/stdlib/js/src/generated/_UArraysJs.kt index 0260b62541d..ebdf41a5445 100644 --- a/libraries/stdlib/js/src/generated/_UArraysJs.kt +++ b/libraries/stdlib/js/src/generated/_UArraysJs.kt @@ -158,3 +158,43 @@ public actual fun UShortArray.asList(): List { } } +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UIntArray.fill(element: UInt, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toInt(), fromIndex, toIndex) +} + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ULongArray.fill(element: ULong, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toLong(), fromIndex, toIndex) +} + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UByteArray.fill(element: UByte, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toByte(), fromIndex, toIndex) +} + +/** + * Fills original array with the provided value. + */ +@SinceKotlin("1.3") +@ExperimentalUnsignedTypes +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UShortArray.fill(element: UShort, fromIndex: Int = 0, toIndex: Int = size): Unit { + storage.fill(element.toShort(), fromIndex, toIndex) +} + diff --git a/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt b/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt index 6c2cdd5c009..d40e7c48a2a 100644 --- a/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt +++ b/libraries/stdlib/jvm/src/generated/_ArraysJvm.kt @@ -1379,63 +1379,72 @@ internal fun CharArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): CharArray /** * Fills original array with the provided value. */ -public fun Array.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun Array.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ShortArray.fill(element: Short, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun IntArray.fill(element: Int, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun LongArray.fill(element: Long, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun FloatArray.fill(element: Float, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun DoubleArray.fill(element: Double, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun BooleanArray.fill(element: Boolean, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } /** * Fills original array with the provided value. */ -public fun CharArray.fill(element: Char, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun CharArray.fill(element: Char, fromIndex: Int = 0, toIndex: Int = size): Unit { java.util.Arrays.fill(this, fromIndex, toIndex, element) } diff --git a/libraries/stdlib/jvm/src/generated/_UArraysJvm.kt b/libraries/stdlib/jvm/src/generated/_UArraysJvm.kt index c7ede9bd19d..734ba388539 100644 --- a/libraries/stdlib/jvm/src/generated/_UArraysJvm.kt +++ b/libraries/stdlib/jvm/src/generated/_UArraysJvm.kt @@ -262,7 +262,8 @@ public fun UShortArray.binarySearch(element: UShort, fromIndex: Int = 0, toIndex */ @SinceKotlin("1.3") @ExperimentalUnsignedTypes -public fun UIntArray.fill(element: UInt, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UIntArray.fill(element: UInt, fromIndex: Int = 0, toIndex: Int = size): Unit { storage.fill(element.toInt(), fromIndex, toIndex) } @@ -271,7 +272,8 @@ public fun UIntArray.fill(element: UInt, fromIndex: Int = 0, toIndex: Int = size */ @SinceKotlin("1.3") @ExperimentalUnsignedTypes -public fun ULongArray.fill(element: ULong, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun ULongArray.fill(element: ULong, fromIndex: Int = 0, toIndex: Int = size): Unit { storage.fill(element.toLong(), fromIndex, toIndex) } @@ -280,7 +282,8 @@ public fun ULongArray.fill(element: ULong, fromIndex: Int = 0, toIndex: Int = si */ @SinceKotlin("1.3") @ExperimentalUnsignedTypes -public fun UByteArray.fill(element: UByte, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UByteArray.fill(element: UByte, fromIndex: Int = 0, toIndex: Int = size): Unit { storage.fill(element.toByte(), fromIndex, toIndex) } @@ -289,7 +292,8 @@ public fun UByteArray.fill(element: UByte, fromIndex: Int = 0, toIndex: Int = si */ @SinceKotlin("1.3") @ExperimentalUnsignedTypes -public fun UShortArray.fill(element: UShort, fromIndex: Int = 0, toIndex: Int = size): Unit { +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual fun UShortArray.fill(element: UShort, fromIndex: Int = 0, toIndex: Int = size): Unit { storage.fill(element.toShort(), fromIndex, toIndex) } diff --git a/libraries/stdlib/jvm/test/collections/UArrayJVMTest.kt b/libraries/stdlib/jvm/test/collections/UArrayJVMTest.kt index ca2228d35ee..b37fac0f7c3 100644 --- a/libraries/stdlib/jvm/test/collections/UArrayJVMTest.kt +++ b/libraries/stdlib/jvm/test/collections/UArrayJVMTest.kt @@ -6,7 +6,6 @@ package test.collections import kotlin.test.Test -import kotlin.test.assertTrue import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -68,65 +67,15 @@ class UArrayJVMTest { test(array.toULongArray(), ULongArray::binarySearch, operations, UInt::toULong) } - @Test - fun fill() { - fun testFailures(array: A, fill: A.(E, Int, Int) -> Unit, element: E, arraySize: Int) { - assertFailsWith { - array.fill(element, -1, arraySize) - } - assertFailsWith { - array.fill(element, 0, arraySize + 1) - } - assertFailsWith { - array.fill(element, 1, 0) - } - } - - testFailures(UByteArray(5) { it.toUByte() }, UByteArray::fill, 0u, 5) - testFailures(UShortArray(5) { it.toUShort() }, UShortArray::fill, 0u, 5) - testFailures(UIntArray(5) { it.toUInt() }, UIntArray::fill, 0u, 5) - testFailures(ULongArray(5) { it.toULong() }, ULongArray::fill, 0u, 5) - - fun test( - array: UIntArray, - fill: A.(E, Int, Int) -> Unit, - operations: List>, - arrayTransform: UIntArray.() -> A, - elementTransform: UInt.() -> E, - contentEquals: A.(A) -> Boolean - ) { - for (o in operations) { - val result = array.arrayTransform() - result.fill(o.element.elementTransform(), o.fromIndex, o.toIndex) - assertTrue(o.expectedResult.arrayTransform().contentEquals(result)) - } - } - - val array = UIntArray(5) { it.toUInt() } - - val operations = listOf( - OperationOnRange(5u, 1, 4, uintArrayOf(0u, 5u, 5u, 5u, 4u)), - OperationOnRange(1u, 0, 5, uintArrayOf(1u, 1u, 1u, 1u, 1u)), - OperationOnRange(2u, 0, 3, uintArrayOf(2u, 2u, 2u, 3u, 4u)), - OperationOnRange(3u, 2, 5, uintArrayOf(0u, 1u, 3u, 3u, 3u)) - ) - - test(array, UByteArray::fill, operations, UIntArray::toUByteArray, UInt::toUByte, UByteArray::contentEquals) - test(array, UShortArray::fill, operations, UIntArray::toUShortArray, UInt::toUShort, UShortArray::contentEquals) - test(array, UIntArray::fill, operations, UIntArray::copyOf, UInt::toUInt, UIntArray::contentEquals) - test(array, ULongArray::fill, operations, UIntArray::toULongArray, UInt::toULong, ULongArray::contentEquals) - } + private class OperationOnRange( + val element: E, + val fromIndex: Int, + val toIndex: Int, + val expectedResult: R + ) } -private class OperationOnRange( - val element: E, - val fromIndex: Int, - val toIndex: Int, - val expectedResult: R -) - - private fun UIntArray.toUByteArray(): UByteArray { return UByteArray(size) { get(it).toUByte() } } diff --git a/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt b/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt index d530cac3193..20be2a28453 100644 --- a/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt +++ b/libraries/stdlib/src/kotlin/collections/SlidingWindow.kt @@ -187,11 +187,4 @@ private class RingBuffer(val capacity: Int) : AbstractList(), RandomAccess @Suppress("NOTHING_TO_INLINE") private inline fun Int.forward(n: Int): Int = (this + n) % capacity - - // TODO: replace with Array.fill from stdlib when available in common - private fun Array.fill(element: T, fromIndex: Int = 0, toIndex: Int = size): Unit { - for (idx in fromIndex until toIndex) { - this[idx] = element - } - } } diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 45657e1a255..a334892cf79 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -1500,8 +1500,83 @@ class ArraysTest { assertFailsWith { arrayOf().elementAt(0) } assertFailsWith { longArrayOf(0, 1, 2).elementAt(-1) } } + + @Test + fun fill() { + fun testFailures(array: A, fill: A.(E, Int, Int) -> Unit, element: E, arraySize: Int) { + assertFailsWith { + array.fill(element, -1, arraySize) + } + assertFailsWith { + array.fill(element, 0, arraySize + 1) + } + assertFailsWith { + array.fill(element, 1, 0) + } + } + + testFailures(BooleanArray(5) { it % 2 == 0 }, BooleanArray::fill, true, 5) + testFailures(ByteArray(5) { it.toByte() }, ByteArray::fill, 0.toByte(), 5) + testFailures(CharArray(5) { it.toChar() }, CharArray::fill, 0.toChar(), 5) + testFailures(FloatArray(5) { it.toFloat() }, FloatArray::fill, 0.0f, 5) + testFailures(DoubleArray(5) { it.toDouble() }, DoubleArray::fill, 0.0, 5) + testFailures(ShortArray(5) { it.toShort() }, ShortArray::fill, 0.toShort(), 5) + testFailures(IntArray(5) { it }, IntArray::fill, 0, 5) + testFailures(LongArray(5) { it.toLong() }, LongArray::fill, 0L, 5) + testFailures(Array(5) { it.toString() }, Array::fill, "0", 5) + + fun test( + array: IntArray, + fill: A.(E, Int, Int) -> Unit, + operations: List>, + arrayTransform: IntArray.() -> A, + elementTransform: Int.() -> E, + contentEquals: A.(A) -> Boolean + ) { + for (o in operations) { + val result = array.arrayTransform() + result.fill(o.element.elementTransform(), o.fromIndex, o.toIndex) + assertTrue(o.expectedResult.arrayTransform().contentEquals(result)) + } + } + + val array = IntArray(5) { it } + + val operations = listOf( + OperationOnRange(5, 1, 4, intArrayOf(0, 5, 5, 5, 4)), + OperationOnRange(1, 0, 5, intArrayOf(1, 1, 1, 1, 1)), + OperationOnRange(2, 0, 3, intArrayOf(2, 2, 2, 3, 4)), + OperationOnRange(3, 2, 5, intArrayOf(0, 1, 3, 3, 3)) + ) + + test(array, BooleanArray::fill, operations, IntArray::toBooleanArray, { this % 2 == 0 }, BooleanArray::contentEquals) + test(array, ByteArray::fill, operations, IntArray::toByteArray, Int::toByte, ByteArray::contentEquals) + test(array, CharArray::fill, operations, IntArray::toCharArray, Int::toChar, CharArray::contentEquals) + test(array, FloatArray::fill, operations, IntArray::toFloatArray, Int::toFloat, FloatArray::contentEquals) + test(array, DoubleArray::fill, operations, IntArray::toDoubleArray, Int::toDouble, DoubleArray::contentEquals) + test(array, ShortArray::fill, operations, IntArray::toShortArray, Int::toShort, ShortArray::contentEquals) + test(array, IntArray::fill, operations, IntArray::copyOf, { this }, IntArray::contentEquals) + test(array, LongArray::fill, operations, IntArray::toLongArray, Int::toLong, LongArray::contentEquals) + test(array, Array::fill, operations, IntArray::toStringArray, Int::toString, { contentEquals(it) }) + } + + private class OperationOnRange( + val element: E, + val fromIndex: Int, + val toIndex: Int, + val expectedResult: R + ) } +private fun IntArray.toBooleanArray() = BooleanArray(size) { get(it) % 2 == 0 } +private fun IntArray.toByteArray() = ByteArray(size) { get(it).toByte() } +private fun IntArray.toCharArray() = CharArray(size) { get(it).toChar() } +private fun IntArray.toFloatArray() = FloatArray(size) { get(it).toFloat() } +private fun IntArray.toDoubleArray() = DoubleArray(size) { get(it).toDouble() } +private fun IntArray.toShortArray() = ShortArray(size) { get(it).toShort() } +private fun IntArray.toLongArray() = LongArray(size) { get(it).toLong() } +private fun IntArray.toStringArray() = Array(size) { get(it).toString() } + fun > Array>.assertStableSorted(descending: Boolean = false) = iterator().assertStableSorted(descending = descending) diff --git a/libraries/stdlib/test/collections/UnsignedArraysTest.kt b/libraries/stdlib/test/collections/UnsignedArraysTest.kt index ed66a3a0119..030e1bfebbf 100644 --- a/libraries/stdlib/test/collections/UnsignedArraysTest.kt +++ b/libraries/stdlib/test/collections/UnsignedArraysTest.kt @@ -1031,4 +1031,72 @@ class UnsignedArraysTest { assertArrayContentEquals(ulongArrayOf(ULong.MAX_VALUE, ULong.MAX_VALUE - 123, 80, 9, 5, 2, 1, 0), ulongArray.sortedArrayDescending()) } -} \ No newline at end of file + @Test + fun fill() { + fun testFailures(array: A, fill: A.(E, Int, Int) -> Unit, element: E, arraySize: Int) { + assertFailsWith { + array.fill(element, -1, arraySize) + } + assertFailsWith { + array.fill(element, 0, arraySize + 1) + } + assertFailsWith { + array.fill(element, 1, 0) + } + } + + testFailures(UByteArray(5) { it.toUByte() }, UByteArray::fill, 0u, 5) + testFailures(UShortArray(5) { it.toUShort() }, UShortArray::fill, 0u, 5) + testFailures(UIntArray(5) { it.toUInt() }, UIntArray::fill, 0u, 5) + testFailures(ULongArray(5) { it.toULong() }, ULongArray::fill, 0u, 5) + + fun test( + array: UIntArray, + fill: A.(E, Int, Int) -> Unit, + operations: List>, + arrayTransform: UIntArray.() -> A, + elementTransform: UInt.() -> E, + contentEquals: A.(A) -> Boolean + ) { + for (o in operations) { + val result = array.arrayTransform() + result.fill(o.element.elementTransform(), o.fromIndex, o.toIndex) + assertTrue(o.expectedResult.arrayTransform().contentEquals(result)) + } + } + + val array = UIntArray(5) { it.toUInt() } + + val operations = listOf( + OperationOnRange(5u, 1, 4, uintArrayOf(0u, 5u, 5u, 5u, 4u)), + OperationOnRange(1u, 0, 5, uintArrayOf(1u, 1u, 1u, 1u, 1u)), + OperationOnRange(2u, 0, 3, uintArrayOf(2u, 2u, 2u, 3u, 4u)), + OperationOnRange(3u, 2, 5, uintArrayOf(0u, 1u, 3u, 3u, 3u)) + ) + + test(array, UByteArray::fill, operations, UIntArray::toUByteArray, UInt::toUByte, UByteArray::contentEquals) + test(array, UShortArray::fill, operations, UIntArray::toUShortArray, UInt::toUShort, UShortArray::contentEquals) + test(array, UIntArray::fill, operations, UIntArray::copyOf, UInt::toUInt, UIntArray::contentEquals) + test(array, ULongArray::fill, operations, UIntArray::toULongArray, UInt::toULong, ULongArray::contentEquals) + } + + private class OperationOnRange( + val element: E, + val fromIndex: Int, + val toIndex: Int, + val expectedResult: R + ) +} + + +private fun UIntArray.toUByteArray(): UByteArray { + return UByteArray(size) { get(it).toUByte() } +} + +private fun UIntArray.toUShortArray(): UShortArray { + return UShortArray(size) { get(it).toUShort() } +} + +private fun UIntArray.toULongArray(): ULongArray { + return ULongArray(size) { get(it).toULong() } +} diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt index dd3a2e8cdf6..4244a4d422b 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt @@ -6,8 +6,8 @@ package templates import templates.Family.* -import templates.Ordering.stableSortNote import templates.Ordering.appendStableSortNote +import templates.Ordering.stableSortNote object ArrayOps : TemplateGroupBase() { @@ -1273,15 +1273,41 @@ object ArrayOps : TemplateGroupBase() { } val f_fill = fn("fill(element: T, fromIndex: Int = 0, toIndex: Int = size)") { - platforms(Platform.JVM) include(InvariantArraysOfObjects, ArraysOfPrimitives, ArraysOfUnsigned) } builder { doc { "Fills original array with the provided value." } returns("Unit") - body { - """ - java.util.Arrays.fill(this, fromIndex, toIndex, element) - """ + + on(Platform.JVM) { + suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") + body { + """ + java.util.Arrays.fill(this, fromIndex, toIndex, element) + """ + } + } + on(Platform.JS) { + suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") + body { + """ + if (fromIndex !in 0..size) { + throw IndexOutOfBoundsException("fromIndex ${'$'}fromIndex out of range [0, ${'$'}size]") + } + if (toIndex > size) { + throw IndexOutOfBoundsException("toIndex ${'$'}toIndex out of range [${'$'}fromIndex, ${'$'}size]") + } + require(fromIndex <= toIndex) { "fromIndex(${'$'}fromIndex) > toIndex(${'$'}toIndex)" } + this.asDynamic().fill(element, fromIndex, toIndex); + """ + } + } + on(Platform.Native) { + suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") + body { + """ + arrayFill(this, element, fromIndex, toIndex) + """ + } } specialFor(ArraysOfUnsigned) {