From c54bc2ea18e697b8895218151dab6cf24134fe34 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Wed, 24 Aug 2016 19:35:42 +0300 Subject: [PATCH] Import AbstractMap implementation from GWT. #KT-12386 --- .../src/core/collections/AbstractMap.kt | 294 ++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 js/js.libraries/src/core/collections/AbstractMap.kt diff --git a/js/js.libraries/src/core/collections/AbstractMap.kt b/js/js.libraries/src/core/collections/AbstractMap.kt new file mode 100644 index 00000000000..8b83dc37492 --- /dev/null +++ b/js/js.libraries/src/core/collections/AbstractMap.kt @@ -0,0 +1,294 @@ +/* + * 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 AbstractMap + * Copyright 2007 Google Inc. + */ + +package kotlin.collections + +abstract class AbstractMap protected constructor() : MutableMap { + + /** + * A mutable [Map.Entry] shared by several [Map] implementations. + */ + open class SimpleEntry : AbstractEntry { + constructor(key: K, value: V) : super(key, value) { + } + + constructor(entry: Entry) : super(entry.key, entry.value) { + } + } + + /** + * An immutable [Map.Entry] shared by several [Map] implementations. + */ + class SimpleImmutableEntry : AbstractEntry { + constructor(key: K, value: V) : super(key, value) { + } + + constructor(entry: Entry) : super(entry.key, entry.value) { + } + + override fun setValue(value: V): V { + throw UnsupportedOperationException() + } + } + + /** + * Basic [Map.Entry] implementation used by [SimpleEntry] + * and [SimpleImmutableEntry]. + */ + private abstract class AbstractEntry protected constructor(private val key: K, private var value: V?) : Map.Entry { + + override fun getKey(): K { + return key + } + + override fun getValue(): V { + return value + } + + override fun setValue(value: V): V { + val oldValue = this.value + this.value = value + return oldValue + } + + override fun equals(other: Any?): Boolean { + if (other !is Entry<*, *>) { + return false + } + val entry = other as Entry<*, *>? + return key == entry!!.key && value == entry!!.value + } + + /** + * Calculate the hash code using Sun's specified algorithm. + */ + override fun hashCode(): Int { + return Objects.hashCode(key) xor Objects.hashCode(value) + } + + override fun toString(): String { + // for compatibility with the real Jre: issue 3422 + return key + "=" + value + } + } + + override fun clear() { + entries.clear() + } + + override fun containsKey(key: Any): Boolean { + return implFindEntry(key, false) != null + } + + override fun containsValue(value: Any): Boolean { + for ((key, v) in entries) { + if (value == v) { + return true + } + } + return false + } + + internal fun containsEntry(entry: Entry<*, *>): Boolean { + val key = entry.key + val value = entry.value + val ourValue = get(key) + + if (value != ourValue) { + return false + } + + // Perhaps it was null and we don't contain the key? + if (ourValue == null && !containsKey(key)) { + return false + } + + return true + } + + override fun equals(obj: Any?): Boolean { + if (obj === this) { + return true + } + if (obj !is Map<*, *>) { + return false + } + if (size != obj.size) { + return false + } + + for (entry in obj.entries) { + if (!containsEntry(entry)) { + return false + } + } + return true + } + + override operator fun get(key: Any): V? { + return getEntryValueOrNull(implFindEntry(key, false)) + } + + override fun hashCode(): Int { + return Collections.hashCode(entries) + } + + override fun isEmpty(): Boolean { + return size == 0 + } + + override fun keySet(): Set { + return object : AbstractSet() { + override fun clear() { + this@AbstractMap.clear() + } + + override operator fun contains(key: Any?): Boolean { + return containsKey(key) + } + + override operator fun iterator(): Iterator { + val outerIter = entries.iterator() + return object : Iterator { + override fun hasNext(): Boolean { + return outerIter.hasNext() + } + + override fun next(): K { + val entry = outerIter.next() + return entry.key + } + + override fun remove() { + outerIter.remove() + } + } + } + + override fun remove(key: Any?): Boolean { + if (containsKey(key)) { + this@AbstractMap.remove(key) + return true + } + return false + } + + override fun size(): Int { + return this@AbstractMap.size + } + } + } + + override fun put(key: K, value: V): V { + throw UnsupportedOperationException("Put not supported on this map") + } + + override fun putAll(map: Map) { + checkNotNull(map) + for ((key, value) in map) { + put(key, value) + } + } + + override fun remove(key: Any): V { + return getEntryValueOrNull(implFindEntry(key, true)) + } + + override fun size(): Int { + return entries.size + } + + override fun toString(): String { + val joiner = StringJoiner(", ", "{", "}") + for (entry in entries) { + joiner.add(toString(entry)) + } + return joiner.toString() + } + + private fun toString(entry: Entry): String { + return toString(entry.key) + "=" + toString(entry.value) + } + + private fun toString(o: Any): String { + return if (o === this) "(this Map)" else o.toString() + } + + override fun values(): Collection { + return object : AbstractCollection() { + override fun clear() { + this@AbstractMap.clear() + } + + override operator fun contains(value: Any?): Boolean { + return containsValue(value) + } + + override operator fun iterator(): Iterator { + val outerIter = entries.iterator() + return object : Iterator { + override fun hasNext(): Boolean { + return outerIter.hasNext() + } + + override fun next(): V { + val entry = outerIter.next() + return entry.value + } + + override fun remove() { + outerIter.remove() + } + } + } + + override fun size(): Int { + return this@AbstractMap.size + } + } + } + + private fun implFindEntry(key: Any, remove: Boolean): Entry? { + val iter = entries.iterator() + while (iter.hasNext()) { + var entry = iter.next() + val k = entry.key + if (key == k) { + if (remove) { + entry = SimpleEntry(entry.key, entry.value) + iter.remove() + } + return entry + } + } + return null + } + + companion object { + + internal fun getEntryKeyOrNull(entry: Entry?): K? { + return if (entry == null) null else entry!!.key + } + + internal fun getEntryValueOrNull(entry: Entry?): V? { + return if (entry == null) null else entry!!.value + } + } +}