Provide protected toArray implementation in AbstractCollection.

Relates to #KT-13898
This commit is contained in:
Ilya Gorbunov
2016-12-24 04:28:32 +03:00
parent bbf61664ea
commit cdfb72ab76
8 changed files with 71 additions and 11 deletions
@@ -8,10 +8,10 @@ open class SingletonCollection<T>(val value: T) : AbstractCollection<T>() {
override val size = 1
override fun iterator(): Iterator<T> = listOf(value).iterator()
protected fun toArray(): Array<Any?> =
protected override final fun toArray(): Array<Any?> =
arrayOf<Any?>(value)
protected fun <E> toArray(a: Array<E>): Array<E> {
protected override final fun <E> toArray(a: Array<E>): Array<E> {
a[0] = value as E
return a
}
@@ -8,10 +8,10 @@ open class SingletonCollection<T>(val value: T) : AbstractCollection<T>() {
override val size = 1
override fun iterator(): Iterator<T> = listOf(value).iterator()
protected open fun toArray(): Array<Any?> =
protected override fun toArray(): Array<Any?> =
arrayOf<Any?>(value)
protected open fun <E> toArray(a: Array<E>): Array<E> {
protected override fun <E> toArray(a: Array<E>): Array<E> {
a[0] = value as E
return a
}
+17 -1
View File
@@ -27,7 +27,7 @@ public inline fun <T> Collection<T>.toTypedArray(): Array<T> = copyToArray(this)
@JsName("copyToArray")
internal fun <T> copyToArray(collection: Collection<T>): Array<T> {
return if (collection.asDynamic().toArray !== undefined)
collection.asDynamic().toArray()
collection.asDynamic().toArray().unsafeCast<Array<T>>()
else
copyToArrayImpl(collection).unsafeCast<Array<T>>()
}
@@ -41,6 +41,22 @@ internal fun copyToArrayImpl(collection: Collection<*>): Array<Any?> {
return array
}
@JsName("copyToExistingArrayImpl")
internal fun <T> copyToArrayImpl(collection: Collection<*>, array: Array<T>): Array<T> {
if (array.size < collection.size)
return copyToArrayImpl(collection).unsafeCast<Array<T>>()
val iterator = collection.iterator()
var index = 0
while (iterator.hasNext()) {
array[index++] = iterator.next().unsafeCast<T>()
}
if (index < array.size) {
array[index] = null.unsafeCast<T>()
}
return array
}
@library("arrayToString")
internal fun arrayToString(array: Array<*>): String = noImpl
@@ -51,9 +51,6 @@ public abstract class AbstractMutableCollection<E> protected constructor() : Abs
}
}
// TODO: move somehow to AbstractCollection: can't move now, because it cannot be protected on JVM, just public
protected open fun toArray(): Array<Any?> = copyToArrayImpl(this)
open fun toJSON(): Any = this.toArray()
}
@@ -158,4 +158,8 @@ header operator fun <K, V> MutableMap<K, V>.set(key: K, value: V): Unit
// from Grouping.kt
public header fun <T, K> Grouping<T, K>.eachCount(): Map<K, Int>
// public header inline fun <T, K> Grouping<T, K>.eachSumOf(valueSelector: (T) -> Int): Map<K, Int>
// public header inline fun <T, K> Grouping<T, K>.eachSumOf(valueSelector: (T) -> Int): Map<K, Int>
internal header fun copyToArrayImpl(collection: Collection<*>): Array<Any?>
internal header fun <T> copyToArrayImpl(collection: Collection<*>, array: Array<T>): Array<T>
@@ -31,7 +31,14 @@ public abstract class AbstractCollection<out E> protected constructor() : Collec
if (it === this) "(this Collection)" else it.toString()
}
/**
* Returns new array of type `Array<Any?>` with the elements of this collection.
*/
protected open fun toArray(): Array<Any?> = copyToArrayImpl(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 <T> toArray(array: Array<T>): Array<T> = copyToArrayImpl(this, array)
}
@@ -182,6 +182,16 @@ internal fun <T> List<T>.optimizeReadOnlyList() = when (size) {
else -> this
}
@JvmVersion
@kotlin.internal.InlineOnly
internal inline fun copyToArrayImpl(collection: Collection<*>): Array<Any?> =
kotlin.jvm.internal.CollectionToArray.toArray(collection)
@JvmVersion
@kotlin.internal.InlineOnly
internal inline fun <T> copyToArrayImpl(collection: Collection<*>, array: Array<T>): Array<T> =
kotlin.jvm.internal.CollectionToArray.toArray(collection, array)
// copies typed varargs array to array of objects
@JvmVersion
private fun <T> Array<out T>.copyToArrayOfAny(isVarargs: Boolean): Array<Any?> =
@@ -905,4 +905,30 @@ class CollectionTest {
assertTrue(listOf(1) is RandomAccess, "Default singleton list is RandomAccess")
assertTrue(emptyList<Int>() is RandomAccess, "Empty list is RandomAccess")
}
@Test fun abstractCollectionToArray() {
class TestCollection<out E>(val data: Collection<E>) : AbstractCollection<E>() {
val invocations = mutableListOf<String>()
override val size get() = data.size
override fun iterator() = data.iterator()
override fun toArray(): Array<Any?> {
invocations += "toArray1"
return data.toTypedArray()
}
public override fun <T> toArray(array: Array<T>): Array<T> {
invocations += "toArray2"
return super.toArray(array)
}
}
val data = listOf("abc", "def")
val coll = TestCollection(data)
val arr1 = coll.toTypedArray()
assertEquals(data, arr1.asList())
assertTrue("toArray1" in coll.invocations || "toArray2" in coll.invocations)
val arr2: Array<String> = coll.toArray(Array(coll.size + 1) { "" })
assertEquals(data + listOf(null), arr2.asList())
}
}