All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kotlin.collections.AbstractMap.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1
Show newest version
/*
 * 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

/**
 * Provides a skeletal implementation of the read-only [Map] interface.
 *
 * The implementor is required to implement [entries] property, which should return read-only set of map entries.
 *
 * @param K the type of map keys. The map is invariant on its key type.
 * @param V the type of map values. The map is covariant on its value type.
*/
@SinceKotlin("1.1")
public abstract class AbstractMap protected constructor() : Map {

    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
    }


    /**
     * Compares this map with other instance with the ordered structural equality.
     *
     * @return true, if [other] instance is a [Map] of the same size, all entries of which are contained in the [entries] set of this map.
     */
    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


    /**
     * Returns the hash code value for this map.
     *
     * It is the same as the hashCode of [entries] set.
     */
    override fun hashCode(): Int = entries.hashCode()

    override fun isEmpty(): Boolean = size == 0
    override val size: Int get() = entries.size

    /**
     * Returns a read-only [Set] of all keys in this map.
     *
     * Accessing this property first time creates a keys view from [entries].
     * All subsequent accesses just return the created instance.
     */
    private @Volatile var _keys: Set? = null
    override val keys: Set get() {
        if (_keys == null) {
            _keys = object : AbstractSet() {
                override operator fun contains(element: K): Boolean = containsKey(element)

                override operator fun iterator(): Iterator {
                    val entryIterator = entries.iterator()
                    return object : Iterator {
                        override fun hasNext(): Boolean = entryIterator.hasNext()
                        override fun next(): K = entryIterator.next().key
                    }
                }

                override val size: Int get() = [email protected]
            }
        }
        return _keys!!
    }

    override fun toString(): String = entries.joinToString(", ", "{", "}") { toString(it) }

    private fun toString(entry: Map.Entry): String = toString(entry.key) + "=" + toString(entry.value)

    private fun toString(o: Any?): String = if (o === this) "(this Map)" else o.toString()

    /**
     * Returns a read-only [Collection] of all values in this map.
     *
     * Accessing this property first time creates a values view from [entries].
     * All subsequent accesses just return the created instance.
     */
    private @Volatile var _values: Collection? = null
    override val values: Collection get() {
        if (_values == null) {
            _values = object : AbstractCollection() {
                override operator fun contains(element: @UnsafeVariance V): Boolean = containsValue(element)

                override operator fun iterator(): Iterator {
                    val entryIterator = entries.iterator()
                    return object : Iterator {
                        override fun hasNext(): Boolean = entryIterator.hasNext()
                        override fun next(): V = entryIterator.next().value
                    }
                }

                override val size: Int get() = [email protected]
            }
        }
        return _values!!
    }

    private fun implFindEntry(key: K): Map.Entry? = 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
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy