Optimized toArray method for ArrayDeque and ListBuilder #KT-42720

This commit is contained in:
Abduqodiri Qurbonzoda
2021-01-22 13:12:50 +03:00
parent c2f6a2cb96
commit 421cb6971d
8 changed files with 194 additions and 23 deletions
@@ -130,13 +130,25 @@ internal class ListBuilder<E> private constructor(
return ListBuilder(array, offset + fromIndex, toIndex - fromIndex, isReadOnly, this, root ?: this)
}
@OptIn(ExperimentalStdlibApi::class)
private fun ensureCapacity(minCapacity: Int) {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ListBuilder
if (minCapacity > array.size) {
val newSize = ArrayDeque.newCapacity(array.size, minCapacity)
array = array.copyOfUninitializedElements(newSize)
override fun <T> toArray(destination: Array<T>): Array<T> {
if (destination.size < length) {
return java.util.Arrays.copyOfRange(array, offset, offset + length, destination.javaClass)
}
@Suppress("UNCHECKED_CAST")
(array as Array<T>).copyInto(destination, 0, startIndex = offset, endIndex = offset + length)
if (destination.size > length) {
@Suppress("UNCHECKED_CAST")
destination[length] = null as T // null-terminate
}
return destination
}
override fun toArray(): Array<Any?> {
@Suppress("UNCHECKED_CAST")
return array.copyOfRange(fromIndex = offset, toIndex = offset + length) as Array<Any?>
}
override fun equals(other: Any?): Boolean {
@@ -154,6 +166,14 @@ internal class ListBuilder<E> private constructor(
// ---------------------------- private ----------------------------
private fun ensureCapacity(minCapacity: Int) {
if (backing != null) throw IllegalStateException() // just in case somebody casts subList to ListBuilder
if (minCapacity > array.size) {
val newSize = ArrayDeque.newCapacity(array.size, minCapacity)
array = array.copyOfUninitializedElements(newSize)
}
}
private fun checkIsMutable() {
if (isReadOnly || root != null && root.isReadOnly) throw UnsupportedOperationException()
}
@@ -0,0 +1,60 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package test.collections
import kotlin.collections.builders.*
import kotlin.test.Test
import kotlin.test.assertSame
import kotlin.test.assertTrue
@Suppress("INVISIBLE_MEMBER")
class ListBuilderTest {
@Test
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
fun toArray() {
val numberOfElements = 5
val expected = ArrayList<Int>().apply { addAll(0 until numberOfElements) }
val builder = ListBuilder<Int>().apply { addAll(0 until numberOfElements) }
fun testToArray(getter: List<Int>.() -> Array<Any?>) {
assertTrue(expected.getter() contentEquals builder.getter())
assertTrue(expected.subList(2, 4).getter() contentEquals builder.subList(2, 4).getter())
}
testToArray { (this as java.util.Collection<Int>).toArray() }
}
@Test
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNCHECKED_CAST")
fun toArrayDestination() {
val numberOfElements = 5
val expected = ArrayList<Int>().apply { addAll(0 until numberOfElements) }
val builder = ListBuilder<Int>().apply { addAll(0 until numberOfElements) }
fun testToArray(destSize: Int, getter: List<Int>.(Array<Int>) -> Array<Int>) {
repeat(2) { index ->
val expectedDest = Array(destSize) { -it - 1 }
val builderDest = Array(destSize) { -it - 1 }
val takeSubList = index == 1
val expectedResult = (if (!takeSubList) expected else expected.subList(2, 4)).getter(expectedDest)
val builderResult = (if (!takeSubList) builder else builder.subList(2, 4)).getter(builderDest)
if (expectedResult.size <= expectedDest.size) {
assertSame(expectedDest, expectedResult)
assertSame(builderDest, builderResult)
}
assertTrue(expectedResult contentEquals builderResult)
}
}
testToArray(0) { (this as java.util.Collection<Int>).toArray(it) }
testToArray(numberOfElements - 1) { (this as java.util.Collection<Int>).toArray(it) }
testToArray(numberOfElements) { (this as java.util.Collection<Int>).toArray(it) }
testToArray(numberOfElements + 1) { (this as java.util.Collection<Int>).toArray(it) }
testToArray(numberOfElements + 2) { (this as java.util.Collection<Int>).toArray(it) }
}
}