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

loggersoft.kotlin.utils.graph.GraphImpl.kt Maven / Gradle / Ivy

/*
 * Copyright (C) 2018 Alexander Kornilov ([email protected])
 *
 * 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.
 */

package loggersoft.kotlin.utils.graph

import java.util.*

@Suppress("NOTHING_TO_INLINE")
internal open class GraphImpl : Graph {

    /**
     *
     */
    constructor(vararg edges: Edge) {
        for(edge in edges) insertEdge(edge)
    }

    override fun equals(other: Any?): Boolean =
        other != null && (this === other || (other is GraphImpl<*, *> && vertexesMap == other.vertexesMap))

    override fun hashCode(): Int = vertexesMap.hashCode()

    override fun clone(): Graph = GraphImpl(this)

    override fun cloneAsMutable(): MutableGraph = MutableGraphImpl(this)

    override val values: Collection
        get() = vertexesMap.keys

    override val vertexes: Collection>
        get() = vertexesMap.values

    override var edgesCount: Int = 0
        protected set

    override var orientedEdgesCount: Int = 0
        protected set

    override var dynamicEdgesCount: Int = 0
        protected set

    override fun get(value: V): Vertex = vertexesMap[value] ?: throw NoSuchElementException()

    override fun getEdges(startFrom: V, endWith: V, limit: Int): Collection> {
        val startVertex = getVertex(startFrom)
        val endVertex = getVertex(endWith)
        val edges = startVertex.startsIn.asSequence().filter { it in endVertex.endsIn }.take(if (limit > 0) limit else edgesCount).toList()
        return if (isOriented || (limit > 0 && edges.size >= limit)) edges
               else edges + startVertex.endsIn.asSequence().filter { !it.isOriented && it in endVertex.startsIn }.take(if (limit > 0) limit - edges.size else edgesCount)
    }

    protected constructor(graph: Graph) {
        for(vertex in graph.vertexes) {
            vertex.startsIn.forEach(::cloneEdge)
            vertex.endsIn.forEach(::cloneEdge)
        }
    }

    protected inline fun getVertex(value: V): VertexImpl = vertexesMap[value] as VertexImpl? ?: throw NoSuchElementException()

    protected inline fun insertVertex(value: V): VertexImpl = vertexesMap.getOrPut(value) { VertexImpl(value) } as VertexImpl

    protected fun insertEdge(edge: Edge): Edge {
        if (insertVertex(edge.startFrom).startsIn.add(edge)) {
            insertVertex(edge.endWith).endsIn.add(edge)
            edgesCount++
            if (edge.isOriented) orientedEdgesCount++
            if (edge.isDynamicWeight) dynamicEdgesCount++
        }
        return edge
    }

    protected inner class VertexImpl(override val value: V) : Vertex {

        override fun equals(other: Any?): Boolean =
                other != null && (this === other || (other is Vertex<*, *>
                        && value == other.value
                        && startsIn == other.startsIn
                        && endsIn == other.endsIn))

        override fun hashCode(): Int = Objects.hash(startsIn, endsIn, value)

        override val startsIn: MutableSet> = mutableSetOf()
        override val endsIn: MutableSet> = mutableSetOf()

        override fun isConnectedWith(value: V) = isConnected(this.value, value)
    }

    protected val vertexesMap: MutableMap> = mutableMapOf()

    private inline fun cloneEdge(edge: Edge) {
        insertEdge(copyEdge(edge))
    }

    @Suppress("UNCHECKED_CAST")
    private inline fun copyEdge(edge: Edge): Edge =
        when {
            edge is ExternalEdge || edge is StaticEdge -> edge
            edge.value is AbstractEdge -> ExternalEdge(edge.startFrom, edge.endWith, edge.value as AbstractEdge) as Edge
            edge.isDynamicWeight -> DynamicEdge(edge.startFrom, edge.endWith, edge.value, edge.isOriented).apply {
                hasWeight = edge.hasWeight
                weight = edge.weight
            }
            else -> edge
        }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy