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

commonMain.implementations.immutableMap.PersistentHashMapContentIterators.kt Maven / Gradle / Ivy

The 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.immutableMap

import kotlinx.collections.immutable.internal.assert
import kotlin.js.JsName

internal const val TRIE_MAX_HEIGHT = 7

internal abstract class TrieNodeBaseIterator : Iterator {
    protected var buffer = TrieNode.EMPTY.buffer
        private set
    private var dataSize = 0
    protected var index = 0

    fun reset(buffer: Array, dataSize: Int, index: Int) {
        this.buffer = buffer
        this.dataSize = dataSize
        this.index = index
    }

    fun reset(buffer: Array, dataSize: Int) {
        reset(buffer, dataSize, 0)
    }

    fun hasNextKey(): Boolean {
        return index < dataSize
    }

    fun currentKey(): K {
        assert(hasNextKey())
        @Suppress("UNCHECKED_CAST")
        return buffer[index] as K
    }

    fun moveToNextKey() {
        assert(hasNextKey())
        index += 2
    }

    fun hasNextNode(): Boolean {
        assert(index >= dataSize)
        return index < buffer.size
    }

    fun currentNode(): TrieNode {
        assert(hasNextNode())
        @Suppress("UNCHECKED_CAST")
        return buffer[index] as TrieNode
    }

    fun moveToNextNode() {
        assert(hasNextNode())
        index++
    }

    override fun hasNext(): Boolean {
        return hasNextKey()
    }
}

internal class TrieNodeKeysIterator : TrieNodeBaseIterator() {
    override fun next(): K {
        assert(hasNextKey())
        index += 2
        @Suppress("UNCHECKED_CAST")
        return buffer[index - 2] as K
    }
}

internal class TrieNodeValuesIterator : TrieNodeBaseIterator() {
    override fun next(): V {
        assert(hasNextKey())
        index += 2
        @Suppress("UNCHECKED_CAST")
        return buffer[index - 1] as V
    }
}

internal class TrieNodeEntriesIterator : TrieNodeBaseIterator>() {
    override fun next(): Map.Entry {
        assert(hasNextKey())
        index += 2
        @Suppress("UNCHECKED_CAST")
        return MapEntry(buffer[index - 2] as K, buffer[index - 1] as V)
    }
}

internal open class MapEntry(override val key: K, override val value: V) : Map.Entry {
    override fun hashCode(): Int = key.hashCode() xor value.hashCode()
    override fun equals(other: Any?): Boolean =
            (other as? Map.Entry<*, *>)?.let { it.key == key && it.value == value } ?: false

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


internal abstract class PersistentHashMapBaseIterator(
        node: TrieNode,
        protected val path: Array>
) : Iterator {

    protected var pathLastIndex = 0
    @JsName("_hasNext")
    private var hasNext = true

    init {
        path[0].reset(node.buffer, ENTRY_SIZE * node.entryCount())
        pathLastIndex = 0
        ensureNextEntryIsReady()
    }

    private fun moveToNextNodeWithData(pathIndex: Int): Int {
        if (path[pathIndex].hasNextKey()) {
            return pathIndex
        }
        if (path[pathIndex].hasNextNode()) {
            val node = path[pathIndex].currentNode()
            if (pathIndex == TRIE_MAX_HEIGHT - 1) {     // collision
                path[pathIndex + 1].reset(node.buffer, node.buffer.size)
            } else {
                path[pathIndex + 1].reset(node.buffer, ENTRY_SIZE * node.entryCount())
            }
            return moveToNextNodeWithData(pathIndex + 1)
        }
        return -1
    }

    private fun ensureNextEntryIsReady() {
        if (path[pathLastIndex].hasNextKey()) {
            return
        }
        for(i in pathLastIndex downTo 0) {
            var result = moveToNextNodeWithData(i)

            if (result == -1 && path[i].hasNextNode()) {
                path[i].moveToNextNode()
                result = moveToNextNodeWithData(i)
            }
            if (result != -1) {
                pathLastIndex = result
                return
            }
            if (i > 0) {
                path[i - 1].moveToNextNode()
            }
            path[i].reset(TrieNode.EMPTY.buffer, 0)
        }
        hasNext = false
    }

    protected fun currentKey(): K {
        checkHasNext()
        return path[pathLastIndex].currentKey()
    }

    override fun hasNext(): Boolean {
        return hasNext
    }

    override fun next(): T {
        checkHasNext()
        val result = path[pathLastIndex].next()
        ensureNextEntryIsReady()
        return result
    }

    private fun checkHasNext() {
        if (!hasNext())
            throw NoSuchElementException()
    }
}

internal class PersistentHashMapEntriesIterator(node: TrieNode)
    : PersistentHashMapBaseIterator>(node, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeEntriesIterator() })

internal class PersistentHashMapKeysIterator(node: TrieNode)
    : PersistentHashMapBaseIterator(node, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeKeysIterator() })

internal class PersistentHashMapValuesIterator(node: TrieNode)
    : PersistentHashMapBaseIterator(node, Array(TRIE_MAX_HEIGHT + 1) { TrieNodeValuesIterator() })




© 2015 - 2024 Weber Informatics LLC | Privacy Policy