Improve argument validation in copyOfRange

Make copyOfRange implementation non-inline in order not to expose
copyOfRangeToIndexCheck implementation detail.

It will be possible to make the function non-inline itself later without
that JvmName trick, when apiVersion 1.2 support is discontinued.

#KT-19489
This commit is contained in:
Ilya Gorbunov
2018-08-04 22:07:06 +03:00
parent 58a3b64baf
commit 85af1f5d38
8 changed files with 355 additions and 51 deletions
@@ -5737,48 +5737,75 @@ public expect fun CharArray.copyOf(newSize: Int): CharArray
public expect fun <T> Array<T>.copyOf(newSize: Int): Array<T?> public expect fun <T> Array<T>.copyOf(newSize: Int): Array<T?>
/** /**
* Returns new array which is a copy of range of original array. * 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("NO_ACTUAL_FOR_EXPECT") @Suppress("NO_ACTUAL_FOR_EXPECT")
public expect fun <T> Array<T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<T> public expect fun <T> Array<T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<T>
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray public expect fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray public expect fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun IntArray.copyOfRange(fromIndex: Int, toIndex: Int): IntArray public expect fun IntArray.copyOfRange(fromIndex: Int, toIndex: Int): IntArray
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun LongArray.copyOfRange(fromIndex: Int, toIndex: Int): LongArray public expect fun LongArray.copyOfRange(fromIndex: Int, toIndex: Int): LongArray
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun FloatArray.copyOfRange(fromIndex: Int, toIndex: Int): FloatArray public expect fun FloatArray.copyOfRange(fromIndex: Int, toIndex: Int): FloatArray
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun DoubleArray.copyOfRange(fromIndex: Int, toIndex: Int): DoubleArray public expect fun DoubleArray.copyOfRange(fromIndex: Int, toIndex: Int): DoubleArray
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun BooleanArray.copyOfRange(fromIndex: Int, toIndex: Int): BooleanArray public expect fun BooleanArray.copyOfRange(fromIndex: Int, toIndex: Int): BooleanArray
/** /**
* Returns new array which is a copy of range of original array. * 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 expect fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray public expect fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray
+52 -21
View File
@@ -622,71 +622,102 @@ public actual fun <T> Array<out T>.copyOf(newSize: Int): Array<T?> {
} }
/** /**
* Returns new array which is a copy of range of original array. * 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", "NOTHING_TO_INLINE") @Suppress("ACTUAL_WITHOUT_EXPECT")
public actual inline fun <T> Array<out T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<T> { public actual fun <T> Array<out T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<T> {
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return this.asDynamic().slice(fromIndex, toIndex) return this.asDynamic().slice(fromIndex, toIndex)
} }
/** /**
* Returns new array which is a copy of range of original array. * 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("NOTHING_TO_INLINE") public actual fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray {
public actual inline fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray { AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return this.asDynamic().slice(fromIndex, toIndex) return this.asDynamic().slice(fromIndex, toIndex)
} }
/** /**
* Returns new array which is a copy of range of original array. * 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("NOTHING_TO_INLINE") public actual fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray {
public actual inline fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray { AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return this.asDynamic().slice(fromIndex, toIndex) return this.asDynamic().slice(fromIndex, toIndex)
} }
/** /**
* Returns new array which is a copy of range of original array. * 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("NOTHING_TO_INLINE") public actual fun IntArray.copyOfRange(fromIndex: Int, toIndex: Int): IntArray {
public actual inline fun IntArray.copyOfRange(fromIndex: Int, toIndex: Int): IntArray { AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return this.asDynamic().slice(fromIndex, toIndex) return this.asDynamic().slice(fromIndex, toIndex)
} }
/** /**
* Returns new array which is a copy of range of original array. * 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 { public actual fun LongArray.copyOfRange(fromIndex: Int, toIndex: Int): LongArray {
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return withType("LongArray", this.asDynamic().slice(fromIndex, toIndex)) return withType("LongArray", this.asDynamic().slice(fromIndex, toIndex))
} }
/** /**
* Returns new array which is a copy of range of original array. * 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("NOTHING_TO_INLINE") public actual fun FloatArray.copyOfRange(fromIndex: Int, toIndex: Int): FloatArray {
public actual inline fun FloatArray.copyOfRange(fromIndex: Int, toIndex: Int): FloatArray { AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return this.asDynamic().slice(fromIndex, toIndex) return this.asDynamic().slice(fromIndex, toIndex)
} }
/** /**
* Returns new array which is a copy of range of original array. * 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("NOTHING_TO_INLINE") public actual fun DoubleArray.copyOfRange(fromIndex: Int, toIndex: Int): DoubleArray {
public actual inline fun DoubleArray.copyOfRange(fromIndex: Int, toIndex: Int): DoubleArray { AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return this.asDynamic().slice(fromIndex, toIndex) return this.asDynamic().slice(fromIndex, toIndex)
} }
/** /**
* Returns new array which is a copy of range of original array. * 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 { public actual fun BooleanArray.copyOfRange(fromIndex: Int, toIndex: Int): BooleanArray {
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return withType("BooleanArray", this.asDynamic().slice(fromIndex, toIndex)) return withType("BooleanArray", this.asDynamic().slice(fromIndex, toIndex))
} }
/** /**
* Returns new array which is a copy of range of original array. * 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 { public actual fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray {
AbstractList.checkRangeIndexes(fromIndex, toIndex, size)
return withType("CharArray", this.asDynamic().slice(fromIndex, toIndex)) return withType("CharArray", this.asDynamic().slice(fromIndex, toIndex))
} }
+170 -17
View File
@@ -814,74 +814,227 @@ public actual inline fun <T> Array<T>.copyOf(newSize: Int): Array<T?> {
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun <T> Array<T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<T> { public actual inline fun <T> Array<T>.copyOfRange(fromIndex: Int, toIndex: Int): Array<T> {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray { public actual inline fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray { public actual inline fun ShortArray.copyOfRange(fromIndex: Int, toIndex: Int): ShortArray {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun IntArray.copyOfRange(fromIndex: Int, toIndex: Int): IntArray { public actual inline fun IntArray.copyOfRange(fromIndex: Int, toIndex: Int): IntArray {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun LongArray.copyOfRange(fromIndex: Int, toIndex: Int): LongArray { public actual inline fun LongArray.copyOfRange(fromIndex: Int, toIndex: Int): LongArray {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun FloatArray.copyOfRange(fromIndex: Int, toIndex: Int): FloatArray { public actual inline fun FloatArray.copyOfRange(fromIndex: Int, toIndex: Int): FloatArray {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun DoubleArray.copyOfRange(fromIndex: Int, toIndex: Int): DoubleArray { public actual inline fun DoubleArray.copyOfRange(fromIndex: Int, toIndex: Int): DoubleArray {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun BooleanArray.copyOfRange(fromIndex: Int, toIndex: Int): BooleanArray { public actual inline fun BooleanArray.copyOfRange(fromIndex: Int, toIndex: Int): BooleanArray {
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
} }
/** /**
* Returns new array which is a copy of range of original array. * 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`
*/ */
@JvmName("copyOfRangeInline")
@kotlin.internal.InlineOnly @kotlin.internal.InlineOnly
public actual inline fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray { public actual inline fun CharArray.copyOfRange(fromIndex: Int, toIndex: Int): CharArray {
return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: $toIndex, size: $size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun <T> Array<T>.copyOfRangeImpl(fromIndex: Int, toIndex: Int): Array<T> {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun ByteArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): ByteArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun ShortArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): ShortArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun IntArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): IntArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun LongArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): LongArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun FloatArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): FloatArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun DoubleArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): DoubleArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun BooleanArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): BooleanArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
@SinceKotlin("1.3")
@PublishedApi
@JvmName("copyOfRange")
internal fun CharArray.copyOfRangeImpl(fromIndex: Int, toIndex: Int): CharArray {
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex) return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
} }
@@ -43,3 +43,8 @@ internal actual fun <T> arrayOfNulls(reference: Array<T>, size: Int): Array<T> {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return java.lang.reflect.Array.newInstance(reference.javaClass.componentType, size) as Array<T> return java.lang.reflect.Array.newInstance(reference.javaClass.componentType, size) as Array<T>
} }
@SinceKotlin("1.3")
internal fun copyOfRangeToIndexCheck(toIndex: Int, size: Int) {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex ($toIndex) is greater than size ($size).")
}
@@ -606,6 +606,15 @@ class ArraysTest {
assertEquals(listOf<Short>(200, 100), shortArrayOf(50, 100, 200).slice(2 downTo 1)) assertEquals(listOf<Short>(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(100L, 200L, 30L), longArrayOf(50L, 100L, 200L, 30L).slice(1..3))
assertEquals(listOf(true, false, true), booleanArrayOf(true, false, true, true).slice(iter)) assertEquals(listOf(true, false, true), booleanArrayOf(true, false, true, true).slice(iter))
for (range in listOf(-1 until 0, 0 until 2, 2..2)) {
val bounds = "range: $range"
val exClass = IndexOutOfBoundsException::class
assertFailsWith(exClass, bounds) { arrayOf("x").slice(range) }
assertFailsWith(exClass, bounds) { intArrayOf(1).slice(range) }
assertFailsWith(exClass, bounds) { longArrayOf(1L).slice(range) }
assertFailsWith(exClass, bounds) { charArrayOf('C').slice(range) }
}
} }
@Test fun sliceArray() { @Test fun sliceArray() {
@@ -625,6 +634,15 @@ class ArraysTest {
// assertArrayNotSameButEquals(shortArrayOf(200, 100), shortArrayOf(50, 100, 200).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(longArrayOf(100L, 200L, 30L), longArrayOf(50L, 100L, 200L, 30L).sliceArray(1..3))
assertArrayNotSameButEquals(booleanArrayOf(true, false, true), booleanArrayOf(true, false, true, true).sliceArray(coll)) assertArrayNotSameButEquals(booleanArrayOf(true, false, true), booleanArrayOf(true, false, true, true).sliceArray(coll))
for (range in listOf(-1 until 0, 0 until 2, 2..2)) {
val bounds = "range: $range"
val exClass = IndexOutOfBoundsException::class
assertFailsWith(exClass, bounds) { arrayOf("x").sliceArray(range) }
assertFailsWith(exClass, bounds) { intArrayOf(1).sliceArray(range) }
assertFailsWith(exClass, bounds) { longArrayOf(1L).sliceArray(range) }
assertFailsWith(exClass, bounds) { charArrayOf('C').sliceArray(range) }
}
} }
@Test fun iterators() { @Test fun iterators() {
@@ -738,6 +756,7 @@ class ArraysTest {
} }
@Test fun copyOfRange() { @Test fun copyOfRange() {
assertArrayNotSameButEquals(arrayOf("b", "c"), arrayOf("a", "b", "c").copyOfRange(1, 3))
assertArrayNotSameButEquals(booleanArrayOf(true, false, true), booleanArrayOf(true, false, true, true).copyOfRange(0, 3)) assertArrayNotSameButEquals(booleanArrayOf(true, false, true), booleanArrayOf(true, false, true, true).copyOfRange(0, 3))
assertArrayNotSameButEquals(byteArrayOf(0, 1, 2), byteArrayOf(0, 1, 2, 3, 4, 5).copyOfRange(0, 3)) assertArrayNotSameButEquals(byteArrayOf(0, 1, 2), byteArrayOf(0, 1, 2, 3, 4, 5).copyOfRange(0, 3))
assertArrayNotSameButEquals(shortArrayOf(0, 1, 2), shortArrayOf(0, 1, 2, 3, 4, 5).copyOfRange(0, 3)) assertArrayNotSameButEquals(shortArrayOf(0, 1, 2), shortArrayOf(0, 1, 2, 3, 4, 5).copyOfRange(0, 3))
@@ -746,6 +765,22 @@ class ArraysTest {
assertArrayNotSameButEquals(floatArrayOf(0F, 1F, 2F), floatArrayOf(0F, 1F, 2F, 3F, 4F, 5F).copyOfRange(0, 3)) assertArrayNotSameButEquals(floatArrayOf(0F, 1F, 2F), floatArrayOf(0F, 1F, 2F, 3F, 4F, 5F).copyOfRange(0, 3))
assertArrayNotSameButEquals(doubleArrayOf(0.0, 1.0, 2.0), doubleArrayOf(0.0, 1.0, 2.0, 3.0, 4.0, 5.0).copyOfRange(0, 3)) assertArrayNotSameButEquals(doubleArrayOf(0.0, 1.0, 2.0), doubleArrayOf(0.0, 1.0, 2.0, 3.0, 4.0, 5.0).copyOfRange(0, 3))
assertArrayNotSameButEquals(charArrayOf('0', '1', '2'), charArrayOf('0', '1', '2', '3', '4', '5').copyOfRange(0, 3)) assertArrayNotSameButEquals(charArrayOf('0', '1', '2'), charArrayOf('0', '1', '2', '3', '4', '5').copyOfRange(0, 3))
for (pos in 0..3) {
assertArrayNotSameButEquals(emptyArray(), arrayOf("a", "b", "c").copyOfRange(pos, pos))
assertArrayNotSameButEquals(intArrayOf(), intArrayOf(1, 2, 3).copyOfRange(pos, pos))
assertArrayNotSameButEquals(charArrayOf(), charArrayOf('a', 'b', 'c').copyOfRange(pos, pos))
assertArrayNotSameButEquals(longArrayOf(), LongArray(3) { it.toLong() }.copyOfRange(pos, pos))
}
for ((start, end) in listOf(-1 to 0, 0 to 2, 2 to 2, 1 to 0)) {
val bounds = "start: $start, end: $end"
val exClass = if (start > end) IllegalArgumentException::class else IndexOutOfBoundsException::class
assertFailsWith(exClass, bounds) { arrayOf("x").copyOfRange(start, end) }
assertFailsWith(exClass, bounds) { intArrayOf(1).copyOfRange(start, end) }
assertFailsWith(exClass, bounds) { longArrayOf(1L).copyOfRange(start, end) }
assertFailsWith(exClass, bounds) { charArrayOf('C').copyOfRange(start, end) }
}
} }
@@ -26,6 +26,9 @@ class ListSpecificTest {
@Test @Test
fun slice() { fun slice() {
val list = listOf('A', 'B', 'C', 'D') val list = listOf('A', 'B', 'C', 'D')
assertEquals(emptyList(), list.slice(IntRange.EMPTY))
// ABCD // ABCD
// 0123 // 0123
assertEquals(listOf('B', 'C', 'D'), list.slice(1..3)) assertEquals(listOf('B', 'C', 'D'), list.slice(1..3))
@@ -33,6 +36,13 @@ class ListSpecificTest {
val iter = listOf(2, 0, 3) val iter = listOf(2, 0, 3)
assertEquals(listOf('C', 'A', 'D'), list.slice(iter)) assertEquals(listOf('C', 'A', 'D'), list.slice(iter))
for (range in listOf(-1 until 0, 0 until 2, 2..2)) {
val bounds = "range: $range"
val exClass = IndexOutOfBoundsException::class
assertFailsWith(exClass, bounds) { listOf("x").slice(range) }
assertFailsWith(exClass, bounds) { listOf("x").slice(range.asIterable()) }
}
} }
@Test @Test
@@ -1142,6 +1142,15 @@ public final class kotlin/collections/ArraysKt {
public static final fun contains ([Ljava/lang/Object;Ljava/lang/Object;)Z public static final fun contains ([Ljava/lang/Object;Ljava/lang/Object;)Z
public static final fun contains ([SS)Z public static final fun contains ([SS)Z
public static final fun contains ([ZZ)Z public static final fun contains ([ZZ)Z
public static final fun copyOfRange ([BII)[B
public static final fun copyOfRange ([CII)[C
public static final fun copyOfRange ([DII)[D
public static final fun copyOfRange ([FII)[F
public static final fun copyOfRange ([III)[I
public static final fun copyOfRange ([JII)[J
public static final fun copyOfRange ([Ljava/lang/Object;II)[Ljava/lang/Object;
public static final fun copyOfRange ([SII)[S
public static final fun copyOfRange ([ZII)[Z
public static final fun count ([BLkotlin/jvm/functions/Function1;)I public static final fun count ([BLkotlin/jvm/functions/Function1;)I
public static final fun count ([CLkotlin/jvm/functions/Function1;)I public static final fun count ([CLkotlin/jvm/functions/Function1;)I
public static final fun count ([DLkotlin/jvm/functions/Function1;)I public static final fun count ([DLkotlin/jvm/functions/Function1;)I
@@ -370,11 +370,34 @@ object ArrayOps : TemplateGroupBase() {
} }
} }
val f_copyOfRangeJvmImpl = fn("copyOfRangeImpl(fromIndex: Int, toIndex: Int)") {
include(InvariantArraysOfObjects, ArraysOfPrimitives)
platforms(Platform.JVM)
} builderWith { primitive ->
since("1.3")
visibility("internal")
annotation("@PublishedApi")
annotation("""@JvmName("copyOfRange")""")
returns("SELF")
body {
"""
copyOfRangeToIndexCheck(toIndex, size)
return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
"""
}
}
val f_copyOfRange = fn("copyOfRange(fromIndex: Int, toIndex: Int)") { val f_copyOfRange = fn("copyOfRange(fromIndex: Int, toIndex: Int)") {
include(InvariantArraysOfObjects, ArraysOfPrimitives) include(InvariantArraysOfObjects, ArraysOfPrimitives)
} builderWith { primitive -> } builderWith { primitive ->
doc { "Returns new array which is a copy of range of original array." } doc {
"""
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`
"""
}
returns("SELF") returns("SELF")
on(Platform.JS) { on(Platform.JS) {
@@ -383,18 +406,29 @@ object ArrayOps : TemplateGroupBase() {
suppress("ACTUAL_WITHOUT_EXPECT") // TODO: KT-21937 suppress("ACTUAL_WITHOUT_EXPECT") // TODO: KT-21937
returns("Array<T>") returns("Array<T>")
} }
when(primitive) { val rangeCheck = "AbstractList.checkRangeIndexes(fromIndex, toIndex, size)"
when (primitive) {
PrimitiveType.Char, PrimitiveType.Boolean, PrimitiveType.Long -> PrimitiveType.Char, PrimitiveType.Boolean, PrimitiveType.Long ->
body { "return withType(\"${primitive}Array\", this.asDynamic().slice(fromIndex, toIndex))" } body { "return withType(\"${primitive}Array\", this.asDynamic().slice(fromIndex, toIndex))" }
else -> { else -> {
inline(suppressWarning = true)
body { "return this.asDynamic().slice(fromIndex, toIndex)" } body { "return this.asDynamic().slice(fromIndex, toIndex)" }
} }
} }
body { rangeCheck + "\n" + body }
} }
on(Platform.JVM) { on(Platform.JVM) {
annotation("""@JvmName("copyOfRangeInline")""")
inlineOnly() inlineOnly()
body { "return java.util.Arrays.copyOfRange(this, fromIndex, toIndex)" } body {
"""
return if (kotlin.internal.apiVersionIsAtLeast(1, 3, 0)) {
copyOfRangeImpl(fromIndex, toIndex)
} else {
if (toIndex > size) throw IndexOutOfBoundsException("toIndex: ${'$'}toIndex, size: ${'$'}size")
java.util.Arrays.copyOfRange(this, fromIndex, toIndex)
}
"""
}
} }
on(Platform.Common) { on(Platform.Common) {
specialFor(InvariantArraysOfObjects) { specialFor(InvariantArraysOfObjects) {