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
}