Flatten HashMap hierarhy, provide string-keyed map and set specializations.
This commit is contained in:
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import kotlin.collections.Map.Entry
|
||||
import kotlin.collections.MutableMap.MutableEntry
|
||||
|
||||
abstract class AbstractHashMap<K, V> : AbstractMap<K, V> {
|
||||
|
||||
private inner class EntrySet : AbstractSet<MutableEntry<K, V>>() {
|
||||
|
||||
override fun clear() {
|
||||
this@AbstractHashMap.clear()
|
||||
}
|
||||
|
||||
override operator fun contains(element: MutableEntry<K, V>): Boolean = containsEntry(element)
|
||||
|
||||
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = hashCodeMap.iterator()
|
||||
|
||||
override fun remove(entry: MutableEntry<K, V>): Boolean {
|
||||
if (contains(entry)) {
|
||||
this@AbstractHashMap.remove(entry.key)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override val size: Int get() = this@AbstractHashMap.size
|
||||
}
|
||||
|
||||
/*
|
||||
private inner class EntrySetIterator : Iterator<Entry<K, V>> {
|
||||
private val stringMapEntries = stringMap!!.iterator()
|
||||
private var current: MutableIterator<Entry<K, V>> = stringMapEntries
|
||||
private var last: MutableIterator<Entry<K, V>>? = 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<K, V> {
|
||||
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.
|
||||
*/
|
||||
private var hashCodeMap = InternalHashCodeMap<K, V>(this)
|
||||
|
||||
// /**
|
||||
// * A map of Strings onto values.
|
||||
// */
|
||||
// @Transient private var stringMap: InternalStringMap<K, V>? = null
|
||||
|
||||
constructor() : super()
|
||||
// init {
|
||||
// reset()
|
||||
// }
|
||||
|
||||
constructor(capacity: Int, loadFactor: Float = 0f) : this() {
|
||||
// This implementation of HashMap has no need of load factors or capacities.
|
||||
require(capacity >= 0) { "Negative initial capacity" }
|
||||
require(loadFactor >= 0) { "Non-positive load factor" }
|
||||
}
|
||||
|
||||
constructor(original: Map<out K, V>) : this() {
|
||||
this.putAll(original)
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
// reset()
|
||||
// }
|
||||
//
|
||||
// private fun reset() {
|
||||
hashCodeMap = InternalHashCodeMap<K, V>(this)
|
||||
// stringMap = InternalStringMap<K, V>(this)
|
||||
// structureChanged(this)
|
||||
}
|
||||
|
||||
// @SpecializeMethod(params = { String.class }, target = "hasStringValue")
|
||||
override fun containsKey(key: K): Boolean {
|
||||
return hasHashValue(key)
|
||||
// return if (key is String)
|
||||
// hasStringValue(JsUtils.unsafeCastToString(key))
|
||||
// else
|
||||
// hasHashValue(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: V): Boolean {
|
||||
return /*containsValue(value, stringMap) || */ containsValue(value, hashCodeMap)
|
||||
}
|
||||
|
||||
private fun containsValue(value: V, entries: Iterable<Entry<K, V>>): Boolean = entries.any { equals(it.value, value) }
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() = EntrySet()
|
||||
|
||||
// @SpecializeMethod(params = { String.class }, target = "getStringValue")
|
||||
override operator fun get(key: K): V? {
|
||||
return getHashValue(key)
|
||||
// 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 putHashValue(key, value)
|
||||
// return if (key is String)
|
||||
// putStringValue(JsUtils.unsafeCastToString(key), value)
|
||||
// else
|
||||
// putHashValue(key, value)
|
||||
}
|
||||
|
||||
// @SpecializeMethod(params = { String.class }, target = "removeStringValue")
|
||||
override fun remove(key: K): V? {
|
||||
return removeHashValue(key)
|
||||
// return if (key is String)
|
||||
// removeStringValue(JsUtils.unsafeCastToString(key))
|
||||
// else
|
||||
// removeHashValue(key)
|
||||
}
|
||||
|
||||
override val size: Int get() {
|
||||
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: K): 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: K): V? {
|
||||
return hashCodeMap.getEntry(key)?.value
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 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: K): 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: K): 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)
|
||||
// }
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
package kotlin.collections
|
||||
|
||||
internal interface EqualityComparator {
|
||||
/**
|
||||
* Subclasses must override to return a whether or not two keys or values are
|
||||
* equal.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
abstract fun getHashCode(value: Any?): Int
|
||||
|
||||
|
||||
object HashCode : EqualityComparator {
|
||||
override fun equals(value1: Any?, value2: Any?): Boolean = value1 == value2
|
||||
|
||||
override fun getHashCode(value: Any?): Int = value?.hashCode() ?: 0
|
||||
}
|
||||
}
|
||||
@@ -14,24 +14,264 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Based on GWT HashMap
|
||||
* Based on GWT AbstractHashMap
|
||||
* Copyright 2008 Google Inc.
|
||||
*/
|
||||
|
||||
package kotlin.collections
|
||||
|
||||
import kotlin.collections.Map.Entry
|
||||
import kotlin.collections.MutableMap.MutableEntry
|
||||
|
||||
open class HashMap<K, V> : AbstractHashMap<K, V> {
|
||||
open class HashMap<K, V> : AbstractMap<K, V> {
|
||||
|
||||
constructor() : super()
|
||||
constructor(capacity: Int, loadFactor: Float = 0f) : super(capacity, loadFactor)
|
||||
constructor(original: Map<out K, V>) : super(original)
|
||||
private inner class EntrySet : AbstractSet<MutableEntry<K, V>>() {
|
||||
|
||||
// public override fun clone(): Any {
|
||||
// return HashMap<K, V>(this)
|
||||
override fun clear() {
|
||||
this@HashMap.clear()
|
||||
}
|
||||
|
||||
override operator fun contains(element: MutableEntry<K, V>): Boolean = containsEntry(element)
|
||||
|
||||
override operator fun iterator(): MutableIterator<MutableEntry<K, V>> = internalMap.iterator()
|
||||
|
||||
override fun remove(entry: MutableEntry<K, V>): Boolean {
|
||||
if (contains(entry)) {
|
||||
this@HashMap.remove(entry.key)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override val size: Int get() = this@HashMap.size
|
||||
}
|
||||
|
||||
/*
|
||||
private inner class EntrySetIterator : Iterator<Entry<K, V>> {
|
||||
private val stringMapEntries = stringMap!!.iterator()
|
||||
private var current: MutableIterator<Entry<K, V>> = stringMapEntries
|
||||
private var last: MutableIterator<Entry<K, V>>? = 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<K, V> {
|
||||
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.
|
||||
*/
|
||||
private val internalMap: InternalMap<K, V>
|
||||
|
||||
internal val equality: EqualityComparator
|
||||
|
||||
// /**
|
||||
// * A map of Strings onto values.
|
||||
// */
|
||||
// @Transient private var stringMap: InternalStringMap<K, V>? = null
|
||||
//
|
||||
internal constructor(internalMapProvider: (HashMap<K, V>) -> InternalMap<K, V>, equality: EqualityComparator = EqualityComparator.HashCode) : super() {
|
||||
this.equality = equality
|
||||
this.internalMap = internalMapProvider(this)
|
||||
}
|
||||
|
||||
constructor() : this( { m -> InternalHashCodeMap(m) })
|
||||
// init {
|
||||
// reset()
|
||||
// }
|
||||
|
||||
override fun equals(value1: Any?, value2: Any?): Boolean = value1 == value2
|
||||
constructor(capacity: Int, loadFactor: Float = 0f) : this() {
|
||||
// This implementation of HashMap has no need of load factors or capacities.
|
||||
require(capacity >= 0) { "Negative initial capacity" }
|
||||
require(loadFactor >= 0) { "Non-positive load factor" }
|
||||
}
|
||||
|
||||
override fun getHashCode(key: K): Int = key?.hashCode() ?: 0
|
||||
constructor(original: Map<out K, V>) : this() {
|
||||
this.putAll(original)
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
internalMap.clear()
|
||||
// reset()
|
||||
// }
|
||||
//
|
||||
// private fun reset() {
|
||||
// internalMap = internalMapProvider(this)
|
||||
// stringMap = InternalStringMap<K, V>(this)
|
||||
// structureChanged(this)
|
||||
}
|
||||
|
||||
// @SpecializeMethod(params = { String.class }, target = "hasStringValue")
|
||||
override fun containsKey(key: K): Boolean {
|
||||
return internalMap.contains(key)
|
||||
// return if (key is String)
|
||||
// hasStringValue(JsUtils.unsafeCastToString(key))
|
||||
// else
|
||||
// hasHashValue(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: V): Boolean {
|
||||
return /*containsValue(value, stringMap) || */ containsValue(value, internalMap)
|
||||
}
|
||||
|
||||
private fun containsValue(value: V, entries: Iterable<Entry<K, V>>): Boolean = entries.any { equality.equals(it.value, value) }
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() = EntrySet()
|
||||
|
||||
// @SpecializeMethod(params = { String.class }, target = "getStringValue")
|
||||
override operator fun get(key: K): V? {
|
||||
return internalMap.get(key)
|
||||
// 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 internalMap.put(key, value)
|
||||
// return if (key is String)
|
||||
// putStringValue(JsUtils.unsafeCastToString(key), value)
|
||||
// else
|
||||
// putHashValue(key, value)
|
||||
}
|
||||
|
||||
// @SpecializeMethod(params = { String.class }, target = "removeStringValue")
|
||||
override fun remove(key: K): V? {
|
||||
return internalMap.remove(key)
|
||||
// return if (key is String)
|
||||
// removeStringValue(JsUtils.unsafeCastToString(key))
|
||||
// else
|
||||
// removeHashValue(key)
|
||||
}
|
||||
|
||||
override val size: Int get() {
|
||||
return internalMap.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: K): 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: K): V? {
|
||||
// return hashCodeMap.getEntry(key)?.value
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 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: K): 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: K): 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)
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
public fun <V> stringMapOf(vararg pairs: Pair<String, V>): HashMap<String, V> {
|
||||
return HashMap<String, V>({ m -> InternalStringMap(m) }).apply { putAll(pairs) }
|
||||
}
|
||||
@@ -44,7 +44,7 @@ open class HashSet<E> : AbstractSet<E> {
|
||||
|
||||
* @param map underlying map to use.
|
||||
*/
|
||||
protected constructor(map: HashMap<E, Any>) {
|
||||
internal constructor(map: HashMap<E, Any>) {
|
||||
this.map = map
|
||||
}
|
||||
|
||||
@@ -72,3 +72,7 @@ open class HashSet<E> : AbstractSet<E> {
|
||||
override val size: Int get() = map.size
|
||||
|
||||
}
|
||||
|
||||
public fun stringSetOf(vararg elements: String): HashSet<String> {
|
||||
return HashSet(stringMapOf<Any>()).apply { addAll(elements) }
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@ import kotlin.collections.AbstractMap.SimpleEntry
|
||||
* 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>(private val host: AbstractHashMap<K, V>) : MutableIterable<MutableEntry<K, V>> {
|
||||
internal class InternalHashCodeMap<K, V>(private val host: HashMap<K, V>) : InternalMap<K, V> {
|
||||
|
||||
private val backingMap: dynamic = js("new Object()")
|
||||
var size: Int = 0
|
||||
private var backingMap: dynamic = js("Object.create(null)")
|
||||
override var size: Int = 0
|
||||
private set
|
||||
|
||||
fun put(key: K, value: V): V? {
|
||||
val hashCode = host.getHashCode(key)
|
||||
override fun put(key: K, value: V): V? {
|
||||
val hashCode = host.equality.getHashCode(key)
|
||||
val chain = getChainOrNull(hashCode)
|
||||
if (chain == null) {
|
||||
// This is a new chain, put it to the map.
|
||||
@@ -61,12 +61,12 @@ internal class InternalHashCodeMap<K, V>(private val host: AbstractHashMap<K, V>
|
||||
return null
|
||||
}
|
||||
|
||||
fun remove(key: K): V? {
|
||||
val hashCode = host.getHashCode(key)
|
||||
override fun remove(key: K): V? {
|
||||
val hashCode = host.equality.getHashCode(key)
|
||||
val chain = getChainOrNull(hashCode) ?: return null
|
||||
for (index in 0..chain.size-1) {
|
||||
val entry = chain[index]
|
||||
if (host.equals(key, entry.key)) {
|
||||
if (host.equality.equals(key, entry.key)) {
|
||||
if (chain.size == 1) {
|
||||
chain.asDynamic().length = 0
|
||||
// remove the whole array
|
||||
@@ -84,11 +84,20 @@ internal class InternalHashCodeMap<K, V>(private val host: AbstractHashMap<K, V>
|
||||
return null
|
||||
}
|
||||
|
||||
fun getEntry(key: K): MutableEntry<K, V>? =
|
||||
getChainOrNull(host.getHashCode(key))?.findEntryInChain(key)
|
||||
override fun clear() {
|
||||
backingMap = js("Object.create(null)")
|
||||
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>? =
|
||||
getChainOrNull(host.equality.getHashCode(key))?.findEntryInChain(key)
|
||||
|
||||
private fun Array<MutableEntry<K, V>>.findEntryInChain(key: K): MutableEntry<K, V>? =
|
||||
firstOrNull { entry -> host.equals(entry.key, key) }
|
||||
firstOrNull { entry -> host.equality.equals(entry.key, key) }
|
||||
|
||||
override fun iterator(): MutableIterator<MutableEntry<K, V>> {
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package kotlin.collections
|
||||
|
||||
internal interface InternalMap<K, V> : MutableIterable<MutableMap.MutableEntry<K, V>> {
|
||||
val size: Int
|
||||
operator fun contains(key: K): Boolean
|
||||
operator fun get(key: K): V?
|
||||
|
||||
fun put(key: K, value: V): V?
|
||||
fun remove(key: K): V?
|
||||
fun clear(): Unit
|
||||
}
|
||||
@@ -19,106 +19,103 @@
|
||||
*/
|
||||
package kotlin.collections
|
||||
|
||||
import kotlin.collections.MutableMap.MutableEntry
|
||||
|
||||
/**
|
||||
* A simple wrapper around JavaScript Map for key type is string.
|
||||
*/
|
||||
internal class InternalStringMap<K, V>(private val host: AbstractHashMap<K, V>) : Iterable<Entry<K, V>> {
|
||||
internal class InternalStringMap<K, V>(private val host: HashMap<K, V>) : InternalMap<K, V> {
|
||||
|
||||
private val backingMap = InternalJsMapFactory.newJsMap()
|
||||
private var size: Int = 0
|
||||
private var backingMap: dynamic = js("Object.create(null)")
|
||||
override var size: Int = 0
|
||||
private set
|
||||
|
||||
/**
|
||||
* A mod count to track 'value' replacements in map to ensure that the 'value' that we have in the
|
||||
* iterator entry is guaranteed to be still correct.
|
||||
* This is to optimize for the common scenario where the values are not modified during
|
||||
* iterations where the entries are never stale.
|
||||
*/
|
||||
private var valueMod: Int = 0
|
||||
// /**
|
||||
// * A mod count to track 'value' replacements in map to ensure that the 'value' that we have in the
|
||||
// * iterator entry is guaranteed to be still correct.
|
||||
// * This is to optimize for the common scenario where the values are not modified during
|
||||
// * iterations where the entries are never stale.
|
||||
// */
|
||||
// private var valueMod: Int = 0
|
||||
|
||||
operator fun contains(key: String): Boolean {
|
||||
return !JsUtils.isUndefined(backingMap.get(key))
|
||||
override operator fun contains(key: K): Boolean {
|
||||
if (key !is String) return false
|
||||
return backingMap[key] !== undefined
|
||||
}
|
||||
|
||||
operator fun get(key: String): V {
|
||||
return backingMap.get(key)
|
||||
override operator fun get(key: K): V? {
|
||||
if (key !is String) return null
|
||||
val value = backingMap[key]
|
||||
return if (value !== undefined) value as V else null
|
||||
}
|
||||
|
||||
fun put(key: String, value: V): V {
|
||||
val oldValue = backingMap.get(key)
|
||||
backingMap.set(key, toNullIfUndefined(value))
|
||||
|
||||
if (JsUtils.isUndefined(oldValue)) {
|
||||
override fun put(key: K, value: V): V? {
|
||||
require(key is String)
|
||||
val oldValue = backingMap[key]
|
||||
backingMap[key] = value
|
||||
|
||||
if (oldValue == undefined) {
|
||||
size++
|
||||
structureChanged(host)
|
||||
// structureChanged(host)
|
||||
return null
|
||||
}
|
||||
else {
|
||||
valueMod++
|
||||
// valueMod++
|
||||
return oldValue as V
|
||||
}
|
||||
return oldValue
|
||||
}
|
||||
|
||||
fun remove(key: String): V {
|
||||
val value = backingMap.get(key)
|
||||
if (!JsUtils.isUndefined(value)) {
|
||||
backingMap.delete(key)
|
||||
override fun remove(key: K): V? {
|
||||
if (key !is String) return null
|
||||
val value = backingMap[key]
|
||||
if (value !== undefined) {
|
||||
deleteProperty(backingMap, key!!)
|
||||
size--
|
||||
structureChanged(host)
|
||||
// structureChanged(host)
|
||||
return value as V
|
||||
}
|
||||
else {
|
||||
valueMod++
|
||||
// valueMod++
|
||||
return null
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
fun size(): Int {
|
||||
return size
|
||||
|
||||
override fun clear() {
|
||||
backingMap = js("Object.create(null)")
|
||||
size = 0
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Entry<K, V>> {
|
||||
return object : Iterator<Entry<K, V>> {
|
||||
internal var entries = backingMap.entries()
|
||||
internal var current = entries.next()
|
||||
internal var last: InternalJsMap.IteratorEntry<V>
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return !current.done
|
||||
}
|
||||
override fun iterator(): MutableIterator<MutableEntry<K, V>> {
|
||||
return object : MutableIterator<MutableEntry<K, V>> {
|
||||
private val keys: Array<String> = js("Object").keys(backingMap)
|
||||
private val iterator = keys.iterator()
|
||||
private var lastKey: String? = null
|
||||
|
||||
override fun next(): Entry<K, V> {
|
||||
last = current
|
||||
current = entries.next()
|
||||
return newMapEntry(last, valueMod)
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
|
||||
override fun next(): MutableEntry<K, V> {
|
||||
val key = iterator.next()
|
||||
lastKey = key
|
||||
return newMapEntry(key as K)
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
this@InternalStringMap.remove(last.getKey())
|
||||
this@InternalStringMap.remove(checkNotNull(lastKey) as K)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun newMapEntry(entry: InternalJsMap.IteratorEntry<V>,
|
||||
lastValueMod: Int): Entry<K, V> {
|
||||
return object : AbstractMapEntry<K, V>() {
|
||||
val key: K
|
||||
@SuppressWarnings("unchecked")
|
||||
get() = entry.getKey()
|
||||
// Let's get a fresh copy as the value may have changed.
|
||||
val value: V
|
||||
get() {
|
||||
if (valueMod != lastValueMod) {
|
||||
return get(entry.getKey())
|
||||
}
|
||||
return entry.getValue()
|
||||
}
|
||||
private fun newMapEntry(key: K): MutableEntry<K, V> = object : MutableEntry<K, V> {
|
||||
override val key: K get() = key
|
||||
override val value: V get() = this@InternalStringMap[key] as V
|
||||
|
||||
fun setValue(`object`: V): V {
|
||||
return put(entry.getKey(), `object`)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun setValue(value: V): V = this@InternalStringMap.put(key, value) as V
|
||||
|
||||
private fun <T> toNullIfUndefined(value: T): T? {
|
||||
return if (JsUtils.isUndefined(value)) null else value
|
||||
override fun hashCode(): Int = AbstractMap.entryHashCode(this)
|
||||
override fun toString(): String = AbstractMap.entryToString(this)
|
||||
override fun equals(other: Any?): Boolean = AbstractMap.entryEquals(this, other)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class PrimitiveMapJsTest : MapJsTest() {
|
||||
}
|
||||
|
||||
override fun <T : kotlin.Comparable<T>> Collection<T>.toNormalizedList(): List<T> = this.sorted()
|
||||
override fun emptyMutableMap(): MutableMap<String, Int> = HashMap()
|
||||
override fun emptyMutableMap(): MutableMap<String, Int> = stringMapOf()
|
||||
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = HashMap()
|
||||
|
||||
@test fun compareBehavior() {
|
||||
|
||||
@@ -31,7 +31,7 @@ class ComplexSetJsTest : SetJsTest() {
|
||||
}
|
||||
|
||||
class PrimitiveSetJsTest : SetJsTest() {
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = HashSet()
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = stringSetOf()
|
||||
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = HashSet()
|
||||
@Test
|
||||
override fun constructors() {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package test.collections.js
|
||||
|
||||
import java.util.*
|
||||
|
||||
public fun <V> stringMapOf(vararg pairs: Pair<String, V>): HashMap<String, V> = hashMapOf<String, V>(*pairs)
|
||||
public fun stringSetOf(vararg elements: String): HashSet<String> = hashSetOf(*elements)
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
|
||||
<!-- exclude JVM tests-->
|
||||
<exclude name="**/*JVM.kt"/>
|
||||
<exclude name="**/*JVMTest.kt"/>
|
||||
<exclude name="**/*JVMTests.kt"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user