KT-54739 Return single empty inst from collection builders(all src-sets)
Fixed remaining builders, added additional checks to a test. ^KT-54739 fixed
This commit is contained in:
committed by
Space Team
parent
0c1d957711
commit
cadf4f63b0
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 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.
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,10 @@ package kotlin.collections
|
||||
* capacity and "growth increment" concepts.
|
||||
*/
|
||||
public actual open class ArrayList<E> internal constructor(private var array: Array<Any?>) : AbstractMutableList<E>(), MutableList<E>, RandomAccess {
|
||||
private companion object {
|
||||
private val Empty = ArrayList<Nothing>(0).also { it.isReadOnly = true }
|
||||
}
|
||||
|
||||
private var isReadOnly: Boolean = false
|
||||
|
||||
/**
|
||||
@@ -35,7 +39,7 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
|
||||
internal fun build(): List<E> {
|
||||
checkIsMutable()
|
||||
isReadOnly = true
|
||||
return this
|
||||
return if (size > 0) this else Empty
|
||||
}
|
||||
|
||||
/** Does nothing in this ArrayList implementation. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 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.
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,9 @@ import kotlin.collections.MutableMap.MutableEntry
|
||||
* The insertion order is preserved by maintaining a doubly-linked list of all of its entries.
|
||||
*/
|
||||
public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
|
||||
private companion object {
|
||||
private val Empty = LinkedHashMap<Nothing, Nothing>(0).also { it.isReadOnly = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* The entry we use includes next/prev pointers for a doubly-linked circular
|
||||
@@ -204,7 +207,8 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
|
||||
internal fun build(): Map<K, V> {
|
||||
checkIsMutable()
|
||||
isReadOnly = true
|
||||
return this
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return if (size > 0) this else (Empty as Map<K, V>)
|
||||
}
|
||||
|
||||
actual override fun clear() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2023 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.
|
||||
*/
|
||||
/*
|
||||
@@ -15,6 +15,11 @@ package kotlin.collections
|
||||
* This implementation preserves the insertion order of elements during the iteration.
|
||||
*/
|
||||
public actual open class LinkedHashSet<E> : HashSet<E>, MutableSet<E> {
|
||||
private companion object {
|
||||
private val Empty = LinkedHashSet<Nothing>(0).also {
|
||||
(it.map as LinkedHashMap<Nothing, Any>).build()
|
||||
}
|
||||
}
|
||||
|
||||
internal constructor(map: LinkedHashMap<E, Any>) : super(map)
|
||||
|
||||
@@ -45,7 +50,7 @@ public actual open class LinkedHashSet<E> : HashSet<E>, MutableSet<E> {
|
||||
@PublishedApi
|
||||
internal fun build(): Set<E> {
|
||||
(map as LinkedHashMap<E, Any>).build()
|
||||
return this
|
||||
return if (size > 0) this else Empty
|
||||
}
|
||||
|
||||
internal override fun checkIsMutable(): Unit = map.checkIsMutable()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,9 @@ actual class ArrayList<E> private constructor(
|
||||
private val backingList: ArrayList<E>?,
|
||||
private val root: ArrayList<E>?
|
||||
) : MutableList<E>, RandomAccess, AbstractMutableList<E>() {
|
||||
private companion object {
|
||||
private val Empty = ArrayList<Nothing>(0).also { it.isReadOnly = true }
|
||||
}
|
||||
|
||||
actual constructor() : this(10)
|
||||
|
||||
@@ -28,7 +31,7 @@ actual class ArrayList<E> private constructor(
|
||||
if (backingList != null) throw IllegalStateException() // just in case somebody casts subList to ArrayList
|
||||
checkIsMutable()
|
||||
isReadOnly = true
|
||||
return this
|
||||
return if (length > 0) this else Empty
|
||||
}
|
||||
|
||||
override actual val size: Int
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,7 @@ actual class HashMap<K, V> private constructor(
|
||||
internal fun build(): Map<K, V> {
|
||||
checkIsMutable()
|
||||
isReadOnly = true
|
||||
return this
|
||||
return if (size > 0) this else EmptyHolder.value()
|
||||
}
|
||||
|
||||
override actual fun isEmpty(): Boolean = _size == 0
|
||||
@@ -488,6 +488,15 @@ actual class HashMap<K, V> private constructor(
|
||||
private fun computeShift(hashSize: Int): Int = hashSize.countLeadingZeroBits() + 1
|
||||
}
|
||||
|
||||
internal object EmptyHolder {
|
||||
val value_ = HashMap<Nothing, Nothing>(0).also { it.isReadOnly = true }
|
||||
|
||||
fun <K, V> value(): HashMap<K, V> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return value_ as HashMap<K, V>
|
||||
}
|
||||
}
|
||||
|
||||
internal open class Itr<K, V>(
|
||||
internal val map: HashMap<K, V>
|
||||
) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,9 @@ package kotlin.collections
|
||||
actual class HashSet<E> internal constructor(
|
||||
private val backing: HashMap<E, *>
|
||||
) : MutableSet<E>, kotlin.native.internal.KonanSet<E>, AbstractMutableSet<E>() {
|
||||
private companion object {
|
||||
private val Empty = HashSet(HashMap.EmptyHolder.value<Nothing, Nothing>())
|
||||
}
|
||||
|
||||
actual constructor() : this(HashMap<E, Nothing>())
|
||||
|
||||
@@ -23,7 +26,7 @@ actual class HashSet<E> internal constructor(
|
||||
@PublishedApi
|
||||
internal fun build(): Set<E> {
|
||||
backing.build()
|
||||
return this
|
||||
return if (size > 0) this else Empty
|
||||
}
|
||||
|
||||
override actual val size: Int get() = backing.size
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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 test.collections.behaviors.listBehavior
|
||||
@@ -57,6 +62,38 @@ class ContainerBuilderTest {
|
||||
"entries.iterator().next().setValue(v)" to { entries.iterator().next().setValue(v) }
|
||||
)
|
||||
|
||||
private fun <E> emptyCollectionOperations(value: E) = listOf<Pair<String, MutableCollection<E>.() -> Unit>> (
|
||||
"add(value)" to { add(value) },
|
||||
|
||||
"addAll(listOf(value))" to { addAll(listOf(value)) },
|
||||
"addAll(emptyList())" to { addAll(emptyList()) },
|
||||
|
||||
"remove(value)" to { remove(value) },
|
||||
|
||||
"removeAll(listOf(value))" to { removeAll(listOf(value)) },
|
||||
"removeAll(emptyList())" to { removeAll(emptyList()) },
|
||||
|
||||
"retainAll(listOf(value))" to { retainAll(listOf(value)) },
|
||||
"retailAll(emptyList())" to { retainAll(emptyList()) },
|
||||
|
||||
"clear()" to { clear() }
|
||||
)
|
||||
|
||||
private fun <E> emptyListOperations(value: E) = emptyCollectionOperations(value) + listOf<Pair<String, MutableList<E>.() -> Unit>>(
|
||||
"add(0, value)" to { add(0, value) },
|
||||
"addAll(0, listOf(value))" to { addAll(0, listOf(value)) },
|
||||
"addAll(0, emptyList())" to { addAll(0, emptyList()) },
|
||||
"listIterator().add(value)" to { listIterator().add(value) }
|
||||
)
|
||||
|
||||
private fun <K, V> emptyMapOperations(k: K, v: V) = listOf<Pair<String, MutableMap<K, V>.() -> Unit>>(
|
||||
"put(k, v)" to { put(k, v) },
|
||||
"remove(k)" to { remove(k) },
|
||||
"putAll(mapOf(k to v))" to { putAll(mapOf(k to v)) },
|
||||
"putAll(emptyMap())" to { putAll(emptyMap()) },
|
||||
"clear()" to { clear() }
|
||||
)
|
||||
|
||||
@Test
|
||||
fun buildList() {
|
||||
val x = buildList {
|
||||
@@ -91,6 +128,22 @@ class ContainerBuilderTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun buildEmptyList() {
|
||||
val empty = buildList<Int> {}
|
||||
assertSame(empty, buildList {})
|
||||
assertTrue(empty is MutableList<Int>)
|
||||
for ((fName, operation) in emptyListOperations(0)) {
|
||||
assertFailsWith<UnsupportedOperationException>("empty.$fName") { empty.operation() }
|
||||
}
|
||||
|
||||
assertEquals(0, empty.size)
|
||||
assertTrue(empty.isEmpty())
|
||||
assertFalse(empty.contains(42))
|
||||
assertFalse(empty.containsAll(listOf(42)))
|
||||
assertTrue(empty.containsAll(emptyList()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun listBuilderSubList() {
|
||||
buildList<Char> {
|
||||
@@ -150,6 +203,22 @@ class ContainerBuilderTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun buildEmptySet() {
|
||||
val empty = buildSet<Int> {}
|
||||
assertSame(empty, buildSet {})
|
||||
assertTrue(empty is MutableSet<Int>)
|
||||
for ((fName, operation) in emptyCollectionOperations(0)) {
|
||||
assertFailsWith<UnsupportedOperationException>("empty.$fName") { empty.operation() }
|
||||
}
|
||||
|
||||
assertEquals(0, empty.size)
|
||||
assertTrue(empty.isEmpty())
|
||||
assertFalse(empty.contains(42))
|
||||
assertFalse(empty.containsAll(listOf(42)))
|
||||
assertTrue(empty.containsAll(emptyList()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun buildMap() {
|
||||
val x = buildMap<Char, Int> {
|
||||
@@ -191,4 +260,20 @@ class ContainerBuilderTest {
|
||||
assertFailsWith<UnsupportedOperationException>("y.entries.$fName") { y.entries.operation() }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testBuildEmptyMap() {
|
||||
val empty = buildMap<Char, Int> {}
|
||||
assertSame(empty, buildMap {})
|
||||
assertTrue(empty is MutableMap<Char, Int>)
|
||||
for ((fName, operation) in emptyMapOperations('0', 0)) {
|
||||
assertFailsWith<UnsupportedOperationException>("empty.$fName") { empty.operation() }
|
||||
}
|
||||
|
||||
assertEquals(0, empty.size)
|
||||
assertTrue(empty.isEmpty())
|
||||
assertFalse(empty.contains('0'))
|
||||
assertFalse(empty.containsKey('0'))
|
||||
assertFalse(empty.containsValue(0))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user