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

commonMain.implementations.persistentOrderedMap.PersistentOrderedMap.kt Maven / Gradle / Ivy

There is a newer version: 0.3.8
Show newest version
/*
 * Copyright 2016-2019 JetBrains s.r.o.
 * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
 */

package kotlinx.collections.immutable.implementations.persistentOrderedMap

import kotlinx.collections.immutable.ImmutableCollection
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMap
import kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMapBuilder
import kotlinx.collections.immutable.internal.EndOfChain
import kotlinx.collections.immutable.mutate

internal class LinkedValue(val value: V, val previous: Any?, val next: Any?) {
    /** Constructs LinkedValue for a new single entry */
    constructor(value: V) : this(value, EndOfChain, EndOfChain)
    /** Constructs LinkedValue for a new last entry */
    constructor(value: V, previous: Any?) : this(value, previous, EndOfChain)

    fun withValue(newValue: V) = LinkedValue(newValue, previous, next)
    fun withPrevious(newPrevious: Any?) = LinkedValue(value, newPrevious, next)
    fun withNext(newNext: Any?) = LinkedValue(value, previous, newNext)

    val hasNext get() = next !== EndOfChain
    val hasPrevious get() = previous !== EndOfChain
}

internal class PersistentOrderedMap(
        internal val firstKey: Any?,
        internal val lastKey: Any?,
        internal val hashMap: PersistentHashMap>
) : AbstractMap(), PersistentMap {

    override val size: Int get() = hashMap.size

    override val keys: ImmutableSet
        get() {
            return PersistentOrderedMapKeys(this)
        }

    override val values: ImmutableCollection
        get() {
            return PersistentOrderedMapValues(this)
        }

    override val entries: ImmutableSet>
        get() {
            return createEntries()
        }

    private fun createEntries(): ImmutableSet> {
        return PersistentOrderedMapEntries(this)
    }

    // TODO: compiler bug: this bridge should be generated automatically
    @PublishedApi
    internal fun getEntries(): Set> {
        return createEntries()
    }

    override fun containsKey(key: K): Boolean = hashMap.containsKey(key)

    override fun get(key: K): V? = hashMap[key]?.value

    override fun put(key: K, value: @UnsafeVariance V): PersistentOrderedMap {
        if (isEmpty()) {
            val newMap = hashMap.put(key, LinkedValue(value))
            return PersistentOrderedMap(key, key, newMap)
        }

        val links = hashMap[key]
        if (links != null) {
            if (links.value === value) {
                return this
            }
            val newMap = hashMap.put(key, links.withValue(value))
            return PersistentOrderedMap(firstKey, lastKey, newMap)
        }

        @Suppress("UNCHECKED_CAST")
        val lastKey = lastKey as K
        val lastLinks = hashMap[lastKey]!!
//        assert(!lastLink.hasNext)
        val newMap = hashMap
                .put(lastKey, lastLinks.withNext(key))
                .put(key, LinkedValue(value, previous = lastKey))
        return PersistentOrderedMap(firstKey, key, newMap)
    }

    override fun remove(key: K): PersistentOrderedMap {
        val links = hashMap[key] ?: return this

        var newMap = hashMap.remove(key)
        if (links.hasPrevious) {
            val previousLinks = newMap[links.previous]!!
//            assert(previousLinks.next == key)
            @Suppress("UNCHECKED_CAST")
            newMap = newMap.put(links.previous as K, previousLinks.withNext(links.next))
        }
        if (links.hasNext) {
            val nextLinks = newMap[links.next]!!
//            assert(nextLinks.previous == key)
            @Suppress("UNCHECKED_CAST")
            newMap = newMap.put(links.next as K, nextLinks.withPrevious(links.previous))
        }

        val newFirstKey = if (!links.hasPrevious) links.next else firstKey
        val newLastKey = if (!links.hasNext) links.previous else lastKey
        return PersistentOrderedMap(newFirstKey, newLastKey, newMap)
    }

    override fun remove(key: K, value: @UnsafeVariance V): PersistentOrderedMap {
        val links = hashMap[key] ?: return this
        return if (links.value == value) this.remove(key) else this
    }

    override fun putAll(m: Map): PersistentMap {
        return this.mutate { it.putAll(m) }
    }

    override fun clear(): PersistentMap {
        return emptyOf()
    }

    override fun builder(): PersistentMap.Builder {
        return PersistentOrderedMapBuilder(this)
    }

    override fun equals(other: Any?): Boolean {
        if (other === this) return true
        if (other !is Map<*, *>) return false
        if (size != other.size) return false

        return when (other) {
            is PersistentOrderedMap<*, *> -> {
                hashMap.node.equalsWith(other.hashMap.node) { a, b ->
                    a.value == b.value
                }
            }
            is PersistentOrderedMapBuilder<*, *> -> {
                hashMap.node.equalsWith(other.hashMapBuilder.node) { a, b ->
                    a.value == b.value
                }
            }
            is PersistentHashMap<*, *> -> {
                hashMap.node.equalsWith(other.node) { a, b ->
                    a.value == b
                }
            }
            is PersistentHashMapBuilder<*, *> -> {
                hashMap.node.equalsWith(other.node) { a, b ->
                    a.value == b
                }
            }
            else -> super.equals(other)
        }
    }

    /**
     * We provide [equals], so as a matter of style, we should also provide [hashCode].
     * However, the implementation from [AbstractMap] is enough.
     */
    override fun hashCode(): Int = super.hashCode()

    internal companion object {
        private val EMPTY = PersistentOrderedMap(EndOfChain, EndOfChain, PersistentHashMap.emptyOf())
        @Suppress("UNCHECKED_CAST")
        internal fun  emptyOf(): PersistentOrderedMap = EMPTY as PersistentOrderedMap
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy