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 val size = 1
override fun iterator(): Iterator<T> = listOf(value).iterator() override fun iterator(): Iterator<T> = listOf(value).iterator()
protected fun toArray(): Array<Any?> = protected override final fun toArray(): Array<Any?> =
arrayOf<Any?>(value) 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 a[0] = value as E
return a return a
} }
@@ -8,10 +8,10 @@ open class SingletonCollection<T>(val value: T) : AbstractCollection<T>() {
override val size = 1 override val size = 1
override fun iterator(): Iterator<T> = listOf(value).iterator() override fun iterator(): Iterator<T> = listOf(value).iterator()
protected open fun toArray(): Array<Any?> = protected override fun toArray(): Array<Any?> =
arrayOf<Any?>(value) 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 a[0] = value as E
return a return a
} }
+17 -1
View File
@@ -27,7 +27,7 @@ public inline fun <T> Collection<T>.toTypedArray(): Array<T> = copyToArray(this)
@JsName("copyToArray") @JsName("copyToArray")
internal fun <T> copyToArray(collection: Collection<T>): Array<T> { internal fun <T> copyToArray(collection: Collection<T>): Array<T> {
return if (collection.asDynamic().toArray !== undefined) return if (collection.asDynamic().toArray !== undefined)
collection.asDynamic().toArray() collection.asDynamic().toArray().unsafeCast<Array<T>>()
else else
copyToArrayImpl(collection).unsafeCast<Array<T>>() copyToArrayImpl(collection).unsafeCast<Array<T>>()
} }
@@ -41,6 +41,22 @@ internal fun copyToArrayImpl(collection: Collection<*>): Array<Any?> {
return array 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") @library("arrayToString")
internal fun arrayToString(array: Array<*>): String = noImpl 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() 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 // from Grouping.kt
public header fun <T, K> Grouping<T, K>.eachCount(): Map<K, Int> 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() 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 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 // copies typed varargs array to array of objects
@JvmVersion @JvmVersion
private fun <T> Array<out T>.copyToArrayOfAny(isVarargs: Boolean): Array<Any?> = 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(listOf(1) is RandomAccess, "Default singleton list is RandomAccess")
assertTrue(emptyList<Int>() is RandomAccess, "Empty 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())
}
} }