diff --git a/backend.native/tests/external/stdlib/collections/CollectionTest/abstractCollectionToArray.kt b/backend.native/tests/external/stdlib/collections/CollectionTest/abstractCollectionToArray.kt index 6418b8b4742..1070df762e3 100644 --- a/backend.native/tests/external/stdlib/collections/CollectionTest/abstractCollectionToArray.kt +++ b/backend.native/tests/external/stdlib/collections/CollectionTest/abstractCollectionToArray.kt @@ -3,28 +3,30 @@ import kotlin.comparisons.* fun box() { class TestCollection(val data: Collection) : AbstractCollection() { - val invocations = mutableListOf() override val size get() = data.size override fun iterator() = data.iterator() - override fun toArray(): Array { - invocations += "toArray1" - return data.toTypedArray() - } - - public override fun toArray(array: Array): Array { - invocations += "toArray2" - return super.toArray(array) - } + public override fun toArray(): Array = super.toArray() + public override fun toArray(array: Array): Array = super.toArray(array) } - val data = listOf("abc", "def") - val coll = TestCollection(data) + val data = listOf(1, 2, 3) + assertEquals(TestCollection(data).toArray().asList(), data) + assertEquals(TestCollection(listOf()).toArray().size, 0) - val arr1 = coll.toTypedArray() - assertEquals(data, arr1.asList()) - assertTrue("toArray1" in coll.invocations || "toArray2" in coll.invocations) + var arr1 = Array(3) { -1 } + var arr2 = TestCollection(data).toArray(arr1) + assertTrue(arr1 === arr2) + assertEquals(arr2.asList(), data) + + arr1 = Array(4) { -1 } + arr2 = TestCollection(data).toArray(arr1) + assertTrue(arr1 === arr2) + assertEquals(arr2.asList(), data + listOf(-1)) + + arr1 = Array(2) { -1 } + arr2 = TestCollection(data).toArray(arr1) + assertFalse(arr1 === arr2) + assertEquals(arr2.asList(), data) - val arr2: Array = coll.toArray(Array(coll.size + 1) { "" }) - assertEquals(data + listOf(null), arr2.asList()) } diff --git a/runtime/src/main/kotlin/kotlin/collections/AbstractCollection.kt b/runtime/src/main/kotlin/kotlin/collections/AbstractCollection.kt index d90b065087a..451bdfa4e02 100644 --- a/runtime/src/main/kotlin/kotlin/collections/AbstractCollection.kt +++ b/runtime/src/main/kotlin/kotlin/collections/AbstractCollection.kt @@ -16,6 +16,12 @@ package kotlin.collections +/** + * Provides a skeletal implementation of the read-only [Collection] interface. + * + * @param E the type of elements contained in the collection. The collection is covariant on its element type. + */ +@SinceKotlin("1.1") public abstract class AbstractCollection protected constructor() : Collection { abstract override val size: Int abstract override fun iterator(): Iterator @@ -31,4 +37,15 @@ public abstract class AbstractCollection protected constructor() : Collec override fun toString(): String = joinToString(", ", "[", "]") { if (it === this) "(this Collection)" else it.toString() } + + /** + * Returns new array of type `Array` with the elements of this collection. + */ + protected open fun toArray(): Array = collectionToArray(this) + + /** + * Fills the provided [array] or creates new array of the same type + * and fills it with the elements of this collection. + */ + protected open fun toArray(array: Array): Array = collectionToArray(this, array) } diff --git a/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt b/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt index 5d09a8e9e75..579d6daf3cd 100644 --- a/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt +++ b/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt @@ -55,6 +55,33 @@ fun Array.copyOfNulls(fromIndex: Int, toIndex: Int): Array { return result } +/** + * Copies elements of the [collection] into the given [array]. + * If the array is too small, allocates a new one of collection.size size. + * @return [array] with the elements copied from the collection. + */ +internal fun collectionToArray(collection: Collection, array: Array): Array { + val toArray = if (collection.size > array.size) { + arrayOfUninitializedElements(collection.size) + } else { + array + } + var i = 0 + // TODO: What about a concurrent modification of the collection? Do we need to handle it here? + for (v in collection) { + toArray[i] = v as T + i++ + } + return toArray +} + +/** + * Creates an array of collection.size size and copies elements of the [collection] into it. + * @return [array] with the elements copied from the collection. + */ +internal fun collectionToArray(collection: Collection): Array + = collectionToArray(collection, arrayOfUninitializedElements(collection.size)) + /** * Returns new array which is a copy of the original array's range between [fromIndex] (inclusive) * and [toIndex] (exclusive) with new elements filled with **lateinit** _uninitialized_ values.