Split AbstractMap into readonly and mutable.

This commit is contained in:
Ilya Gorbunov
2016-09-01 00:53:59 +03:00
parent a5c0f11d60
commit 38f030dce4
7 changed files with 163 additions and 87 deletions
@@ -20,7 +20,7 @@
package kotlin.collections
public abstract class AbstractMap<K, V> protected constructor() : MutableMap<K, V> {
public abstract class AbstractMutableMap<K, V> protected constructor() : AbstractMap<K, V>(), MutableMap<K, V> {
/**
* A mutable [Map.Entry] shared by several [Map] implementations.
@@ -44,67 +44,14 @@ public abstract class AbstractMap<K, V> protected constructor() : MutableMap<K,
}
/**
* An immutable [Map.Entry] shared by several [Map] implementations.
*/
class SimpleImmutableEntry<out K, out V>(override val key: K, override val value: V) : Map.Entry<K, V> {
constructor(entry: Map.Entry<K, V>) : this(entry.key, entry.value)
override fun hashCode(): Int = entryHashCode(this)
override fun toString(): String = entryToString(this)
override fun equals(other: Any?): Boolean = entryEquals(this, other)
}
override fun clear() {
entries.clear()
}
override fun containsKey(key: K): Boolean {
return implFindEntry(key, false) != null
}
override fun containsValue(value: V): Boolean = entries.any { it.value == value }
internal fun containsEntry(entry: Map.Entry<*, *>?): Boolean {
// since entry comes from @UnsafeVariance parameters it can be virtually anything
if (entry !is Map.Entry<*, *>) return false
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(other: Any?): Boolean {
if (other === this) return true
if (other !is Map<*, *>) return false
if (size != other.size) return false
return other.entries.all { containsEntry(it) }
}
override operator fun get(key: K): V? = implFindEntry(key, false)?.value
override fun hashCode(): Int = entries.hashCode()
override fun isEmpty(): Boolean = size == 0
override val size: Int get() = entries.size
override val keys: MutableSet<K> get() {
return object : AbstractMutableSet<K>() {
override fun clear() {
this@AbstractMap.clear()
this@AbstractMutableMap.clear()
}
override operator fun contains(element: K): Boolean = containsKey(element)
@@ -120,13 +67,13 @@ public abstract class AbstractMap<K, V> protected constructor() : MutableMap<K,
override fun remove(element: K): Boolean {
if (containsKey(element)) {
this@AbstractMap.remove(element)
this@AbstractMutableMap.remove(element)
return true
}
return false
}
override val size: Int get() = this@AbstractMap.size
override val size: Int get() = this@AbstractMutableMap.size
}
}
@@ -140,17 +87,9 @@ public abstract class AbstractMap<K, V> protected constructor() : MutableMap<K,
}
}
override fun remove(key: K): V? = implFindEntry(key, true)?.value
override fun toString(): String = entries.joinToString(", ", "{", "}") { toString(it) }
private fun toString(entry: Map.Entry<K, V>): String = toString(entry.key) + "=" + toString(entry.value)
private fun toString(o: Any?): String = if (o === this) "(this Map)" else o.toString()
override val values: MutableCollection<V> get() {
return object : AbstractMutableCollection<V>() {
override fun clear() = this@AbstractMap.clear()
override fun clear() = this@AbstractMutableMap.clear()
override operator fun contains(element: V): Boolean = containsValue(element)
@@ -163,7 +102,7 @@ public abstract class AbstractMap<K, V> protected constructor() : MutableMap<K,
}
}
override val size: Int get() = this@AbstractMap.size
override val size: Int get() = this@AbstractMutableMap.size
// TODO: should we implement them this way? Currently it's unspecified in JVM
override fun equals(other: Any?): Boolean {
@@ -175,29 +114,18 @@ public abstract class AbstractMap<K, V> protected constructor() : MutableMap<K,
}
}
private fun implFindEntry(key: K, remove: Boolean): Map.Entry<K, V>? {
override fun remove(key: K): V? {
val iter = entries.iterator()
while (iter.hasNext()) {
var entry = iter.next()
val k = entry.key
if (key == k) {
if (remove) {
entry = SimpleEntry(entry)
iter.remove()
}
return entry
val value = entry.value
iter.remove()
return value
}
}
return null
}
companion object {
internal fun entryHashCode(e: Map.Entry<*, *>): Int = with(e) { (key?.hashCode() ?: 0) xor (value?.hashCode() ?: 0) }
internal fun entryToString(e: Map.Entry<*, *>): String = with(e) { "$key=$value" }
internal fun entryEquals(e: Map.Entry<*, *>, other: Any?): Boolean {
if (other !is Map.Entry<*, *>) return false
return e.key == other.key && e.value == other.value
}
}
}
@@ -23,7 +23,7 @@ package kotlin.collections
import kotlin.collections.Map.Entry
import kotlin.collections.MutableMap.MutableEntry
open class HashMap<K, V> : AbstractMap<K, V> {
public open class HashMap<K, V> : AbstractMutableMap<K, V> {
private inner class EntrySet : AbstractMutableSet<MutableEntry<K, V>>() {
@@ -21,7 +21,7 @@
package kotlin.collections
import kotlin.collections.MutableMap.MutableEntry
import kotlin.collections.AbstractMap.SimpleEntry
import kotlin.collections.AbstractMutableMap.SimpleEntry
/**
* A simple wrapper around JavaScriptObject to provide [java.util.Map]-like semantics for any
@@ -21,7 +21,7 @@ package kotlin.collections
import kotlin.collections.MutableMap.MutableEntry
open class LinkedHashMap<K, V> : HashMap<K, V>, Map<K, V> {
public open class LinkedHashMap<K, V> : HashMap<K, V>, Map<K, V> {
/**
* The entry we use includes next/prev pointers for a doubly-linked circular
@@ -35,7 +35,7 @@ open class LinkedHashMap<K, V> : HashMap<K, V>, Map<K, V> {
* small modifications. Paying a small storage cost only if you use
* LinkedHashMap and minimizing code size seemed like a better tradeoff
*/
private class ChainEntry<K, V>(key: K, value: V) : AbstractMap.SimpleEntry<K, V>(key, value) {
private class ChainEntry<K, V>(key: K, value: V) : AbstractMutableMap.SimpleEntry<K, V>(key, value) {
internal var next: ChainEntry<K, V>? = null
internal var prev: ChainEntry<K, V>? = null
}
@@ -0,0 +1,123 @@
/*
* 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
public abstract class AbstractMap<K, out V> protected constructor() : Map<K, V> {
override fun containsKey(key: K): Boolean {
return implFindEntry(key) != null
}
override fun containsValue(value: @UnsafeVariance V): Boolean = entries.any { it.value == value }
internal fun containsEntry(entry: Map.Entry<*, *>?): Boolean {
// since entry comes from @UnsafeVariance parameters it can be virtually anything
if (entry !is Map.Entry<*, *>) return false
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(other: Any?): Boolean {
if (other === this) return true
if (other !is Map<*, *>) return false
if (size != other.size) return false
return other.entries.all { containsEntry(it) }
}
override operator fun get(key: K): V? = implFindEntry(key)?.value
override fun hashCode(): Int = entries.hashCode()
override fun isEmpty(): Boolean = size == 0
override val size: Int get() = entries.size
override val keys: Set<K> get() {
return object : AbstractSet<K>() {
override operator fun contains(element: K): Boolean = containsKey(element)
override operator fun iterator(): Iterator<K> {
val outerIter = entries.iterator()
return object : Iterator<K> {
override fun hasNext(): Boolean = outerIter.hasNext()
override fun next(): K = outerIter.next().key
}
}
override val size: Int get() = this@AbstractMap.size
}
}
override fun toString(): String = entries.joinToString(", ", "{", "}") { toString(it) }
private fun toString(entry: Map.Entry<K, V>): String = toString(entry.key) + "=" + toString(entry.value)
private fun toString(o: Any?): String = if (o === this) "(this Map)" else o.toString()
override val values: Collection<V> get() {
return object : AbstractCollection<V>() {
override operator fun contains(element: @UnsafeVariance V): Boolean = containsValue(element)
override operator fun iterator(): Iterator<V> {
val outerIter = entries.iterator()
return object : Iterator<V> {
override fun hasNext(): Boolean = outerIter.hasNext()
override fun next(): V = outerIter.next().value
}
}
override val size: Int get() = this@AbstractMap.size
// TODO: should we implement them this way? Currently it's unspecified in JVM
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Collection<*>) return false
return AbstractList.orderedEquals(this, other)
}
override fun hashCode(): Int = AbstractList.orderedHashCode(this)
}
}
private fun implFindEntry(key: K): Map.Entry<K, V>? = entries.firstOrNull { it.key == key }
internal companion object {
internal fun entryHashCode(e: Map.Entry<*, *>): Int = with(e) { (key?.hashCode() ?: 0) xor (value?.hashCode() ?: 0) }
internal fun entryToString(e: Map.Entry<*, *>): String = with(e) { "$key=$value" }
internal fun entryEquals(e: Map.Entry<*, *>, other: Any?): Boolean {
if (other !is Map.Entry<*, *>) return false
return e.key == other.key && e.value == other.value
}
}
}
@@ -3,4 +3,5 @@ package kotlin.collections
public typealias AbstractMutableCollection<E> = java.util.AbstractCollection<E>
public typealias AbstractMutableList<E> = java.util.AbstractList<E>
public typealias AbstractMutableSet<E> = java.util.AbstractSet<E>
public typealias AbstractMutableSet<E> = java.util.AbstractSet<E>
public typealias AbstractMutableMap<K, V> = java.util.AbstractMap<K, V>
@@ -125,6 +125,30 @@ public abstract class kotlin/collections/AbstractList : kotlin/collections/Abstr
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
}
public abstract class kotlin/collections/AbstractMap : java/util/Map, kotlin/jvm/internal/markers/KMappedMarker {
public static final field Companion Lkotlin/collections/AbstractMap$Companion;
protected fun <init> ()V
public fun clear ()V
public fun containsKey (Ljava/lang/Object;)Z
public fun containsValue (Ljava/lang/Object;)Z
public final fun entrySet ()Ljava/util/Set;
public fun equals (Ljava/lang/Object;)Z
public fun get (Ljava/lang/Object;)Ljava/lang/Object;
public abstract fun getEntries ()Ljava/util/Set;
public fun getKeys ()Ljava/util/Set;
public fun getSize ()I
public fun getValues ()Ljava/util/Collection;
public fun hashCode ()I
public fun isEmpty ()Z
public final fun keySet ()Ljava/util/Set;
public fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun putAll (Ljava/util/Map;)V
public fun remove (Ljava/lang/Object;)Ljava/lang/Object;
public final fun size ()I
public fun toString ()Ljava/lang/String;
public final fun values ()Ljava/util/Collection;
}
public abstract class kotlin/collections/AbstractSet : kotlin/collections/AbstractCollection, java/util/Set, kotlin/jvm/internal/markers/KMappedMarker {
public static final field Companion Lkotlin/collections/AbstractSet$Companion;
protected fun <init> ()V