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

it.unibo.alchemist.boundary.loader.Context.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2010-2023, Danilo Pianini and contributors
 * listed, for each module, in the respective subproject's build.gradle.kts file.
 *
 * This file is part of Alchemist, and is distributed under the terms of the
 * GNU General Public License, with a linking exception,
 * as described in the file LICENSE in the Alchemist distribution's top directory.
 */

package it.unibo.alchemist.boundary.loader

import it.unibo.alchemist.boundary.loader.LoadingSystemLogger.logger
import org.danilopianini.jirf.Factory
import java.util.Collections.unmodifiableMap

internal data class Context constructor(
    private val namedLookup: MutableMap>,
    private val elementLookup: MutableMap, Any?> = mutableMapOf(),
    val factory: Factory = ObjectFactory.makeBaseFactory(),
) {
    private val backingConstants: MutableMap = mutableMapOf()
    private val fixedVariables = mutableSetOf()

    val constants: Map get() = unmodifiableMap(backingConstants)

    constructor() : this(namedLookup = mutableMapOf())

    fun child(): Context = Context(namedLookup = this.namedLookup)

    fun registerConstant(
        name: String,
        representation: Map<*, *>,
        value: Any?,
    ) {
        logger.debug("Injecting constant {} with value {} represented by {}", name, value, representation)
        if (constants.containsKey(name)) {
            val previous = elementLookup[representation]
            require(value == previous) {
                """
                Inconsistent definition of constant named $name:
                  - previous evaluation: ${elementLookup[representation]}
                  - current value: $value
                Item originating this issue: $representation
                Context at time of failure: $this
                """.trimIndent()
            }
        }
        namedLookup[name] = representation
        elementLookup[representation] = value
        backingConstants[name] = value
    }

    fun registerVariable(
        name: String,
        representation: Map<*, *>,
    ) {
        logger.debug("Injecting variable {} represented by {}", name, representation)
        namedLookup[name] = representation
        elementLookup[representation] = SimulationModel.PlaceHolderForVariables(name)
    }

    fun fixVariableValue(
        name: String,
        value: Any?,
    ) {
        val key =
            requireNotNull(namedLookup[name]) {
                """
                There is no known "$name" object in the lookup table, although there should be by construction.
                Known object names: ${namedLookup.keys}
                This sounds like a bug in Alchemist.
                """.trimIndent()
            }
        elementLookup[key] = value
        fixedVariables += name
        logger.debug("Contextually set {} = {}. Currently fixed: {}.", name, value, fixedVariables)
    }

    /**
     * Returns null if the element is not a resolvable entity.
     * Othewise, returns a Result with the resolution result.
     */
    fun lookup(representation: Map<*, *>): Any? =
        if (elementLookup.containsKey(representation)) elementLookup[representation] else null

    /**
     * Returns null if the element is not a resolvable entity.
     * Othewise, returns a Result with the resolution result.
     */
    fun lookup(placeholder: SimulationModel.PlaceHolderForVariables): Any? =
        placeholder.takeUnless { placeholder.name in fixedVariables }
            ?: requireNotNull(namedLookup[placeholder.name]) {
                "Bug in Alchemist: unresolvable variable ${placeholder.name}"
            }.let { lookup(it) }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy