diff --git a/js/js.libraries/src/core/kotlin_special.kt b/js/js.libraries/src/core/kotlin_special.kt index 10d290347dd..6cd1e4b6370 100644 --- a/js/js.libraries/src/core/kotlin_special.kt +++ b/js/js.libraries/src/core/kotlin_special.kt @@ -615,6 +615,13 @@ public fun ShortArray.sort(comparison: (Short, Short) -> Int): Unit { return noImpl } +/** + * Sorts the array inplace according to the order specified by the given [comparator] object. + */ +public fun Array.sortWith(comparator: Comparator): Unit { + sort { a, b -> comparator.compare(a, b) } +} + /** * Returns a *typed* object array containing all of the elements of this primitive array. */ diff --git a/libraries/stdlib/src/generated/_Ordering.kt b/libraries/stdlib/src/generated/_Ordering.kt index 1fc60c751b6..8d778c06745 100644 --- a/libraries/stdlib/src/generated/_Ordering.kt +++ b/libraries/stdlib/src/generated/_Ordering.kt @@ -205,6 +205,120 @@ public fun String.reversed(): String { return StringBuilder().append(this).reverse().toString() } +/** + * Returns an array with elements of this array in reversed order. + */ +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 + } + return result as A +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun BooleanArray.reversedArray(): BooleanArray { + if (isEmpty()) return this + val result = BooleanArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun ByteArray.reversedArray(): ByteArray { + if (isEmpty()) return this + val result = ByteArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun CharArray.reversedArray(): CharArray { + if (isEmpty()) return this + val result = CharArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun DoubleArray.reversedArray(): DoubleArray { + if (isEmpty()) return this + val result = DoubleArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun FloatArray.reversedArray(): FloatArray { + if (isEmpty()) return this + val result = FloatArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun IntArray.reversedArray(): IntArray { + if (isEmpty()) return this + val result = IntArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun LongArray.reversedArray(): LongArray { + if (isEmpty()) return this + val result = LongArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + +/** + * Returns an array with elements of this array in reversed order. + */ +public fun ShortArray.reversedArray(): ShortArray { + if (isEmpty()) return this + val result = ShortArray(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result +} + /** * Returns a sorted list of all elements. */ @@ -383,6 +497,150 @@ public fun > Sequence.sorted(): Sequence { } } +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun , A: Array> A.sortedArray(): A { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as A +} + +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun ByteArray.sortedArray(): ByteArray { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as ByteArray +} + +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun CharArray.sortedArray(): CharArray { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as CharArray +} + +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun DoubleArray.sortedArray(): DoubleArray { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as DoubleArray +} + +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun FloatArray.sortedArray(): FloatArray { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as FloatArray +} + +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun IntArray.sortedArray(): IntArray { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as IntArray +} + +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun LongArray.sortedArray(): LongArray { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as LongArray +} + +/** + * Returns an array with all elements of this array sorted according to their natural sort order. + */ +public fun ShortArray.sortedArray(): ShortArray { + if (isEmpty()) return this + return this.copyOf().apply { sort() } as ShortArray +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun , A: Array> A.sortedArrayDescending(): A { + if (isEmpty()) return this + // TODO: Use reverseOrder() + return this.copyOf().apply { sortWith(comparator { a, b -> b.compareTo(a) }) } as A +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun ByteArray.sortedArrayDescending(): ByteArray { + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as ByteArray +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun CharArray.sortedArrayDescending(): CharArray { + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as CharArray +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun DoubleArray.sortedArrayDescending(): DoubleArray { + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as DoubleArray +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun FloatArray.sortedArrayDescending(): FloatArray { + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as FloatArray +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun IntArray.sortedArrayDescending(): IntArray { + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as IntArray +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun LongArray.sortedArrayDescending(): LongArray { + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as LongArray +} + +/** + * Returns an array with all elements of this array sorted descending according to their natural sort order. + */ +public fun ShortArray.sortedArrayDescending(): ShortArray { + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as ShortArray +} + +/** + * Returns an array with all elements of this array sorted according the specified [comparator]. + */ +public fun > A.sortedArrayWith(comparator: Comparator): A { + if (isEmpty()) return this + return this.copyOf().apply { sortWith(comparator) } as A +} + /** * Returns a list of all elements sorted according to natural sort order of the value returned by specified [selector] function. */ diff --git a/libraries/stdlib/src/generated/_SpecialJVM.kt b/libraries/stdlib/src/generated/_SpecialJVM.kt index 21b31cbba84..6e204b2a29f 100644 --- a/libraries/stdlib/src/generated/_SpecialJVM.kt +++ b/libraries/stdlib/src/generated/_SpecialJVM.kt @@ -885,6 +885,13 @@ public fun ShortArray.sort(fromIndex: Int = 0, toIndex: Int = size()): Unit { Arrays.sort(this, fromIndex, toIndex) } +/** + * Sorts array or range in array inplace. + */ +public fun Array.sortWith(comparator: Comparator, fromIndex: Int = 0, toIndex: Int = size()): Unit { + Arrays.sort(this, fromIndex, toIndex, comparator) +} + /** * Returns a *typed* object array containing all of the elements of this primitive array. */ diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 277926a6532..a2a9d7fd38d 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -1,5 +1,6 @@ package test.collections +import java.util.* import kotlin.test.* import org.junit.Test as test @@ -528,7 +529,7 @@ class ArraysTest { } is UnsupportedOperationException) } - test fun reverse() { + test fun reversed() { expect(listOf(3, 2, 1)) { intArrayOf(1, 2, 3).reversed() } expect(listOf(3, 2, 1)) { byteArrayOf(1, 2, 3).reversed() } expect(listOf(3, 2, 1)) { shortArrayOf(1, 2, 3).reversed() } @@ -539,6 +540,17 @@ class ArraysTest { expect(listOf(false, false, true)) { booleanArrayOf(true, false, false).reversed() } } + test fun reversedArray() { + assertArrayNotSameButEquals(intArrayOf(3, 2, 1), intArrayOf(1, 2, 3).reversedArray()) + assertArrayNotSameButEquals(byteArrayOf(3, 2, 1), byteArrayOf(1, 2, 3).reversedArray()) + assertArrayNotSameButEquals(shortArrayOf(3, 2, 1), shortArrayOf(1, 2, 3).reversedArray()) + assertArrayNotSameButEquals(longArrayOf(3, 2, 1), longArrayOf(1, 2, 3).reversedArray()) + assertArrayNotSameButEquals(floatArrayOf(3F, 2F, 1F), floatArrayOf(1F, 2F, 3F).reversedArray()) + assertArrayNotSameButEquals(doubleArrayOf(3.0, 2.0, 1.0), doubleArrayOf(1.0, 2.0, 3.0).reversedArray()) + assertArrayNotSameButEquals(charArrayOf('3', '2', '1'), charArrayOf('1', '2', '3').reversedArray()) + assertArrayNotSameButEquals(booleanArrayOf(false, false, true), booleanArrayOf(true, false, false).reversedArray()) + } + test fun drop() { expect(listOf(1), { intArrayOf(1).drop(0) }) expect(listOf(), { intArrayOf().drop(1) }) @@ -786,34 +798,37 @@ class ArraysTest { assertTrue(arrayOf().sorted().none()) assertEquals(listOf(1), arrayOf(1).sorted()) - arrayOf("ac", "aD", "aba").let { - it.sorted().assertSorted { a, b -> a <= b } - it.sortedDescending().assertSorted { a, b -> a >= b } + fun arrayData>(vararg values: T, toArray: Array.() -> A) = ArraySortedChecker(values.toArray(), comparator { a, b -> a.compareTo(b) }) + + with (arrayData("ac", "aD", "aba") { toList().toTypedArray() }) { + checkSorted>({ sorted() }, { sortedDescending() }, { iterator() }) + checkSorted>({ sortedArray() }, { sortedArrayDescending()}, { iterator() } ) } - intArrayOf(3, 7, 1).let { - it.sorted().assertSorted { a, b -> a <= b } - it.sortedDescending().assertSorted { a, b -> a >= b } + with (arrayData(3, 7, 1) { toIntArray() }) { + checkSorted>( { sorted() }, { sortedDescending() }, { iterator() }) + checkSorted( { sortedArray() }, { sortedArrayDescending() }, { iterator() }) } - longArrayOf(1, Long.MIN_VALUE, Long.MAX_VALUE).let { - it.sorted().assertSorted { a, b -> a <= b } - it.sortedDescending().assertSorted { a, b -> a >= b } + + with (arrayData(1L, Long.MIN_VALUE, Long.MAX_VALUE) { toLongArray() }) { + checkSorted>( { sorted() }, { sortedDescending() }, { iterator() }) + checkSorted( { sortedArray() }, { sortedArrayDescending() }, { iterator() }) } - charArrayOf('a', 'D', 'c').let { - it.sorted().assertSorted { a, b -> a <= b } - it.sortedDescending().assertSorted { a, b -> a >= b } + with (arrayData('a', 'D', 'c') { toCharArray() }) { + checkSorted>( { sorted() }, { sortedDescending() }, { iterator() }) + checkSorted( { sortedArray() }, { sortedArrayDescending() }, { iterator() }) } - byteArrayOf(1, Byte.MAX_VALUE, Byte.MIN_VALUE).let { - it.sorted().assertSorted { a, b -> a <= b } - it.sortedDescending().assertSorted { a, b -> a >= b } + with (arrayData(1.toByte(), Byte.MAX_VALUE, Byte.MIN_VALUE) { toByteArray() }) { + checkSorted>( { sorted() }, { sortedDescending() }, { iterator() }) + checkSorted( { sortedArray() }, { sortedArrayDescending() }, { iterator() }) } - doubleArrayOf(Double.POSITIVE_INFINITY, 1.0, Double.MAX_VALUE).let { - it.sorted().assertSorted { a, b -> a <= b } - it.sortedDescending().assertSorted { a, b -> a >= b } + with(arrayData(Double.POSITIVE_INFINITY, 1.0, Double.MAX_VALUE) { toDoubleArray() }) { + checkSorted>( { sorted() }, { sortedDescending() }, { iterator() }) + checkSorted( { sortedArray() }, { sortedArrayDescending() }, { iterator() }) } } @@ -834,6 +849,20 @@ class ArraysTest { } test fun sortedWith() { - assertEquals(listOf(3, 0, 4, 1, 5, 2), intArrayOf(0, 1, 2, 3, 4, 5).sortedWith( compareBy { it: Int -> it % 3 }.thenByDescending { it } )) + val comparator = compareBy { it: Int -> it % 3 }.thenByDescending { it } + fun arrayData(array: A, comparator: Comparator) = ArraySortedChecker(array, comparator) + + arrayData(intArrayOf(0, 1, 2, 3, 4, 5), comparator) + .checkSorted>( { sortedWith(comparator) }, { sortedWith(comparator.reversed()) }, { iterator() }) + + arrayData(arrayOf(0, 1, 2, 3, 4, 5), comparator) + .checkSorted>( { sortedArrayWith(comparator) }, { sortedArrayWith(comparator.reversed()) }, { iterator() }) } } + +private class ArraySortedChecker(val array: A, val comparator: Comparator) { + public fun checkSorted(sorted: A.() -> R, sortedDescending: A.() -> R, iterator: R.() -> Iterator) { + array.sorted().iterator().assertSorted { a, b -> comparator.compare(a, b) <= 0 } + array.sortedDescending().iterator().assertSorted { a, b -> comparator.compare(a, b) >= 0 } + } +} \ 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 ca15fe1db1d..1b0009f8cfd 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Ordering.kt @@ -51,6 +51,38 @@ fun ordering(): List { exclude(Sequences) } + templates add f("reversedArray()") { + doc { "Returns an array with elements of this array in reversed order." } + only(ArraysOfObjectsSubtype, ArraysOfPrimitives) + returns("SELF") + 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 + } + return result as A + """ + } + body(ArraysOfPrimitives) { + """ + if (isEmpty()) return this + val result = SELF(size()) + val lastIndex = lastIndex + for (i in 0..lastIndex) + result[lastIndex - i] = this[i] + return result + """ + } + } + templates add f("sorted()") { exclude(Strings) exclude(PrimitiveType.Boolean) @@ -87,6 +119,22 @@ fun ordering(): List { } } + templates add f("sortedArray()") { + only(ArraysOfObjectsSubtype, ArraysOfPrimitives) + exclude(PrimitiveType.Boolean) + doc { + "Returns an array with all elements of this array sorted according to their natural sort order." + } + typeParam("T : Comparable") + returns("SELF") + body() { + """ + if (isEmpty()) return this + return this.copyOf().apply { sort() } as SELF + """ + } + } + templates add f("sortedDescending()") { exclude(Strings) exclude(PrimitiveType.Boolean) @@ -120,6 +168,31 @@ fun ordering(): List { } } + templates add f("sortedArrayDescending()") { + only(ArraysOfObjectsSubtype, ArraysOfPrimitives) + exclude(PrimitiveType.Boolean) + doc { + "Returns an array with all elements of this array sorted descending according to their natural sort order." + } + typeParam("T : Comparable") + returns("SELF") + body(ArraysOfObjectsSubtype) { + """ + if (isEmpty()) return this + // TODO: Use reverseOrder() + return this.copyOf().apply { sortWith(comparator { a, b -> b.compareTo(a) }) } as SELF + """ + + } + body() { + """ + if (isEmpty()) return this + // TODO: Use in-place reverse + return this.copyOf().apply { sort() }.reversedArray() as SELF + """ + } + } + templates add f("sortedWith(comparator: Comparator)") { exclude(Strings) returns("List") @@ -153,6 +226,20 @@ fun ordering(): List { } } + templates add f("sortedArrayWith(comparator: Comparator)") { + only(ArraysOfObjectsSubtype) + doc { + "Returns an array with all elements of this array sorted according the specified [comparator]." + } + returns("SELF") + body() { + """ + if (isEmpty()) return this + return this.copyOf().apply { sortWith(comparator) } as SELF + """ + } + } + templates add f("sortedBy(inlineOptions(InlineOption.ONLY_LOCAL_RETURN) selector: (T) -> R?)") { exclude(Strings) inline(true) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJS.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJS.kt index 8f412e7f8cf..cf35d7d26a7 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJS.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJS.kt @@ -140,6 +140,14 @@ fun specialJS(): List { body { "return noImpl" } } + templates add f("sortWith(comparator: Comparator)") { + only(ArraysOfObjects) + exclude(PrimitiveType.Boolean) + returns("Unit") + doc { "Sorts the array inplace according to the order specified by the given [comparator] object." } + body { "sort { a, b -> comparator.compare(a, b) }" } + } + templates add f("sort()") { only(ArraysOfPrimitives) only(numericPrimitives + PrimitiveType.Char) diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt index 826ba0af2b4..bc4240273e1 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/SpecialJVM.kt @@ -127,6 +127,16 @@ fun specialJVM(): List { } } + templates add f("sortWith(comparator: Comparator, fromIndex: Int = 0, toIndex: Int = size())") { + only(ArraysOfObjects) + doc { "Sorts array or range in array inplace." } + returns("Unit") + body { + "Arrays.sort(this, fromIndex, toIndex, comparator)" + } + + } + templates add f("filterIsInstanceTo(destination: C, klass: Class)") { doc { "Appends all elements that are instances of specified class to the given [destination]." } receiverAsterisk(true)