JS: Do not create a copy of already cloned vararg array.
JVM: Do not create copy of vararg array it it's already Object[].
This commit is contained in:
@@ -75,6 +75,10 @@ internal fun <T> arrayPlusCollection(array: dynamic, collection: Collection<T>):
|
||||
return result
|
||||
}
|
||||
|
||||
// copies vararg array due to different spread vararg behavior in JS.
|
||||
// After fixing #KT-6491 may return `this`
|
||||
internal inline fun <T> Array<out T>.varargToArrayOfAny(): Array<out Any?> = this.copyOf()
|
||||
|
||||
internal inline fun <T> Array<out T>.copyToArrayOfAny(isVarargs: Boolean): Array<out Any?> =
|
||||
if (isVarargs)
|
||||
// no need to copy vararg array in JS
|
||||
this
|
||||
else
|
||||
this.copyOf()
|
||||
@@ -45,16 +45,16 @@ internal object EmptyList : List<Nothing>, Serializable {
|
||||
private fun readResolve(): Any = EmptyList
|
||||
}
|
||||
|
||||
internal fun <T> Array<out T>.asCollection(): Collection<T> = ArrayAsCollection(this)
|
||||
internal fun <T> Array<out T>.asCollection(): Collection<T> = ArrayAsCollection(this, isVarargs = false)
|
||||
|
||||
private class ArrayAsCollection<T>(val values: Array<out T>): Collection<T> {
|
||||
private class ArrayAsCollection<T>(val values: Array<out T>, val isVarargs: Boolean): Collection<T> {
|
||||
override val size: Int get() = values.size
|
||||
override fun isEmpty(): Boolean = values.isEmpty()
|
||||
override fun contains(element: T): Boolean = values.contains(element)
|
||||
override fun containsAll(elements: Collection<T>): Boolean = elements.all { contains(it) }
|
||||
override fun iterator(): Iterator<T> = values.iterator()
|
||||
// override hidden toArray implementation to prevent copying of values array
|
||||
public fun toArray(): Array<out Any?> = values.varargToArrayOfAny()
|
||||
public fun toArray(): Array<out Any?> = values.copyToArrayOfAny(isVarargs)
|
||||
}
|
||||
|
||||
/** Returns an empty read-only list. The returned list is serializable (JVM). */
|
||||
@@ -76,11 +76,11 @@ public fun <T> listOf(element: T): List<T> = Collections.singletonList(element)
|
||||
|
||||
/** Returns a new [MutableList] with the given elements. */
|
||||
public fun <T> mutableListOf(vararg elements: T): MutableList<T>
|
||||
= if (elements.size == 0) ArrayList() else ArrayList(ArrayAsCollection(elements))
|
||||
= if (elements.size == 0) ArrayList() else ArrayList(ArrayAsCollection(elements, isVarargs = true))
|
||||
|
||||
/** Returns a new [ArrayList] with the given elements. */
|
||||
public fun <T> arrayListOf(vararg elements: T): ArrayList<T>
|
||||
= if (elements.size == 0) ArrayList() else ArrayList(ArrayAsCollection(elements))
|
||||
= if (elements.size == 0) ArrayList() else ArrayList(ArrayAsCollection(elements, isVarargs = true))
|
||||
|
||||
/** Returns a new read-only list either of single given element, if it is not null, or empty list it the element is null. The returned list is serializable (JVM). */
|
||||
public fun <T : Any> listOfNotNull(element: T?): List<T> = if (element != null) listOf(element) else emptyList()
|
||||
@@ -133,8 +133,12 @@ public inline fun <@kotlin.internal.OnlyInputTypes T> Collection<T>.containsAll(
|
||||
|
||||
// copies typed varargs array to array of objects
|
||||
@JvmVersion
|
||||
private fun <T> Array<out T>.varargToArrayOfAny(): Array<Any?>
|
||||
= Arrays.copyOf(this, this.size, Array<Any?>::class.java)
|
||||
private fun <T> Array<out T>.copyToArrayOfAny(isVarargs: Boolean): Array<Any?> =
|
||||
if (isVarargs && this.javaClass == Array<Any?>::class.java)
|
||||
// if the array came from varargs and already is array of Any, copying isn't required
|
||||
@Suppress("CAST_NEVER_SUCCEEDS") (this as Array<Any?>)
|
||||
else
|
||||
Arrays.copyOf(this, this.size, Array<Any?>::class.java)
|
||||
|
||||
/**
|
||||
* Searches this list or its range for the provided [element] index using binary search algorithm.
|
||||
|
||||
@@ -35,17 +35,39 @@ class JavautilCollectionsTest {
|
||||
assertEquals(array.toList(), TEST_LIST)
|
||||
}
|
||||
|
||||
@test fun arrayListDoesNotCreateArrayView() {
|
||||
val array = arrayOf(1)
|
||||
val list = arrayListOf(*array)
|
||||
assertEquals(1, list[0])
|
||||
array[0] = 2
|
||||
assertEquals(1, list[0])
|
||||
@test fun toListDoesNotCreateArrayView() {
|
||||
snapshotDoesNotCreateView(arrayOf("first", "last"), { it.toList() })
|
||||
snapshotDoesNotCreateView(arrayOf<Any>("item", 1), { it.toList() })
|
||||
}
|
||||
|
||||
val arrayOfAny = arrayOf<Any>("first")
|
||||
val listOfAny = arrayListOf(*arrayOfAny)
|
||||
assertEquals("first", listOfAny[0])
|
||||
arrayOfAny[0] = "last"
|
||||
assertEquals("first", listOfAny[0])
|
||||
@test fun toMutableListDoesNotCreateArrayView() {
|
||||
snapshotDoesNotCreateView(arrayOf("first", "last"), { it.toMutableList() })
|
||||
snapshotDoesNotCreateView(arrayOf<Any>("item", 2), { it.toMutableList() })
|
||||
}
|
||||
|
||||
@test fun listOfDoesNotCreateView() {
|
||||
snapshotDoesNotCreateView(arrayOf("first", "last"), { listOf(*it) })
|
||||
snapshotDoesNotCreateView(arrayOf<Any>("item", 3), { listOf(*it) })
|
||||
}
|
||||
|
||||
@test fun mutableListOfDoesNotCreateView() {
|
||||
snapshotDoesNotCreateView(arrayOf("first", "last"), { mutableListOf(*it) })
|
||||
snapshotDoesNotCreateView(arrayOf<Any>("item", 4), { mutableListOf(*it) })
|
||||
}
|
||||
|
||||
@test fun arrayListDoesNotCreateArrayView() {
|
||||
snapshotDoesNotCreateView(arrayOf(1, 2), { arrayListOf(*it) })
|
||||
snapshotDoesNotCreateView(arrayOf<Any>("first", "last"), { arrayListOf(*it) })
|
||||
}
|
||||
|
||||
|
||||
private fun <T> snapshotDoesNotCreateView(array: Array<T>, snapshot: (Array<T>) -> List<T>) {
|
||||
val first = array.first()
|
||||
val last = array.last()
|
||||
|
||||
val list = snapshot(array)
|
||||
assertEquals(first, list[0])
|
||||
array[0] = last
|
||||
assertEquals(first, list[0])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user