it.unibo.alchemist.model.nodes.GenericNode.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alchemist-implementationbase Show documentation
Show all versions of alchemist-implementationbase Show documentation
Abstract, incarnation independent implementations of the Alchemist's interfaces. Provides support for those who want to write incarnations.
/*
* 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.model.nodes
import com.google.common.collect.MapMaker
import it.unibo.alchemist.model.Environment
import it.unibo.alchemist.model.Incarnation
import it.unibo.alchemist.model.Molecule
import it.unibo.alchemist.model.Node
import it.unibo.alchemist.model.NodeProperty
import it.unibo.alchemist.model.Reaction
import it.unibo.alchemist.model.Time
import java.util.Collections
import java.util.Spliterator
import java.util.concurrent.Semaphore
import java.util.concurrent.atomic.AtomicInteger
import java.util.function.Consumer
import javax.annotation.Nonnull
/**
* This class realizes an abstract node. You may extend it to realize your own
* nodes.
*
* @param concentration type
*/
open class GenericNode @JvmOverloads constructor(
/**
* simulation incarnation.
*/
val incarnation: Incarnation,
/**
* The environment in which the node is places.
*/
val environment: Environment,
final override val id: Int = idFromEnv(environment),
final override val reactions: MutableList> = ArrayList(),
/**
* The node's molecules.
*/
val molecules: MutableMap = LinkedHashMap(),
final override val properties: MutableList> = ArrayList(),
) : Node {
constructor(
environment: Environment,
) : this(environment.incarnation, environment)
final override fun addReaction(reactionToAdd: Reaction) {
reactions.add(reactionToAdd)
}
override fun cloneNode(currentTime: Time): Node = GenericNode(environment).also {
this.properties.forEach { property -> it.addProperty(property.cloneOnNewNode(it)) }
this.contents.forEach(it::setConcentration)
this.reactions.forEach { reaction -> it.addReaction(reaction.cloneOnNewNode(it, currentTime)) }
}
final override fun compareTo(@Nonnull other: Node): Int = id.compareTo(other.id)
override fun contains(molecule: Molecule): Boolean = molecules.containsKey(molecule)
/**
* @return an empty concentration
*/
protected open fun createT(): T = incarnation.createConcentration()
final override fun equals(other: Any?): Boolean = other is Node<*> && other.id == id
/**
* Performs an [action] for every reaction.
*/
final override fun forEach(action: Consumer>) = reactions.forEach(action)
override fun getConcentration(molecule: Molecule): T = molecules[molecule] ?: createT()
override val contents: Map = Collections.unmodifiableMap(molecules)
override val moleculeCount: Int get() = molecules.size
final override fun hashCode(): Int = id // TODO: better hashing
final override fun iterator(): Iterator> = reactions.iterator()
final override fun removeConcentration(moleculeToRemove: Molecule) {
if (molecules.remove(moleculeToRemove) == null) {
throw NoSuchElementException("$moleculeToRemove was not present in node $id")
}
}
final override fun removeReaction(reactionToRemove: Reaction) {
reactions.remove(reactionToRemove)
}
override fun setConcentration(molecule: Molecule, concentration: T) {
molecules[molecule] = concentration
}
final override fun addProperty(nodeProperty: NodeProperty) {
if (properties.none { it::class == nodeProperty::class }) {
properties.add(nodeProperty)
} else {
error(
"Node with id ${this.id} already contains a property of type ${nodeProperty::class}, " +
"this may lead to an inconsistent state",
)
}
}
/**
* Returns the [reactions] [Spliterator].
*/
final override fun spliterator(): Spliterator> = reactions.spliterator()
override fun toString(): String = "Node$id{ properties: $properties, molecules: $molecules }"
companion object {
private const val serialVersionUID = 2496775909028222278L
private val IDGENERATOR = MapMaker().weakKeys().makeMap, AtomicInteger>()
private val MUTEX = Semaphore(1)
private fun idFromEnv(environment: Environment<*, *>): Int {
MUTEX.acquireUninterruptibly()
var idgen = IDGENERATOR[environment]
if (idgen == null) {
idgen = AtomicInteger()
IDGENERATOR[environment] = idgen
}
MUTEX.release()
return idgen.getAndIncrement()
}
}
}