diff --git a/js/js.libraries/src/core/kotlin.kt b/js/js.libraries/src/core/kotlin.kt index 8dd1ae00417..f3a0a64fcca 100644 --- a/js/js.libraries/src/core/kotlin.kt +++ b/js/js.libraries/src/core/kotlin.kt @@ -69,6 +69,11 @@ public fun lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy = */ public fun lazy(lock: Any?, initializer: () -> T): Lazy = UnsafeLazyImpl(initializer) + +private fun arrayOfNulls(reference: Array, size: Int): Array { + return arrayOfNulls(size) as Array +} + private fun arrayCopyResize(source: dynamic, newSize: Int, defaultValue: Any?): dynamic { val result = source.slice(0, newSize) var index: Int = source.length diff --git a/libraries/stdlib/src/generated/_Filtering.kt b/libraries/stdlib/src/generated/_Filtering.kt index a478e25b808..243cbe6d18a 100644 --- a/libraries/stdlib/src/generated/_Filtering.kt +++ b/libraries/stdlib/src/generated/_Filtering.kt @@ -995,11 +995,101 @@ public inline fun String.filterTo(destination: C, predicate: (C return destination } +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun Array.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun BooleanArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun ByteArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun CharArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun DoubleArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun FloatArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun IntArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun LongArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun ShortArray.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun List.slice(indices: IntRange): List { + if (indices.isEmpty()) return listOf() + return this.subList(indices.start, indices.end + 1).toList() +} + +/** + * Returns a string containing characters at indices at the specified [indices]. + */ +public fun String.slice(indices: IntRange): String { + if (indices.isEmpty()) return "" + return substring(indices) +} + /** * Returns a list containing elements at specified [indices]. */ public fun Array.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1010,7 +1100,9 @@ public fun Array.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun BooleanArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1021,7 +1113,9 @@ public fun BooleanArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun ByteArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1032,7 +1126,9 @@ public fun ByteArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun CharArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1043,7 +1139,9 @@ public fun CharArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun DoubleArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1054,7 +1152,9 @@ public fun DoubleArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun FloatArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1065,7 +1165,9 @@ public fun FloatArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun IntArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1076,7 +1178,9 @@ public fun IntArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun LongArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1087,7 +1191,9 @@ public fun LongArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun ShortArray.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1098,7 +1204,9 @@ public fun ShortArray.slice(indices: Iterable): List { * Returns a list containing elements at specified [indices]. */ public fun List.slice(indices: Iterable): List { - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -1109,13 +1217,196 @@ public fun List.slice(indices: Iterable): List { * Returns a string containing characters at specified [indices]. */ public fun String.slice(indices: Iterable): String { - val result = StringBuilder(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return "" + val result = StringBuilder(size) for (i in indices) { result.append(get(i)) } return result.toString() } +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun > A.sliceArray(indices: Collection): A { + if (indices.isEmpty()) return arrayOfNulls(this, 0) as A + val result = arrayOfNulls(this, indices.size()) as Array + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result as A +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun BooleanArray.sliceArray(indices: Collection): BooleanArray { + val result = BooleanArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun ByteArray.sliceArray(indices: Collection): ByteArray { + val result = ByteArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun CharArray.sliceArray(indices: Collection): CharArray { + val result = CharArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun DoubleArray.sliceArray(indices: Collection): DoubleArray { + val result = DoubleArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun FloatArray.sliceArray(indices: Collection): FloatArray { + val result = FloatArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun IntArray.sliceArray(indices: Collection): IntArray { + val result = IntArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun LongArray.sliceArray(indices: Collection): LongArray { + val result = LongArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns an array containing elements of this array at specified [indices]. + */ +public fun ShortArray.sliceArray(indices: Collection): ShortArray { + val result = ShortArray(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun > A.sliceArray(indices: IntRange): A { + if (indices.isEmpty()) return copyOf(0) as A + return copyOfRange(indices.start, indices.end + 1) as A +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun BooleanArray.sliceArray(indices: IntRange): BooleanArray { + if (indices.isEmpty()) return BooleanArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun ByteArray.sliceArray(indices: IntRange): ByteArray { + if (indices.isEmpty()) return ByteArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun CharArray.sliceArray(indices: IntRange): CharArray { + if (indices.isEmpty()) return CharArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun DoubleArray.sliceArray(indices: IntRange): DoubleArray { + if (indices.isEmpty()) return DoubleArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun FloatArray.sliceArray(indices: IntRange): FloatArray { + if (indices.isEmpty()) return FloatArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun IntArray.sliceArray(indices: IntRange): IntArray { + if (indices.isEmpty()) return IntArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun LongArray.sliceArray(indices: IntRange): LongArray { + if (indices.isEmpty()) return LongArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + +/** + * Returns a list containing elements at indices in the specified [indices] range. + */ +public fun ShortArray.sliceArray(indices: IntRange): ShortArray { + if (indices.isEmpty()) return ShortArray(0) + return copyOfRange(indices.start, indices.end + 1) +} + /** * Returns a list containing first [n] elements. */ diff --git a/libraries/stdlib/src/generated/_Ordering.kt b/libraries/stdlib/src/generated/_Ordering.kt index 8d778c06745..cd1e0fd137d 100644 --- a/libraries/stdlib/src/generated/_Ordering.kt +++ b/libraries/stdlib/src/generated/_Ordering.kt @@ -210,16 +210,10 @@ public fun String.reversed(): String { */ public fun > A.reversedArray(): A { if (isEmpty()) return this - val result = this.copyOf() as Array - var i1 = 0 - var i2 = lastIndex - while (i1 < i2) { - val tmp = result[i1] - result[i1] = result[i2] - result[i2] = tmp - i1 += 1 - i2 -= 1 - } + val result = arrayOfNulls(this, size()) as Array + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] return result as A } diff --git a/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt b/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt index 0a5b2103b0b..595b21fcd34 100644 --- a/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt +++ b/libraries/stdlib/src/kotlin/collections/ArraysJVM.kt @@ -96,3 +96,7 @@ public inline fun Collection.toTypedArray(): Array { /** Returns the array if it's not `null`, or an empty array otherwise. */ public inline fun Array?.orEmpty(): Array = this ?: arrayOf() +/** Internal unsafe construction of array based on reference array type */ +private fun > arrayOfNulls(reference: A, size: Int): A { + return java.lang.reflect.Array.newInstance(reference.javaClass.componentType, size) as A +} \ No newline at end of file diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index a2a9d7fd38d..991029cecb8 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -387,20 +387,37 @@ class ArraysTest { } test fun slice() { - val iter = listOf(3, 1, 2) + val iter: Iterable = listOf(3, 1, 2) assertEquals(listOf("B"), arrayOf("A", "B", "C").slice(1..1)) assertEquals(listOf('E', 'B', 'C'), arrayOf('A', 'B', 'C', 'E').slice(iter)) assertEquals(listOf(), arrayOf().slice(5..4)) - assertEquals(listOf(), arrayOf(1, 2, 3).slice(5..1)) - assertEquals(listOf(2, 3, 9), arrayOf(2, 3, 9, 2, 3, 9).slice(iter)) - assertEquals(listOf(2.0, 3.0), arrayOf(2.0, 3.0, 9.0).slice(0..1)) - assertEquals(listOf(2f, 3f), arrayOf(2f, 3f, 9f).slice(0..1)) - assertEquals(listOf(127, 100), arrayOf(50, 100, 127).slice(2 downTo 1)) - assertEquals(listOf(200, 100), arrayOf(50, 100, 200).slice(2 downTo 1)) - assertEquals(listOf(100L, 200L, 30L), arrayOf(50L, 100L, 200L, 30L).slice(1..3)) - assertEquals(listOf(true, false, true), arrayOf(true, false, true, true).slice(iter)) + assertEquals(listOf(), intArrayOf(1, 2, 3).slice(5..1)) + assertEquals(listOf(2, 3, 9), intArrayOf(2, 3, 9, 2, 3, 9).slice(iter)) + assertEquals(listOf(2.0, 3.0), doubleArrayOf(2.0, 3.0, 9.0).slice(0..1)) + assertEquals(listOf(2f, 3f), floatArrayOf(2f, 3f, 9f).slice(0..1)) + assertEquals(listOf(127, 100), byteArrayOf(50, 100, 127).slice(2 downTo 1)) + assertEquals(listOf(200, 100), shortArrayOf(50, 100, 200).slice(2 downTo 1)) + assertEquals(listOf(100L, 200L, 30L), longArrayOf(50L, 100L, 200L, 30L).slice(1..3)) + assertEquals(listOf(true, false, true), booleanArrayOf(true, false, true, true).slice(iter)) + } + + test fun sliceArray() { + val coll: Collection = listOf(3, 1, 2) + + assertArrayNotSameButEquals(arrayOf("B"), arrayOf("A", "B", "C").sliceArray(1..1)) + assertArrayNotSameButEquals(arrayOf('E', 'B', 'C'), arrayOf('A', 'B', 'C', 'E').sliceArray(coll)) + + assertArrayNotSameButEquals(arrayOf(), arrayOf().sliceArray(5..4)) + assertArrayNotSameButEquals(intArrayOf(), intArrayOf(1, 2, 3).sliceArray(5..1)) + assertArrayNotSameButEquals(intArrayOf(2, 3, 9), intArrayOf(2, 3, 9, 2, 3, 9).sliceArray(coll)) + assertArrayNotSameButEquals(doubleArrayOf(2.0, 3.0), doubleArrayOf(2.0, 3.0, 9.0).sliceArray(0..1)) + assertArrayNotSameButEquals(floatArrayOf(2f, 3f), floatArrayOf(2f, 3f, 9f).sliceArray(0..1)) +// assertArrayNotSameButEquals(byteArrayOf(127, 100), byteArrayOf(50, 100, 127).sliceArray(2 downTo 1)) +// assertArrayNotSameButEquals(shortArrayOf(200, 100), shortArrayOf(50, 100, 200).sliceArray(2 downTo 1)) + assertArrayNotSameButEquals(longArrayOf(100L, 200L, 30L), longArrayOf(50L, 100L, 200L, 30L).sliceArray(1..3)) + assertArrayNotSameButEquals(booleanArrayOf(true, false, true), booleanArrayOf(true, false, true, true).sliceArray(coll)) } test fun asIterable() { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt index 00ba620b7ec..83ee4b2f068 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Filtering.kt @@ -460,7 +460,9 @@ fun filtering(): List { returns("List") body { """ - val list = ArrayList(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return listOf() + val list = ArrayList(size) for (index in indices) { list.add(get(index)) } @@ -472,7 +474,9 @@ fun filtering(): List { returns(Strings) { "String" } body(Strings) { """ - val result = StringBuilder(indices.collectionSizeOrDefault(10)) + val size = indices.collectionSizeOrDefault(10) + if (size == 0) return "" + val result = StringBuilder(size) for (i in indices) { result.append(get(i)) } @@ -481,5 +485,77 @@ fun filtering(): List { } } + templates add f("slice(indices: IntRange)") { + only(Strings, Lists, ArraysOfPrimitives, ArraysOfObjects) + doc { "Returns a list containing elements at indices in the specified [indices] range." } + returns("List") + body(Lists) { + """ + if (indices.isEmpty()) return listOf() + return this.subList(indices.start, indices.end + 1).toList() + """ + } + body(ArraysOfPrimitives, ArraysOfObjects) { + """ + if (indices.isEmpty()) return listOf() + return copyOfRange(indices.start, indices.end + 1).asList() + """ + } + + doc(Strings) { "Returns a string containing characters at indices at the specified [indices]." } + returns(Strings) { "String" } + body(Strings) { + """ + if (indices.isEmpty()) return "" + return substring(indices) + """ + } + } + + templates add f("sliceArray(indices: Collection)") { + only(ArraysOfObjectsSubtype, ArraysOfPrimitives) + doc { "Returns an array containing elements of this array at specified [indices]." } + returns("SELF") + body(ArraysOfObjectsSubtype) { + """ + if (indices.isEmpty()) return arrayOfNulls(this, 0) as SELF + val result = arrayOfNulls(this, indices.size()) as Array + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result as SELF + """ + } + body(ArraysOfPrimitives) { + """ + val result = SELF(indices.size()) + var targetIndex = 0 + for (sourceIndex in indices) { + result[targetIndex++] = this[sourceIndex] + } + return result + """ + } + } + + templates add f("sliceArray(indices: IntRange)") { + only(ArraysOfObjectsSubtype, ArraysOfPrimitives) + doc { "Returns a list containing elements at indices in the specified [indices] range." } + returns("SELF") + body(ArraysOfObjectsSubtype) { + """ + if (indices.isEmpty()) return copyOf(0) as SELF + return copyOfRange(indices.start, indices.end + 1) as SELF + """ + } + body(ArraysOfPrimitives) { + """ + if (indices.isEmpty()) return SELF(0) + return copyOfRange(indices.start, indices.end + 1) + """ + } + } + return templates } \ No newline at end of file diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt index 1b0009f8cfd..c86612cb757 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt @@ -58,16 +58,10 @@ fun ordering(): List { body(ArraysOfObjectsSubtype) { """ if (isEmpty()) return this - val result = this.copyOf() as Array - var i1 = 0 - var i2 = lastIndex - while (i1 < i2) { - val tmp = result[i1] - result[i1] = result[i2] - result[i2] = tmp - i1 += 1 - i2 -= 1 - } + val result = arrayOfNulls(this, size()) as Array + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] return result as A """ }