From b05c2c1f6aff8e7dc4dd123f2cf63fb1e12e84bd Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Thu, 25 Aug 2016 21:14:17 +0300 Subject: [PATCH] Import AbstractHashMap, HashMap, HashSet, LinkedHashMap, LinkedHashSet from GWT #KT-12386 --- .../src/core/collections/AbstractHashMap.kt | 279 ++++++++++++++++++ .../src/core/collections/HashMap.kt | 64 ++++ .../src/core/collections/HashSet.kt | 101 +++++++ .../core/collections/InternalHashCodeMap.kt | 163 ++++++++++ .../src/core/collections/LinkedHashMap.kt | 260 ++++++++++++++++ .../src/core/collections/LinkedHashSet.kt | 38 +++ 6 files changed, 905 insertions(+) create mode 100644 js/js.libraries/src/core/collections/AbstractHashMap.kt create mode 100644 js/js.libraries/src/core/collections/HashMap.kt create mode 100644 js/js.libraries/src/core/collections/HashSet.kt create mode 100644 js/js.libraries/src/core/collections/InternalHashCodeMap.kt create mode 100644 js/js.libraries/src/core/collections/LinkedHashMap.kt create mode 100644 js/js.libraries/src/core/collections/LinkedHashSet.kt diff --git a/js/js.libraries/src/core/collections/AbstractHashMap.kt b/js/js.libraries/src/core/collections/AbstractHashMap.kt new file mode 100644 index 00000000000..d35a929d5ee --- /dev/null +++ b/js/js.libraries/src/core/collections/AbstractHashMap.kt @@ -0,0 +1,279 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Based on GWT AbstractHashMap + * Copyright 2008 Google Inc. + */ + +package kotlin.collections + +abstract class AbstractHashMap : AbstractMap { + + private inner class EntrySet : AbstractSet>() { + + override fun clear() { + this@AbstractHashMap.clear() + } + + override operator fun contains(o: Any?): Boolean { + if (o is Entry<*, *>) { + return containsEntry(o as Entry<*, *>?) + } + return false + } + + override operator fun iterator(): Iterator> { + return EntrySetIterator() + } + + override fun remove(entry: Any?): Boolean { + if (contains(entry)) { + val key = (entry as Entry<*, *>).key + this@AbstractHashMap.remove(key) + return true + } + return false + } + + override fun size(): Int { + return this@AbstractHashMap.size + } + } + + /** + * Iterator for `EntrySet`. + */ + private inner class EntrySetIterator : Iterator> { + private val stringMapEntries = stringMap!!.iterator() + private var current: MutableIterator> = stringMapEntries + private var last: MutableIterator>? = null + private var hasNext = computeHasNext() + + init { + recordLastKnownStructure(this@AbstractHashMap, this) + } + + override fun hasNext(): Boolean { + return hasNext + } + + private fun computeHasNext(): Boolean { + if (current.hasNext()) { + return true + } + if (current !== stringMapEntries) { + return false + } + current = hashCodeMap!!.iterator() + return current.hasNext() + } + + override fun next(): Entry { + checkStructuralChange(this@AbstractHashMap, this) + checkElement(hasNext()) + + last = current + val rv = current.next() + hasNext = computeHasNext() + + return rv + } + + override fun remove() { + checkState(last != null) + checkStructuralChange(this@AbstractHashMap, this) + + last!!.remove() + last = null + hasNext = computeHasNext() + + recordLastKnownStructure(this@AbstractHashMap, this) + } + } + + /** + * A map of integral hashCodes onto entries. + */ + @Transient private var hashCodeMap: InternalHashCodeMap? = null + + /** + * A map of Strings onto values. + */ + @Transient private var stringMap: InternalStringMap? = null + + constructor() { + reset() + } + + @JvmOverloads constructor(ignored: Int, alsoIgnored: Float = 0f) { + // This implementation of HashMap has no need of load factors or capacities. + checkArgument(ignored >= 0, "Negative initial capacity") + checkArgument(alsoIgnored >= 0, "Non-positive load factor") + + reset() + } + + constructor(toBeCopied: Map) { + reset() + this.putAll(toBeCopied) + } + + override fun clear() { + reset() + } + + private fun reset() { + hashCodeMap = InternalHashCodeMap(this) + stringMap = InternalStringMap(this) + structureChanged(this) + } + + @SpecializeMethod(params = { String.class }, target = "hasStringValue") + override fun containsKey(key: Any?): Boolean { + return if (key is String) + hasStringValue(JsUtils.unsafeCastToString(key)) + else + hasHashValue(key) + } + + override fun containsValue(value: Any?): Boolean { + return containsValue(value, stringMap) || containsValue(value, hashCodeMap) + } + + private fun containsValue(value: Any, entries: Iterable>): Boolean { + for (entry in entries) { + if (equals(value, entry.value)) { + return true + } + } + return false + } + + override fun entrySet(): Set> { + return EntrySet() + } + + @SpecializeMethod(params = { String.class }, target = "getStringValue") + override operator fun get(key: Any?): V { + return if (key is String) + getStringValue(JsUtils.unsafeCastToString(key)) + else + getHashValue(key) + } + + @SpecializeMethod(params = { String.class, Object .class }, target = "putStringValue") + override fun put(key: K?, value: V?): V { + return if (key is String) + putStringValue(JsUtils.unsafeCastToString(key), value) + else + putHashValue(key, value) + } + + @SpecializeMethod(params = { String.class }, target = "removeStringValue") + override fun remove(key: Any?): V { + return if (key is String) + removeStringValue(JsUtils.unsafeCastToString(key)) + else + removeHashValue(key) + } + + override fun size(): Int { + return hashCodeMap!!.size() + stringMap!!.size() + } + + /** + * Subclasses must override to return a whether or not two keys or values are + * equal. + */ + internal abstract fun equals(value1: Any, value2: Any): Boolean + + /** + * Subclasses must override to return a hash code for a given key. The key is + * guaranteed to be non-null and not a String. + */ + internal abstract fun getHashCode(key: Any): Int + + /** + * Returns the Map.Entry whose key is Object equal to `key`, + * provided that `key`'s hash code is `hashCode`; + * or `null` if no such Map.Entry exists at the specified + * hashCode. + */ + private fun getHashValue(key: Any?): V { + return getEntryValueOrNull(hashCodeMap!!.getEntry(key)) + } + + /** + * Returns the value for the given key in the stringMap. Returns + * `null` if the specified key does not exist. + */ + private fun getStringValue(key: String?): V { + return if (key == null) getHashValue(null) else stringMap!!.get(key) + } + + /** + * Returns true if the a key exists in the hashCodeMap that is Object equal to + * `key`, provided that `key`'s hash code is + * `hashCode`. + */ + private fun hasHashValue(key: Any?): Boolean { + return hashCodeMap!!.getEntry(key) != null + } + + /** + * Returns true if the given key exists in the stringMap. + */ + private fun hasStringValue(key: String?): Boolean { + return if (key == null) hasHashValue(null) else stringMap!!.contains(key) + } + + /** + * Sets the specified key to the specified value in the hashCodeMap. Returns + * the value previously at that key. Returns `null` if the + * specified key did not exist. + */ + private fun putHashValue(key: K?, value: V): V { + return hashCodeMap!!.put(key, value) + } + + /** + * Sets the specified key to the specified value in the stringMap. Returns the + * value previously at that key. Returns `null` if the specified + * key did not exist. + */ + private fun putStringValue(key: String?, value: V): V { + return if (key == null) putHashValue(null, value) else stringMap!!.put(key, value) + } + + /** + * Removes the pair whose key is Object equal to `key` from + * `hashCodeMap`, provided that `key`'s hash code + * is `hashCode`. Returns the value that was associated with the + * removed key, or null if no such key existed. + */ + private fun removeHashValue(key: Any?): V { + return hashCodeMap!!.remove(key) + } + + /** + * Removes the specified key from the stringMap and returns the value that was + * previously there. Returns `null` if the specified key does not + * exist. + */ + private fun removeStringValue(key: String?): V { + return if (key == null) removeHashValue(null) else stringMap!!.remove(key) + } +}// This implementation of HashMap has no need of initial capacities. \ No newline at end of file diff --git a/js/js.libraries/src/core/collections/HashMap.kt b/js/js.libraries/src/core/collections/HashMap.kt new file mode 100644 index 00000000000..6f4999cada6 --- /dev/null +++ b/js/js.libraries/src/core/collections/HashMap.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Based on GWT HashMap + * Copyright 2008 Google Inc. + */ + +package kotlin.collections + +open class HashMap : AbstractHashMap, Cloneable, Serializable { + + /** + * Ensures that RPC will consider type parameter K to be exposed. It will be + * pruned by dead code elimination. + */ + @SuppressWarnings("unused") + private val exposeKey: K? = null + + /** + * Ensures that RPC will consider type parameter V to be exposed. It will be + * pruned by dead code elimination. + */ + @SuppressWarnings("unused") + private val exposeValue: V? = null + + constructor() { + } + + constructor(ignored: Int) : super(ignored) { + } + + constructor(ignored: Int, alsoIgnored: Float) : super(ignored, alsoIgnored) { + } + + constructor(toBeCopied: Map) : super(toBeCopied) { + } + + public override fun clone(): Any { + return HashMap(this) + } + + internal fun equals(value1: Any, value2: Any): Boolean { + return value1 == value2 + } + + internal fun getHashCode(key: Any): Int { + val hashCode = key.hashCode() + // Coerce to int -- our classes all do this, but a user-written class might not. + return ensureInt(hashCode) + } +} diff --git a/js/js.libraries/src/core/collections/HashSet.kt b/js/js.libraries/src/core/collections/HashSet.kt new file mode 100644 index 00000000000..523bb79ba41 --- /dev/null +++ b/js/js.libraries/src/core/collections/HashSet.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Based on GWT HashSet + * Copyright 2008 Google Inc. + */ + +package kotlin.collections + + +/** + * Implements a set in terms of a hash table. [[Sun + * docs]](http://java.sun.com/j2se/1.5.0/docs/api/java/util/HashSet.html) + + * @param element type. + */ +open class HashSet : AbstractSet, Set, Cloneable, Serializable { + + @Transient private var map: HashMap? = null + + /** + * Ensures that RPC will consider type parameter E to be exposed. It will be + * pruned by dead code elimination. + */ + @SuppressWarnings("unused") + private val exposeElement: E? = null + + constructor() { + map = HashMap() + } + + constructor(c: Collection) { + map = HashMap(c.size) + addAll(c) + } + + constructor(initialCapacity: Int) { + map = HashMap(initialCapacity) + } + + constructor(initialCapacity: Int, loadFactor: Float) { + map = HashMap(initialCapacity, loadFactor) + } + + /** + * Protected constructor to specify the underlying map. This is used by + * LinkedHashSet. + + * @param map underlying map to use. + */ + protected constructor(map: HashMap) { + this.map = map + } + + override fun add(o: E?): Boolean { + val old = map!!.put(o, this) + return old == null + } + + override fun clear() { + map!!.clear() + } + + public override fun clone(): Any { + return HashSet(this) + } + + override operator fun contains(o: Any?): Boolean { + return map!!.containsKey(o) + } + + override fun isEmpty(): Boolean { + return map!!.isEmpty() + } + + override fun iterator(): Iterator { + return map!!.keys.iterator() + } + + override fun remove(o: Any?): Boolean { + return map!!.remove(o) != null + } + + override fun size(): Int { + return map!!.size + } + +} diff --git a/js/js.libraries/src/core/collections/InternalHashCodeMap.kt b/js/js.libraries/src/core/collections/InternalHashCodeMap.kt new file mode 100644 index 00000000000..6cedb1c64be --- /dev/null +++ b/js/js.libraries/src/core/collections/InternalHashCodeMap.kt @@ -0,0 +1,163 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Based on GWT InternalHashCodeMap + * Copyright 2008 Google Inc. + */ + +package kotlin.collections + +import java.util.ConcurrentModificationDetector.structureChanged + +import java.util.AbstractMap.SimpleEntry + +import javaemul.internal.ArrayHelper + +/** + * 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. + */ +private class InternalHashCodeMap(private val host: AbstractHashMap) : Iterable> { + + private val backingMap = InternalJsMapFactory.newJsMap() + private var size: Int = 0 + + fun put(key: K, value: V): V? { + val hashCode = hash(key) + val chain = getChainOrEmpty(hashCode) + + if (chain.size == 0) { + // This is a new chain, put it to the map. + backingMap.set(hashCode, chain) + } + else { + // Chain already exists, perhaps key also exists. + val entry = findEntryInChain(key, chain) + if (entry != null) { + return entry!!.setValue(value) + } + } + chain[chain.size] = SimpleEntry(key, value) + size++ + structureChanged(host) + return null + } + + fun remove(key: Any): V? { + val hashCode = hash(key) + val chain = getChainOrEmpty(hashCode) + for (i in chain.indices) { + val entry = chain[i] + if (host.equals(key, entry.key)) { + if (chain.size == 1) { + ArrayHelper.setLength(chain, 0) + // remove the whole array + backingMap.delete(hashCode) + } + else { + // splice out the entry we're removing + ArrayHelper.removeFrom(chain, i, 1) + } + size-- + structureChanged(host) + return entry.value + } + } + return null + } + + fun getEntry(key: Any): Entry { + return findEntryInChain(key, getChainOrEmpty(hash(key))) + } + + private fun findEntryInChain(key: Any, chain: Array>): Entry? { + for (entry in chain) { + if (host.equals(key, entry.key)) { + return entry + } + } + return null + } + + fun size(): Int { + return size + } + + override fun iterator(): Iterator> { + return object : Iterator> { + internal val chains = backingMap.entries() + internal var itemIndex = 0 + internal var chain = newEntryChain() + internal var lastEntry: Entry? = null + + override fun hasNext(): Boolean { + if (itemIndex < chain.size) { + return true + } + val current = chains.next() + if (!current.done) { + // Move to the beginning of next chain + chain = unsafeCastToArray(current.getValue()) + itemIndex = 0 + return true + } + return false + } + + override fun next(): Entry { + lastEntry = chain[itemIndex++] + return lastEntry + } + + override fun remove() { + this@InternalHashCodeMap.remove(lastEntry!!.key) + // Unless we are in a new chain, all items have shifted so our itemIndex should as well... + if (itemIndex != 0) { + itemIndex-- + } + } + } + } + + private fun getChainOrEmpty(hashCode: Int): Array> { + val chain = unsafeCastToArray(backingMap.get(hashCode)) + return chain ?: newEntryChain() + } + + private fun newEntryChain(/*-{ + return []; + }-*/): Array> + + private fun unsafeCastToArray(arr: Any /*-{ + return arr; + }-*/): Array>? + + /** + * Returns hash code of the key as calculated by [AbstractHashMap.getHashCode] but + * also handles null keys as well. + */ + private fun hash(key: Any?): Int { + return if (key == null) 0 else host.getHashCode(key) + } +} diff --git a/js/js.libraries/src/core/collections/LinkedHashMap.kt b/js/js.libraries/src/core/collections/LinkedHashMap.kt new file mode 100644 index 00000000000..d66647cc521 --- /dev/null +++ b/js/js.libraries/src/core/collections/LinkedHashMap.kt @@ -0,0 +1,260 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Based on GWT LinkedHashMap + * Copyright 2008 Google Inc. + */ +package kotlin.collections + +open class LinkedHashMap : HashMap, Map { + + /** + * 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 @JvmOverloads constructor(key: K? = null, value: V? = null) : AbstractMap.SimpleEntry(key, value) { + @Transient private var next: ChainEntry? = null + @Transient private var prev: ChainEntry? = null + + /** + * Add this node to the end of the chain. + */ + fun addToEnd() { + val tail = head.prev + + // Chain is valid. + assert(head != null && tail != null) + + // This entry is not in the list. + assert(next == null && prev == null) + + // Update me. + prev = tail + next = head + tail!!.next = head.prev = this + } + + /** + * Remove this node from any list it may be a part of. + */ + fun remove() { + next!!.prev = prev + prev!!.next = next + next = prev = null + } + } + + private inner class EntrySet : AbstractSet>() { + + private inner class EntryIterator : Iterator> { + // The last entry that was returned from this iterator. + private var last: ChainEntry? = null + + // The next entry to return from this iterator. + private var next: ChainEntry? = null + + init { + next = head.next + recordLastKnownStructure(map, this) + } + + override fun hasNext(): Boolean { + return next !== head + } + + override fun next(): Entry { + checkStructuralChange(map, this) + checkCriticalElement(hasNext()) + + last = next + next = next!!.next + return last + } + + override fun remove() { + checkState(last != null) + checkStructuralChange(map, this) + + last!!.remove() + map.remove(last!!.key) + recordLastKnownStructure(map, this) + last = null + } + } + + override fun clear() { + this@LinkedHashMap.clear() + } + + override operator fun contains(o: Any?): Boolean { + if (o is Entry<*, *>) { + return containsEntry(o as Entry<*, *>?) + } + return false + } + + override operator fun iterator(): Iterator> { + return EntryIterator() + } + + override fun remove(entry: Any?): Boolean { + if (contains(entry)) { + val key = (entry as Entry<*, *>).key + this@LinkedHashMap.remove(key) + return true + } + return false + } + + override fun size(): Int { + return this@LinkedHashMap.size + } + } + + // True if we should use the access order (ie, for LRU caches) instead of + // insertion order. + @Transient private val accessOrder: Boolean + + /* + * The head of the LRU/insert order chain, which is a doubly-linked circular + * list. The key and value of head should never be read. + * + * The most recently inserted/accessed node is at the end of the chain, ie. + * chain.prev. + */ + @Transient private val head = ChainEntry() + + /* + * 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. + */ + @Transient private val map = HashMap() + + constructor() { + resetChainEntries() + } + + @JvmOverloads constructor(ignored: Int, alsoIgnored: Float = 0f) : super(ignored, alsoIgnored) { + resetChainEntries() + } + + constructor(ignored: Int, alsoIgnored: Float, accessOrder: Boolean) : super(ignored, alsoIgnored) { + this.accessOrder = accessOrder + resetChainEntries() + } + + constructor(toBeCopied: Map) { + resetChainEntries() + this.putAll(toBeCopied) + } + + override fun clear() { + map.clear() + resetChainEntries() + } + + private fun resetChainEntries() { + head.prev = head + head.next = head + } + + override fun clone(): Any { + return LinkedHashMap(this) + } + + override fun containsKey(key: Any?): Boolean { + return map.containsKey(key) + } + + override fun containsValue(value: Any?): Boolean { + var node: ChainEntry = head.next + while (node !== head) { + if (node.value == value) { + return true + } + node = node.next + } + return false + } + + override fun entrySet(): Set> { + return EntrySet() + } + + override operator fun get(key: Any?): V? { + val entry = map.get(key) + if (entry != null) { + recordAccess(entry) + return entry!!.value + } + return null + } + + override fun put(key: K?, value: V?): V? { + val old = map.get(key) + if (old == null) { + val newEntry = ChainEntry(key, value) + map.put(key, newEntry) + newEntry.addToEnd() + val eldest = head.next + if (removeEldestEntry(eldest)) { + eldest!!.remove() + map.remove(eldest.key) + } + return null + } + else { + val oldValue = old!!.setValue(value) + recordAccess(old) + return oldValue + } + } + + override fun remove(key: Any?): V? { + val entry = map.remove(key) + if (entry != null) { + entry!!.remove() + return entry!!.value + } + return null + } + + override fun size(): Int { + return map.size + } + + @SuppressWarnings("unused") + protected fun removeEldestEntry(eldest: Entry): Boolean { + return false + } + + private fun recordAccess(entry: ChainEntry) { + if (accessOrder) { + // Move to the tail of the chain on access. + entry.remove() + entry.addToEnd() + } + } +} diff --git a/js/js.libraries/src/core/collections/LinkedHashSet.kt b/js/js.libraries/src/core/collections/LinkedHashSet.kt new file mode 100644 index 00000000000..d24ba8e9d7c --- /dev/null +++ b/js/js.libraries/src/core/collections/LinkedHashSet.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * Based on GWT LinkedHashSet + * Copyright 2008 Google Inc. + */ + +package kotlin.collections + +open class LinkedHashSet : HashSet { + + constructor() : super(LinkedHashMap()) + + constructor(c: Collection) : super(LinkedHashMap()) { + addAll(c) + } + + constructor(capacity: Int) : super(LinkedHashMap(capacity)) + constructor(capacity: Int, loadFactor: Float = 0.0f) : super(LinkedHashMap(capacity, loadFactor)) + +// public override fun clone(): Any { +// return LinkedHashSet(this) +// } + +}