From 59f88cfb523eab14e80eb74be242b47f126397d9 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Fri, 16 Oct 2015 05:12:43 +0300 Subject: [PATCH] Ensure vararg copy behavior for specific case of arrayListOf in JS. --- js/js.libraries/src/core/javautilCode.kt | 15 ++++++++++----- js/js.libraries/src/core/kotlin.kt | 4 ++++ libraries/stdlib/src/kotlin/collections/JUtil.kt | 15 +++++++++++---- .../stdlib/test/js/javautilCollectionsTest.kt | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/js/js.libraries/src/core/javautilCode.kt b/js/js.libraries/src/core/javautilCode.kt index c7e51323c09..50399886b5c 100644 --- a/js/js.libraries/src/core/javautilCode.kt +++ b/js/js.libraries/src/core/javautilCode.kt @@ -16,13 +16,18 @@ package java.util -public fun HashSet(c: Collection): HashSet = HashSet(c.size()).apply { addAll(c) } +public fun HashSet(c: Collection): HashSet + = HashSet(c.size()).apply { addAll(c) } -public fun LinkedHashSet(c: Collection): HashSet = LinkedHashSet(c.size()).apply { addAll(c) } +public fun LinkedHashSet(c: Collection): HashSet + = LinkedHashSet(c.size()).apply { addAll(c) } -public fun HashMap(m: Map): HashMap = HashMap(m.size()).apply { putAll(m) } +public fun HashMap(m: Map): HashMap + = HashMap(m.size()).apply { putAll(m) } -public fun LinkedHashMap(m: Map): LinkedHashMap = LinkedHashMap(m.size()).apply { putAll(m) } +public fun LinkedHashMap(m: Map): LinkedHashMap + = LinkedHashMap(m.size()).apply { putAll(m) } -public fun ArrayList(c: Collection): ArrayList = ArrayList().apply { asDynamic().array = c.toTypedArray() } // black dynamic magic +public fun ArrayList(c: Collection): ArrayList + = ArrayList().apply { asDynamic().array = c.toTypedArray() } // black dynamic magic diff --git a/js/js.libraries/src/core/kotlin.kt b/js/js.libraries/src/core/kotlin.kt index 24da6f117cd..2b1a01fc1c5 100644 --- a/js/js.libraries/src/core/kotlin.kt +++ b/js/js.libraries/src/core/kotlin.kt @@ -91,3 +91,7 @@ internal fun arrayPlusCollection(array: dynamic, collection: Collection): for (element in collection) result[index++] = element return result } + +// copies vararg array due to different spread vararg behavior in JS. +// After fixing #KT-6491 may return `this` +internal inline fun Array.varargToArrayOfAny(): Array = this.copyOf() diff --git a/libraries/stdlib/src/kotlin/collections/JUtil.kt b/libraries/stdlib/src/kotlin/collections/JUtil.kt index 23c8418154f..95187ecf927 100644 --- a/libraries/stdlib/src/kotlin/collections/JUtil.kt +++ b/libraries/stdlib/src/kotlin/collections/JUtil.kt @@ -50,8 +50,8 @@ private class ArrayAsCollection(val values: Array): Collection { override fun contains(o: T): Boolean = values.contains(o) override fun containsAll(c: Collection): Boolean = c.all { contains(it) } override fun iterator(): Iterator = values.iterator() - // override of hidden toArray method implementation to prevent copying of values array - public fun toArray(): Array = values + // override hidden toArray implementation to prevent copying of values array + public fun toArray(): Array = values.varargToArrayOfAny() } /** Returns an empty read-only list. The returned list is serializable (JVM). */ @@ -72,10 +72,12 @@ public fun listOf(value: T): List = Collections.singletonList(value) /** Returns a new [LinkedList] with the given elements. */ @JvmVersion -public fun linkedListOf(vararg values: T): LinkedList = LinkedList(ArrayAsCollection(values)) +public fun linkedListOf(vararg values: T): LinkedList + = if (values.size() == 0) LinkedList() else LinkedList(ArrayAsCollection(values)) /** Returns a new [ArrayList] with the given elements. */ -public fun arrayListOf(vararg values: T): ArrayList = ArrayList(ArrayAsCollection(values)) +public fun arrayListOf(vararg values: T): ArrayList + = if (values.size() == 0) ArrayList() else ArrayList(ArrayAsCollection(values)) /** 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 listOfNotNull(value: T?): List = if (value != null) listOf(value) else emptyList() @@ -146,6 +148,11 @@ internal fun Iterable.convertToSetForSetOperation(): Collection = else -> toHashSet() } +// copies typed varargs array to array of objects +@JvmVersion +private fun Array.varargToArrayOfAny(): Array + = Arrays.copyOf(this, this.size(), Array::class.java) + /** * Searches this list or its range for the provided [element] index using binary search algorithm. * The list is expected to be sorted into ascending order according to the Comparable natural ordering of its elements. diff --git a/libraries/stdlib/test/js/javautilCollectionsTest.kt b/libraries/stdlib/test/js/javautilCollectionsTest.kt index 72360e8e060..b4727769dd8 100644 --- a/libraries/stdlib/test/js/javautilCollectionsTest.kt +++ b/libraries/stdlib/test/js/javautilCollectionsTest.kt @@ -34,4 +34,18 @@ class JavautilCollectionsTest { val array = TEST_LIST.toTypedArray() 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]) + + val arrayOfAny = arrayOf("first") + val listOfAny = arrayListOf(*arrayOfAny) + assertEquals("first", listOfAny[0]) + arrayOfAny[0] = "last" + assertEquals("first", listOfAny[0]) + } }