Decommonize collection builder implementations

This commit is contained in:
Abduqodiri Qurbonzoda
2020-04-30 11:40:17 +03:00
parent 379c6944a2
commit f3145454f2
20 changed files with 471 additions and 169 deletions
+54 -1
View File
@@ -49,22 +49,75 @@ internal actual fun <T> copyToArrayImpl(collection: Collection<*>, array: Array<
return array
}
/**
* Returns an immutable list containing only the specified object [element].
*/
public fun <T> listOf(element: T): List<T> = arrayListOf(element)
@PublishedApi
@SinceKotlin("1.3")
@ExperimentalStdlibApi
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildListInternal(builderAction: MutableList<E>.() -> Unit): List<E> {
return ArrayList<E>().apply(builderAction).build()
}
@PublishedApi
@SinceKotlin("1.3")
@ExperimentalStdlibApi
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildListInternal(capacity: Int, builderAction: MutableList<E>.() -> Unit): List<E> {
checkBuilderCapacity(capacity)
return ArrayList<E>(capacity).apply(builderAction).build()
}
/**
* Returns an immutable set containing only the specified object [element].
*/
public fun <T> setOf(element: T): Set<T> = hashSetOf(element)
@PublishedApi
@SinceKotlin("1.3")
@ExperimentalStdlibApi
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildSetInternal(builderAction: MutableSet<E>.() -> Unit): Set<E> {
return LinkedHashSet<E>().apply(builderAction).build()
}
@PublishedApi
@SinceKotlin("1.3")
@ExperimentalStdlibApi
@kotlin.internal.InlineOnly
internal actual inline fun <E> buildSetInternal(capacity: Int, builderAction: MutableSet<E>.() -> Unit): Set<E> {
return LinkedHashSet<E>(capacity).apply(builderAction).build()
}
/**
* Returns an immutable map, mapping only the specified key to the
* specified value.
*/
public fun <K, V> mapOf(pair: Pair<K, V>): Map<K, V> = hashMapOf(pair)
@PublishedApi
@SinceKotlin("1.3")
@ExperimentalStdlibApi
@kotlin.internal.InlineOnly
internal actual inline fun <K, V> buildMapInternal(builderAction: MutableMap<K, V>.() -> Unit): Map<K, V> {
return LinkedHashMap<K, V>().apply(builderAction).build()
}
@PublishedApi
@SinceKotlin("1.3")
@ExperimentalStdlibApi
@kotlin.internal.InlineOnly
internal actual inline fun <K, V> buildMapInternal(capacity: Int, builderAction: MutableMap<K, V>.() -> Unit): Map<K, V> {
return LinkedHashMap<K, V>(capacity).apply(builderAction).build()
}
/**
* Fills the list with the provided [value].
*
@@ -196,6 +249,6 @@ internal actual fun mapCapacity(expectedSize: Int) = expectedSize
@SinceKotlin("1.3")
@ExperimentalStdlibApi
@PublishedApi
internal actual fun checkBuilderCapacity(capacity: Int) {
internal fun checkBuilderCapacity(capacity: Int) {
require(capacity >= 0) { "capacity must be non-negative." }
}
@@ -15,6 +15,7 @@ public actual abstract class AbstractMutableCollection<E> protected actual const
actual abstract override fun add(element: E): Boolean
actual override fun remove(element: E): Boolean {
checkIsMutable()
val iterator = iterator()
while (iterator.hasNext()) {
if (iterator.next() == element) {
@@ -26,6 +27,7 @@ public actual abstract class AbstractMutableCollection<E> protected actual const
}
actual override fun addAll(elements: Collection<E>): Boolean {
checkIsMutable()
var modified = false
for (element in elements) {
if (add(element)) modified = true
@@ -33,10 +35,18 @@ public actual abstract class AbstractMutableCollection<E> protected actual const
return modified
}
actual override fun removeAll(elements: Collection<E>): Boolean = (this as MutableIterable<E>).removeAll { it in elements }
actual override fun retainAll(elements: Collection<E>): Boolean = (this as MutableIterable<E>).removeAll { it !in elements }
actual override fun removeAll(elements: Collection<E>): Boolean {
checkIsMutable()
return (this as MutableIterable<E>).removeAll { it in elements }
}
actual override fun retainAll(elements: Collection<E>): Boolean {
checkIsMutable()
return (this as MutableIterable<E>).removeAll { it !in elements }
}
actual override fun clear(): Unit {
checkIsMutable()
val iterator = this.iterator()
while (iterator.hasNext()) {
iterator.next()
@@ -46,5 +56,12 @@ public actual abstract class AbstractMutableCollection<E> protected actual const
@JsName("toJSON")
open fun toJSON(): Any = this.toArray()
/**
* This method is called every time when a mutating method is called on this mutable collection.
* Mutable collections that are built (frozen) must throw `UnsupportedOperationException`.
*/
internal open fun checkIsMutable(): Unit { }
}
@@ -28,11 +28,13 @@ public actual abstract class AbstractMutableList<E> protected actual constructor
* @return `true` because the list is always modified as the result of this operation.
*/
actual override fun add(element: E): Boolean {
checkIsMutable()
add(size, element)
return true
}
actual override fun addAll(index: Int, elements: Collection<E>): Boolean {
checkIsMutable()
var _index = index
var changed = false
for (e in elements) {
@@ -43,11 +45,19 @@ public actual abstract class AbstractMutableList<E> protected actual constructor
}
actual override fun clear() {
checkIsMutable()
removeRange(0, size)
}
actual override fun removeAll(elements: Collection<E>): Boolean = removeAll { it in elements }
actual override fun retainAll(elements: Collection<E>): Boolean = removeAll { it !in elements }
actual override fun removeAll(elements: Collection<E>): Boolean {
checkIsMutable()
return removeAll { it in elements }
}
actual override fun retainAll(elements: Collection<E>): Boolean {
checkIsMutable()
return removeAll { it !in elements }
}
actual override fun iterator(): MutableIterator<E> = IteratorImpl()
@@ -164,7 +174,7 @@ public actual abstract class AbstractMutableList<E> protected actual constructor
override fun set(element: E) {
check(last != -1) { "Call next() or previous() before updating element value with the iterator." }
this@AbstractMutableList[last] = element
set(last, element)
}
}
@@ -204,6 +214,8 @@ public actual abstract class AbstractMutableList<E> protected actual constructor
}
override val size: Int get() = _size
internal override fun checkIsMutable(): Unit = list.checkIsMutable()
}
}
@@ -30,6 +30,10 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
override val value: V get() = _value
override fun setValue(newValue: V): V {
// Should check if the map containing this entry is mutable.
// However, to not increase entry memory footprint it might be worthwhile not to check it here and
// force subclasses that implement `build()` (freezing) operation to implement their own `MutableEntry`.
// this@AbstractMutableMap.checkIsMutable()
val oldValue = this._value
this._value = newValue
return oldValue
@@ -67,6 +71,7 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
}
override fun remove(element: K): Boolean {
checkIsMutable()
if (containsKey(element)) {
this@AbstractMutableMap.remove(element)
return true
@@ -75,6 +80,8 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
}
override val size: Int get() = this@AbstractMutableMap.size
override fun checkIsMutable(): Unit = this@AbstractMutableMap.checkIsMutable()
}
}
return _keys!!
@@ -83,6 +90,7 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
actual abstract override fun put(key: K, value: V): V?
actual override fun putAll(from: Map<out K, V>) {
checkIsMutable()
for ((key, value) in from) {
put(key, value)
}
@@ -117,12 +125,15 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
}
override fun hashCode(): Int = AbstractList.orderedHashCode(this)
override fun checkIsMutable(): Unit = this@AbstractMutableMap.checkIsMutable()
}
}
return _values!!
}
actual override fun remove(key: K): V? {
checkIsMutable()
val iter = entries.iterator()
while (iter.hasNext()) {
val entry = iter.next()
@@ -136,4 +147,10 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
return null
}
/**
* This method is called every time when a mutating method is called on this mutable map.
* Mutable maps that are built (frozen) must throw `UnsupportedOperationException`.
*/
internal open fun checkIsMutable(): Unit {}
}
@@ -13,6 +13,7 @@ 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 var isReadOnly: Boolean = false
/**
* Creates an empty [ArrayList].
@@ -31,6 +32,13 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
*/
public actual constructor(elements: Collection<E>) : this(elements.toTypedArray<Any?>()) {}
@PublishedApi
internal fun build(): List<E> {
checkIsMutable()
isReadOnly = true
return this
}
/** Does nothing in this ArrayList implementation. */
public actual fun trimToSize() {}
@@ -41,23 +49,27 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
@Suppress("UNCHECKED_CAST")
actual override fun get(index: Int): E = array[rangeCheck(index)] as E
actual override fun set(index: Int, element: E): E {
checkIsMutable()
rangeCheck(index)
@Suppress("UNCHECKED_CAST")
return array[index].apply { array[index] = element } as E
}
actual override fun add(element: E): Boolean {
checkIsMutable()
array.asDynamic().push(element)
modCount++
return true
}
actual override fun add(index: Int, element: E): Unit {
checkIsMutable()
array.asDynamic().splice(insertionRangeCheck(index), 0, element)
modCount++
}
actual override fun addAll(elements: Collection<E>): Boolean {
checkIsMutable()
if (elements.isEmpty()) return false
array += elements.toTypedArray<Any?>()
@@ -66,6 +78,7 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
}
actual override fun addAll(index: Int, elements: Collection<E>): Boolean {
checkIsMutable()
insertionRangeCheck(index)
if (index == size) return addAll(elements)
@@ -81,6 +94,7 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
}
actual override fun removeAt(index: Int): E {
checkIsMutable()
rangeCheck(index)
modCount++
return if (index == lastIndex)
@@ -90,6 +104,7 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
}
actual override fun remove(element: E): Boolean {
checkIsMutable()
for (index in array.indices) {
if (array[index] == element) {
array.asDynamic().splice(index, 1)
@@ -101,11 +116,13 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
}
override fun removeRange(fromIndex: Int, toIndex: Int) {
checkIsMutable()
modCount++
array.asDynamic().splice(fromIndex, toIndex - fromIndex)
}
actual override fun clear() {
checkIsMutable()
array = emptyArray()
modCount++
}
@@ -119,6 +136,10 @@ public actual open class ArrayList<E> internal constructor(private var array: Ar
override fun toArray(): Array<Any?> = js("[]").slice.call(array)
internal override fun checkIsMutable() {
if (isReadOnly) throw UnsupportedOperationException()
}
private fun rangeCheck(index: Int) = index.apply {
AbstractList.checkElementIndex(index, size)
}
@@ -16,6 +16,8 @@ import kotlin.collections.MutableMap.MutableEntry
*
* This implementation makes no guarantees regarding the order of enumeration of [keys], [values] and [entries] collections.
*/
// Classes that extend HashMap and implement `build()` (freezing) operation
// have to make sure mutating methods check `checkIsMutable`.
public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K, V> {
private inner class EntrySet : AbstractMutableSet<MutableEntry<K, V>>() {
@@ -12,9 +12,11 @@ package kotlin.collections
/**
* The implementation of the [MutableSet] interface, backed by a [HashMap] instance.
*/
// Classes that extend HashSet and implement `build()` (freezing) operation
// have to make sure mutating methods check `checkIsMutable`.
public actual open class HashSet<E> : AbstractMutableSet<E>, MutableSet<E> {
private val map: HashMap<E, Any>
internal val map: HashMap<E, Any>
/**
* Constructs a new empty [HashSet].
@@ -30,9 +30,14 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
* small modifications. Paying a small storage cost only if you use
* LinkedHashMap and minimizing code size seemed like a better tradeoff
*/
private class ChainEntry<K, V>(key: K, value: V) : AbstractMutableMap.SimpleEntry<K, V>(key, value) {
private inner class ChainEntry<K, V>(key: K, value: V) : AbstractMutableMap.SimpleEntry<K, V>(key, value) {
internal var next: ChainEntry<K, V>? = null
internal var prev: ChainEntry<K, V>? = null
override fun setValue(newValue: V): V {
this@LinkedHashMap.checkIsMutable()
return super.setValue(newValue)
}
}
private inner class EntrySet : AbstractMutableSet<MutableEntry<K, V>>() {
@@ -65,6 +70,7 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
override fun remove() {
check(last != null)
this@EntrySet.checkIsMutable()
// checkStructuralChange(map, this)
last!!.remove()
@@ -84,6 +90,7 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = EntryIterator()
override fun remove(element: MutableEntry<K, V>): Boolean {
checkIsMutable()
if (contains(element)) {
this@LinkedHashMap.remove(element.key)
return true
@@ -92,6 +99,8 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
}
override val size: Int get() = this@LinkedHashMap.size
override fun checkIsMutable(): Unit = this@LinkedHashMap.checkIsMutable()
}
@@ -154,6 +163,8 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
*/
private val map: HashMap<K, ChainEntry<K, V>>
private var isReadOnly: Boolean = false
/**
* Constructs an empty [LinkedHashMap] instance.
*/
@@ -189,7 +200,15 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
this.putAll(original)
}
@PublishedApi
internal fun build(): Map<K, V> {
checkIsMutable()
isReadOnly = true
return this
}
actual override fun clear() {
checkIsMutable()
map.clear()
head = null
}
@@ -219,6 +238,8 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
actual override operator fun get(key: K): V? = map.get(key)?.value
actual override fun put(key: K, value: V): V? {
checkIsMutable()
val old = map.get(key)
if (old == null) {
val newEntry = ChainEntry(key, value)
@@ -231,6 +252,8 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
}
actual override fun remove(key: K): V? {
checkIsMutable()
val entry = map.remove(key)
if (entry != null) {
entry.remove()
@@ -241,6 +264,9 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
actual override val size: Int get() = map.size
internal override fun checkIsMutable() {
if (isReadOnly) throw UnsupportedOperationException()
}
}
/**
@@ -43,6 +43,14 @@ public actual open class LinkedHashSet<E> : HashSet<E>, MutableSet<E> {
actual constructor(initialCapacity: Int) : this(initialCapacity, 0.0f)
@PublishedApi
internal fun build(): Set<E> {
(map as LinkedHashMap<E, Any>).build()
return this
}
internal override fun checkIsMutable(): Unit = map.checkIsMutable()
// public override fun clone(): Any {
// return LinkedHashSet(this)
// }