[JS IR] Rework HashMapEntries, get rid of LinkedHashMap
^KT-59001
This commit is contained in:
committed by
Space Team
parent
f202865080
commit
2300facead
@@ -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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -20,82 +20,22 @@ package kotlin.collections
|
|||||||
*/
|
*/
|
||||||
public actual abstract class AbstractMutableMap<K, V> protected actual constructor() : AbstractMap<K, V>(), MutableMap<K, V> {
|
public actual abstract class AbstractMutableMap<K, V> protected actual constructor() : AbstractMap<K, V>(), MutableMap<K, V> {
|
||||||
|
|
||||||
/**
|
internal open fun createKeysView(): MutableSet<K> = HashMapKeysDefault(this)
|
||||||
* A mutable [Map.Entry] shared by several [Map] implementations.
|
internal open fun createValuesView(): MutableCollection<V> = HashMapValuesDefault(this)
|
||||||
*/
|
|
||||||
internal open class SimpleEntry<K, V>(override val key: K, value: V) : MutableMap.MutableEntry<K, V> {
|
|
||||||
constructor(entry: Map.Entry<K, V>) : this(entry.key, entry.value)
|
|
||||||
|
|
||||||
private var _value = value
|
private var keysView: MutableSet<K>? = null
|
||||||
|
private var valuesView: MutableCollection<V>? = null
|
||||||
|
|
||||||
override val value: V get() = _value
|
actual override val keys: MutableSet<K>
|
||||||
|
get() = keysView ?: createKeysView().also { keysView = it }
|
||||||
|
|
||||||
override fun setValue(newValue: V): V {
|
actual override val values: MutableCollection<V>
|
||||||
// Should check if the map containing this entry is mutable.
|
get() = valuesView ?: createValuesView().also { valuesView = it }
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int = entryHashCode(this)
|
|
||||||
override fun toString(): String = entryToString(this)
|
|
||||||
override fun equals(other: Any?): Boolean = entryEquals(this, other)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// intermediate abstract class to workaround KT-43321
|
|
||||||
internal abstract class AbstractEntrySet<E : Map.Entry<K, V>, K, V> : AbstractMutableSet<E>() {
|
|
||||||
final override fun contains(element: E): Boolean = containsEntry(element)
|
|
||||||
abstract fun containsEntry(element: Map.Entry<K, V>): Boolean
|
|
||||||
final override fun remove(element: E): Boolean = removeEntry(element)
|
|
||||||
abstract fun removeEntry(element: Map.Entry<K, V>): Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
actual override fun clear() {
|
actual override fun clear() {
|
||||||
entries.clear()
|
entries.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _keys: MutableSet<K>? = null
|
|
||||||
actual override val keys: MutableSet<K>
|
|
||||||
get() {
|
|
||||||
if (_keys == null) {
|
|
||||||
_keys = object : AbstractMutableSet<K>() {
|
|
||||||
override fun add(element: K): Boolean = throw UnsupportedOperationException("Add is not supported on keys")
|
|
||||||
override fun clear() {
|
|
||||||
this@AbstractMutableMap.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun contains(element: K): Boolean = containsKey(element)
|
|
||||||
|
|
||||||
override operator fun iterator(): MutableIterator<K> {
|
|
||||||
val entryIterator = entries.iterator()
|
|
||||||
return object : MutableIterator<K> {
|
|
||||||
override fun hasNext(): Boolean = entryIterator.hasNext()
|
|
||||||
override fun next(): K = entryIterator.next().key
|
|
||||||
override fun remove() = entryIterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove(element: K): Boolean {
|
|
||||||
checkIsMutable()
|
|
||||||
if (containsKey(element)) {
|
|
||||||
this@AbstractMutableMap.remove(element)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int get() = this@AbstractMutableMap.size
|
|
||||||
|
|
||||||
override fun checkIsMutable(): Unit = this@AbstractMutableMap.checkIsMutable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _keys!!
|
|
||||||
}
|
|
||||||
|
|
||||||
actual abstract override fun put(key: K, value: V): V?
|
actual abstract override fun put(key: K, value: V): V?
|
||||||
|
|
||||||
actual override fun putAll(from: Map<out K, V>) {
|
actual override fun putAll(from: Map<out K, V>) {
|
||||||
@@ -105,33 +45,6 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _values: MutableCollection<V>? = null
|
|
||||||
actual override val values: MutableCollection<V>
|
|
||||||
get() {
|
|
||||||
if (_values == null) {
|
|
||||||
_values = object : AbstractMutableCollection<V>() {
|
|
||||||
override fun add(element: V): Boolean = throw UnsupportedOperationException("Add is not supported on values")
|
|
||||||
override fun clear() = this@AbstractMutableMap.clear()
|
|
||||||
|
|
||||||
override operator fun contains(element: V): Boolean = containsValue(element)
|
|
||||||
|
|
||||||
override operator fun iterator(): MutableIterator<V> {
|
|
||||||
val entryIterator = entries.iterator()
|
|
||||||
return object : MutableIterator<V> {
|
|
||||||
override fun hasNext(): Boolean = entryIterator.hasNext()
|
|
||||||
override fun next(): V = entryIterator.next().value
|
|
||||||
override fun remove() = entryIterator.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int get() = this@AbstractMutableMap.size
|
|
||||||
|
|
||||||
override fun checkIsMutable(): Unit = this@AbstractMutableMap.checkIsMutable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _values!!
|
|
||||||
}
|
|
||||||
|
|
||||||
actual override fun remove(key: K): V? {
|
actual override fun remove(key: K): V? {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
val iter = entries.iterator()
|
val iter = entries.iterator()
|
||||||
@@ -152,5 +65,5 @@ public actual abstract class AbstractMutableMap<K, V> protected actual construct
|
|||||||
* This method is called every time when a mutating method is called on this mutable map.
|
* 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`.
|
* Mutable maps that are built (frozen) must throw `UnsupportedOperationException`.
|
||||||
*/
|
*/
|
||||||
internal open fun checkIsMutable(): Unit {}
|
internal open fun checkIsMutable() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -20,34 +20,10 @@ import kotlin.collections.MutableMap.MutableEntry
|
|||||||
// Classes that extend HashMap and implement `build()` (freezing) operation
|
// Classes that extend HashMap and implement `build()` (freezing) operation
|
||||||
// have to make sure mutating methods check `checkIsMutable`.
|
// have to make sure mutating methods check `checkIsMutable`.
|
||||||
public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K, V> {
|
public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K, V> {
|
||||||
|
|
||||||
private inner class EntrySet : AbstractEntrySet<MutableEntry<K, V>, K, V>() {
|
|
||||||
|
|
||||||
override fun add(element: MutableEntry<K, V>): Boolean = throw UnsupportedOperationException("Add is not supported on entries")
|
|
||||||
override fun clear() {
|
|
||||||
this@HashMap.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsEntry(element: Map.Entry<K, V>): Boolean = this@HashMap.containsEntry(element)
|
|
||||||
|
|
||||||
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = internalMap.entriesIterator()
|
|
||||||
|
|
||||||
override fun removeEntry(element: Map.Entry<K, V>): Boolean {
|
|
||||||
if (contains(element)) {
|
|
||||||
this@HashMap.remove(element.key)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int get() = this@HashMap.size
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal implementation of the map: either string-based or hashcode-based.
|
* Internal implementation of the map: either string-based or hashcode-based.
|
||||||
*/
|
*/
|
||||||
private val internalMap: InternalMap<K, V>
|
internal val internalMap: InternalMap<K, V>
|
||||||
|
|
||||||
internal constructor(internalMap: InternalMap<K, V>) : super() {
|
internal constructor(internalMap: InternalMap<K, V>) : super() {
|
||||||
this.internalMap = internalMap
|
this.internalMap = internalMap
|
||||||
@@ -92,7 +68,6 @@ public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K,
|
|||||||
*/
|
*/
|
||||||
actual constructor(initialCapacity: Int) : this(initialCapacity, 1.0f)
|
actual constructor(initialCapacity: Int) : this(initialCapacity, 1.0f)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new [HashMap] filled with the contents of the specified [original] map.
|
* Creates a new [HashMap] filled with the contents of the specified [original] map.
|
||||||
*/
|
*/
|
||||||
@@ -109,16 +84,12 @@ public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K,
|
|||||||
|
|
||||||
actual override fun containsValue(value: V): Boolean = internalMap.containsValue(value)
|
actual override fun containsValue(value: V): Boolean = internalMap.containsValue(value)
|
||||||
|
|
||||||
private var _entries: MutableSet<MutableMap.MutableEntry<K, V>>? = null
|
override fun createKeysView(): MutableSet<K> = HashMapKeys(internalMap)
|
||||||
actual override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
override fun createValuesView(): MutableCollection<V> = HashMapValues(internalMap)
|
||||||
get() {
|
|
||||||
if (_entries == null) {
|
|
||||||
_entries = createEntrySet()
|
|
||||||
}
|
|
||||||
return _entries!!
|
|
||||||
}
|
|
||||||
|
|
||||||
internal open fun createEntrySet(): MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet()
|
private var entriesView: HashMapEntrySet<K, V>? = null
|
||||||
|
actual override val entries: MutableSet<MutableEntry<K, V>>
|
||||||
|
get() = entriesView ?: HashMapEntrySet(internalMap).also { entriesView = it }
|
||||||
|
|
||||||
actual override operator fun get(key: K): V? = internalMap.get(key)
|
actual override operator fun get(key: K): V? = internalMap.get(key)
|
||||||
|
|
||||||
@@ -128,6 +99,7 @@ public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K,
|
|||||||
|
|
||||||
actual override val size: Int get() = internalMap.size
|
actual override val size: Int get() = internalMap.size
|
||||||
|
|
||||||
|
actual override fun putAll(from: Map<out K, V>) = internalMap.putAll(from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin.collections
|
||||||
|
|
||||||
|
internal class HashMapKeys<E> internal constructor(
|
||||||
|
private val backing: InternalMap<E, *>,
|
||||||
|
) : MutableSet<E>, AbstractMutableSet<E>() {
|
||||||
|
|
||||||
|
override val size: Int get() = backing.size
|
||||||
|
override fun isEmpty(): Boolean = backing.size == 0
|
||||||
|
override fun contains(element: E): Boolean = backing.contains(element)
|
||||||
|
override fun clear() = backing.clear()
|
||||||
|
override fun add(element: E): Boolean = throw UnsupportedOperationException()
|
||||||
|
override fun addAll(elements: Collection<E>): Boolean = throw UnsupportedOperationException()
|
||||||
|
override fun remove(element: E): Boolean = backing.remove(element) != null
|
||||||
|
override fun iterator(): MutableIterator<E> = backing.keysIterator()
|
||||||
|
|
||||||
|
override fun checkIsMutable() = backing.checkIsMutable()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class HashMapValues<V> internal constructor(
|
||||||
|
private val backing: InternalMap<*, V>,
|
||||||
|
) : MutableCollection<V>, AbstractMutableCollection<V>() {
|
||||||
|
|
||||||
|
override val size: Int get() = backing.size
|
||||||
|
override fun isEmpty(): Boolean = backing.size == 0
|
||||||
|
override fun contains(element: V): Boolean = backing.containsValue(element)
|
||||||
|
override fun add(element: V): Boolean = throw UnsupportedOperationException()
|
||||||
|
override fun addAll(elements: Collection<V>): Boolean = throw UnsupportedOperationException()
|
||||||
|
override fun clear() = backing.clear()
|
||||||
|
override fun iterator(): MutableIterator<V> = backing.valuesIterator()
|
||||||
|
override fun remove(element: V): Boolean = backing.removeValue(element)
|
||||||
|
|
||||||
|
override fun checkIsMutable() = backing.checkIsMutable()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: intermediate class with [E] `: Map.Entry<K, V>` is required to support
|
||||||
|
* [contains] for values that are [Map.Entry] but not [MutableMap.MutableEntry],
|
||||||
|
* and probably same for other functions.
|
||||||
|
* This is important because an instance of this class can be used as a result of [Map.entries],
|
||||||
|
* which should support [contains] for [Map.Entry].
|
||||||
|
* For example, this happens when upcasting [MutableMap] to [Map].
|
||||||
|
*
|
||||||
|
* The compiler enables special type-safe barriers to methods like [contains], which has [UnsafeVariance].
|
||||||
|
* Changing type from [MutableMap.MutableEntry] to [E] makes the compiler generate barriers checking that
|
||||||
|
* argument `is` [E] (so technically `is` [Map.Entry]) instead of `is` [MutableMap.MutableEntry].
|
||||||
|
*
|
||||||
|
* See also [KT-42248](https://youtrack.jetbrains.com/issue/KT-42428).
|
||||||
|
*/
|
||||||
|
internal abstract class HashMapEntrySetBase<K, V, E : Map.Entry<K, V>> internal constructor(
|
||||||
|
val backing: InternalMap<K, V>,
|
||||||
|
) : MutableSet<E>, AbstractMutableSet<E>() {
|
||||||
|
|
||||||
|
override val size: Int get() = backing.size
|
||||||
|
override fun isEmpty(): Boolean = backing.size == 0
|
||||||
|
override fun contains(element: E): Boolean = backing.containsEntry(element)
|
||||||
|
protected abstract fun getEntry(element: Map.Entry<K, V>): E?
|
||||||
|
override fun clear() = backing.clear()
|
||||||
|
override fun add(element: E): Boolean = throw UnsupportedOperationException()
|
||||||
|
override fun addAll(elements: Collection<E>): Boolean = throw UnsupportedOperationException()
|
||||||
|
override fun remove(element: E): Boolean = backing.removeEntry(element)
|
||||||
|
override fun containsAll(elements: Collection<E>): Boolean = backing.containsAllEntries(elements)
|
||||||
|
|
||||||
|
override fun checkIsMutable() = backing.checkIsMutable()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class HashMapEntrySet<K, V> internal constructor(
|
||||||
|
backing: InternalMap<K, V>,
|
||||||
|
) : HashMapEntrySetBase<K, V, MutableMap.MutableEntry<K, V>>(backing) {
|
||||||
|
|
||||||
|
override fun getEntry(element: Map.Entry<K, V>): MutableMap.MutableEntry<K, V>? = backing.getEntry(element)
|
||||||
|
|
||||||
|
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = backing.entriesIterator()
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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 kotlin.collections
|
||||||
|
|
||||||
|
internal class HashMapKeysDefault<K, V>(private val backingMap: AbstractMutableMap<K, V>) : AbstractMutableSet<K>() {
|
||||||
|
override fun add(element: K): Boolean = throw UnsupportedOperationException("Add is not supported on keys")
|
||||||
|
override fun clear() = backingMap.clear()
|
||||||
|
override operator fun contains(element: K): Boolean = backingMap.containsKey(element)
|
||||||
|
|
||||||
|
override operator fun iterator(): MutableIterator<K> {
|
||||||
|
val entryIterator = backingMap.entries.iterator()
|
||||||
|
return object : MutableIterator<K> {
|
||||||
|
override fun hasNext(): Boolean = entryIterator.hasNext()
|
||||||
|
override fun next(): K = entryIterator.next().key
|
||||||
|
override fun remove() = entryIterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(element: K): Boolean {
|
||||||
|
checkIsMutable()
|
||||||
|
if (backingMap.containsKey(element)) {
|
||||||
|
backingMap.remove(element)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override val size: Int get() = backingMap.size
|
||||||
|
|
||||||
|
override fun checkIsMutable(): Unit = backingMap.checkIsMutable()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class HashMapValuesDefault<K, V>(private val backingMap: AbstractMutableMap<K, V>) : AbstractMutableCollection<V>() {
|
||||||
|
override fun add(element: V): Boolean = throw UnsupportedOperationException("Add is not supported on values")
|
||||||
|
override fun clear() = backingMap.clear()
|
||||||
|
|
||||||
|
override operator fun contains(element: V): Boolean = backingMap.containsValue(element)
|
||||||
|
|
||||||
|
override operator fun iterator(): MutableIterator<V> {
|
||||||
|
val entryIterator = backingMap.entries.iterator()
|
||||||
|
return object : MutableIterator<V> {
|
||||||
|
override fun hasNext(): Boolean = entryIterator.hasNext()
|
||||||
|
override fun next(): V = entryIterator.next().value
|
||||||
|
override fun remove() = entryIterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val size: Int get() = backingMap.size
|
||||||
|
|
||||||
|
override fun checkIsMutable(): Unit = backingMap.checkIsMutable()
|
||||||
|
}
|
||||||
@@ -19,10 +19,6 @@ internal class InternalHashMap<K, V> private constructor(
|
|||||||
override val size: Int
|
override val size: Int
|
||||||
get() = _size
|
get() = _size
|
||||||
|
|
||||||
private var keysView: HashMapKeys<K>? = null
|
|
||||||
private var valuesView: HashMapValues<V>? = null
|
|
||||||
private var entriesView: HashMapEntrySet<K, V>? = null
|
|
||||||
|
|
||||||
private var isReadOnly: Boolean = false
|
private var isReadOnly: Boolean = false
|
||||||
|
|
||||||
// ---------------------------- functions ----------------------------
|
// ---------------------------- functions ----------------------------
|
||||||
@@ -78,11 +74,9 @@ internal class InternalHashMap<K, V> private constructor(
|
|||||||
require(loadFactor > 0) { "Non-positive load factor: $loadFactor" }
|
require(loadFactor > 0) { "Non-positive load factor: $loadFactor" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@PublishedApi
|
override fun build() {
|
||||||
internal fun build(): InternalHashMap<K, V> {
|
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
isReadOnly = true
|
isReadOnly = true
|
||||||
return if (size > 0) this else EmptyHolder.value()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isEmpty(): Boolean = _size == 0
|
fun isEmpty(): Boolean = _size == 0
|
||||||
@@ -143,36 +137,6 @@ internal class InternalHashMap<K, V> private constructor(
|
|||||||
length = 0
|
length = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
val keys: MutableSet<K>
|
|
||||||
get() {
|
|
||||||
val cur = keysView
|
|
||||||
return if (cur == null) {
|
|
||||||
val new = HashMapKeys(this)
|
|
||||||
keysView = new
|
|
||||||
new
|
|
||||||
} else cur
|
|
||||||
}
|
|
||||||
|
|
||||||
val values: MutableCollection<V>
|
|
||||||
get() {
|
|
||||||
val cur = valuesView
|
|
||||||
return if (cur == null) {
|
|
||||||
val new = HashMapValues(this)
|
|
||||||
valuesView = new
|
|
||||||
new
|
|
||||||
} else cur
|
|
||||||
}
|
|
||||||
|
|
||||||
val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
|
||||||
get() {
|
|
||||||
val cur = entriesView
|
|
||||||
return if (cur == null) {
|
|
||||||
val new = HashMapEntrySet(this)
|
|
||||||
entriesView = new
|
|
||||||
new
|
|
||||||
} else cur
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return other === this ||
|
return other === this ||
|
||||||
(other is Map<*, *>) &&
|
(other is Map<*, *>) &&
|
||||||
@@ -488,9 +452,9 @@ internal class InternalHashMap<K, V> private constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeValue(element: V): Boolean {
|
override fun removeValue(value: V): Boolean {
|
||||||
checkIsMutable()
|
checkIsMutable()
|
||||||
val index = findValue(element)
|
val index = findValue(value)
|
||||||
if (index < 0) return false
|
if (index < 0) return false
|
||||||
removeKeyAt(index)
|
removeKeyAt(index)
|
||||||
return true
|
return true
|
||||||
@@ -511,15 +475,6 @@ internal class InternalHashMap<K, V> private constructor(
|
|||||||
private fun computeShift(hashSize: Int): Int = hashSize.countLeadingZeroBits() + 1
|
private fun computeShift(hashSize: Int): Int = hashSize.countLeadingZeroBits() + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object EmptyHolder {
|
|
||||||
val value_ = InternalHashMap<Nothing, Nothing>(0).also { it.isReadOnly = true }
|
|
||||||
|
|
||||||
fun <K, V> value(): InternalHashMap<K, V> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return value_ as InternalHashMap<K, V>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal open class Itr<K, V>(
|
internal open class Itr<K, V>(
|
||||||
internal val map: InternalHashMap<K, V>,
|
internal val map: InternalHashMap<K, V>,
|
||||||
) {
|
) {
|
||||||
@@ -622,99 +577,3 @@ internal class InternalHashMap<K, V> private constructor(
|
|||||||
override fun toString(): String = "$key=$value"
|
override fun toString(): String = "$key=$value"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class HashMapKeys<E> internal constructor(
|
|
||||||
private val backing: InternalMap<E, *>,
|
|
||||||
) : MutableSet<E>, AbstractMutableSet<E>() {
|
|
||||||
|
|
||||||
override val size: Int get() = backing.size
|
|
||||||
override fun isEmpty(): Boolean = backing.size == 0
|
|
||||||
override fun contains(element: E): Boolean = backing.contains(element)
|
|
||||||
override fun clear() = backing.clear()
|
|
||||||
override fun add(element: E): Boolean = throw UnsupportedOperationException()
|
|
||||||
override fun addAll(elements: Collection<E>): Boolean = throw UnsupportedOperationException()
|
|
||||||
override fun remove(element: E): Boolean = backing.remove(element) != null
|
|
||||||
override fun iterator(): MutableIterator<E> = backing.keysIterator()
|
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<E>): Boolean {
|
|
||||||
backing.checkIsMutable()
|
|
||||||
return super.removeAll(elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<E>): Boolean {
|
|
||||||
backing.checkIsMutable()
|
|
||||||
return super.retainAll(elements)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class HashMapValues<V> internal constructor(
|
|
||||||
private val backing: InternalMap<*, V>,
|
|
||||||
) : MutableCollection<V>, AbstractMutableCollection<V>() {
|
|
||||||
|
|
||||||
override val size: Int get() = backing.size
|
|
||||||
override fun isEmpty(): Boolean = backing.size == 0
|
|
||||||
override fun contains(element: V): Boolean = backing.containsValue(element)
|
|
||||||
override fun add(element: V): Boolean = throw UnsupportedOperationException()
|
|
||||||
override fun addAll(elements: Collection<V>): Boolean = throw UnsupportedOperationException()
|
|
||||||
override fun clear() = backing.clear()
|
|
||||||
override fun iterator(): MutableIterator<V> = backing.valuesIterator()
|
|
||||||
override fun remove(element: V): Boolean = backing.removeValue(element)
|
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<V>): Boolean {
|
|
||||||
backing.checkIsMutable()
|
|
||||||
return super.removeAll(elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<V>): Boolean {
|
|
||||||
backing.checkIsMutable()
|
|
||||||
return super.retainAll(elements)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: intermediate class with [E] `: Map.Entry<K, V>` is required to support
|
|
||||||
* [contains] for values that are [Map.Entry] but not [MutableMap.MutableEntry],
|
|
||||||
* and probably same for other functions.
|
|
||||||
* This is important because an instance of this class can be used as a result of [Map.entries],
|
|
||||||
* which should support [contains] for [Map.Entry].
|
|
||||||
* For example, this happens when upcasting [MutableMap] to [Map].
|
|
||||||
*
|
|
||||||
* The compiler enables special type-safe barriers to methods like [contains], which has [UnsafeVariance].
|
|
||||||
* Changing type from [MutableMap.MutableEntry] to [E] makes the compiler generate barriers checking that
|
|
||||||
* argument `is` [E] (so technically `is` [Map.Entry]) instead of `is` [MutableMap.MutableEntry].
|
|
||||||
*
|
|
||||||
* See also [KT-42248](https://youtrack.jetbrains.com/issue/KT-42428).
|
|
||||||
*/
|
|
||||||
internal abstract class HashMapEntrySetBase<K, V, E : Map.Entry<K, V>> internal constructor(
|
|
||||||
val backing: InternalMap<K, V>,
|
|
||||||
) : MutableSet<E>, AbstractMutableSet<E>() {
|
|
||||||
|
|
||||||
override val size: Int get() = backing.size
|
|
||||||
override fun isEmpty(): Boolean = backing.size == 0
|
|
||||||
override fun contains(element: E): Boolean = backing.containsEntry(element)
|
|
||||||
protected abstract fun getEntry(element: Map.Entry<K, V>): E?
|
|
||||||
override fun clear() = backing.clear()
|
|
||||||
override fun add(element: E): Boolean = throw UnsupportedOperationException()
|
|
||||||
override fun addAll(elements: Collection<E>): Boolean = throw UnsupportedOperationException()
|
|
||||||
override fun remove(element: E): Boolean = backing.removeEntry(element)
|
|
||||||
override fun containsAll(elements: Collection<E>): Boolean = backing.containsAllEntries(elements)
|
|
||||||
|
|
||||||
override fun removeAll(elements: Collection<E>): Boolean {
|
|
||||||
backing.checkIsMutable()
|
|
||||||
return super.removeAll(elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun retainAll(elements: Collection<E>): Boolean {
|
|
||||||
backing.checkIsMutable()
|
|
||||||
return super.retainAll(elements)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class HashMapEntrySet<K, V> internal constructor(
|
|
||||||
backing: InternalMap<K, V>,
|
|
||||||
) : HashMapEntrySetBase<K, V, MutableMap.MutableEntry<K, V>>(backing) {
|
|
||||||
|
|
||||||
override fun getEntry(element: Map.Entry<K, V>): MutableMap.MutableEntry<K, V>? = backing.getEntry(element)
|
|
||||||
|
|
||||||
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = backing.entriesIterator()
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -32,9 +32,14 @@ internal interface InternalMap<K, V> {
|
|||||||
fun valuesIterator(): MutableIterator<V>
|
fun valuesIterator(): MutableIterator<V>
|
||||||
fun entriesIterator(): MutableIterator<MutableMap.MutableEntry<K, V>>
|
fun entriesIterator(): MutableIterator<MutableMap.MutableEntry<K, V>>
|
||||||
|
|
||||||
fun checkIsMutable() {}
|
fun checkIsMutable()
|
||||||
|
fun build()
|
||||||
|
|
||||||
fun containsAllEntries(m: Collection<Map.Entry<*, *>>): Boolean {
|
fun containsAllEntries(m: Collection<Map.Entry<*, *>>): Boolean {
|
||||||
return m.all(this::containsOtherEntry)
|
return m.all {
|
||||||
|
// entry can be null due to variance.
|
||||||
|
val entry = it.unsafeCast<Any?>()
|
||||||
|
(entry is Map.Entry<*, *>) && containsOtherEntry(entry)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
@@ -163,6 +163,13 @@ internal open class InternalStringMap<K, V> : InternalMap<K, V> {
|
|||||||
values = createJsArray()
|
values = createJsArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun build() {
|
||||||
|
throw UnsupportedOperationException("build method is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun checkIsMutable() {
|
||||||
|
}
|
||||||
|
|
||||||
override fun keysIterator(): MutableIterator<K> = KeysItr(this)
|
override fun keysIterator(): MutableIterator<K> = KeysItr(this)
|
||||||
override fun valuesIterator(): MutableIterator<V> = ValuesItr(this)
|
override fun valuesIterator(): MutableIterator<V> = ValuesItr(this)
|
||||||
override fun entriesIterator(): MutableIterator<MutableEntry<K, V>> = EntriesItr(this)
|
override fun entriesIterator(): MutableIterator<MutableEntry<K, V>> = EntriesItr(this)
|
||||||
|
|||||||
@@ -9,177 +9,31 @@
|
|||||||
*/
|
*/
|
||||||
package kotlin.collections
|
package kotlin.collections
|
||||||
|
|
||||||
import kotlin.collections.MutableMap.MutableEntry
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash table based implementation of the [MutableMap] interface, which additionally preserves the insertion order
|
* Hash table based implementation of the [MutableMap] interface, which additionally preserves the insertion order
|
||||||
* of entries during the iteration.
|
* of entries during the iteration.
|
||||||
*
|
*
|
||||||
* The insertion order is preserved by maintaining a doubly-linked list of all of its entries.
|
* The insertion order is preserved natively by the HashMap implementation.
|
||||||
*/
|
*/
|
||||||
public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
|
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
|
|
||||||
* list with a head node. This reduces the special cases we have to deal with
|
|
||||||
* in the list operations.
|
|
||||||
|
|
||||||
* Note that we duplicate the key from the underlying hash map so we can find
|
|
||||||
* the eldest entry. The alternative would have been to modify HashMap so more
|
|
||||||
* of the code was directly usable here, but this would have added some
|
|
||||||
* overhead to HashMap, or to reimplement most of the HashMap code here with
|
|
||||||
* small modifications. Paying a small storage cost only if you use
|
|
||||||
* LinkedHashMap and minimizing code size seemed like a better tradeoff
|
|
||||||
*/
|
|
||||||
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 : AbstractEntrySet<MutableEntry<K, V>, K, V>() {
|
|
||||||
|
|
||||||
private inner class EntryIterator : MutableIterator<MutableEntry<K, V>> {
|
|
||||||
// The last entry that was returned from this iterator.
|
|
||||||
private var last: ChainEntry<K, V>? = null
|
|
||||||
|
|
||||||
// The next entry to return from this iterator.
|
|
||||||
private var next: ChainEntry<K, V>? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
next = head
|
|
||||||
// recordLastKnownStructure(map, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
|
||||||
return next !== null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun next(): MutableEntry<K, V> {
|
|
||||||
// checkStructuralChange(map, this)
|
|
||||||
if (!hasNext()) throw NoSuchElementException()
|
|
||||||
|
|
||||||
val current = next!!
|
|
||||||
last = current
|
|
||||||
next = current.next.takeIf { it !== head }
|
|
||||||
return current
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove() {
|
|
||||||
check(last != null)
|
|
||||||
this@EntrySet.checkIsMutable()
|
|
||||||
// checkStructuralChange(map, this)
|
|
||||||
|
|
||||||
last!!.remove()
|
|
||||||
map.remove(last!!.key)
|
|
||||||
// recordLastKnownStructure(map, this)
|
|
||||||
last = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun add(element: MutableEntry<K, V>): Boolean = throw UnsupportedOperationException("Add is not supported on entries")
|
|
||||||
override fun clear() {
|
|
||||||
this@LinkedHashMap.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsEntry(element: Map.Entry<K, V>): Boolean = this@LinkedHashMap.containsEntry(element)
|
|
||||||
|
|
||||||
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = EntryIterator()
|
|
||||||
|
|
||||||
override fun removeEntry(element: Map.Entry<K, V>): Boolean {
|
|
||||||
checkIsMutable()
|
|
||||||
if (contains(element)) {
|
|
||||||
this@LinkedHashMap.remove(element.key)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override val size: Int get() = this@LinkedHashMap.size
|
|
||||||
|
|
||||||
override fun checkIsMutable(): Unit = this@LinkedHashMap.checkIsMutable()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The head of the insert order chain, which is a doubly-linked circular
|
|
||||||
* list.
|
|
||||||
*
|
|
||||||
* The most recently inserted node is at the end of the chain, ie.
|
|
||||||
* chain.prev.
|
|
||||||
*/
|
|
||||||
private var head: ChainEntry<K, V>? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add this node to the end of the chain.
|
|
||||||
*/
|
|
||||||
private fun ChainEntry<K, V>.addToEnd() {
|
|
||||||
// This entry is not in the list.
|
|
||||||
check(next == null && prev == null)
|
|
||||||
|
|
||||||
val _head = head
|
|
||||||
if (_head == null) {
|
|
||||||
head = this
|
|
||||||
next = this
|
|
||||||
prev = this
|
|
||||||
} else {
|
|
||||||
// Chain is valid.
|
|
||||||
val _tail = checkNotNull(_head.prev)
|
|
||||||
// Update me.
|
|
||||||
prev = _tail
|
|
||||||
next = _head
|
|
||||||
// Update my new siblings: current head and old tail
|
|
||||||
_head.prev = this
|
|
||||||
_tail.next = this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove this node from the chain it is a part of.
|
|
||||||
*/
|
|
||||||
private fun ChainEntry<K, V>.remove() {
|
|
||||||
if (this.next === this) {
|
|
||||||
// if this is single element, remove head
|
|
||||||
head = null
|
|
||||||
} else {
|
|
||||||
if (head === this) {
|
|
||||||
// if this is first element, move head to next
|
|
||||||
head = next
|
|
||||||
}
|
|
||||||
next!!.prev = prev
|
|
||||||
prev!!.next = next
|
|
||||||
}
|
|
||||||
next = null
|
|
||||||
prev = null
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The hashmap that keeps track of our entries and the chain. Note that we
|
|
||||||
* duplicate the key here to eliminate changes to HashMap and minimize the
|
|
||||||
* code here, at the expense of additional space.
|
|
||||||
*/
|
|
||||||
private val map: HashMap<K, ChainEntry<K, V>>
|
|
||||||
|
|
||||||
private var isReadOnly: Boolean = false
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new empty [LinkedHashMap].
|
* Creates a new empty [LinkedHashMap].
|
||||||
*/
|
*/
|
||||||
actual constructor() : super() {
|
actual constructor() : super()
|
||||||
map = HashMap<K, ChainEntry<K, V>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal constructor(backingMap: HashMap<K, Any>) : super() {
|
/**
|
||||||
@Suppress("UNCHECKED_CAST") // expected to work due to erasure
|
* Creates a new empty [LinkedHashMap] with the specified initial capacity.
|
||||||
map = backingMap as HashMap<K, ChainEntry<K, V>>
|
*
|
||||||
}
|
* Capacity is the maximum number of entries the map is able to store in current internal data structure.
|
||||||
|
* When the map gets full by a certain default load factor, its capacity is expanded,
|
||||||
|
* which usually leads to rebuild of the internal data structure.
|
||||||
|
*
|
||||||
|
* @param initialCapacity the initial capacity of the created map.
|
||||||
|
* Note that the argument is just a hint for the implementation and can be ignored.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if [initialCapacity] is negative.
|
||||||
|
*/
|
||||||
|
actual constructor(initialCapacity: Int) : super(initialCapacity)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new empty [LinkedHashMap] with the specified initial capacity and load factor.
|
* Creates a new empty [LinkedHashMap] with the specified initial capacity and load factor.
|
||||||
@@ -195,102 +49,28 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
|
|||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if [initialCapacity] is negative or [loadFactor] is non-positive.
|
* @throws IllegalArgumentException if [initialCapacity] is negative or [loadFactor] is non-positive.
|
||||||
*/
|
*/
|
||||||
actual constructor(initialCapacity: Int, loadFactor: Float) : super(initialCapacity, loadFactor) {
|
actual constructor(initialCapacity: Int, loadFactor: Float) : super(initialCapacity, loadFactor)
|
||||||
map = HashMap<K, ChainEntry<K, V>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new empty [LinkedHashMap] with the specified initial capacity.
|
|
||||||
*
|
|
||||||
* Capacity is the maximum number of entries the map is able to store in current internal data structure.
|
|
||||||
* When the map gets full by a certain default load factor, its capacity is expanded,
|
|
||||||
* which usually leads to rebuild of the internal data structure.
|
|
||||||
*
|
|
||||||
* @param initialCapacity the initial capacity of the created map.
|
|
||||||
* Note that the argument is just a hint for the implementation and can be ignored.
|
|
||||||
*
|
|
||||||
* @throws IllegalArgumentException if [initialCapacity] is negative.
|
|
||||||
*/
|
|
||||||
actual constructor(initialCapacity: Int) : this(initialCapacity, 1.0f)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new [LinkedHashMap] filled with the contents of the specified [original] map.
|
* Creates a new [LinkedHashMap] filled with the contents of the specified [original] map.
|
||||||
*
|
*
|
||||||
* The iteration order of entries in the created map is the same as in the [original] map.
|
* The iteration order of entries in the created map is the same as in the [original] map.
|
||||||
*/
|
*/
|
||||||
actual constructor(original: Map<out K, V>) {
|
actual constructor(original: Map<out K, V>) : super(original)
|
||||||
map = HashMap<K, ChainEntry<K, V>>()
|
|
||||||
this.putAll(original)
|
internal constructor(internalMap: InternalMap<K, V>) : super(internalMap)
|
||||||
|
|
||||||
|
private object EmptyHolder {
|
||||||
|
val value = LinkedHashMap(InternalHashMap<Nothing, Nothing>(0).also { it.build() })
|
||||||
}
|
}
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal fun build(): Map<K, V> {
|
internal fun build(): Map<K, V> {
|
||||||
checkIsMutable()
|
internalMap.build()
|
||||||
isReadOnly = true
|
return if (size > 0) this else EmptyHolder.value.unsafeCast<Map<K, V>>()
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return if (size > 0) this else (Empty as Map<K, V>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actual override fun clear() {
|
override fun checkIsMutable() = internalMap.checkIsMutable()
|
||||||
checkIsMutable()
|
|
||||||
map.clear()
|
|
||||||
head = null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// override fun clone(): Any {
|
|
||||||
// return LinkedHashMap(this)
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
actual override fun containsKey(key: K): Boolean = map.containsKey(key)
|
|
||||||
|
|
||||||
actual override fun containsValue(value: V): Boolean {
|
|
||||||
var node: ChainEntry<K, V> = head ?: return false
|
|
||||||
do {
|
|
||||||
if (node.value == value) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
node = node.next!!
|
|
||||||
} while (node !== head)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal override fun createEntrySet(): MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet()
|
|
||||||
|
|
||||||
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)
|
|
||||||
map.put(key, newEntry)
|
|
||||||
newEntry.addToEnd()
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
return old.setValue(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actual override fun remove(key: K): V? {
|
|
||||||
checkIsMutable()
|
|
||||||
|
|
||||||
val entry = map.remove(key)
|
|
||||||
if (entry != null) {
|
|
||||||
entry.remove()
|
|
||||||
return entry.value
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
actual override val size: Int get() = map.size
|
|
||||||
|
|
||||||
internal override fun checkIsMutable() {
|
|
||||||
if (isReadOnly) throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -298,5 +78,5 @@ public actual open class LinkedHashMap<K, V> : HashMap<K, V>, MutableMap<K, V> {
|
|||||||
* JS object without hashing them.
|
* JS object without hashing them.
|
||||||
*/
|
*/
|
||||||
public fun <V> linkedStringMapOf(vararg pairs: Pair<String, V>): LinkedHashMap<String, V> {
|
public fun <V> linkedStringMapOf(vararg pairs: Pair<String, V>): LinkedHashMap<String, V> {
|
||||||
return LinkedHashMap<String, V>(stringMapOf<Any>()).apply { putAll(pairs) }
|
return LinkedHashMap<String, V>(InternalStringMap()).apply { putAll(pairs) }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user