diff --git a/compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayOfObjectArrayWithIndex.kt b/compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayOfObjectArrayWithIndex.kt index 377224f637e..af7852b8309 100644 --- a/compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayOfObjectArrayWithIndex.kt +++ b/compiler/testData/codegen/box/controlStructures/forInArrayWithIndex/forInArrayOfObjectArrayWithIndex.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun box(): String { diff --git a/compiler/testData/codegen/box/regressions/kt5056.kt b/compiler/testData/codegen/box/regressions/kt5056.kt index 758bf8cb75d..eb6855473ee 100644 --- a/compiler/testData/codegen/box/regressions/kt5056.kt +++ b/compiler/testData/codegen/box/regressions/kt5056.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun box(): String { diff --git a/compiler/testData/codegen/box/toArray/kt3177-toTypedArray.kt b/compiler/testData/codegen/box/toArray/kt3177-toTypedArray.kt index c9d65094c29..6d941babc19 100644 --- a/compiler/testData/codegen/box/toArray/kt3177-toTypedArray.kt +++ b/compiler/testData/codegen/box/toArray/kt3177-toTypedArray.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun box(): String { diff --git a/compiler/testData/codegen/box/toArray/returnToTypedArray.kt b/compiler/testData/codegen/box/toArray/returnToTypedArray.kt index 91a159707f9..5986dbe5bf4 100644 --- a/compiler/testData/codegen/box/toArray/returnToTypedArray.kt +++ b/compiler/testData/codegen/box/toArray/returnToTypedArray.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR // WITH_RUNTIME fun getCopyToArray(): Array = listOf(2, 3, 9).toTypedArray() diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt index 56376ff8c19..6e364f9e8b6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/BasicIrBoxTest.kt @@ -65,6 +65,10 @@ private val runtimeSources = listOfKtFilesFrom( "libraries/stdlib/js/src/kotlin/currentBeMisc.kt", + // IR BE has its own generated sources + "libraries/stdlib/js/src/generated", + "libraries/stdlib/js/src/kotlin/collectionsExternal.kt", + // Full version is defined in stdlib // This file is useful for smaller subset of runtime sources "libraries/stdlib/js/irRuntime/rangeExtensions.kt", diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/NashornJsTestChecker.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/NashornJsTestChecker.kt index 6c7658f7605..de99ec56481 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/NashornJsTestChecker.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/NashornJsTestChecker.kt @@ -167,6 +167,7 @@ object NashornIrJsTestChecker : AbstractNashornJsTestChecker() { listOf( BasicBoxTest.TEST_DATA_DIR_PATH + "nashorn-polyfills.js", + "libraries/stdlib/js/src/js/polyfills.js", "js/js.translator/testData/out/irBox/testRuntime.js" ).forEach(engine::loadFile) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 5ba1208d95e..30dba06f274 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -7558,6 +7558,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/standardClasses/arraySize.kt"); } + @TestMetadata("arraySort.kt") + public void testArraySort() throws Exception { + runTest("js/js.translator/testData/box/standardClasses/arraySort.kt"); + } + @TestMetadata("arraysIterator.kt") public void testArraysIterator() throws Exception { runTest("js/js.translator/testData/box/standardClasses/arraysIterator.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java index f98df3880f1..183e8f076f6 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java @@ -7558,6 +7558,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/standardClasses/arraySize.kt"); } + @TestMetadata("arraySort.kt") + public void testArraySort() throws Exception { + runTest("js/js.translator/testData/box/standardClasses/arraySort.kt"); + } + @TestMetadata("arraysIterator.kt") public void testArraysIterator() throws Exception { runTest("js/js.translator/testData/box/standardClasses/arraysIterator.kt"); diff --git a/js/js.translator/testData/box/standardClasses/arraySort.kt b/js/js.translator/testData/box/standardClasses/arraySort.kt new file mode 100644 index 00000000000..64fb3bc9bb1 --- /dev/null +++ b/js/js.translator/testData/box/standardClasses/arraySort.kt @@ -0,0 +1,20 @@ +// EXPECTED_REACHABLE_NODES: 1284 +package foo + +fun test(actual: DoubleArray, expect: DoubleArray): String { + for (index in 0 until expect.size) { + val expectedElem: Any = expect[index] + val actualElem: Any = actual[index] + if (expectedElem != actualElem) { + return "Content at index $index does not match: $expectedElem != $actualElem" + } + } + return "OK" +} + +fun box(): String { + val array = doubleArrayOf(Double.NaN, Double.POSITIVE_INFINITY, Double.NaN, 1.0, Double.NaN, +0.0, Double.NaN, -0.0, Double.NaN, -1.0, Double.NaN, Double.NEGATIVE_INFINITY) + array.sort() + + return test(array, doubleArrayOf(Double.NEGATIVE_INFINITY, -1.0, -0.0, +0.0, 1.0, Double.POSITIVE_INFINITY, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN)) +} \ No newline at end of file diff --git a/libraries/stdlib/js/irRuntime/collectionsHacks.kt b/libraries/stdlib/js/irRuntime/collectionsHacks.kt index 7641d3a4924..03f7a380aa9 100644 --- a/libraries/stdlib/js/irRuntime/collectionsHacks.kt +++ b/libraries/stdlib/js/irRuntime/collectionsHacks.kt @@ -5,9 +5,60 @@ package kotlin.collections +import kotlin.js.* + // Copied from libraries/stdlib/js/src/kotlin/collections/utils.kt // Current inliner doesn't rename symbols inside `js` fun @Suppress("UNUSED_PARAMETER") internal fun deleteProperty(obj: Any, property: Any) { js("delete obj[property]") } + +internal fun arrayToString(array: Array<*>) = array.joinToString(", ", "[", "]") { toString(it) } + +internal fun Array.contentDeepHashCodeInternal(): Int { + var result = 1 + for (element in this) { + val elementHash = when { + element == null -> 0 + isArrayish(element) -> (element.unsafeCast>()).contentDeepHashCodeInternal() + + element is UByteArray -> element.contentHashCode() + element is UShortArray -> element.contentHashCode() + element is UIntArray -> element.contentHashCode() + element is ULongArray -> element.contentHashCode() + + else -> element.hashCode() + } + + result = 31 * result + elementHash + } + return result +} + +internal fun T.contentEqualsInternal(other: T): Boolean { + val a = this.asDynamic() + val b = other.asDynamic() + + if (a === b) return true + + if (!isArrayish(b) || a.length != b.length) return false + + for (i in 0 until a.length) { + if (a[i] != b[i]) { + return false + } + } + return true +} + +internal fun T.contentHashCodeInternal(): Int { + val a = this.asDynamic() + var result = 1 + + for (i in 0 until a.length) { + result = result * 31 + hashCode(a[i]) + } + + return result +} \ No newline at end of file diff --git a/libraries/stdlib/js/irRuntime/generated/_ArraysJs.kt b/libraries/stdlib/js/irRuntime/generated/_ArraysJs.kt new file mode 100644 index 00000000000..2c25bae4445 --- /dev/null +++ b/libraries/stdlib/js/irRuntime/generated/_ArraysJs.kt @@ -0,0 +1,1305 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package kotlin.collections + +// +// NOTE: THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt +// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib +// + +import kotlin.js.* +import primitiveArrayConcat +import withType + +/** + * Returns a [List] that wraps the original array. + */ +public actual fun Array.asList(): List { + return ArrayList(this.unsafeCast>()) +} + +/** + * Returns a [List] that wraps the original array. + */ +@kotlin.internal.InlineOnly +public actual inline fun ByteArray.asList(): List { + return this.unsafeCast>().asList() +} + +/** + * Returns a [List] that wraps the original array. + */ +@kotlin.internal.InlineOnly +public actual inline fun ShortArray.asList(): List { + return this.unsafeCast>().asList() +} + +/** + * Returns a [List] that wraps the original array. + */ +@kotlin.internal.InlineOnly +public actual inline fun IntArray.asList(): List { + return this.unsafeCast>().asList() +} + +/** + * Returns a [List] that wraps the original array. + */ +@kotlin.internal.InlineOnly +public actual inline fun LongArray.asList(): List { + return this.unsafeCast>().asList() +} + +/** + * Returns a [List] that wraps the original array. + */ +@kotlin.internal.InlineOnly +public actual inline fun FloatArray.asList(): List { + return this.unsafeCast>().asList() +} + +/** + * Returns a [List] that wraps the original array. + */ +@kotlin.internal.InlineOnly +public actual inline fun DoubleArray.asList(): List { + return this.unsafeCast>().asList() +} + +/** + * Returns a [List] that wraps the original array. + */ +@kotlin.internal.InlineOnly +public actual inline fun BooleanArray.asList(): List { + return this.unsafeCast>().asList() +} + +/** + * Returns a [List] that wraps the original array. + */ +public actual fun CharArray.asList(): List { + return object : AbstractList(), RandomAccess { + override val size: Int get() = this@asList.size + override fun isEmpty(): Boolean = this@asList.isEmpty() + override fun contains(element: Char): Boolean = this@asList.contains(element) + override fun get(index: Int): Char = this@asList[index] + override fun indexOf(element: Char): Int = this@asList.indexOf(element) + override fun lastIndexOf(element: Char): Int = this@asList.lastIndexOf(element) + } +} + +/** + * Returns `true` if the two specified arrays are *deeply* equal to one another, + * i.e. contain the same number of the same elements in the same order. + * + * If two corresponding elements are nested arrays, they are also compared deeply. + * If any of arrays contains itself on any nesting level the behavior is undefined. + */ +@SinceKotlin("1.1") +public actual infix fun Array.contentDeepEquals(other: Array): Boolean { + return contentDeepEqualsImpl(other) +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + * Nested arrays are treated as lists too. + * + * If any of arrays contains itself on any nesting level the behavior is undefined. + */ +@SinceKotlin("1.1") +public actual fun Array.contentDeepHashCode(): Int { + return contentDeepHashCodeInternal() +} + +/** + * Returns a string representation of the contents of this array as if it is a [List]. + * Nested arrays are treated as lists too. + * + * If any of arrays contains itself on any nesting level that reference + * is rendered as `"[...]"` to prevent recursion. + * + * @sample samples.collections.Arrays.ContentOperations.contentDeepToString + */ +@SinceKotlin("1.1") +public actual fun Array.contentDeepToString(): String { + return contentDeepToStringImpl() +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun Array.contentEquals(other: Array): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun ByteArray.contentEquals(other: ByteArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun ShortArray.contentEquals(other: ShortArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun IntArray.contentEquals(other: IntArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun LongArray.contentEquals(other: LongArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun FloatArray.contentEquals(other: FloatArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun DoubleArray.contentEquals(other: DoubleArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun BooleanArray.contentEquals(other: BooleanArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns `true` if the two specified arrays are *structurally* equal to one another, + * i.e. contain the same number of the same elements in the same order. + */ +@SinceKotlin("1.1") +public actual infix fun CharArray.contentEquals(other: CharArray): Boolean { + return contentEqualsInternal(other) +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun Array.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun ByteArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun ShortArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun IntArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun LongArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun FloatArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun DoubleArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun BooleanArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a hash code based on the contents of this array as if it is [List]. + */ +@SinceKotlin("1.1") +public actual fun CharArray.contentHashCode(): Int { + return contentHashCodeInternal() +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun Array.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun ByteArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun ShortArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun IntArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun LongArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun FloatArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun DoubleArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun BooleanArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Returns a string representation of the contents of the specified array as if it is [List]. + * + * @sample samples.collections.Arrays.ContentOperations.contentToString + */ +@SinceKotlin("1.1") +public actual fun CharArray.contentToString(): String { + return arrayToString(this as Array<*>) +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun Array.copyInto(destination: Array, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): Array { + arrayCopy(this, destination, destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun ByteArray.copyInto(destination: ByteArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): ByteArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun ShortArray.copyInto(destination: ShortArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): ShortArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun IntArray.copyInto(destination: IntArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): IntArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun LongArray.copyInto(destination: LongArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): LongArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun FloatArray.copyInto(destination: FloatArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): FloatArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun DoubleArray.copyInto(destination: DoubleArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): DoubleArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun BooleanArray.copyInto(destination: BooleanArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): BooleanArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Copies this array or its subrange into the [destination] array and returns that array. + * + * It's allowed to pass the same array in the [destination] and even specify the subrange so that it overlaps with the destination range. + * + * @param destination the array to copy to. + * @param destinationOffset the position in the [destination] array to copy to, 0 by default. + * @param startIndex the beginning (inclusive) of the subrange to copy, 0 by default. + * @param endIndex the end (exclusive) of the subrange to copy, size of this array by default. + * + * @throws IndexOutOfBoundsException or [IllegalArgumentException] when [startIndex] or [endIndex] is out of range of this array indices or when `startIndex > endIndex`. + * @throws IndexOutOfBoundsException when the subrange doesn't fit into the [destination] array starting at the specified [destinationOffset], + * or when that index is out of the [destination] array indices range. + * + * @return the [destination] array. + */ +@SinceKotlin("1.3") +@kotlin.internal.InlineOnly +@Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") +public actual inline fun CharArray.copyInto(destination: CharArray, destinationOffset: Int = 0, startIndex: Int = 0, endIndex: Int = size): CharArray { + arrayCopy(this.unsafeCast>(), destination.unsafeCast>(), destinationOffset, startIndex, endIndex) + return destination +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +@Suppress("ACTUAL_WITHOUT_EXPECT", "NOTHING_TO_INLINE") +public actual inline fun Array.copyOf(): Array { + return this.asDynamic().slice() +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline fun ByteArray.copyOf(): ByteArray { + return this.asDynamic().slice() +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline fun ShortArray.copyOf(): ShortArray { + return this.asDynamic().slice() +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline fun IntArray.copyOf(): IntArray { + return this.asDynamic().slice() +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +public actual fun LongArray.copyOf(): LongArray { + return withType("LongArray", this.asDynamic().slice()) +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline fun FloatArray.copyOf(): FloatArray { + return this.asDynamic().slice() +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline fun DoubleArray.copyOf(): DoubleArray { + return this.asDynamic().slice() +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +public actual fun BooleanArray.copyOf(): BooleanArray { + return withType("BooleanArray", this.asDynamic().slice()) +} + +/** + * Returns new array which is a copy of the original array. + * + * @sample samples.collections.Arrays.CopyOfOperations.copyOf + */ +public actual fun CharArray.copyOf(): CharArray { + return withType("CharArray", this.asDynamic().slice()) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with zero values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with zero values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun ByteArray.copyOf(newSize: Int): ByteArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return fillFrom(this, ByteArray(newSize)) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with zero values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with zero values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun ShortArray.copyOf(newSize: Int): ShortArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return fillFrom(this, ShortArray(newSize)) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with zero values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with zero values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun IntArray.copyOf(newSize: Int): IntArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return fillFrom(this, IntArray(newSize)) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with zero values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with zero values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun LongArray.copyOf(newSize: Int): LongArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return withType("LongArray", arrayCopyResize(this, newSize, 0L)) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with zero values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with zero values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun FloatArray.copyOf(newSize: Int): FloatArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return fillFrom(this, FloatArray(newSize)) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with zero values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with zero values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun DoubleArray.copyOf(newSize: Int): DoubleArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return fillFrom(this, DoubleArray(newSize)) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with `false` values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with `false` values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun BooleanArray.copyOf(newSize: Int): BooleanArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return withType("BooleanArray", arrayCopyResize(this, newSize, false)) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with null char (`\u0000`) values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with null char (`\u0000`) values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf + */ +public actual fun CharArray.copyOf(newSize: Int): CharArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return withType("CharArray", fillFrom(this, CharArray(newSize))) +} + +/** + * Returns new array which is a copy of the original array, resized to the given [newSize]. + * The copy is either truncated or padded at the end with `null` values if necessary. + * + * - If [newSize] is less than the size of the original array, the copy array is truncated to the [newSize]. + * - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with `null` values. + * + * @sample samples.collections.Arrays.CopyOfOperations.resizingCopyOf + */ +@Suppress("ACTUAL_WITHOUT_EXPECT") +public actual fun Array.copyOf(newSize: Int): Array { + require(newSize >= 0) { "Invalid new array size: $newSize." } + return arrayCopyResize(this, newSize, null) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +@Suppress("ACTUAL_WITHOUT_EXPECT") +public actual fun Array.copyOfRange(fromIndex: Int, toIndex: Int): Array { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return this.asDynamic().slice(fromIndex, toIndex) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return this.asDynamic().slice(fromIndex, toIndex) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return this.asDynamic().slice(fromIndex, toIndex) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun IntArray.copyOfRange(fromIndex: Int, toIndex: Int): IntArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return this.asDynamic().slice(fromIndex, toIndex) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun LongArray.copyOfRange(fromIndex: Int, toIndex: Int): LongArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return withType("LongArray", this.asDynamic().slice(fromIndex, toIndex)) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun FloatArray.copyOfRange(fromIndex: Int, toIndex: Int): FloatArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return this.asDynamic().slice(fromIndex, toIndex) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun DoubleArray.copyOfRange(fromIndex: Int, toIndex: Int): DoubleArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return this.asDynamic().slice(fromIndex, toIndex) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun BooleanArray.copyOfRange(fromIndex: Int, toIndex: Int): BooleanArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return withType("BooleanArray", this.asDynamic().slice(fromIndex, toIndex)) +} + +/** + * Returns a new array which is a copy of the specified range of the original array. + * + * @param fromIndex the start of the range (inclusive), must be in `0..array.size` + * @param toIndex the end of the range (exclusive), must be in `fromIndex..array.size` + */ +public actual fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray { + AbstractList.checkRangeIndexes(fromIndex, toIndex, size) + return withType("CharArray", this.asDynamic().slice(fromIndex, toIndex)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("ACTUAL_WITHOUT_EXPECT", "NOTHING_TO_INLINE") +public actual inline operator fun Array.plus(element: T): Array { + return this.asDynamic().concat(arrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun ByteArray.plus(element: Byte): ByteArray { + return plus(byteArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun ShortArray.plus(element: Short): ShortArray { + return plus(shortArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun IntArray.plus(element: Int): IntArray { + return plus(intArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun LongArray.plus(element: Long): LongArray { + return plus(longArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun FloatArray.plus(element: Float): FloatArray { + return plus(floatArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun DoubleArray.plus(element: Double): DoubleArray { + return plus(doubleArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun BooleanArray.plus(element: Boolean): BooleanArray { + return plus(booleanArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun CharArray.plus(element: Char): CharArray { + return plus(charArrayOf(element)) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +@Suppress("ACTUAL_WITHOUT_EXPECT") +public actual operator fun Array.plus(elements: Collection): Array { + return arrayPlusCollection(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun ByteArray.plus(elements: Collection): ByteArray { + return fillFromCollection(this.copyOf(size + elements.size), this.size, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun ShortArray.plus(elements: Collection): ShortArray { + return fillFromCollection(this.copyOf(size + elements.size), this.size, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun IntArray.plus(elements: Collection): IntArray { + return fillFromCollection(this.copyOf(size + elements.size), this.size, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun LongArray.plus(elements: Collection): LongArray { + return arrayPlusCollection(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun FloatArray.plus(elements: Collection): FloatArray { + return fillFromCollection(this.copyOf(size + elements.size), this.size, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun DoubleArray.plus(elements: Collection): DoubleArray { + return fillFromCollection(this.copyOf(size + elements.size), this.size, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun BooleanArray.plus(elements: Collection): BooleanArray { + return arrayPlusCollection(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] collection. + */ +public actual operator fun CharArray.plus(elements: Collection): CharArray { + return fillFromCollection(this.copyOf(size + elements.size), this.size, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("ACTUAL_WITHOUT_EXPECT", "NOTHING_TO_INLINE") +public actual inline operator fun Array.plus(elements: Array): Array { + return this.asDynamic().concat(elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun ByteArray.plus(elements: ByteArray): ByteArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun ShortArray.plus(elements: ShortArray): ShortArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun IntArray.plus(elements: IntArray): IntArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun LongArray.plus(elements: LongArray): LongArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun FloatArray.plus(elements: FloatArray): FloatArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun DoubleArray.plus(elements: DoubleArray): DoubleArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun BooleanArray.plus(elements: BooleanArray): BooleanArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then all elements of the given [elements] array. + */ +@Suppress("NOTHING_TO_INLINE") +public actual inline operator fun CharArray.plus(elements: CharArray): CharArray { + return primitiveArrayConcat(this, elements) +} + +/** + * Returns an array containing all elements of the original array and then the given [element]. + */ +@Suppress("ACTUAL_WITHOUT_EXPECT", "NOTHING_TO_INLINE") +public actual inline fun Array.plusElement(element: T): Array { + return this.asDynamic().concat(arrayOf(element)) +} + +/** + * Sorts the array in-place. + */ +public actual fun IntArray.sort(): Unit { + this.asDynamic().sort() +} + +/** + * Sorts the array in-place. + */ +public actual fun LongArray.sort(): Unit { + if (size > 1) + sort { a: Long, b: Long -> a.compareTo(b) } +} + +/** + * Sorts the array in-place. + */ +public actual fun ByteArray.sort(): Unit { + this.asDynamic().sort() +} + +/** + * Sorts the array in-place. + */ +public actual fun ShortArray.sort(): Unit { + this.asDynamic().sort() +} + +/** + * Sorts the array in-place. + */ +public actual fun DoubleArray.sort(): Unit { + this.asDynamic().sort() +} + +/** + * Sorts the array in-place. + */ +public actual fun FloatArray.sort(): Unit { + this.asDynamic().sort() +} + +/** + * Sorts the array in-place. + */ +public actual fun CharArray.sort(): Unit { + this.asDynamic().sort() +} + +/** + * Sorts the array in-place according to the natural order of its elements. + */ +public actual fun > Array.sort(): Unit { + if (size > 1) + sort { a: T, b: T -> a.compareTo(b) } +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun Array.sort(noinline comparison: (a: T, b: T) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun ByteArray.sort(noinline comparison: (a: Byte, b: Byte) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun ShortArray.sort(noinline comparison: (a: Short, b: Short) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun IntArray.sort(noinline comparison: (a: Int, b: Int) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun LongArray.sort(noinline comparison: (a: Long, b: Long) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun FloatArray.sort(noinline comparison: (a: Float, b: Float) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun DoubleArray.sort(noinline comparison: (a: Double, b: Double) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparison] function. + */ +@kotlin.internal.InlineOnly +public inline fun CharArray.sort(noinline comparison: (a: Char, b: Char) -> Int): Unit { + asDynamic().sort(comparison) +} + +/** + * Sorts the array in-place according to the order specified by the given [comparator]. + */ +public actual fun Array.sortWith(comparator: Comparator): Unit { + if (size > 1) + sort { a, b -> comparator.compare(a, b) } +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun ByteArray.toTypedArray(): Array { + return js("[]").slice.call(this) +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun ShortArray.toTypedArray(): Array { + return js("[]").slice.call(this) +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun IntArray.toTypedArray(): Array { + return js("[]").slice.call(this) +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun LongArray.toTypedArray(): Array { + return copyOf().unsafeCast>() +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun FloatArray.toTypedArray(): Array { + return js("[]").slice.call(this) +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun DoubleArray.toTypedArray(): Array { + return js("[]").slice.call(this) +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun BooleanArray.toTypedArray(): Array { + return copyOf().unsafeCast>() +} + +/** + * Returns a *typed* object array containing all of the elements of this primitive array. + */ +public actual fun CharArray.toTypedArray(): Array { + return Array(size) { index -> this[index] } +} + diff --git a/libraries/stdlib/js/irRuntime/generated/_CollectionsJs.kt b/libraries/stdlib/js/irRuntime/generated/_CollectionsJs.kt new file mode 100644 index 00000000000..b6aaf2b983f --- /dev/null +++ b/libraries/stdlib/js/irRuntime/generated/_CollectionsJs.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package kotlin.collections + +// +// NOTE: THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt +// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib +// + +import kotlin.js.* + +/** + * Reverses elements in the list in-place. + */ +public actual fun MutableList.reverse(): Unit { + val midPoint = (size / 2) - 1 + if (midPoint < 0) return + var reverseIndex = lastIndex + for (index in 0..midPoint) { + val tmp = this[index] + this[index] = this[reverseIndex] + this[reverseIndex] = tmp + reverseIndex-- + } +} + diff --git a/libraries/stdlib/js/irRuntime/generated/_ComparisonsJs.kt b/libraries/stdlib/js/irRuntime/generated/_ComparisonsJs.kt new file mode 100644 index 00000000000..4536883bd48 --- /dev/null +++ b/libraries/stdlib/js/irRuntime/generated/_ComparisonsJs.kt @@ -0,0 +1,284 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package kotlin.comparisons + +// +// NOTE: THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt +// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib +// + +import kotlin.js.* + +/** + * Returns the greater of two values. + * If values are equal, returns the first one. + */ +@SinceKotlin("1.1") +public actual fun > maxOf(a: T, b: T): T { + return if (a >= b) a else b +} + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Byte, b: Byte): Byte { + return Math.max(a.toInt(), b.toInt()).unsafeCast() +} + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Short, b: Short): Short { + return Math.max(a.toInt(), b.toInt()).unsafeCast() +} + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Int, b: Int): Int { + return Math.max(a, b) +} + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.1") +@Suppress("DEPRECATION_ERROR", "NOTHING_TO_INLINE") +public actual inline fun maxOf(a: Long, b: Long): Long { + return if (a >= b) a else b +} + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Float, b: Float): Float { + return Math.max(a, b) +} + +/** + * Returns the greater of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Double, b: Double): Double { + return Math.max(a, b) +} + +/** + * Returns the greater of three values. + */ +@SinceKotlin("1.1") +public actual fun > maxOf(a: T, b: T, c: T): T { + return maxOf(a, maxOf(b, c)) +} + +/** + * Returns the greater of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Byte, b: Byte, c: Byte): Byte { + return Math.max(a.toInt(), b.toInt(), c.toInt()).unsafeCast() +} + +/** + * Returns the greater of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Short, b: Short, c: Short): Short { + return Math.max(a.toInt(), b.toInt(), c.toInt()).unsafeCast() +} + +/** + * Returns the greater of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Int, b: Int, c: Int): Int { + return Math.max(a, b, c) +} + +/** + * Returns the greater of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +public actual inline fun maxOf(a: Long, b: Long, c: Long): Long { + return maxOf(a, maxOf(b, c)) +} + +/** + * Returns the greater of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Float, b: Float, c: Float): Float { + return Math.max(a, b, c) +} + +/** + * Returns the greater of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun maxOf(a: Double, b: Double, c: Double): Double { + return Math.max(a, b, c) +} + +/** + * Returns the smaller of two values. + * If values are equal, returns the first one. + */ +@SinceKotlin("1.1") +public actual fun > minOf(a: T, b: T): T { + return if (a <= b) a else b +} + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Byte, b: Byte): Byte { + return Math.min(a.toInt(), b.toInt()).unsafeCast() +} + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Short, b: Short): Short { + return Math.min(a.toInt(), b.toInt()).unsafeCast() +} + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Int, b: Int): Int { + return Math.min(a, b) +} + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.1") +@Suppress("DEPRECATION_ERROR", "NOTHING_TO_INLINE") +public actual inline fun minOf(a: Long, b: Long): Long { + return if (a <= b) a else b +} + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Float, b: Float): Float { + return Math.min(a, b) +} + +/** + * Returns the smaller of two values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Double, b: Double): Double { + return Math.min(a, b) +} + +/** + * Returns the smaller of three values. + */ +@SinceKotlin("1.1") +public actual fun > minOf(a: T, b: T, c: T): T { + return minOf(a, minOf(b, c)) +} + +/** + * Returns the smaller of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Byte, b: Byte, c: Byte): Byte { + return Math.min(a.toInt(), b.toInt(), c.toInt()).unsafeCast() +} + +/** + * Returns the smaller of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Short, b: Short, c: Short): Short { + return Math.min(a.toInt(), b.toInt(), c.toInt()).unsafeCast() +} + +/** + * Returns the smaller of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Int, b: Int, c: Int): Int { + return Math.min(a, b, c) +} + +/** + * Returns the smaller of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +public actual inline fun minOf(a: Long, b: Long, c: Long): Long { + return minOf(a, minOf(b, c)) +} + +/** + * Returns the smaller of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Float, b: Float, c: Float): Float { + return Math.min(a, b, c) +} + +/** + * Returns the smaller of three values. + */ +@SinceKotlin("1.1") +@kotlin.internal.InlineOnly +@Suppress("DEPRECATION_ERROR") +public actual inline fun minOf(a: Double, b: Double, c: Double): Double { + return Math.min(a, b, c) +} + diff --git a/libraries/stdlib/js/irRuntime/typeCheckUtils.kt b/libraries/stdlib/js/irRuntime/typeCheckUtils.kt index 88130ce41f1..8f56d0187ec 100644 --- a/libraries/stdlib/js/irRuntime/typeCheckUtils.kt +++ b/libraries/stdlib/js/irRuntime/typeCheckUtils.kt @@ -103,14 +103,14 @@ public fun isChar(c: Any): Boolean { } // TODO: Distinguish Boolean/Byte and Short/Char -public fun isBooleanArray(a: dynamic): Boolean = isArray(a) && a.asDynamic().`$type$` == "BooleanArray" +public fun isBooleanArray(a: dynamic): Boolean = isArray(a) && a.`$type$` == "BooleanArray" public fun isByteArray(a: dynamic): Boolean = js("a instanceof Int8Array").unsafeCast() public fun isShortArray(a: dynamic): Boolean = js("a instanceof Int16Array").unsafeCast() -public fun isCharArray(a: dynamic): Boolean = isArray(a) && a.asDynamic().`$type$` == "CharArray" +public fun isCharArray(a: dynamic): Boolean = isArray(a) && a.`$type$` == "CharArray" public fun isIntArray(a: dynamic): Boolean = js("a instanceof Int32Array").unsafeCast() public fun isFloatArray(a: dynamic): Boolean = js("a instanceof Float32Array").unsafeCast() public fun isDoubleArray(a: dynamic): Boolean = js("a instanceof Float64Array").unsafeCast() -public fun isLongArray(a: dynamic): Boolean = isArray(a) && a.asDynamic().`$type$` == "LongArray" +public fun isLongArray(a: dynamic): Boolean = isArray(a) && a.`$type$` == "LongArray" internal fun jsIn(x: String, y: dynamic): Boolean = js("x in y") diff --git a/libraries/stdlib/js/src/js/polyfills.js b/libraries/stdlib/js/src/js/polyfills.js index da1765ea686..364345f33e1 100644 --- a/libraries/stdlib/js/src/js/polyfills.js +++ b/libraries/stdlib/js/src/js/polyfills.js @@ -288,12 +288,27 @@ if (typeof ArrayBuffer.isView === "undefined") { } // Patch sort to work with TypedArrays if needed. + // TODO: consider to remove following function and replace it with `Kotlin.doubleCompareTo` (see misc.js) + var totalOrderComparator = function (a, b) { + if (a < b) return -1; + if (a > b) return 1; + + if (a === b) { + if (a !== 0) return 0; + + var ia = 1 / a; + return ia === 1 / b ? 0 : (ia < 0 ? -1 : 1); + } + + return a !== a ? (b !== b ? 0 : 1) : -1 + }; + for (var i = 0; i < arrays.length; ++i) { var TypedArray = arrays[i]; if (typeof TypedArray.prototype.sort === "undefined") { Object.defineProperty(TypedArray.prototype, 'sort', { value: function(compareFunction) { - return Array.prototype.sort.call(this, compareFunction); + return Array.prototype.sort.call(this, compareFunction || totalOrderComparator); } }); } diff --git a/libraries/stdlib/js/src/kotlin/collections.kt b/libraries/stdlib/js/src/kotlin/collections.kt index 80ed17f84de..a54948cec2f 100644 --- a/libraries/stdlib/js/src/kotlin/collections.kt +++ b/libraries/stdlib/js/src/kotlin/collections.kt @@ -6,7 +6,6 @@ package kotlin.collections import kotlin.comparisons.naturalOrder -import kotlin.internal.InlineOnly import kotlin.random.Random /** Returns the array if it's not `null`, or an empty array otherwise. */ @@ -50,10 +49,6 @@ internal actual fun copyToArrayImpl(collection: Collection<*>, array: Array< return array } -@library("arrayToString") -@Suppress("UNUSED_PARAMETER") -internal fun arrayToString(array: Array<*>): String = definedExternally - /** * Returns an immutable list containing only the specified object [element]. */ diff --git a/libraries/stdlib/js/src/kotlin/collectionsExternal.kt b/libraries/stdlib/js/src/kotlin/collectionsExternal.kt new file mode 100644 index 00000000000..eb51e6c5dff --- /dev/null +++ b/libraries/stdlib/js/src/kotlin/collectionsExternal.kt @@ -0,0 +1,10 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package kotlin.collections + +@library("arrayToString") +@Suppress("UNUSED_PARAMETER") +internal fun arrayToString(array: Array<*>): String = definedExternally \ No newline at end of file diff --git a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt index 0f1b5a4b0c2..28e67f1928c 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/generators/GenerateStandardLib.kt @@ -46,14 +46,16 @@ fun main(args: Array) { val commonDir = baseDir.resolveExistingDir("libraries/stdlib/common/src/generated") val jvmDir = baseDir.resolveExistingDir("libraries/stdlib/jvm/src/generated") val jsDir = baseDir.resolveExistingDir("libraries/stdlib/js/src/generated") + val jsIrDir = baseDir.resolveExistingDir("libraries/stdlib/js/irRuntime/generated") - templateGroups.groupByFileAndWrite { (platform, source) -> + templateGroups.groupByFileAndWrite { (target, source) -> // File("build/out/$platform/$source.kt") - when (platform) { - Platform.Common -> commonDir.resolve("_${source.name.capitalize()}.kt") - Platform.JVM -> jvmDir.resolve("_${source.name.capitalize()}Jvm.kt") - Platform.JS -> jsDir.resolve("_${source.name.capitalize()}Js.kt") - Platform.Native -> error("Native is unsupported yet") + when (target) { + KotlinTarget.Common -> commonDir.resolve("_${source.name.capitalize()}.kt") + KotlinTarget.JVM -> jvmDir.resolve("_${source.name.capitalize()}Jvm.kt") + KotlinTarget.JS -> jsDir.resolve("_${source.name.capitalize()}Js.kt") + KotlinTarget.JS_IR -> jsIrDir.resolve("_${source.name.capitalize()}Js.kt") + KotlinTarget.Native -> error("Native is unsupported yet") } } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt index 72541471a0b..bcb9555c96a 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt @@ -83,8 +83,14 @@ object ArrayOps : TemplateGroupBase() { } on(Platform.JS) { - annotation("""@library("arrayEquals")""") - body { "definedExternally" } + on(Backend.Legacy) { + annotation("""@library("arrayEquals")""") + body { "definedExternally" } + } + + on(Backend.IR) { + body { "return contentEqualsInternal(other)" } + } } } @@ -116,8 +122,14 @@ object ArrayOps : TemplateGroupBase() { } } on(Platform.JS) { - annotation("""@library("arrayDeepEquals")""") - body { "definedExternally" } + on(Backend.Legacy) { + annotation("""@library("arrayDeepEquals")""") + body { "definedExternally" } + } + + on(Backend.IR) { + body { "return contentDeepEqualsImpl(other)" } + } } } @@ -141,8 +153,13 @@ object ArrayOps : TemplateGroupBase() { body { "return java.util.Arrays.toString(this)" } } on(Platform.JS) { - annotation("""@library("arrayToString")""") - body { "definedExternally" } + on(Backend.Legacy) { + annotation("""@library("arrayToString")""") + body { "definedExternally" } + } + on(Backend.IR) { + body { "return arrayToString(this as Array<*>)" } + } } } @@ -174,8 +191,13 @@ object ArrayOps : TemplateGroupBase() { } } on(Platform.JS) { - annotation("""@library("arrayDeepToString")""") - body { "definedExternally" } + on(Backend.Legacy) { + annotation("""@library("arrayDeepToString")""") + body { "definedExternally" } + } + on(Backend.IR) { + body { "return contentDeepToStringImpl()" } + } } } @@ -196,8 +218,13 @@ object ArrayOps : TemplateGroupBase() { body { "return java.util.Arrays.hashCode(this)" } } on(Platform.JS) { - annotation("""@library("arrayHashCode")""") - body { "definedExternally" } + on(Backend.Legacy) { + annotation("""@library("arrayHashCode")""") + body { "definedExternally" } + } + on(Backend.IR) { + body { "return contentHashCodeInternal()" } + } } } @@ -227,8 +254,13 @@ object ArrayOps : TemplateGroupBase() { } } on(Platform.JS) { - annotation("""@library("arrayDeepHashCode")""") - body { "definedExternally" } + on(Backend.Legacy) { + annotation("""@library("arrayDeepHashCode")""") + body { "definedExternally" } + } + on(Backend.IR) { + body { "return contentDeepHashCodeInternal()" } + } } } @@ -756,8 +788,13 @@ object ArrayOps : TemplateGroupBase() { } specialFor(ArraysOfPrimitives) { if (primitive != PrimitiveType.Long) { - annotation("""@library("primitiveArraySort")""") - body { "definedExternally" } + on(Backend.Legacy) { + annotation("""@library("primitiveArraySort")""") + body { "definedExternally" } + } + on(Backend.IR) { + body { "this.asDynamic().sort()" } + } } } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt index 014f70e16e2..4afd8048e89 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt @@ -86,12 +86,26 @@ enum class Platform { Common, JVM, JS, - Native; + Native +} + +enum class Backend { + Any, + Legacy, + IR +} + +enum class KotlinTarget(val platform: Platform, val backend: Backend) { + Common(Platform.Common, Backend.Any), + JVM(Platform.JVM, Backend.Any), + JS(Platform.JS, Backend.Legacy), + JS_IR(Platform.JS, Backend.IR), + Native(Platform.Native, Backend.IR); val fullName get() = "Kotlin/$name" companion object { - val values = values().toList() + val values = KotlinTarget.values().toList() } } diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt index c301abc612d..53da9208aeb 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt @@ -25,7 +25,7 @@ private fun getDefaultSourceFile(f: Family): SourceFile = when (f) { @TemplateDsl class MemberBuilder( val allowedPlatforms: Set, - val platform: Platform, + val target: KotlinTarget, var family: Family, var sourceFile: SourceFile = getDefaultSourceFile(family), var primitive: PrimitiveType? = null @@ -143,13 +143,18 @@ class MemberBuilder( fun on(platform: Platform, action: () -> Unit) { require(platform in allowedPlatforms) { "Platform $platform is not in the list of allowed platforms $allowedPlatforms" } - if (this.platform == platform) + if (target.platform == platform) action() else { hasPlatformSpecializations = true } } + fun on(backend: Backend, action: () -> Unit) { + require(target.platform == Platform.JS) + if (target.backend == backend) action() + } + fun specialFor(f: Family, action: () -> Unit) { if (family == f) action() @@ -165,14 +170,14 @@ class MemberBuilder( val headerOnly: Boolean val isImpl: Boolean if (!legacyMode) { - headerOnly = platform == Platform.Common && hasPlatformSpecializations - isImpl = platform != Platform.Common && Platform.Common in allowedPlatforms + headerOnly = target.platform == Platform.Common && hasPlatformSpecializations + isImpl = target.platform != Platform.Common && Platform.Common in allowedPlatforms } else { // legacy mode when all is headerOnly + no_impl // except functions with optional parameters - they are common + no_impl val hasOptionalParams = signature.contains("=") - headerOnly = platform == Platform.Common && !hasOptionalParams + headerOnly = target.platform == Platform.Common && !hasOptionalParams isImpl = false } @@ -376,7 +381,7 @@ class MemberBuilder( val body = (body ?: deprecate?.replaceWith?.let { "return $it" } ?: - throw RuntimeException("$signature for ${platform.fullName}: no body specified for ${family to primitive}") + throw RuntimeException("$signature for ${target.fullName}: no body specified for ${family to primitive}") ).trim('\n') val indent: Int = body.takeWhile { it == ' ' }.length diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt index 1b91de826a2..deb9094b2ba 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt @@ -53,7 +53,7 @@ interface MemberTemplate { /** Specifies which platforms this member template should be generated for */ fun platforms(vararg platforms: Platform) - fun instantiate(platforms: List = Platform.values): Sequence + fun instantiate(targets: List = KotlinTarget.values): Sequence /** Registers parameterless member builder function */ fun builder(b: MemberBuildAction) @@ -78,9 +78,9 @@ abstract class MemberTemplateDefinition : MemberTemplate { private val buildActions = mutableListOf() - private var targetPlatforms = setOf(*Platform.values()) + private var allowedPlatforms = setOf(*Platform.values()) override fun platforms(vararg platforms: Platform) { - targetPlatforms = setOf(*platforms) + allowedPlatforms = setOf(*platforms) } @@ -105,23 +105,24 @@ abstract class MemberTemplateDefinition : MemberTemplate { } ?: this - override fun instantiate(platforms: List): Sequence { - val resultingPlatforms = platforms.intersect(targetPlatforms) - val specificPlatforms by lazy { resultingPlatforms - Platform.Common } + override fun instantiate(targets: List): Sequence { + val resultingTargets = targets.filter { it.platform in allowedPlatforms } + val resultingPlatforms = resultingTargets.map { it.platform }.distinct() + val specificTargets by lazy { resultingTargets - KotlinTarget.Common } fun platformMemberBuilders(family: Family, p: TParam) = - if (Platform.Common in targetPlatforms) { - val commonMemberBuilder = createMemberBuilder(Platform.Common, family, p) + if (Platform.Common in allowedPlatforms) { + val commonMemberBuilder = createMemberBuilder(KotlinTarget.Common, family, p) mutableListOf().also { builders -> if (Platform.Common in resultingPlatforms) builders.add(commonMemberBuilder) if (commonMemberBuilder.hasPlatformSpecializations) { - specificPlatforms.mapTo(builders) { + specificTargets.mapTo(builders) { createMemberBuilder(it, family, p) } } } } else { - resultingPlatforms.map { createMemberBuilder(it, family, p) } + resultingTargets.map { createMemberBuilder(it, family, p) } } return parametrize() @@ -130,8 +131,8 @@ abstract class MemberTemplateDefinition : MemberTemplate { .flatten() } - private fun createMemberBuilder(platform: Platform, family: Family, p: TParam): MemberBuilder { - return MemberBuilder(targetPlatforms, platform, family).also { builder -> + private fun createMemberBuilder(target: KotlinTarget, family: Family, p: TParam): MemberBuilder { + return MemberBuilder(allowedPlatforms, target, family).also { builder -> for (action in buildActions) { when (action) { is BuildAction.Generic -> action(builder) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt index 614c9045fdd..35f43e7ed61 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt @@ -29,37 +29,37 @@ fun readCopyrightNoticeFromProfile(copyrightProfile: File): String { } -data class PlatformSourceFile( - val platform: Platform, - val sourceFile: SourceFile +data class TargetedSourceFile( + val target: KotlinTarget, + val sourceFile: SourceFile ) -private val platformsToGenerate = Platform.values - Platform.Native +private val targetsToGenerate = KotlinTarget.values - KotlinTarget.Native @JvmName("groupByFileAndWriteGroups") fun Sequence.groupByFileAndWrite( - fileNameBuilder: (PlatformSourceFile) -> File + fileNameBuilder: (TargetedSourceFile) -> File ) { flatMap { group -> group.invoke() - .flatMap { it.instantiate(platformsToGenerate) } + .flatMap { it.instantiate(targetsToGenerate) } .sortedBy { it.sortingSignature } }.groupByFileAndWrite(fileNameBuilder) } @JvmName("groupByFileAndWriteTemplates") fun Sequence.groupByFileAndWrite( - fileNameBuilder: (PlatformSourceFile) -> File + fileNameBuilder: (TargetedSourceFile) -> File ) { - flatMap { it.instantiate(platformsToGenerate) } + flatMap { it.instantiate(targetsToGenerate) } .groupByFileAndWrite(fileNameBuilder) } @JvmName("groupByFileAndWriteMembers") fun Sequence.groupByFileAndWrite( - fileNameBuilder: (PlatformSourceFile) -> File + fileNameBuilder: (TargetedSourceFile) -> File ) { - val groupedMembers = groupBy { PlatformSourceFile(it.platform, it.sourceFile) } + val groupedMembers = groupBy { TargetedSourceFile(it.target, it.sourceFile) } for ((psf, members) in groupedMembers) { val file = fileNameBuilder(psf) @@ -67,14 +67,14 @@ fun Sequence.groupByFileAndWrite( } } -fun List.writeTo(file: File, platformSource: PlatformSourceFile) { - val (platform, sourceFile) = platformSource +fun List.writeTo(file: File, targetedSource: TargetedSourceFile) { + val (target, sourceFile) = targetedSource println("Generating file: $file") file.parentFile.mkdirs() FileWriter(file).use { writer -> writer.appendln(COPYRIGHT_NOTICE) - when (platform) { + when (target.platform) { Platform.Common, Platform.JVM -> { if (sourceFile.multifile) { writer.appendln("@file:kotlin.jvm.JvmMultifileClass") @@ -87,14 +87,14 @@ fun List.writeTo(file: File, platformSource: PlatformSourceFile) writer.append("package ${sourceFile.packageName ?: "kotlin"}\n\n") writer.append("${COMMON_AUTOGENERATED_WARNING}\n\n") - if (platform == Platform.JS) { + if (target.platform == Platform.JS) { writer.appendln("import kotlin.js.*") if (sourceFile == SourceFile.Arrays) { writer.appendln("import primitiveArrayConcat") writer.appendln("import withType") } } - if (platform == Platform.Common) { + if (target.platform == Platform.Common) { writer.appendln("import kotlin.random.*") }