diff --git a/libraries/stdlib/js/src/kotlin/collections/ArrayFunctions.kt b/libraries/stdlib/js/src/kotlin/collections/ArrayFunctions.kt new file mode 100644 index 00000000000..2708c83fd50 --- /dev/null +++ b/libraries/stdlib/js/src/kotlin/collections/ArrayFunctions.kt @@ -0,0 +1,23 @@ +/* + * 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 fun Array.resetAt(index: Int) { + this.unsafeCast>()[index] = null +} + +internal fun Array.resetRange(fromIndex: Int, toIndex: Int) { + this.nativeFill(null, fromIndex, toIndex) +} + +internal fun Array.copyOfUninitializedElements(newSize: Int): Array { + return this.copyOf(newSize).unsafeCast>() +} + +internal fun arrayOfUninitializedElements(capacity: Int): Array { + require(capacity >= 0) { "capacity must be non-negative." } + return arrayOfNulls(capacity).unsafeCast>() +} diff --git a/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt b/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt index a1956b25f29..cff437f6e40 100644 --- a/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt @@ -5,22 +5,18 @@ package kotlin.collections -import kotlin.native.concurrent.isFrozen -import kotlin.native.FreezingIsDeprecated - -@OptIn(FreezingIsDeprecated::class) -actual class HashMap private constructor( - private var keysArray: Array, - private var valuesArray: Array?, // allocated only when actually used, always null in pure HashSet - private var presenceArray: IntArray, - private var hashArray: IntArray, - private var maxProbeDistance: Int, - private var length: Int -) : MutableMap { +internal class InternalHashMap private constructor( + private var keysArray: Array, + private var valuesArray: Array?, // allocated only when actually used, always null in pure HashSet + private var presenceArray: IntArray, + private var hashArray: IntArray, + private var maxProbeDistance: Int, + private var length: Int, +) { private var hashShift: Int = computeShift(hashSize) private var _size: Int = 0 - override actual val size: Int + val size: Int get() = _size private var keysView: HashMapKeys? = null @@ -34,7 +30,7 @@ actual class HashMap private constructor( /** * Creates a new empty [HashMap]. */ - actual constructor() : this(INITIAL_CAPACITY) + constructor() : this(INITIAL_CAPACITY) /** * Creates a new empty [HashMap] with the specified initial capacity. @@ -48,18 +44,19 @@ actual class HashMap private constructor( * * @throws IllegalArgumentException if [initialCapacity] is negative. */ - actual constructor(initialCapacity: Int) : this( - arrayOfUninitializedElements(initialCapacity), - null, - IntArray(initialCapacity), - IntArray(computeHashSize(initialCapacity)), - INITIAL_MAX_PROBE_DISTANCE, - 0) + constructor(initialCapacity: Int) : this( + arrayOfUninitializedElements(initialCapacity), + null, + IntArray(initialCapacity), + IntArray(computeHashSize(initialCapacity)), + INITIAL_MAX_PROBE_DISTANCE, + 0 + ) /** * Creates a new [HashMap] filled with the contents of the specified [original] map. */ - actual constructor(original: Map) : this(original.size) { + constructor(original: Map) : this(original.size) { putAll(original) } @@ -77,28 +74,28 @@ actual class HashMap private constructor( * * @throws IllegalArgumentException if [initialCapacity] is negative or [loadFactor] is non-positive. */ - actual constructor(initialCapacity: Int, loadFactor: Float) : this(initialCapacity) { + constructor(initialCapacity: Int, loadFactor: Float) : this(initialCapacity) { require(loadFactor > 0) { "Non-positive load factor: $loadFactor" } } @PublishedApi - internal fun build(): Map { + internal fun build(): InternalHashMap { checkIsMutable() isReadOnly = true return if (size > 0) this else EmptyHolder.value() } - override actual fun isEmpty(): Boolean = _size == 0 - override actual fun containsKey(key: K): Boolean = findKey(key) >= 0 - override actual fun containsValue(value: V): Boolean = findValue(value) >= 0 + fun isEmpty(): Boolean = _size == 0 + fun containsKey(key: K): Boolean = findKey(key) >= 0 + fun containsValue(value: V): Boolean = findValue(value) >= 0 - override actual operator fun get(key: K): V? { + operator fun get(key: K): V? { val index = findKey(key) if (index < 0) return null return valuesArray!![index] } - override actual fun put(key: K, value: V): V? { + fun put(key: K, value: V): V? { checkIsMutable() val index = addKey(key) val valuesArray = allocateValuesArray() @@ -112,12 +109,12 @@ actual class HashMap private constructor( } } - override actual fun putAll(from: Map) { + fun putAll(from: Map) { checkIsMutable() putAllEntries(from.entries) } - override actual fun remove(key: K): V? { + fun remove(key: K): V? { val index = removeKey(key) // mutability gets checked here if (index < 0) return null val valuesArray = valuesArray!! @@ -126,7 +123,7 @@ actual class HashMap private constructor( return oldValue } - override actual fun clear() { + fun clear() { checkIsMutable() // O(length) implementation for hashArray cleanup for (i in 0..length - 1) { @@ -142,35 +139,35 @@ actual class HashMap private constructor( length = 0 } - override actual val keys: MutableSet get() { - val cur = keysView - return if (cur == null) { - val new = HashMapKeys(this) - if (!isFrozen) + val keys: MutableSet + get() { + val cur = keysView + return if (cur == null) { + val new = HashMapKeys(this) keysView = new - new - } else cur - } + new + } else cur + } - override actual val values: MutableCollection get() { - val cur = valuesView - return if (cur == null) { - val new = HashMapValues(this) - if (!isFrozen) + val values: MutableCollection + get() { + val cur = valuesView + return if (cur == null) { + val new = HashMapValues(this) valuesView = new - new - } else cur - } + new + } else cur + } - override actual val entries: MutableSet> get() { - val cur = entriesView - return if (cur == null) { - val new = HashMapEntrySet(this) - if (!isFrozen) + val entries: MutableSet> + get() { + val cur = entriesView + return if (cur == null) { + val new = HashMapEntrySet(this) entriesView = new - new - } else cur - } + new + } else cur + } override fun equals(other: Any?): Boolean { return other === this || @@ -227,7 +224,7 @@ actual class HashMap private constructor( } private fun ensureCapacity(minCapacity: Int) { - if (minCapacity < 0) throw OutOfMemoryError() // overflow + if (minCapacity < 0) throw RuntimeException("too many elements") // overflow if (minCapacity > this.capacity) { val newSize = AbstractList.newCapacity(this.capacity, minCapacity) keysArray = keysArray.copyOfUninitializedElements(newSize) @@ -278,8 +275,9 @@ actual class HashMap private constructor( var i = 0 while (i < length) { if (!putRehash(i++)) { - throw IllegalStateException("This cannot happen with fixed magic multiplier and grow-only hash array. " + - "Have object hashCodes changed?") + throw IllegalStateException( + "This cannot happen with fixed magic multiplier and grow-only hash array. Have object hashCodes changed?" + ) } } } @@ -508,7 +506,6 @@ actual class HashMap private constructor( internal fun valuesIterator() = ValuesItr(this) internal fun entriesIterator() = EntriesItr(this) - @kotlin.native.internal.CanBePrecreated private companion object { private const val MAGIC = -1640531527 // 2654435769L.toInt(), golden ratio private const val INITIAL_CAPACITY = 8 @@ -521,16 +518,16 @@ actual class HashMap private constructor( } internal object EmptyHolder { - val value_ = HashMap(0).also { it.isReadOnly = true } + val value_ = InternalHashMap(0).also { it.isReadOnly = true } - fun value(): HashMap { + fun value(): InternalHashMap { @Suppress("UNCHECKED_CAST") - return value_ as HashMap + return value_ as InternalHashMap } } internal open class Itr( - internal val map: HashMap + internal val map: InternalHashMap, ) { internal var index = 0 internal var lastIndex: Int = -1 @@ -553,7 +550,7 @@ actual class HashMap private constructor( } } - internal class KeysItr(map: HashMap) : Itr(map), MutableIterator { + internal class KeysItr(map: InternalHashMap) : Itr(map), MutableIterator { override fun next(): K { if (index >= map.length) throw NoSuchElementException() lastIndex = index++ @@ -564,7 +561,7 @@ actual class HashMap private constructor( } - internal class ValuesItr(map: HashMap) : Itr(map), MutableIterator { + internal class ValuesItr(map: InternalHashMap) : Itr(map), MutableIterator { override fun next(): V { if (index >= map.length) throw NoSuchElementException() lastIndex = index++ @@ -574,8 +571,7 @@ actual class HashMap private constructor( } } - internal class EntriesItr(map: HashMap) : Itr(map), - MutableIterator> { + internal class EntriesItr(map: InternalHashMap) : Itr(map), MutableIterator> { override fun next(): EntryRef { if (index >= map.length) throw NoSuchElementException() lastIndex = index++ @@ -605,8 +601,8 @@ actual class HashMap private constructor( } internal class EntryRef( - private val map: HashMap, - private val index: Int + private val map: InternalHashMap, + private val index: Int, ) : MutableMap.MutableEntry { override val key: K get() = map.keysArray[index] @@ -623,9 +619,9 @@ actual class HashMap private constructor( } 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() @@ -634,13 +630,12 @@ actual class HashMap private constructor( } internal class HashMapKeys internal constructor( - private val backing: HashMap -) : MutableSet, kotlin.native.internal.KonanSet, AbstractMutableSet() { + private val backing: InternalHashMap, +) : MutableSet, AbstractMutableSet() { override val size: Int get() = backing.size override fun isEmpty(): Boolean = backing.isEmpty() override fun contains(element: E): Boolean = backing.containsKey(element) - override fun getElement(element: E): E? = backing.getKey(element) override fun clear() = backing.clear() override fun add(element: E): Boolean = throw UnsupportedOperationException() override fun addAll(elements: Collection): Boolean = throw UnsupportedOperationException() @@ -659,7 +654,7 @@ internal class HashMapKeys internal constructor( } internal class HashMapValues internal constructor( - val backing: HashMap<*, V> + val backing: InternalHashMap<*, V>, ) : MutableCollection, AbstractMutableCollection() { override val size: Int get() = backing.size @@ -697,13 +692,12 @@ internal class HashMapValues internal constructor( * See also [KT-42248](https://youtrack.jetbrains.com/issue/KT-42428). */ internal abstract class HashMapEntrySetBase> internal constructor( - val backing: HashMap -) : MutableSet, kotlin.native.internal.KonanSet, AbstractMutableSet() { + val backing: InternalHashMap, +) : MutableSet, AbstractMutableSet() { override val size: Int get() = backing.size override fun isEmpty(): Boolean = backing.isEmpty() override fun contains(element: E): Boolean = backing.containsEntry(element) - override fun getElement(element: E): E? = getEntry(element) protected abstract fun getEntry(element: Map.Entry): E? override fun clear() = backing.clear() override fun add(element: E): Boolean = throw UnsupportedOperationException() @@ -723,13 +717,10 @@ internal abstract class HashMapEntrySetBase> internal } internal class HashMapEntrySet internal constructor( - backing: HashMap + backing: InternalHashMap, ) : HashMapEntrySetBase>(backing) { override fun getEntry(element: Map.Entry): MutableMap.MutableEntry? = backing.getEntry(element) override fun iterator(): MutableIterator> = backing.entriesIterator() } - -// This hash map keeps insertion order. -actual typealias LinkedHashMap = HashMap \ No newline at end of file