Revert unification of operations on Array<T> and Array<out T> (copyOf, copyOfRange) which return the same type as the receiver.

Leave sortedArray, reversedArray and sliceArray only for covariant projection of array as the receiver.
This commit is contained in:
Ilya Gorbunov
2015-09-17 18:12:21 +03:00
committed by Alexander Udalov
parent c12f44fa22
commit e95be9096e
9 changed files with 73 additions and 68 deletions
+5 -6
View File
@@ -1229,14 +1229,13 @@ public fun String.slice(indices: Iterable<Int>): String {
/** /**
* Returns an array containing elements of this array at specified [indices]. * Returns an array containing elements of this array at specified [indices].
*/ */
public fun <T, A: Array<out T>> A.sliceArray(indices: Collection<Int>): A { public fun <T> Array<out T>.sliceArray(indices: Collection<Int>): Array<out T> {
if (indices.isEmpty()) return arrayOfNulls(this, 0) as A
val result = arrayOfNulls(this, indices.size()) as Array<T> val result = arrayOfNulls(this, indices.size()) as Array<T>
var targetIndex = 0 var targetIndex = 0
for (sourceIndex in indices) { for (sourceIndex in indices) {
result[targetIndex++] = this[sourceIndex] result[targetIndex++] = this[sourceIndex]
} }
return result as A return result
} }
/** /**
@@ -1338,9 +1337,9 @@ public fun ShortArray.sliceArray(indices: Collection<Int>): ShortArray {
/** /**
* Returns a list containing elements at indices in the specified [indices] range. * Returns a list containing elements at indices in the specified [indices] range.
*/ */
public fun <T, A: Array<out T>> A.sliceArray(indices: IntRange): A { public fun <T> Array<out T>.sliceArray(indices: IntRange): Array<out T> {
if (indices.isEmpty()) return copyOf(0) as A if (indices.isEmpty()) return copyOfRange(0, 0)
return copyOfRange(indices.start, indices.end + 1) as A return copyOfRange(indices.start, indices.end + 1)
} }
/** /**
+22 -22
View File
@@ -208,13 +208,13 @@ public fun String.reversed(): String {
/** /**
* Returns an array with elements of this array in reversed order. * Returns an array with elements of this array in reversed order.
*/ */
public fun <T, A: Array<out T>> A.reversedArray(): A { public fun <T> Array<out T>.reversedArray(): Array<out T> {
if (isEmpty()) return this if (isEmpty()) return this
val result = arrayOfNulls(this, size()) as Array<T> val result = arrayOfNulls(this, size()) as Array<T>
val lastIndex = lastIndex val lastIndex = lastIndex
for (i in 0..lastIndex) for (i in 0..lastIndex)
result[lastIndex - i] = this[i] result[lastIndex - i] = this[i]
return result as A return result
} }
/** /**
@@ -494,9 +494,9 @@ public fun <T : Comparable<T>> Sequence<T>.sorted(): Sequence<T> {
/** /**
* Returns an array with all elements of this array sorted according to their natural sort order. * Returns an array with all elements of this array sorted according to their natural sort order.
*/ */
public fun <T : Comparable<T>, A: Array<out T>> A.sortedArray(): A { public fun <T : Comparable<T>> Array<out T>.sortedArray(): Array<out T> {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as A return this.copyOf().apply { sort() }
} }
/** /**
@@ -504,7 +504,7 @@ public fun <T : Comparable<T>, A: Array<out T>> A.sortedArray(): A {
*/ */
public fun ByteArray.sortedArray(): ByteArray { public fun ByteArray.sortedArray(): ByteArray {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as ByteArray return this.copyOf().apply { sort() }
} }
/** /**
@@ -512,7 +512,7 @@ public fun ByteArray.sortedArray(): ByteArray {
*/ */
public fun CharArray.sortedArray(): CharArray { public fun CharArray.sortedArray(): CharArray {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as CharArray return this.copyOf().apply { sort() }
} }
/** /**
@@ -520,7 +520,7 @@ public fun CharArray.sortedArray(): CharArray {
*/ */
public fun DoubleArray.sortedArray(): DoubleArray { public fun DoubleArray.sortedArray(): DoubleArray {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as DoubleArray return this.copyOf().apply { sort() }
} }
/** /**
@@ -528,7 +528,7 @@ public fun DoubleArray.sortedArray(): DoubleArray {
*/ */
public fun FloatArray.sortedArray(): FloatArray { public fun FloatArray.sortedArray(): FloatArray {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as FloatArray return this.copyOf().apply { sort() }
} }
/** /**
@@ -536,7 +536,7 @@ public fun FloatArray.sortedArray(): FloatArray {
*/ */
public fun IntArray.sortedArray(): IntArray { public fun IntArray.sortedArray(): IntArray {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as IntArray return this.copyOf().apply { sort() }
} }
/** /**
@@ -544,7 +544,7 @@ public fun IntArray.sortedArray(): IntArray {
*/ */
public fun LongArray.sortedArray(): LongArray { public fun LongArray.sortedArray(): LongArray {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as LongArray return this.copyOf().apply { sort() }
} }
/** /**
@@ -552,16 +552,16 @@ public fun LongArray.sortedArray(): LongArray {
*/ */
public fun ShortArray.sortedArray(): ShortArray { public fun ShortArray.sortedArray(): ShortArray {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as ShortArray return this.copyOf().apply { sort() }
} }
/** /**
* Returns an array with all elements of this array sorted descending according to their natural sort order. * Returns an array with all elements of this array sorted descending according to their natural sort order.
*/ */
public fun <T : Comparable<T>, A: Array<out T>> A.sortedArrayDescending(): A { public fun <T : Comparable<T>> Array<out T>.sortedArrayDescending(): Array<out T> {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use reverseOrder<T>() // TODO: Use reverseOrder<T>()
return this.copyOf().apply { sortWith(comparator { a, b -> b.compareTo(a) }) } as A return this.copyOf().apply { sortWith(comparator { a, b -> b.compareTo(a) }) }
} }
/** /**
@@ -570,7 +570,7 @@ public fun <T : Comparable<T>, A: Array<out T>> A.sortedArrayDescending(): A {
public fun ByteArray.sortedArrayDescending(): ByteArray { public fun ByteArray.sortedArrayDescending(): ByteArray {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as ByteArray return this.copyOf().apply { sort() }.reversedArray()
} }
/** /**
@@ -579,7 +579,7 @@ public fun ByteArray.sortedArrayDescending(): ByteArray {
public fun CharArray.sortedArrayDescending(): CharArray { public fun CharArray.sortedArrayDescending(): CharArray {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as CharArray return this.copyOf().apply { sort() }.reversedArray()
} }
/** /**
@@ -588,7 +588,7 @@ public fun CharArray.sortedArrayDescending(): CharArray {
public fun DoubleArray.sortedArrayDescending(): DoubleArray { public fun DoubleArray.sortedArrayDescending(): DoubleArray {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as DoubleArray return this.copyOf().apply { sort() }.reversedArray()
} }
/** /**
@@ -597,7 +597,7 @@ public fun DoubleArray.sortedArrayDescending(): DoubleArray {
public fun FloatArray.sortedArrayDescending(): FloatArray { public fun FloatArray.sortedArrayDescending(): FloatArray {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as FloatArray return this.copyOf().apply { sort() }.reversedArray()
} }
/** /**
@@ -606,7 +606,7 @@ public fun FloatArray.sortedArrayDescending(): FloatArray {
public fun IntArray.sortedArrayDescending(): IntArray { public fun IntArray.sortedArrayDescending(): IntArray {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as IntArray return this.copyOf().apply { sort() }.reversedArray()
} }
/** /**
@@ -615,7 +615,7 @@ public fun IntArray.sortedArrayDescending(): IntArray {
public fun LongArray.sortedArrayDescending(): LongArray { public fun LongArray.sortedArrayDescending(): LongArray {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as LongArray return this.copyOf().apply { sort() }.reversedArray()
} }
/** /**
@@ -624,15 +624,15 @@ public fun LongArray.sortedArrayDescending(): LongArray {
public fun ShortArray.sortedArrayDescending(): ShortArray { public fun ShortArray.sortedArrayDescending(): ShortArray {
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as ShortArray return this.copyOf().apply { sort() }.reversedArray()
} }
/** /**
* Returns an array with all elements of this array sorted according the specified [comparator]. * Returns an array with all elements of this array sorted according the specified [comparator].
*/ */
public fun <T, A: Array<out T>> A.sortedArrayWith(comparator: Comparator<in T>): A { public fun <T> Array<out T>.sortedArrayWith(comparator: Comparator<in T>): Array<out T> {
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sortWith(comparator) } as A return this.copyOf().apply { sortWith(comparator) }
} }
/** /**
+20 -4
View File
@@ -203,8 +203,8 @@ public fun ShortArray.binarySearch(element: Short, fromIndex: Int = 0, toIndex:
/** /**
* Returns new array which is a copy of the original array. * Returns new array which is a copy of the original array.
*/ */
public fun <T, A: Array<out T>> A.copyOf(): A { public fun <T> Array<out T>.copyOf(): Array<out T> {
return Arrays.copyOf(this, size()) as A return Arrays.copyOf(this, size())
} }
/** /**
@@ -263,6 +263,14 @@ public fun ShortArray.copyOf(): ShortArray {
return Arrays.copyOf(this, size()) return Arrays.copyOf(this, size())
} }
/**
* Returns new array which is a copy of the original array.
*/
platformName("mutableCopyOf")
public fun <T> Array<T>.copyOf(): Array<T> {
return Arrays.copyOf(this, size())
}
/** /**
* Returns new array which is a copy of the original array. * Returns new array which is a copy of the original array.
*/ */
@@ -337,8 +345,8 @@ public fun <T> Array<T>.copyOf(newSize: Int): Array<T?> {
/** /**
* Returns new array which is a copy of range of original array. * Returns new array which is a copy of range of original array.
*/ */
public fun <T, A: Array<out T>> A.copyOfRange(fromIndex: Int, toIndex: Int): A { public fun <T> Array<out T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<out T> {
return Arrays.copyOfRange(this, fromIndex, toIndex) as A return Arrays.copyOfRange(this, fromIndex, toIndex)
} }
/** /**
@@ -397,6 +405,14 @@ public fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray {
return Arrays.copyOfRange(this, fromIndex, toIndex) return Arrays.copyOfRange(this, fromIndex, toIndex)
} }
/**
* Returns new array which is a copy of range of original array.
*/
platformName("mutableCopyOfRange")
public fun <T> Array<T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<T> {
return Arrays.copyOfRange(this, fromIndex, toIndex)
}
/** /**
* Fills original array with the provided value. * Fills original array with the provided value.
*/ */
@@ -97,6 +97,6 @@ public inline fun <reified T> Collection<T>.toTypedArray(): Array<T> {
public inline fun <reified T> Array<out T>?.orEmpty(): Array<out T> = this ?: arrayOf<T>() public inline fun <reified T> Array<out T>?.orEmpty(): Array<out T> = this ?: arrayOf<T>()
/** Internal unsafe construction of array based on reference array type */ /** Internal unsafe construction of array based on reference array type */
private fun <T, A: Array<out T>> arrayOfNulls(reference: A, size: Int): A { private fun <T> arrayOfNulls(reference: Array<out T>, size: Int): Array<out T> {
return java.lang.reflect.Array.newInstance(reference.javaClass.componentType, size) as A return java.lang.reflect.Array.newInstance(reference.javaClass.componentType, size) as Array<out T>
} }
@@ -819,7 +819,7 @@ class ArraysTest {
with (arrayData("ac", "aD", "aba") { toList().toTypedArray() }) { with (arrayData("ac", "aD", "aba") { toList().toTypedArray() }) {
checkSorted<List<String>>({ sorted() }, { sortedDescending() }, { iterator() }) checkSorted<List<String>>({ sorted() }, { sortedDescending() }, { iterator() })
checkSorted<Array<String>>({ sortedArray() }, { sortedArrayDescending()}, { iterator() } ) checkSorted<Array<out String>>({ sortedArray() }, { sortedArrayDescending()}, { iterator() } )
} }
with (arrayData(3, 7, 1) { toIntArray() }) { with (arrayData(3, 7, 1) { toIntArray() }) {
@@ -873,7 +873,7 @@ class ArraysTest {
.checkSorted<List<Int>>( { sortedWith(comparator) }, { sortedWith(comparator.reversed()) }, { iterator() }) .checkSorted<List<Int>>( { sortedWith(comparator) }, { sortedWith(comparator.reversed()) }, { iterator() })
arrayData(arrayOf(0, 1, 2, 3, 4, 5), comparator) arrayData(arrayOf(0, 1, 2, 3, 4, 5), comparator)
.checkSorted<Array<Int>>( { sortedArrayWith(comparator) }, { sortedArrayWith(comparator.reversed()) }, { iterator() }) .checkSorted<Array<out Int>>( { sortedArrayWith(comparator) }, { sortedArrayWith(comparator.reversed()) }, { iterator() })
} }
} }
@@ -16,7 +16,6 @@ enum class Family {
ArraysOfObjects, ArraysOfObjects,
ArraysOfPrimitives, ArraysOfPrimitives,
InvariantArraysOfObjects, InvariantArraysOfObjects,
ArraysOfObjectsSubtype,
Strings, Strings,
Ranges, Ranges,
RangesOfPrimitives, RangesOfPrimitives,
@@ -263,7 +262,6 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
Sets -> "Set<$isAsteriskOrT>" Sets -> "Set<$isAsteriskOrT>"
Sequences -> "Sequence<$isAsteriskOrT>" Sequences -> "Sequence<$isAsteriskOrT>"
InvariantArraysOfObjects -> "Array<T>" InvariantArraysOfObjects -> "Array<T>"
ArraysOfObjectsSubtype -> "A"
ArraysOfObjects -> "Array<${isAsteriskOrT.replace("T", "out T")}>" ArraysOfObjects -> "Array<${isAsteriskOrT.replace("T", "out T")}>"
Strings -> "String" Strings -> "String"
Ranges -> "Range<$isAsteriskOrT>" Ranges -> "Range<$isAsteriskOrT>"
@@ -287,9 +285,6 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
// TODO: Model for type parameter // TODO: Model for type parameter
val types = ArrayList(typeParams) val types = ArrayList(typeParams)
if (f == ArraysOfObjectsSubtype) {
types.add("A: Array<out T>")
}
if (f == Generic) { if (f == Generic) {
// ensure type parameter T, if it's not added to typeParams before // ensure type parameter T, if it's not added to typeParams before
if (!types.any { it == "T" || it.startsWith("T:")}) { if (!types.any { it == "T" || it.startsWith("T:")}) {
@@ -513,18 +513,17 @@ fun filtering(): List<GenericFunction> {
} }
templates add f("sliceArray(indices: Collection<Int>)") { templates add f("sliceArray(indices: Collection<Int>)") {
only(ArraysOfObjectsSubtype, ArraysOfPrimitives) only(ArraysOfObjects, ArraysOfPrimitives)
doc { "Returns an array containing elements of this array at specified [indices]." } doc { "Returns an array containing elements of this array at specified [indices]." }
returns("SELF") returns("SELF")
body(ArraysOfObjectsSubtype) { body(ArraysOfObjects) {
""" """
if (indices.isEmpty()) return arrayOfNulls(this, 0) as SELF
val result = arrayOfNulls(this, indices.size()) as Array<T> val result = arrayOfNulls(this, indices.size()) as Array<T>
var targetIndex = 0 var targetIndex = 0
for (sourceIndex in indices) { for (sourceIndex in indices) {
result[targetIndex++] = this[sourceIndex] result[targetIndex++] = this[sourceIndex]
} }
return result as SELF return result
""" """
} }
body(ArraysOfPrimitives) { body(ArraysOfPrimitives) {
@@ -540,13 +539,13 @@ fun filtering(): List<GenericFunction> {
} }
templates add f("sliceArray(indices: IntRange)") { templates add f("sliceArray(indices: IntRange)") {
only(ArraysOfObjectsSubtype, ArraysOfPrimitives) only(ArraysOfObjects, ArraysOfPrimitives)
doc { "Returns a list containing elements at indices in the specified [indices] range." } doc { "Returns a list containing elements at indices in the specified [indices] range." }
returns("SELF") returns("SELF")
body(ArraysOfObjectsSubtype) { body(ArraysOfObjects) {
""" """
if (indices.isEmpty()) return copyOf(0) as SELF if (indices.isEmpty()) return copyOfRange(0, 0)
return copyOfRange(indices.start, indices.end + 1) as SELF return copyOfRange(indices.start, indices.end + 1)
""" """
} }
body(ArraysOfPrimitives) { body(ArraysOfPrimitives) {
@@ -53,16 +53,16 @@ fun ordering(): List<GenericFunction> {
templates add f("reversedArray()") { templates add f("reversedArray()") {
doc { "Returns an array with elements of this array in reversed order." } doc { "Returns an array with elements of this array in reversed order." }
only(ArraysOfObjectsSubtype, ArraysOfPrimitives) only(ArraysOfObjects, ArraysOfPrimitives)
returns("SELF") returns("SELF")
body(ArraysOfObjectsSubtype) { body(ArraysOfObjects) {
""" """
if (isEmpty()) return this if (isEmpty()) return this
val result = arrayOfNulls(this, size()) as Array<T> val result = arrayOfNulls(this, size()) as Array<T>
val lastIndex = lastIndex val lastIndex = lastIndex
for (i in 0..lastIndex) for (i in 0..lastIndex)
result[lastIndex - i] = this[i] result[lastIndex - i] = this[i]
return result as A return result
""" """
} }
body(ArraysOfPrimitives) { body(ArraysOfPrimitives) {
@@ -114,7 +114,7 @@ fun ordering(): List<GenericFunction> {
} }
templates add f("sortedArray()") { templates add f("sortedArray()") {
only(ArraysOfObjectsSubtype, ArraysOfPrimitives) only(ArraysOfObjects, ArraysOfPrimitives)
exclude(PrimitiveType.Boolean) exclude(PrimitiveType.Boolean)
doc { doc {
"Returns an array with all elements of this array sorted according to their natural sort order." "Returns an array with all elements of this array sorted according to their natural sort order."
@@ -124,7 +124,7 @@ fun ordering(): List<GenericFunction> {
body() { body() {
""" """
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sort() } as SELF return this.copyOf().apply { sort() }
""" """
} }
} }
@@ -163,18 +163,18 @@ fun ordering(): List<GenericFunction> {
} }
templates add f("sortedArrayDescending()") { templates add f("sortedArrayDescending()") {
only(ArraysOfObjectsSubtype, ArraysOfPrimitives) only(ArraysOfObjects, ArraysOfPrimitives)
exclude(PrimitiveType.Boolean) exclude(PrimitiveType.Boolean)
doc { doc {
"Returns an array with all elements of this array sorted descending according to their natural sort order." "Returns an array with all elements of this array sorted descending according to their natural sort order."
} }
typeParam("T : Comparable<T>") typeParam("T : Comparable<T>")
returns("SELF") returns("SELF")
body(ArraysOfObjectsSubtype) { body(ArraysOfObjects) {
""" """
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use reverseOrder<T>() // TODO: Use reverseOrder<T>()
return this.copyOf().apply { sortWith(comparator { a, b -> b.compareTo(a) }) } as SELF return this.copyOf().apply { sortWith(comparator { a, b -> b.compareTo(a) }) }
""" """
} }
@@ -182,7 +182,7 @@ fun ordering(): List<GenericFunction> {
""" """
if (isEmpty()) return this if (isEmpty()) return this
// TODO: Use in-place reverse // TODO: Use in-place reverse
return this.copyOf().apply { sort() }.reversedArray() as SELF return this.copyOf().apply { sort() }.reversedArray()
""" """
} }
} }
@@ -221,7 +221,7 @@ fun ordering(): List<GenericFunction> {
} }
templates add f("sortedArrayWith(comparator: Comparator<in T>)") { templates add f("sortedArrayWith(comparator: Comparator<in T>)") {
only(ArraysOfObjectsSubtype) only(ArraysOfObjects)
doc { doc {
"Returns an array with all elements of this array sorted according the specified [comparator]." "Returns an array with all elements of this array sorted according the specified [comparator]."
} }
@@ -229,7 +229,7 @@ fun ordering(): List<GenericFunction> {
body() { body() {
""" """
if (isEmpty()) return this if (isEmpty()) return this
return this.copyOf().apply { sortWith(comparator) } as SELF return this.copyOf().apply { sortWith(comparator) }
""" """
} }
} }
@@ -51,27 +51,23 @@ fun specialJVM(): List<GenericFunction> {
templates add f("copyOfRange(fromIndex: Int, toIndex: Int)") { templates add f("copyOfRange(fromIndex: Int, toIndex: Int)") {
only(ArraysOfObjectsSubtype, ArraysOfPrimitives) only(ArraysOfObjects, InvariantArraysOfObjects, ArraysOfPrimitives)
doc { "Returns new array which is a copy of range of original array." } doc { "Returns new array which is a copy of range of original array." }
returns("SELF") returns("SELF")
annotations(InvariantArraysOfObjects) { """platformName("mutableCopyOfRange")"""}
body { body {
"return Arrays.copyOfRange(this, fromIndex, toIndex)" "return Arrays.copyOfRange(this, fromIndex, toIndex)"
} }
body(ArraysOfObjectsSubtype) {
"return Arrays.copyOfRange(this, fromIndex, toIndex) as A"
}
} }
templates add f("copyOf()") { templates add f("copyOf()") {
only(ArraysOfObjectsSubtype, ArraysOfPrimitives) only(ArraysOfObjects, InvariantArraysOfObjects, ArraysOfPrimitives)
doc { "Returns new array which is a copy of the original array." } doc { "Returns new array which is a copy of the original array." }
returns("SELF") returns("SELF")
annotations(InvariantArraysOfObjects) { """platformName("mutableCopyOf")"""}
body { body {
"return Arrays.copyOf(this, size())" "return Arrays.copyOf(this, size())"
} }
body(ArraysOfObjectsSubtype) {
"return Arrays.copyOf(this, size()) as A"
}
} }
// This overload can cause nulls if array size is expanding, hence different return overload // This overload can cause nulls if array size is expanding, hence different return overload