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

This commit is contained in:
Ilya Gorbunov
2015-08-28 19:02:49 +03:00
parent a3056bea1a
commit 89df3925fa
3 changed files with 31 additions and 30 deletions
+4 -20
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.
*/
public fun <T> Array<out T>.copyOf(): Array<out T> {
return Arrays.copyOf(this, size())
public fun <T, A: Array<out T>> A.copyOf(): A {
return Arrays.copyOf(this, size()) as A
}
/**
@@ -263,14 +263,6 @@ public fun ShortArray.copyOf(): ShortArray {
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.
*/
@@ -345,8 +337,8 @@ public fun <T> Array<T>.copyOf(newSize: Int): Array<T?> {
/**
* Returns new array which is a copy of range of original array.
*/
public fun <T> Array<out T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<out T> {
return Arrays.copyOfRange(this, fromIndex, toIndex)
public fun <T, A: Array<out T>> A.copyOfRange(fromIndex: Int, toIndex: Int): A {
return Arrays.copyOfRange(this, fromIndex, toIndex) as A
}
/**
@@ -405,14 +397,6 @@ public fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray {
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.
*/
@@ -16,6 +16,7 @@ enum class Family {
ArraysOfObjects,
ArraysOfPrimitives,
InvariantArraysOfObjects,
ArraysOfObjectsSubtype,
Strings,
Ranges,
RangesOfPrimitives,
@@ -167,7 +168,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
fun build(vararg families: Family = Family.values()): String {
val builder = StringBuilder()
for (family in families.sortBy { it.name() }) {
for (family in families.sortedBy { it.name() }) {
if (buildFamilies.contains(family))
build(builder, family)
}
@@ -177,7 +178,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
fun build(builder: StringBuilder, f: Family) {
val onlyPrimitives = buildFamilyPrimitives[f]
if (f.isPrimitiveSpecialization || onlyPrimitives != null) {
for (primitive in (onlyPrimitives ?: buildPrimitives).sortBy { it.name() })
for (primitive in (onlyPrimitives ?: buildPrimitives).sortedBy { it.name() })
build(builder, f, primitive)
} else {
build(builder, f, null)
@@ -262,6 +263,7 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
Sets -> "Set<$isAsteriskOrT>"
Sequences -> "Sequence<$isAsteriskOrT>"
InvariantArraysOfObjects -> "Array<T>"
ArraysOfObjectsSubtype -> "A"
ArraysOfObjects -> "Array<${isAsteriskOrT.replace("T", "out T")}>"
Strings -> "String"
Ranges -> "Range<$isAsteriskOrT>"
@@ -275,8 +277,19 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
fun String.renderType(): String = renderType(this, receiver)
fun effectiveTypeParams(): List<String> {
fun getGenericTypeParameters(genericType: String) =
genericType
.dropWhile { it != '<' }
.drop(1)
.takeWhile { it != '>' }
.split(",")
.map { it.removePrefix("out").removePrefix("in").trim() }
// TODO: Model for type parameter
val types = ArrayList(typeParams)
if (f == ArraysOfObjectsSubtype) {
types.add("A: Array<out T>")
}
if (f == Generic) {
// ensure type parameter T, if it's not added to typeParams before
if (!types.any { it == "T" || it.startsWith("T:")}) {
@@ -285,9 +298,8 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
return types
}
else if (primitive == null && f != Strings) {
val implicitTypeParameters = receiver.dropWhile { it != '<' }.drop(1).takeWhile { it != '>' }.split(",")
.map { it.removePrefix("out").removePrefix("in").trim() }
for (implicit in implicitTypeParameters.reverse()) {
val implicitTypeParameters = getGenericTypeParameters(receiver) + types.flatMap { getGenericTypeParameters(it) }
for (implicit in implicitTypeParameters.reversed()) {
if (implicit != "*" && !types.any { it.startsWith(implicit) || it.startsWith("reified " + implicit) }) {
types.add(0, implicit)
}
@@ -295,7 +307,8 @@ class GenericFunction(val signature: String, val keyword: String = "fun") : Comp
return types
} else {
// primitive type arrays should drop constraints
// remove T as parameter
// TODO: Substitute primitive or String instead of T in other parameters from effective types not from original typeParams
return typeParams.filter { !it.startsWith("T") }
}
}
@@ -51,23 +51,27 @@ fun specialJVM(): List<GenericFunction> {
templates add f("copyOfRange(fromIndex: Int, toIndex: Int)") {
only(ArraysOfObjects, InvariantArraysOfObjects, ArraysOfPrimitives)
only(ArraysOfObjectsSubtype, ArraysOfPrimitives)
doc { "Returns new array which is a copy of range of original array." }
returns("SELF")
annotations(InvariantArraysOfObjects) { """platformName("mutableCopyOfRange")"""}
body {
"return Arrays.copyOfRange(this, fromIndex, toIndex)"
}
body(ArraysOfObjectsSubtype) {
"return Arrays.copyOfRange(this, fromIndex, toIndex) as A"
}
}
templates add f("copyOf()") {
only(ArraysOfObjects, InvariantArraysOfObjects, ArraysOfPrimitives)
only(ArraysOfObjectsSubtype, ArraysOfPrimitives)
doc { "Returns new array which is a copy of the original array." }
returns("SELF")
annotations(InvariantArraysOfObjects) { """platformName("mutableCopyOf")"""}
body {
"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