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

commonMain.org.antlr.v4.kotlinruntime.misc.FlexibleHashMap.kt Maven / Gradle / Ivy

/*
 * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */

package org.antlr.v4.kotlinruntime.misc

/** A limited map (many unsupported operations) that lets me use
 * varying hashCode/equals.
 */
open class FlexibleHashMap constructor(
        comparator: AbstractEqualityComparator? = null,
        initialCapacity: Int = INITAL_CAPACITY,
        initialBucketCapacity: Int = INITAL_BUCKET_CAPACITY
) : MutableMap {

    //TODO efficiency
    override val keys: MutableSet
        get() = buckets.filterNotNull().flatMap { it.filterNotNull().map { it.key } }.toMutableSet()

    //TODO efficiency
    override val values: MutableCollection
        get() = buckets.filterNotNull().flatMap { it.filterNotNull().map { it.value } }.toMutableList()

    override val entries: MutableSet>
        get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.

    protected val comparator: AbstractEqualityComparator

    // TODO are bucket entries actually nullable?
    protected var buckets: Array?>?>

    /** How many elements in set  */
    protected var n = 0

    override val size: Int = n

    protected var threshold = (INITAL_CAPACITY * LOAD_FACTOR).toInt() // when to expand

    protected var currentPrime = 1 // jump by 4 primes each expand or whatever
    protected var initialBucketCapacity = INITAL_BUCKET_CAPACITY

    class Entry(val key: K, var value: V) {

        override fun toString(): String {
            return key.toString() + ":" + value.toString()
        }
    }

    init {
        var comparator = comparator
        if (comparator == null) {
            comparator = ObjectEqualityComparator.INSTANCE
        }

        this.comparator = comparator
        this.buckets = createEntryListArray(initialBucketCapacity)
        this.initialBucketCapacity = initialBucketCapacity
    }

    protected fun getBucket(key: K): Int {
        val hash = comparator.hashCode(key)
        return hash and buckets.size - 1
    }

    override fun get(key: K): V? {
        if (key == null) return null
        val b = getBucket(key)
        val bucket = buckets[b] ?: return null
// no bucket
        for (e in bucket) {
            if (comparator.equals(e?.key, key)) {
                return e?.value
            }
        }
        return null
    }

    override fun put(key: K, value: V): V? {
        if (key == null) return null
        if (n > threshold) expand()
        val b = getBucket(key)

        val existingBucket = buckets[b]
        val bucket: MutableList?> = if (existingBucket != null) existingBucket else {
            buckets[b] = mutableListOf()
            buckets[b]!!
        }

        for (e in bucket) {
            if (comparator.equals(e?.key, key)) {
                val prev = e?.value
                e?.value = value
                n++
                return prev
            }
        }
        // not there
        bucket.add(Entry(key, value))
        n++
        return null
    }

    override fun remove(key: K): V {
        throw UnsupportedOperationException()
    }

    override fun putAll(from: Map) {
        throw UnsupportedOperationException()
    }
//
//    fun keySet(): Set {
//        throw UnsupportedOperationException()
//    }

//    fun values(): Collection {
//        val a = ArrayList(size)
//        for (bucket in buckets) {
//            if (bucket == null) continue
//            for (e in bucket) {
//                a.add(e.value)
//            }
//        }
//        return a
//    }

//    fun entrySet(): Set> {
//        throw UnsupportedOperationException()
//    }

    override fun containsKey(key: K): Boolean {
        return get(key) != null
    }

    override fun containsValue(value: V): Boolean {
        throw UnsupportedOperationException()
    }

    override fun hashCode(): Int {
        var hash = MurmurHash.initialize()
        for (bucket in buckets) {
            if (bucket == null) continue
            for (e in bucket) {
                if (e == null) break
                hash = MurmurHash.update(hash, comparator.hashCode(e.key))
            }
        }

        hash = MurmurHash.finish(hash, size)
        return hash
    }

    override fun equals(o: Any?): Boolean {
        throw UnsupportedOperationException()
    }

    protected fun expand() {

        val old = buckets
        // TODO better mode of growing that always size * 2
        val newCapacity = buckets.size * 2
        val newTable = createEntryListArray(newCapacity)
        buckets = newTable
        threshold = (newCapacity * LOAD_FACTOR).toInt()
        //		System.out.println("new size="+newCapacity+", thres="+threshold);
        // rehash all existing entries
        val oldSize = size
        for (bucket in old) {
            if (bucket == null) continue
            for (e in bucket) {
                if (e == null) break
                put(e.key, e.value)
            }
        }
        n = oldSize
    }

//    fun size(): Int {
//        return n
//    }

    override fun isEmpty(): Boolean {
        return n == 0
    }

    override fun clear() {
        buckets = createEntryListArray(INITAL_CAPACITY)
        n = 0
    }

    override fun toString(): String {
        if (size == 0) return "{}"

        val buf = StringBuilder()
        buf.append('{')
        var first = true
        for (bucket in buckets) {
            if (bucket == null) continue
            for (e in bucket) {
                if (e == null) break
                if (first)
                    first = false
                else
                    buf.append(", ")
                buf.append(e.toString())
            }
        }
        buf.append('}')
        return buf.toString()
    }

    fun toTableString(): String {
        val buf = StringBuilder()
        for (bucket in buckets) {
            if (bucket == null) {
                buf.append("null\n")
                continue
            }
            buf.append('[')
            var first = true
            for (e in bucket) {
                if (first)
                    first = false
                else
                    buf.append(" ")
                if (e == null)
                    buf.append("_")
                else
                    buf.append(e.toString())
            }
            buf.append("]\n")
        }
        return buf.toString()
    }

    companion object {
        val INITAL_CAPACITY = 16 // must be power of 2
        val INITAL_BUCKET_CAPACITY = 8
        val LOAD_FACTOR = 0.75

        private fun  createEntryListArray(length: Int): Array?>?> {
            return arrayOfNulls>(length) as Array?>?>
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy