diff --git a/libraries/stdlib/js/src/kotlin/collections/HashMap.kt b/libraries/stdlib/js/src/kotlin/collections/HashMap.kt index a03890507cd..642a421d11a 100644 --- a/libraries/stdlib/js/src/kotlin/collections/HashMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/HashMap.kt @@ -96,8 +96,8 @@ public actual open class HashMap : AbstractMutableMap, MutableMap stringMapOf(vararg pairs: Pair): HashMap { return HashMap(InternalStringMap()).apply { putAll(pairs) } diff --git a/libraries/stdlib/js/src/kotlin/collections/HashMapEntry.kt b/libraries/stdlib/js/src/kotlin/collections/HashMapEntry.kt index 767ae3b40e0..821a3aedff2 100644 --- a/libraries/stdlib/js/src/kotlin/collections/HashMapEntry.kt +++ b/libraries/stdlib/js/src/kotlin/collections/HashMapEntry.kt @@ -5,6 +5,11 @@ package kotlin.collections +/** + * This is the most performant implementations of [HashMap.keys] container. + * It is implemented over [InternalMap] interface and can not be used without it. + * [HashMapKeys] is more efficient than the implementation [HashMapKeysDefault] from HashMapEntryDefault.kt. + */ internal class HashMapKeys internal constructor( private val backing: InternalMap, ) : MutableSet, AbstractMutableSet() { @@ -21,6 +26,11 @@ internal class HashMapKeys internal constructor( override fun checkIsMutable() = backing.checkIsMutable() } +/** + * This is the most performant implementations of [HashMap.values] container. + * It is implemented over [InternalMap] interface and can not be used without it. + * [HashMapValues] is more efficient than the implementation [HashMapValuesDefault] from HashMapEntryDefault.kt. + */ internal class HashMapValues internal constructor( private val backing: InternalMap<*, V>, ) : MutableCollection, AbstractMutableCollection() { @@ -68,6 +78,10 @@ internal abstract class HashMapEntrySetBase> internal override fun checkIsMutable() = backing.checkIsMutable() } +/** + * This is the implementations of [HashMap.entries] container. + * It is implemented over [InternalMap] interface and can not be used without it. + */ internal class HashMapEntrySet internal constructor( backing: InternalMap, ) : HashMapEntrySetBase>(backing) { diff --git a/libraries/stdlib/js/src/kotlin/collections/HashMapEntryDefault.kt b/libraries/stdlib/js/src/kotlin/collections/HashMapEntryDefault.kt index 79c1ed3a8d1..cd88e1d698b 100644 --- a/libraries/stdlib/js/src/kotlin/collections/HashMapEntryDefault.kt +++ b/libraries/stdlib/js/src/kotlin/collections/HashMapEntryDefault.kt @@ -5,6 +5,11 @@ package kotlin.collections +/** + * This is a default implementations of [AbstractMutableMap.keys] container. + * It is implemented over [AbstractMutableMap] and can be used directly from [AbstractMutableMap]. + * [HashMapKeysDefault] is less efficient than the implementation [HashMapKeys] from HashMapEntry.kt. + */ internal class HashMapKeysDefault(private val backingMap: AbstractMutableMap) : AbstractMutableSet() { override fun add(element: K): Boolean = throw UnsupportedOperationException("Add is not supported on keys") override fun clear() = backingMap.clear() @@ -33,6 +38,11 @@ internal class HashMapKeysDefault(private val backingMap: AbstractMutableM override fun checkIsMutable(): Unit = backingMap.checkIsMutable() } +/** + * This is a default implementations of [AbstractMutableMap.values] container. + * They are implemented over [AbstractMutableMap] and can be used directly from [AbstractMutableMap]. + * [HashMapValuesDefault] is efficient than the implementations [HashMapValues] from HashMapEntry.kt. + */ internal class HashMapValuesDefault(private val backingMap: AbstractMutableMap) : AbstractMutableCollection() { override fun add(element: V): Boolean = throw UnsupportedOperationException("Add is not supported on values") override fun clear() = backingMap.clear() diff --git a/libraries/stdlib/js/src/kotlin/collections/HashSet.kt b/libraries/stdlib/js/src/kotlin/collections/HashSet.kt index aaaf0ed0387..f2eaf7308e1 100644 --- a/libraries/stdlib/js/src/kotlin/collections/HashSet.kt +++ b/libraries/stdlib/js/src/kotlin/collections/HashSet.kt @@ -10,7 +10,7 @@ package kotlin.collections /** - * The implementation of the [MutableSet] interface, backed by a [HashMap] instance. + * The implementation of the [MutableSet] interface, backed by a [InternalMap] implementation. */ // Classes that extend HashSet and implement `build()` (freezing) operation // have to make sure mutating methods check `checkIsMutable`. diff --git a/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt b/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt index 8d99b6aea36..3d806018022 100644 --- a/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/InternalHashMap.kt @@ -5,6 +5,11 @@ package kotlin.collections +/** + * This is an open addressing hash map implementation. + * + * Copied from libraries/stdlib/native-wasm/src/kotlin/collections/HashMap.kt + */ internal class InternalHashMap private constructor( // keys in insert order private var keysArray: Array, diff --git a/libraries/stdlib/js/src/kotlin/collections/InternalStringLinkedMap.kt b/libraries/stdlib/js/src/kotlin/collections/InternalStringLinkedMap.kt index c25007eba86..bda373d04e3 100644 --- a/libraries/stdlib/js/src/kotlin/collections/InternalStringLinkedMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/InternalStringLinkedMap.kt @@ -5,6 +5,19 @@ package kotlin.collections +/** + * Extends [InternalStringMap] by preserving the insertion order. + * + * Two [IntArray]s are used to implement a linked list: + * the [nextIndexes] Array keeps the next indexes of the corresponding node, + * the [prevIndexes] Array keeps the previous indexes of the corresponding node. + * + * When adding a new key, we append its previous index (which points to the tail) to the end of the [prevIndexes] Array + * and update the next index of the tail. The last element of the [nextIndexes] array for the new key is set to [EMPTY_INDEX]. + * + * When removing a key, we update the next and previous indexes of adjacent nodes + * and move the last next-prev pair to the position of the removing key. + */ internal class InternalStringLinkedMap : InternalStringMap() { companion object { private const val EMPTY_INDEX = -1 diff --git a/libraries/stdlib/js/src/kotlin/collections/InternalStringMap.kt b/libraries/stdlib/js/src/kotlin/collections/InternalStringMap.kt index a85ca81a42b..c0ee7acd9bc 100644 --- a/libraries/stdlib/js/src/kotlin/collections/InternalStringMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/InternalStringMap.kt @@ -31,11 +31,34 @@ private inline fun JsRawArray.replaceElementAtWithLast(index: Int) { } /** - * A simple wrapper around JavaScript Map for key type is string. + * A simple wrapper around JavaScript Object for key type is string. * * Though this map is instantiated only with K=String, the K type is not fixed to String statically, * because we want to have it erased to Any? in order not to generate type-safe override bridges for * [get], [contains], [remove] etc, if they ever are generated. + * + * The string map has the following structure: + * A JavaScript Object keeps a mapping from a string key to an integer index: + * { : 0, : 1, ..., : n } + * + * Two separate JavaScript Arrays store key-value pairs corresponding to their indexes: + * [, , ..., ] + * [, , ..., ] + * + * When adding a new key-value pair, we append them to the end of the Arrays: + * [, , ..., , ] + * [, , ..., , ] + * and then set the new key with the last index in the Object: + * { : 0, : 1, ..., : n, : n + 1 } + * + * When removing a pair, we retrieve the index from the Object: + * { : 0, [[[: 1]]], ..., : n, : n + 1 } + * ^remove ^ + * and replace the removing pair with the last pair: + * [, , ..., ] + * [, , ..., ] + * After that, we update the moved key's index in the Object: + * { : 0, : 1, ..., : n } */ internal open class InternalStringMap : InternalMap { private fun createJsMap(): dynamic { diff --git a/libraries/stdlib/js/src/kotlin/collections/LinkedHashMap.kt b/libraries/stdlib/js/src/kotlin/collections/LinkedHashMap.kt index 5a9abacf604..169e4829e44 100644 --- a/libraries/stdlib/js/src/kotlin/collections/LinkedHashMap.kt +++ b/libraries/stdlib/js/src/kotlin/collections/LinkedHashMap.kt @@ -10,10 +10,10 @@ package kotlin.collections /** - * Hash table based implementation of the [MutableMap] interface, which additionally preserves the insertion order - * of entries during the iteration. + * Hash table based implementation of the [MutableMap] interface, + * which additionally preserves the insertion order of entries during the iteration. * - * The insertion order is preserved natively by the HashMap implementation. + * The insertion order is preserved by the corresponding [InternalMap] implementation. */ public actual open class LinkedHashMap : HashMap, MutableMap { /** @@ -74,8 +74,8 @@ public actual open class LinkedHashMap : HashMap, MutableMap { } /** - * Constructs the specialized implementation of [LinkedHashMap] with [String] keys, which stores the keys as properties of - * JS object without hashing them. + * Constructs the specialized implementation of [LinkedHashMap] with [String] keys, + * which stores the keys as properties of JS object without hashing them. */ public fun linkedStringMapOf(vararg pairs: Pair): LinkedHashMap { return LinkedHashMap(InternalStringLinkedMap()).apply { putAll(pairs) } diff --git a/libraries/stdlib/js/src/kotlin/collections/LinkedHashSet.kt b/libraries/stdlib/js/src/kotlin/collections/LinkedHashSet.kt index fdd7edbdb40..8fd0a8ffb98 100644 --- a/libraries/stdlib/js/src/kotlin/collections/LinkedHashSet.kt +++ b/libraries/stdlib/js/src/kotlin/collections/LinkedHashSet.kt @@ -10,9 +10,9 @@ package kotlin.collections /** - * The implementation of the [MutableSet] interface, backed by a [LinkedHashMap] instance. + * The implementation of the [MutableSet] interface, backed by a [InternalMap] implementation. * - * The insertion order is preserved natively by the HashSet implementation. + * The insertion order is preserved by the corresponding [InternalMap] implementation. */ public actual open class LinkedHashSet : HashSet, MutableSet { /**