[JS IR] Implement InternalStringLinkedMap
^KT-59001
This commit is contained in:
committed by
Space Team
parent
058cc9def2
commit
5e2c1761fc
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* 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 InternalStringLinkedMap<K, V> : InternalStringMap<K, V>() {
|
||||||
|
companion object {
|
||||||
|
private const val EMPTY_INDEX = -1
|
||||||
|
private const val INITIAL_CAPACITY = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
private var nextIndexes = IntArray(INITIAL_CAPACITY)
|
||||||
|
private var prevIndexes = IntArray(INITIAL_CAPACITY)
|
||||||
|
|
||||||
|
private var headIndex = EMPTY_INDEX
|
||||||
|
private var tailIndex = EMPTY_INDEX
|
||||||
|
|
||||||
|
private fun ensureCapacity() {
|
||||||
|
if (nextIndexes.size < size) {
|
||||||
|
val newCapacity = AbstractList.newCapacity(nextIndexes.size, size)
|
||||||
|
nextIndexes = nextIndexes.copyOf(newCapacity)
|
||||||
|
prevIndexes = prevIndexes.copyOf(newCapacity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun put(key: K, value: V): V? {
|
||||||
|
val prevValue = super.put(key, value)
|
||||||
|
// new element inserted
|
||||||
|
if (prevValue == null) {
|
||||||
|
ensureCapacity()
|
||||||
|
if (size == 1) {
|
||||||
|
headIndex = 0
|
||||||
|
tailIndex = 0
|
||||||
|
nextIndexes[0] = EMPTY_INDEX
|
||||||
|
prevIndexes[0] = EMPTY_INDEX
|
||||||
|
} else {
|
||||||
|
val oldTail = tailIndex
|
||||||
|
tailIndex = size - 1
|
||||||
|
|
||||||
|
nextIndexes[oldTail] = size - 1
|
||||||
|
prevIndexes[tailIndex] = oldTail
|
||||||
|
nextIndexes[tailIndex] = EMPTY_INDEX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prevValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeKeyIndex(key: K, removingIndex: Int) {
|
||||||
|
super.removeKeyIndex(key, removingIndex)
|
||||||
|
|
||||||
|
// remove removedIndex from the list
|
||||||
|
val nextIndex = nextIndexes[removingIndex]
|
||||||
|
val prevIndex = prevIndexes[removingIndex]
|
||||||
|
|
||||||
|
nextIndexes[prevIndex] = nextIndex
|
||||||
|
prevIndexes[nextIndex] = prevIndex
|
||||||
|
|
||||||
|
if (headIndex == removingIndex) {
|
||||||
|
headIndex = nextIndex
|
||||||
|
}
|
||||||
|
if (tailIndex == removingIndex) {
|
||||||
|
tailIndex = prevIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the removed index from the middle, we have to move the last index on its place
|
||||||
|
val lastIndex = size
|
||||||
|
if (removingIndex != lastIndex) {
|
||||||
|
nextIndexes[removingIndex] = nextIndexes[lastIndex]
|
||||||
|
prevIndexes[removingIndex] = prevIndexes[lastIndex]
|
||||||
|
nextIndexes[prevIndexes[removingIndex]] = removingIndex
|
||||||
|
prevIndexes[nextIndexes[removingIndex]] = removingIndex
|
||||||
|
if (headIndex == lastIndex) {
|
||||||
|
headIndex = removingIndex
|
||||||
|
}
|
||||||
|
if (tailIndex == lastIndex) {
|
||||||
|
tailIndex = removingIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
super.clear()
|
||||||
|
headIndex = EMPTY_INDEX
|
||||||
|
tailIndex = EMPTY_INDEX
|
||||||
|
|
||||||
|
nextIndexes = IntArray(INITIAL_CAPACITY)
|
||||||
|
prevIndexes = IntArray(INITIAL_CAPACITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun keysIterator(): MutableIterator<K> = KeysLinkedItr(this)
|
||||||
|
override fun valuesIterator(): MutableIterator<V> = ValuesLinkedItr(this)
|
||||||
|
override fun entriesIterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = EntriesLinkedItr(this)
|
||||||
|
|
||||||
|
private abstract class BaseLinkedItr<K, V>(protected val map: InternalStringLinkedMap<K, V>) {
|
||||||
|
protected var lastIndex = EMPTY_INDEX
|
||||||
|
protected var index = map.headIndex
|
||||||
|
|
||||||
|
protected fun goNext() {
|
||||||
|
if (index == EMPTY_INDEX) {
|
||||||
|
throw NoSuchElementException()
|
||||||
|
}
|
||||||
|
lastIndex = index
|
||||||
|
index = map.nextIndexes[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasNext(): Boolean = index != EMPTY_INDEX
|
||||||
|
|
||||||
|
fun remove() {
|
||||||
|
map.removeKeyIndex(map.keys.getElement(lastIndex), lastIndex)
|
||||||
|
if (index == map.size) {
|
||||||
|
index = lastIndex
|
||||||
|
}
|
||||||
|
lastIndex = EMPTY_INDEX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract class LinkedItr<I, K, V>(
|
||||||
|
private val iterableArray: JsRawArray<I>,
|
||||||
|
map: InternalStringLinkedMap<K, V>,
|
||||||
|
) : MutableIterator<I>, BaseLinkedItr<K, V>(map) {
|
||||||
|
override fun next(): I {
|
||||||
|
goNext()
|
||||||
|
return iterableArray.getElement(lastIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class KeysLinkedItr<K, V>(map: InternalStringLinkedMap<K, V>) : LinkedItr<K, K, V>(map.keys, map)
|
||||||
|
private class ValuesLinkedItr<K, V>(map: InternalStringLinkedMap<K, V>) : LinkedItr<V, K, V>(map.values, map)
|
||||||
|
|
||||||
|
private class EntriesLinkedItr<K, V>(map: InternalStringLinkedMap<K, V>) :
|
||||||
|
MutableIterator<MutableMap.MutableEntry<K, V>>,
|
||||||
|
BaseLinkedItr<K, V>(map) {
|
||||||
|
override fun next(): MutableMap.MutableEntry<K, V> {
|
||||||
|
goNext()
|
||||||
|
val key = map.keys.getElement(lastIndex)
|
||||||
|
val value = map.values.getElement(lastIndex)
|
||||||
|
return EntryRef(key, value, map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ internal external interface JsRawArray<E> {
|
|||||||
var length: Int
|
var length: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <E> JsRawArray<E>.getElement(index: Int): E {
|
internal inline fun <E> JsRawArray<E>.getElement(index: Int): E {
|
||||||
return (this.asDynamic()[index]).unsafeCast<E>()
|
return (this.asDynamic()[index]).unsafeCast<E>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,8 +51,8 @@ internal open class InternalStringMap<K, V> : InternalMap<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var backingMap: dynamic = createJsMap()
|
private var backingMap: dynamic = createJsMap()
|
||||||
private var values = createJsArray<V>()
|
internal var values = createJsArray<V>()
|
||||||
private var keys = createJsArray<K>()
|
internal var keys = createJsArray<K>()
|
||||||
|
|
||||||
override val size: Int
|
override val size: Int
|
||||||
get() = keys.length
|
get() = keys.length
|
||||||
@@ -144,16 +144,16 @@ internal open class InternalStringMap<K, V> : InternalMap<K, V> {
|
|||||||
return removedValue
|
return removedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun removeKeyIndex(key: K, index: Int) {
|
internal open fun removeKeyIndex(key: K, removingIndex: Int) {
|
||||||
jsDeleteProperty(backingMap.unsafeCast<Any>(), key as Any)
|
jsDeleteProperty(backingMap.unsafeCast<Any>(), key as Any)
|
||||||
|
|
||||||
if (index + 1 == size) {
|
if (removingIndex + 1 == size) {
|
||||||
keys.pop()
|
keys.pop()
|
||||||
values.pop()
|
values.pop()
|
||||||
} else {
|
} else {
|
||||||
keys.replaceElementAtWithLast(index)
|
keys.replaceElementAtWithLast(removingIndex)
|
||||||
values.replaceElementAtWithLast(index)
|
values.replaceElementAtWithLast(removingIndex)
|
||||||
backingMap[keys.getElement(index)] = index
|
backingMap[keys.getElement(removingIndex)] = removingIndex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,11 +164,11 @@ internal open class InternalStringMap<K, V> : InternalMap<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun build() {
|
override fun build() {
|
||||||
|
// Feel free to implement later if it is required
|
||||||
throw UnsupportedOperationException("build method is not implemented")
|
throw UnsupportedOperationException("build method is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun checkIsMutable() {
|
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)
|
||||||
@@ -189,6 +189,7 @@ internal open class InternalStringMap<K, V> : InternalMap<K, V> {
|
|||||||
|
|
||||||
fun remove() {
|
fun remove() {
|
||||||
map.removeKeyIndex(map.keys.getElement(lastIndex), lastIndex)
|
map.removeKeyIndex(map.keys.getElement(lastIndex), lastIndex)
|
||||||
|
index = lastIndex
|
||||||
lastIndex = -1
|
lastIndex = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +216,7 @@ internal open class InternalStringMap<K, V> : InternalMap<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EntryRef<K, V>(
|
protected class EntryRef<K, V>(
|
||||||
override val key: K,
|
override val key: K,
|
||||||
override var value: V,
|
override var value: V,
|
||||||
private val map: InternalStringMap<K, V>,
|
private val map: InternalStringMap<K, V>,
|
||||||
@@ -227,10 +228,7 @@ internal open class InternalStringMap<K, V> : InternalMap<K, V> {
|
|||||||
return prevValue
|
return prevValue
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean =
|
override fun equals(other: Any?): Boolean = other is Map.Entry<*, *> && other.key == key && other.value == value
|
||||||
other is Map.Entry<*, *> &&
|
|
||||||
other.key == key &&
|
|
||||||
other.value == value
|
|
||||||
|
|
||||||
override fun hashCode(): Int = key.hashCode() xor value.hashCode()
|
override fun hashCode(): Int = key.hashCode() xor value.hashCode()
|
||||||
|
|
||||||
|
|||||||
@@ -78,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>(InternalStringMap()).apply { putAll(pairs) }
|
return LinkedHashMap<String, V>(InternalStringLinkedMap()).apply { putAll(pairs) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,5 +77,5 @@ public actual open class LinkedHashSet<E> : HashSet<E>, MutableSet<E> {
|
|||||||
* which elements the keys as properties of JS object without hashing them.
|
* which elements the keys as properties of JS object without hashing them.
|
||||||
*/
|
*/
|
||||||
public fun linkedStringSetOf(vararg elements: String): LinkedHashSet<String> {
|
public fun linkedStringSetOf(vararg elements: String): LinkedHashSet<String> {
|
||||||
return LinkedHashSet<String>(InternalStringMap()).apply { addAll(elements) }
|
return LinkedHashSet<String>(InternalStringLinkedMap()).apply { addAll(elements) }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user