[JS IR] Replace InternalHashCodeMap with InternalHashMap

^KT-59001
This commit is contained in:
Alexander Korepanov
2023-06-19 15:21:22 +02:00
committed by Space Team
parent 6a1e14df0b
commit 6f0628cb8a
2 changed files with 1 additions and 191 deletions
@@ -56,7 +56,7 @@ public actual open class HashMap<K, V> : AbstractMutableMap<K, V>, MutableMap<K,
/**
* Creates a new empty [HashMap].
*/
actual constructor() : this(InternalHashCodeMap())
actual constructor() : this(InternalHashMap())
/**
* Creates a new empty [HashMap] with the specified initial capacity and load factor.
@@ -1,190 +0,0 @@
/*
* Copyright 2010-2018 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.
*/
/*
* Based on GWT InternalHashCodeMap
* Copyright 2008 Google Inc.
*/
package kotlin.collections
import kotlin.collections.MutableMap.MutableEntry
import kotlin.collections.AbstractMutableMap.SimpleEntry
/**
* A simple wrapper around JavaScriptObject to provide [java.util.Map]-like semantics for any
* key type.
*
*
* Implementation notes:
*
*
* A key's hashCode is the index in backingMap which should contain that key. Since several keys may
* have the same hash, each value in hashCodeMap is actually an array containing all entries whose
* keys share the same hash.
*/
internal class InternalHashCodeMap<K, V> : InternalMap<K, V> {
private var backingMap: dynamic = createJsMap()
override var size: Int = 0
private set
override fun put(key: K, value: V): V? {
val hashCode = hash(key)
val chainOrEntry = getChainOrEntryOrNull(hashCode)
if (chainOrEntry == null) {
// This is a new chain, put it to the map.
backingMap[hashCode] = SimpleEntry(key, value)
} else {
if (chainOrEntry !is Array<*>) {
// It is an entry
val entry: SimpleEntry<K, V> = chainOrEntry
if (entry.key == key) {
return entry.setValue(value)
} else {
backingMap[hashCode] = arrayOf(entry, SimpleEntry(key, value))
size++
return null
}
} else {
// Chain already exists, perhaps key also exists.
val chain: Array<MutableEntry<K, V>> = chainOrEntry
val entry = chain.findEntryInChain(key)
if (entry != null) {
return entry.setValue(value)
}
chain.asDynamic().push(SimpleEntry(key, value))
}
}
size++
// structureChanged(host)
return null
}
override fun remove(key: K): V? {
val hashCode = hash(key)
val chainOrEntry = getChainOrEntryOrNull(hashCode) ?: return null
if (chainOrEntry !is Array<*>) {
val entry: MutableEntry<K, V> = chainOrEntry
if (entry.key == key) {
jsDeleteProperty(backingMap, hashCode)
size--
return entry.value
} else {
return null
}
} else {
val chain: Array<MutableEntry<K, V>> = chainOrEntry
for (index in chain.indices) {
val entry = chain[index]
if (key == entry.key) {
if (chain.size == 1) {
chain.asDynamic().length = 0
// remove the whole array
jsDeleteProperty(backingMap, hashCode)
} else {
// splice out the entry we're removing
chain.asDynamic().splice(index, 1)
}
size--
// structureChanged(host)
return entry.value
}
}
}
return null
}
override fun clear() {
backingMap = createJsMap()
size = 0
}
override fun contains(key: K): Boolean = getEntry(key) != null
override fun get(key: K): V? = getEntry(key)?.value
private fun getEntry(key: K): MutableEntry<K, V>? {
val chainOrEntry = getChainOrEntryOrNull(hash(key)) ?: return null
if (chainOrEntry !is Array<*>) {
val entry: MutableEntry<K, V> = chainOrEntry
if (entry.key == key) {
return entry
} else {
return null
}
} else {
val chain: Array<MutableEntry<K, V>> = chainOrEntry
return chain.findEntryInChain(key)
}
}
private fun Array<MutableEntry<K, V>>.findEntryInChain(key: K): MutableEntry<K, V>? =
firstOrNull { entry -> entry.key == key }
override fun iterator(): MutableIterator<MutableEntry<K, V>> {
return object : MutableIterator<MutableEntry<K, V>> {
var state = -1 // -1 not ready, 0 - ready, 1 - done
val keys: Array<String> = js("Object").keys(backingMap)
var keyIndex = -1
var chainOrEntry: dynamic = null
var isChain = false
var itemIndex = -1
var lastEntry: MutableEntry<K, V>? = null
private fun computeNext(): Int {
if (chainOrEntry != null && isChain) {
val chainSize: Int = chainOrEntry.unsafeCast<Array<MutableEntry<K, V>>>().size
if (++itemIndex < chainSize)
return 0
}
if (++keyIndex < keys.size) {
chainOrEntry = backingMap[keys[keyIndex]]
isChain = chainOrEntry is Array<*>
itemIndex = 0
return 0
} else {
chainOrEntry = null
return 1
}
}
override fun hasNext(): Boolean {
if (state == -1)
state = computeNext()
return state == 0
}
override fun next(): MutableEntry<K, V> {
if (!hasNext()) throw NoSuchElementException()
val lastEntry = if (isChain) {
chainOrEntry.unsafeCast<Array<MutableEntry<K, V>>>()[itemIndex]
} else {
chainOrEntry.unsafeCast<MutableEntry<K, V>>()
}
this.lastEntry = lastEntry
state = -1
return lastEntry
}
override fun remove() {
checkNotNull(lastEntry)
this@InternalHashCodeMap.remove(lastEntry!!.key)
lastEntry = null
// the chain being iterated just got modified by InternalHashCodeMap.remove
itemIndex--
}
}
}
private fun getChainOrEntryOrNull(hashCode: Int): dynamic {
val chainOrEntry = backingMap[hashCode]
return if (chainOrEntry === undefined) null else chainOrEntry
}
private fun hash(key: K) = key?.hashCode() ?: 0
}