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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Based on GWT HashMap
|
* Based on GWT AbstractHashMap
|
||||||
* Copyright 2008 Google Inc.
|
* Copyright 2008 Google Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package kotlin.collections
|
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()
|
private inner class EntrySet : AbstractSet<MutableEntry<K, V>>() {
|
||||||
constructor(capacity: Int, loadFactor: Float = 0f) : super(capacity, loadFactor)
|
|
||||||
constructor(original: Map<out K, V>) : super(original)
|
|
||||||
|
|
||||||
// public override fun clone(): Any {
|
override fun clear() {
|
||||||
// return HashMap<K, V>(this)
|
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.
|
* @param map underlying map to use.
|
||||||
*/
|
*/
|
||||||
protected constructor(map: HashMap<E, Any>) {
|
internal constructor(map: HashMap<E, Any>) {
|
||||||
this.map = map
|
this.map = map
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,3 +72,7 @@ open class HashSet<E> : AbstractSet<E> {
|
|||||||
override val size: Int get() = map.size
|
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
|
* have the same hash, each value in hashCodeMap is actually an array containing all entries whose
|
||||||
* keys share the same hash.
|
* 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()")
|
private var backingMap: dynamic = js("Object.create(null)")
|
||||||
var size: Int = 0
|
override var size: Int = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun put(key: K, value: V): V? {
|
override fun put(key: K, value: V): V? {
|
||||||
val hashCode = host.getHashCode(key)
|
val hashCode = host.equality.getHashCode(key)
|
||||||
val chain = getChainOrNull(hashCode)
|
val chain = getChainOrNull(hashCode)
|
||||||
if (chain == null) {
|
if (chain == null) {
|
||||||
// This is a new chain, put it to the map.
|
// 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
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(key: K): V? {
|
override fun remove(key: K): V? {
|
||||||
val hashCode = host.getHashCode(key)
|
val hashCode = host.equality.getHashCode(key)
|
||||||
val chain = getChainOrNull(hashCode) ?: return null
|
val chain = getChainOrNull(hashCode) ?: return null
|
||||||
for (index in 0..chain.size-1) {
|
for (index in 0..chain.size-1) {
|
||||||
val entry = chain[index]
|
val entry = chain[index]
|
||||||
if (host.equals(key, entry.key)) {
|
if (host.equality.equals(key, entry.key)) {
|
||||||
if (chain.size == 1) {
|
if (chain.size == 1) {
|
||||||
chain.asDynamic().length = 0
|
chain.asDynamic().length = 0
|
||||||
// remove the whole array
|
// remove the whole array
|
||||||
@@ -84,11 +84,20 @@ internal class InternalHashCodeMap<K, V>(private val host: AbstractHashMap<K, V>
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEntry(key: K): MutableEntry<K, V>? =
|
override fun clear() {
|
||||||
getChainOrNull(host.getHashCode(key))?.findEntryInChain(key)
|
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>? =
|
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>> {
|
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
|
package kotlin.collections
|
||||||
|
|
||||||
|
import kotlin.collections.MutableMap.MutableEntry
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple wrapper around JavaScript Map for key type is string.
|
* 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 backingMap: dynamic = js("Object.create(null)")
|
||||||
private var size: Int = 0
|
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
|
// * 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.
|
// * iterator entry is guaranteed to be still correct.
|
||||||
* This is to optimize for the common scenario where the values are not modified during
|
// * This is to optimize for the common scenario where the values are not modified during
|
||||||
* iterations where the entries are never stale.
|
// * iterations where the entries are never stale.
|
||||||
*/
|
// */
|
||||||
private var valueMod: Int = 0
|
// private var valueMod: Int = 0
|
||||||
|
|
||||||
operator fun contains(key: String): Boolean {
|
override operator fun contains(key: K): Boolean {
|
||||||
return !JsUtils.isUndefined(backingMap.get(key))
|
if (key !is String) return false
|
||||||
|
return backingMap[key] !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(key: String): V {
|
override operator fun get(key: K): V? {
|
||||||
return backingMap.get(key)
|
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++
|
size++
|
||||||
structureChanged(host)
|
// structureChanged(host)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
valueMod++
|
// valueMod++
|
||||||
|
return oldValue as V
|
||||||
}
|
}
|
||||||
return oldValue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remove(key: String): V {
|
override fun remove(key: K): V? {
|
||||||
val value = backingMap.get(key)
|
if (key !is String) return null
|
||||||
if (!JsUtils.isUndefined(value)) {
|
val value = backingMap[key]
|
||||||
backingMap.delete(key)
|
if (value !== undefined) {
|
||||||
|
deleteProperty(backingMap, key!!)
|
||||||
size--
|
size--
|
||||||
structureChanged(host)
|
// structureChanged(host)
|
||||||
|
return value as V
|
||||||
}
|
}
|
||||||
else {
|
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 {
|
override fun iterator(): MutableIterator<MutableEntry<K, V>> {
|
||||||
return !current.done
|
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> {
|
override fun hasNext(): Boolean = iterator.hasNext()
|
||||||
last = current
|
|
||||||
current = entries.next()
|
override fun next(): MutableEntry<K, V> {
|
||||||
return newMapEntry(last, valueMod)
|
val key = iterator.next()
|
||||||
|
lastKey = key
|
||||||
|
return newMapEntry(key as K)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove() {
|
override fun remove() {
|
||||||
this@InternalStringMap.remove(last.getKey())
|
this@InternalStringMap.remove(checkNotNull(lastKey) as K)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newMapEntry(entry: InternalJsMap.IteratorEntry<V>,
|
private fun newMapEntry(key: K): MutableEntry<K, V> = object : MutableEntry<K, V> {
|
||||||
lastValueMod: Int): Entry<K, V> {
|
override val key: K get() = key
|
||||||
return object : AbstractMapEntry<K, V>() {
|
override val value: V get() = this@InternalStringMap[key] as 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setValue(`object`: V): V {
|
override fun setValue(value: V): V = this@InternalStringMap.put(key, value) as V
|
||||||
return put(entry.getKey(), `object`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> toNullIfUndefined(value: T): T? {
|
override fun hashCode(): Int = AbstractMap.entryHashCode(this)
|
||||||
return if (JsUtils.isUndefined(value)) null else value
|
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 <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()
|
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = HashMap()
|
||||||
|
|
||||||
@test fun compareBehavior() {
|
@test fun compareBehavior() {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class ComplexSetJsTest : SetJsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PrimitiveSetJsTest : SetJsTest() {
|
class PrimitiveSetJsTest : SetJsTest() {
|
||||||
override fun createEmptyMutableSet(): MutableSet<String> = HashSet()
|
override fun createEmptyMutableSet(): MutableSet<String> = stringSetOf()
|
||||||
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = HashSet()
|
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = HashSet()
|
||||||
@Test
|
@Test
|
||||||
override fun constructors() {
|
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 JVM tests-->
|
||||||
|
<exclude name="**/*JVM.kt"/>
|
||||||
<exclude name="**/*JVMTest.kt"/>
|
<exclude name="**/*JVMTest.kt"/>
|
||||||
<exclude name="**/*JVMTests.kt"/>
|
<exclude name="**/*JVMTests.kt"/>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user