From b1c4d1f94e35445bdba5a56b614d0ec28a332624 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Thu, 11 Jan 2018 16:27:05 +0100 Subject: refactor(#18): Redesign core simulation API This change contains the redesign of the core simulation API and provides a cleaner interface for developing simulation models for the users. --- .../atlarge/opendc/model/topology/AdjacencyList.kt | 260 +++++++++++++++++++++ .../com/atlarge/opendc/model/topology/Bootstrap.kt | 23 ++ .../com/atlarge/opendc/model/topology/Component.kt | 33 +++ .../com/atlarge/opendc/model/topology/Edge.kt | 61 +++++ .../opendc/model/topology/MutableTopology.kt | 65 ++++++ .../com/atlarge/opendc/model/topology/Topology.kt | 50 ++++ .../opendc/model/topology/TopologyBuilder.kt | 40 ++++ .../opendc/model/topology/TopologyContext.kt | 50 ++++ .../opendc/model/topology/TopologyFactory.kt | 40 ++++ .../opendc/model/topology/TopologyListener.kt | 63 +++++ .../atlarge/opendc/model/topology/Traversable.kt | 41 ++++ 11 files changed, 726 insertions(+) create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Component.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Traversable.kt (limited to 'opendc-stdlib/src/main/kotlin/com') diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt new file mode 100644 index 00000000..c042a2d5 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt @@ -0,0 +1,260 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity +import com.atlarge.opendc.model.topology.Edge as BaseEdge +import java.util.concurrent.atomic.AtomicInteger + +/** + * This module provides a [Topology] implementation backed internally by an adjacency list. + * + * This implementation is best suited for sparse graphs, where an adjacency matrix would take up too much space with + * empty cells. + * + * *Note that this implementation is not synchronized.* + */ +object AdjacencyList { + /** + * Return a [TopologyBuilder] that constructs the topology represents as an adjacency list. + * + * @return A [TopologyBuilder] instance. + */ + fun builder(): TopologyBuilder = AdjacencyListTopologyBuilder() +} + +/** + * A builder for [Topology] instances, which is backed by an adjacency list. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +internal class AdjacencyListTopologyBuilder : TopologyBuilder { + /** + * Build a [Topology] instance from the current state of this builder. + * + * @return The graph built from this builder. + */ + override fun create(): MutableTopology = AdjacencyListTopology() +} + +/** + * A [Topology] whose graph is represented as adjacency list. + */ +internal class AdjacencyListTopology : MutableTopology { + /** + * The identifier for the next node in the graph. + */ + private var nextId: AtomicInteger = AtomicInteger(0) + + /** + * A mapping of nodes to their internal representation with the edges of the nodes. + */ + private var nodes: MutableMap, Node> = HashMap() + + // Topology + + /** + * The listeners of this topology. + */ + override val listeners: MutableSet = HashSet() + + /** + * A unique identifier of this node within the topology. + */ + override val Entity<*, Topology>.id: Int + get() = nodes[this]!!.id + + /** + * The set of ingoing edges of this node. + */ + override val Entity<*, Topology>.ingoingEdges: MutableSet> + get() = nodes[this]!!.ingoingEdges + + /** + * The set of outgoing edges of this node. + */ + override val Entity<*, Topology>.outgoingEdges: MutableSet> + get() = nodes[this]!!.outgoingEdges + + // MutableTopology + + /** + * Create a directed edge between two [Node]s in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + override fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String?): BaseEdge { + if (!contains(from) || !contains(to)) + throw IllegalArgumentException("One of the entities is not part of the topology") + val edge = Edge(label, tag, from, to) + from.outgoingEdges.add(edge) + to.ingoingEdges.add(edge) + listeners.forEach { it.run { this@AdjacencyListTopology.onEdgeAdded(edge) } } + return edge + } + + // Cloneable + + /** + * Create a copy of the graph. + * + * @return A new [Topology] instance with a copy of the graph. + */ + override fun clone(): Topology { + val copy = AdjacencyListTopology() + copy.nextId = AtomicInteger(nextId.get()) + copy.nodes = HashMap(nodes) + return copy + } + + // Set + + /** + * Returns the size of the collection. + */ + override val size: Int = nodes.size + + /** + * Checks if the specified element is contained in this collection. + */ + override fun contains(element: Entity<*, Topology>): Boolean = nodes.contains(element) + + /** + * Checks if all elements in the specified collection are contained in this collection. + */ + override fun containsAll(elements: Collection>): Boolean = + elements.all { nodes.containsKey(it) } + + /** + * Returns `true` if the collection is empty (contains no elements), `false` otherwise. + */ + override fun isEmpty(): Boolean = nodes.isEmpty() + + // MutableSet + + /** + * Add a node to the graph. + * + * @param element The element to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun add(element: Entity<*, Topology>): Boolean { + if (nodes.putIfAbsent(element, Node(nextId.getAndIncrement())) == null) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeAdded(element) } } + return true + } + return false + } + + /** + * Add all nodes in the specified collection to the graph. + * + * @param elements The nodes to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun addAll(elements: Collection>): Boolean = elements.any { add(it) } + + /** + * Remove all nodes and their respective edges from the graph. + */ + override fun clear() = nodes.clear() + + /** + * Remove the given node and its edges from the graph. + * + * @param element The element to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun remove(element: Entity<*, Topology>): Boolean { + nodes[element]?.ingoingEdges?.forEach { + it.from.outgoingEdges.remove(it) + } + nodes[element]?.outgoingEdges?.forEach { + it.to.ingoingEdges.remove(it) + } + if (nodes.keys.remove(element)) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeRemoved(element) } } + return true + } + return false + } + + + /** + * Remove all nodes in the given collection from the graph. + * + * @param elements The elements to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun removeAll(elements: Collection>): Boolean = elements.any(this::remove) + + /** + * Remove all nodes in the graph, except those in the specified collection. + * + * Take note that this method currently only guarantees a maximum runtime complexity of O(n^2). + * + * @param elements The elements to retain in the graph. + */ + override fun retainAll(elements: Collection>): Boolean { + val iterator = nodes.keys.iterator() + var changed = false + while (iterator.hasNext()) { + val entity = iterator.next() + + if (entity !in elements) { + iterator.remove() + changed = true + } + } + return changed + } + + /** + * Return a mutable iterator over the nodes of the graph. + * + * @return A [MutableIterator] over the nodes of the graph. + */ + override fun iterator(): MutableIterator> = nodes.keys.iterator() + + /** + * The internal representation of a node within the graph. + */ + internal data class Node(val id: Int) { + val ingoingEdges: MutableSet> = HashSet() + val outgoingEdges: MutableSet> = HashSet() + } + + /** + * The internal representation of an edge within the graph. + */ + internal class Edge(override val label: T, + override val tag: String?, + override val from: Entity<*, Topology>, + override val to: Entity<*, Topology>) : BaseEdge +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt new file mode 100644 index 00000000..de9a41d5 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt @@ -0,0 +1,23 @@ +package com.atlarge.opendc.model.topology + +import com.atlarge.opendc.simulator.Bootstrap +import com.atlarge.opendc.simulator.Entity + +/** + * Create a [Bootstrap] procedure for the given [Topology]. + * + * @return A bootstrap procedure for the topology. + */ +fun T.bootstrap(): Bootstrap = Bootstrap.create { ctx -> + forEach { ctx.register(it) } + listeners += object : TopologyListener { + override fun Topology.onNodeAdded(node: Entity<*, Topology>) { + ctx.register(node) + } + + override fun Topology.onNodeRemoved(node: Entity<*, Topology>) { + ctx.deregister(node) + } + } + this +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Component.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Component.kt new file mode 100644 index 00000000..5e8611a0 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Component.kt @@ -0,0 +1,33 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +/** + * A component within a [Topology], which is either a node or an [Edge] representing the relationship between + * entities within a logical topology of a cloud network. + ** + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface Component diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt new file mode 100644 index 00000000..3e507887 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt @@ -0,0 +1,61 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * An edge that represents a directed relationship between exactly two nodes in a logical topology of a cloud network. + * + * @param T The relationship type the edge represents within a logical topology. + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface Edge : Component { + /** + * The label of this edge. + */ + val label: T + + /** + * A tag to uniquely identify the relationship this edge represents. + */ + val tag: String? + + /** + * The source of the edge. + * + * This property is not guaranteed to have a runtime complexity of O(1), but must be at least + * O(n), with respect to the size of the topology. + */ + val from: Entity<*, Topology> + + /** + * The destination of the edge. + * + * This property is not guaranteed to have a runtime complexity of O(1), but must be at least + * O(n), with respect to the size of the topology. + */ + val to: Entity<*, Topology> +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt new file mode 100644 index 00000000..ac1b4ba5 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt @@ -0,0 +1,65 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * A subinterface of [Topology] which adds mutation methods. When mutation is not required, users + * should prefer the [Topology] interface. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface MutableTopology : Topology, MutableSet> { + /** + * Create a directed, labeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String? = null): Edge + + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, tag: String? = null): Edge = + connect(from, to, Unit, tag) + + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param dest The destination of the edge. + * @return The edge that has been created. + */ + infix fun Entity<*, Topology>.to(dest: Entity<*, Topology>): Edge = connect(this, dest) +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt new file mode 100644 index 00000000..1e5a404f --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt @@ -0,0 +1,50 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * A graph data structure which represents the logical topology of a cloud network consisting of one or more + * datacenters. + * + * A topology is [Iterable] and allows implementation-dependent iteration of the nodes in the topology. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface Topology : TopologyContext, Cloneable, Set> { + /** + * The listeners of this topology. + */ + val listeners: MutableSet + + /** + * Create a copy of the topology. + * + * @return A new [Topology] with a copy of the graph. + */ + public override fun clone(): Topology +} + diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt new file mode 100644 index 00000000..44b1cb4e --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt @@ -0,0 +1,40 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +/** + * A builder for [Topology] instances. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyBuilder : TopologyFactory { + /** + * Construct a [Topology] from the given block and return it. + * + * @param block The block to construct the topology. + * @return The topology that has been built. + */ + fun construct(block: MutableTopology.() -> Unit): MutableTopology = create().apply(block) +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt new file mode 100644 index 00000000..2bf87a39 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt @@ -0,0 +1,50 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +import com.atlarge.opendc.simulator.Entity + +/** + * A [TopologyContext] represents the context for entities in a specific topology, providing access to the identifier + * and ingoing and outgoing edges of the [Entity] within a [Topology]. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyContext { + /** + * A unique identifier of an [Entity] within the topology. + */ + val Entity<*, Topology>.id: Int + + /** + * The set of ingoing edges of an [Entity]. + */ + val Entity<*, Topology>.ingoingEdges: Set> + + /** + * The set of outgoing edges of an [Entity]. + */ + val Entity<*, Topology>.outgoingEdges: Set> +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt new file mode 100644 index 00000000..35cfa97a --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt @@ -0,0 +1,40 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +/** + * An interface for producing [Topology] instances. Implementors of this interface provide a way of generating a + * topology based on the state of the factory. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyFactory { + /** + * Create a [MutableTopology] instance. + * + * @return A mutable topology. + */ + fun create(): MutableTopology +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt new file mode 100644 index 00000000..93108cc0 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt @@ -0,0 +1,63 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology; + +import com.atlarge.opendc.simulator.Entity + +/** + * A listener interface for [Topology] instances. The methods of this interface are invoked on + * mutation of the topology the listener is listening to. + * + * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) + */ +interface TopologyListener { + /** + * This method is invoked when an [Entity] is added to the [Topology]. + * + * @param node The entity that has been added to the [Topology]. + */ + fun Topology.onNodeAdded(node: Entity<*, Topology>) {} + + /** + * This method is invoked when an [Entity] is removed from the [Topology]. + * + * @param node The entity that has been removed from the [Topology]. + */ + fun Topology.onNodeRemoved(node: Entity<*, Topology>) {} + + /** + * This method is invoked when an [Edge] is added to the [Topology]. + * + * @param edge The edge that has been added to the [Topology]. + */ + fun Topology.onEdgeAdded(edge: Edge<*>) {} + + /** + * This method is invoked when an [Edge] is removed from the [Topology]. + * + * @param edge The entity that has been removed from the [Topology]. + */ + fun Topology.onEdgeRemoved(edge: Edge<*>) {} +} diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Traversable.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Traversable.kt new file mode 100644 index 00000000..23720c46 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Traversable.kt @@ -0,0 +1,41 @@ +/* + * MIT License + * + * Copyright (c) 2017 atlarge-research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.atlarge.opendc.model.topology + +/** + * Filter a [Set] of [Edge]s based on the tag of the edges and return the origin nodes casted to type `T`. + * + * @param tag The tag of the edges to get. + * @return An [Iterable] of the specified type `T` with the given tag. + */ +inline fun Set>.origins(tag: String) = filter { it.tag == tag }.map { it.from as T } + +/** + * Filter a [Set] of [Edge]s based on the tag of the edges and return the destination nodes casted to type `T`. + * + * @param tag The tag of the edges to get. + * @return An [Iterable] of the specified type `T` with the given tag. + */ +inline fun Set>.destinations(tag: String) = filter { it.tag == tag }.map { it.to as T } -- cgit v1.2.3 From e97d9bf3f2cccf19a21631e26d55d60c9f4d7c7a Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Mon, 12 Feb 2018 14:26:44 +0100 Subject: refactor(#18): Align formatting with official Kotlin Style Guide This change aligns the code formatting of the project with the official Kotlin Style Guide. They can be found at http://kotlinlang.org/docs/reference/coding-conventions.html. --- .../atlarge/opendc/model/topology/AdjacencyList.kt | 414 ++++++++++----------- .../com/atlarge/opendc/model/topology/Bootstrap.kt | 22 +- .../com/atlarge/opendc/model/topology/Edge.kt | 44 +-- .../opendc/model/topology/MutableTopology.kt | 54 +-- .../com/atlarge/opendc/model/topology/Topology.kt | 20 +- .../opendc/model/topology/TopologyBuilder.kt | 14 +- .../opendc/model/topology/TopologyContext.kt | 24 +- .../opendc/model/topology/TopologyFactory.kt | 12 +- .../opendc/model/topology/TopologyListener.kt | 48 +-- 9 files changed, 326 insertions(+), 326 deletions(-) (limited to 'opendc-stdlib/src/main/kotlin/com') diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt index c042a2d5..db117917 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/AdjacencyList.kt @@ -25,8 +25,8 @@ package com.atlarge.opendc.model.topology import com.atlarge.opendc.simulator.Entity -import com.atlarge.opendc.model.topology.Edge as BaseEdge import java.util.concurrent.atomic.AtomicInteger +import com.atlarge.opendc.model.topology.Edge as BaseEdge /** * This module provides a [Topology] implementation backed internally by an adjacency list. @@ -37,12 +37,12 @@ import java.util.concurrent.atomic.AtomicInteger * *Note that this implementation is not synchronized.* */ object AdjacencyList { - /** - * Return a [TopologyBuilder] that constructs the topology represents as an adjacency list. - * - * @return A [TopologyBuilder] instance. - */ - fun builder(): TopologyBuilder = AdjacencyListTopologyBuilder() + /** + * Return a [TopologyBuilder] that constructs the topology represents as an adjacency list. + * + * @return A [TopologyBuilder] instance. + */ + fun builder(): TopologyBuilder = AdjacencyListTopologyBuilder() } /** @@ -51,210 +51,210 @@ object AdjacencyList { * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ internal class AdjacencyListTopologyBuilder : TopologyBuilder { - /** - * Build a [Topology] instance from the current state of this builder. - * - * @return The graph built from this builder. - */ - override fun create(): MutableTopology = AdjacencyListTopology() + /** + * Build a [Topology] instance from the current state of this builder. + * + * @return The graph built from this builder. + */ + override fun create(): MutableTopology = AdjacencyListTopology() } /** * A [Topology] whose graph is represented as adjacency list. */ internal class AdjacencyListTopology : MutableTopology { - /** - * The identifier for the next node in the graph. - */ - private var nextId: AtomicInteger = AtomicInteger(0) - - /** - * A mapping of nodes to their internal representation with the edges of the nodes. - */ - private var nodes: MutableMap, Node> = HashMap() - - // Topology - - /** - * The listeners of this topology. - */ - override val listeners: MutableSet = HashSet() - - /** - * A unique identifier of this node within the topology. - */ - override val Entity<*, Topology>.id: Int - get() = nodes[this]!!.id - - /** - * The set of ingoing edges of this node. - */ - override val Entity<*, Topology>.ingoingEdges: MutableSet> - get() = nodes[this]!!.ingoingEdges - - /** - * The set of outgoing edges of this node. - */ - override val Entity<*, Topology>.outgoingEdges: MutableSet> - get() = nodes[this]!!.outgoingEdges - - // MutableTopology - - /** - * Create a directed edge between two [Node]s in the topology. - * - * @param from The source of the edge. - * @param to The destination of the edge. - * @param label The label of the edge. - * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. - * @return The edge that has been created. - */ - override fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String?): BaseEdge { - if (!contains(from) || !contains(to)) - throw IllegalArgumentException("One of the entities is not part of the topology") - val edge = Edge(label, tag, from, to) - from.outgoingEdges.add(edge) - to.ingoingEdges.add(edge) - listeners.forEach { it.run { this@AdjacencyListTopology.onEdgeAdded(edge) } } - return edge - } - - // Cloneable - - /** - * Create a copy of the graph. - * - * @return A new [Topology] instance with a copy of the graph. - */ - override fun clone(): Topology { - val copy = AdjacencyListTopology() - copy.nextId = AtomicInteger(nextId.get()) - copy.nodes = HashMap(nodes) - return copy - } - - // Set - - /** - * Returns the size of the collection. - */ - override val size: Int = nodes.size - - /** - * Checks if the specified element is contained in this collection. - */ - override fun contains(element: Entity<*, Topology>): Boolean = nodes.contains(element) - - /** - * Checks if all elements in the specified collection are contained in this collection. - */ - override fun containsAll(elements: Collection>): Boolean = - elements.all { nodes.containsKey(it) } - - /** - * Returns `true` if the collection is empty (contains no elements), `false` otherwise. - */ - override fun isEmpty(): Boolean = nodes.isEmpty() - - // MutableSet - - /** - * Add a node to the graph. - * - * @param element The element to add to this graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun add(element: Entity<*, Topology>): Boolean { - if (nodes.putIfAbsent(element, Node(nextId.getAndIncrement())) == null) { - listeners.forEach { it.run { this@AdjacencyListTopology.onNodeAdded(element) } } - return true - } - return false - } - - /** - * Add all nodes in the specified collection to the graph. - * - * @param elements The nodes to add to this graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun addAll(elements: Collection>): Boolean = elements.any { add(it) } - - /** - * Remove all nodes and their respective edges from the graph. - */ - override fun clear() = nodes.clear() - - /** - * Remove the given node and its edges from the graph. - * - * @param element The element to remove from the graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun remove(element: Entity<*, Topology>): Boolean { - nodes[element]?.ingoingEdges?.forEach { - it.from.outgoingEdges.remove(it) - } - nodes[element]?.outgoingEdges?.forEach { - it.to.ingoingEdges.remove(it) - } - if (nodes.keys.remove(element)) { - listeners.forEach { it.run { this@AdjacencyListTopology.onNodeRemoved(element) } } - return true - } - return false - } - - - /** - * Remove all nodes in the given collection from the graph. - * - * @param elements The elements to remove from the graph. - * @return `true` if the graph has changed, `false` otherwise. - */ - override fun removeAll(elements: Collection>): Boolean = elements.any(this::remove) - - /** - * Remove all nodes in the graph, except those in the specified collection. - * - * Take note that this method currently only guarantees a maximum runtime complexity of O(n^2). - * - * @param elements The elements to retain in the graph. - */ - override fun retainAll(elements: Collection>): Boolean { - val iterator = nodes.keys.iterator() - var changed = false - while (iterator.hasNext()) { - val entity = iterator.next() - - if (entity !in elements) { - iterator.remove() - changed = true - } - } - return changed - } - - /** - * Return a mutable iterator over the nodes of the graph. - * - * @return A [MutableIterator] over the nodes of the graph. - */ - override fun iterator(): MutableIterator> = nodes.keys.iterator() - - /** - * The internal representation of a node within the graph. - */ - internal data class Node(val id: Int) { - val ingoingEdges: MutableSet> = HashSet() - val outgoingEdges: MutableSet> = HashSet() - } - - /** - * The internal representation of an edge within the graph. - */ - internal class Edge(override val label: T, - override val tag: String?, - override val from: Entity<*, Topology>, - override val to: Entity<*, Topology>) : BaseEdge + /** + * The identifier for the next node in the graph. + */ + private var nextId: AtomicInteger = AtomicInteger(0) + + /** + * A mapping of nodes to their internal representation with the edges of the nodes. + */ + private var nodes: MutableMap, Node> = HashMap() + + // Topology + + /** + * The listeners of this topology. + */ + override val listeners: MutableSet = HashSet() + + /** + * A unique identifier of this node within the topology. + */ + override val Entity<*, Topology>.id: Int + get() = nodes[this]!!.id + + /** + * The set of ingoing edges of this node. + */ + override val Entity<*, Topology>.ingoingEdges: MutableSet> + get() = nodes[this]!!.ingoingEdges + + /** + * The set of outgoing edges of this node. + */ + override val Entity<*, Topology>.outgoingEdges: MutableSet> + get() = nodes[this]!!.outgoingEdges + + // MutableTopology + + /** + * Create a directed edge between two [Node]s in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + override fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String?): BaseEdge { + if (!contains(from) || !contains(to)) + throw IllegalArgumentException("One of the entities is not part of the topology") + val edge = Edge(label, tag, from, to) + from.outgoingEdges.add(edge) + to.ingoingEdges.add(edge) + listeners.forEach { it.run { this@AdjacencyListTopology.onEdgeAdded(edge) } } + return edge + } + + // Cloneable + + /** + * Create a copy of the graph. + * + * @return A new [Topology] instance with a copy of the graph. + */ + override fun clone(): Topology { + val copy = AdjacencyListTopology() + copy.nextId = AtomicInteger(nextId.get()) + copy.nodes = HashMap(nodes) + return copy + } + + // Set + + /** + * Returns the size of the collection. + */ + override val size: Int = nodes.size + + /** + * Checks if the specified element is contained in this collection. + */ + override fun contains(element: Entity<*, Topology>): Boolean = nodes.contains(element) + + /** + * Checks if all elements in the specified collection are contained in this collection. + */ + override fun containsAll(elements: Collection>): Boolean = + elements.all { nodes.containsKey(it) } + + /** + * Returns `true` if the collection is empty (contains no elements), `false` otherwise. + */ + override fun isEmpty(): Boolean = nodes.isEmpty() + + // MutableSet + + /** + * Add a node to the graph. + * + * @param element The element to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun add(element: Entity<*, Topology>): Boolean { + if (nodes.putIfAbsent(element, Node(nextId.getAndIncrement())) == null) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeAdded(element) } } + return true + } + return false + } + + /** + * Add all nodes in the specified collection to the graph. + * + * @param elements The nodes to add to this graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun addAll(elements: Collection>): Boolean = elements.any { add(it) } + + /** + * Remove all nodes and their respective edges from the graph. + */ + override fun clear() = nodes.clear() + + /** + * Remove the given node and its edges from the graph. + * + * @param element The element to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun remove(element: Entity<*, Topology>): Boolean { + nodes[element]?.ingoingEdges?.forEach { + it.from.outgoingEdges.remove(it) + } + nodes[element]?.outgoingEdges?.forEach { + it.to.ingoingEdges.remove(it) + } + if (nodes.keys.remove(element)) { + listeners.forEach { it.run { this@AdjacencyListTopology.onNodeRemoved(element) } } + return true + } + return false + } + + + /** + * Remove all nodes in the given collection from the graph. + * + * @param elements The elements to remove from the graph. + * @return `true` if the graph has changed, `false` otherwise. + */ + override fun removeAll(elements: Collection>): Boolean = elements.any(this::remove) + + /** + * Remove all nodes in the graph, except those in the specified collection. + * + * Take note that this method currently only guarantees a maximum runtime complexity of O(n^2). + * + * @param elements The elements to retain in the graph. + */ + override fun retainAll(elements: Collection>): Boolean { + val iterator = nodes.keys.iterator() + var changed = false + while (iterator.hasNext()) { + val entity = iterator.next() + + if (entity !in elements) { + iterator.remove() + changed = true + } + } + return changed + } + + /** + * Return a mutable iterator over the nodes of the graph. + * + * @return A [MutableIterator] over the nodes of the graph. + */ + override fun iterator(): MutableIterator> = nodes.keys.iterator() + + /** + * The internal representation of a node within the graph. + */ + internal data class Node(val id: Int) { + val ingoingEdges: MutableSet> = HashSet() + val outgoingEdges: MutableSet> = HashSet() + } + + /** + * The internal representation of an edge within the graph. + */ + internal class Edge(override val label: T, + override val tag: String?, + override val from: Entity<*, Topology>, + override val to: Entity<*, Topology>) : BaseEdge } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt index de9a41d5..1a5bbcaf 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt @@ -8,16 +8,16 @@ import com.atlarge.opendc.simulator.Entity * * @return A bootstrap procedure for the topology. */ -fun T.bootstrap(): Bootstrap = Bootstrap.create { ctx -> - forEach { ctx.register(it) } - listeners += object : TopologyListener { - override fun Topology.onNodeAdded(node: Entity<*, Topology>) { - ctx.register(node) - } +fun T.bootstrap(): Bootstrap = Bootstrap.create { ctx -> + forEach { ctx.register(it) } + listeners += object : TopologyListener { + override fun Topology.onNodeAdded(node: Entity<*, Topology>) { + ctx.register(node) + } - override fun Topology.onNodeRemoved(node: Entity<*, Topology>) { - ctx.deregister(node) - } - } - this + override fun Topology.onNodeRemoved(node: Entity<*, Topology>) { + ctx.deregister(node) + } + } + this } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt index 3e507887..1963a056 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Edge.kt @@ -33,29 +33,29 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Edge : Component { - /** - * The label of this edge. - */ - val label: T + /** + * The label of this edge. + */ + val label: T - /** - * A tag to uniquely identify the relationship this edge represents. - */ - val tag: String? + /** + * A tag to uniquely identify the relationship this edge represents. + */ + val tag: String? - /** - * The source of the edge. - * - * This property is not guaranteed to have a runtime complexity of O(1), but must be at least - * O(n), with respect to the size of the topology. - */ - val from: Entity<*, Topology> + /** + * The source of the edge. + * + * This property is not guaranteed to have a runtime complexity of O(1), but must be at least + * O(n), with respect to the size of the topology. + */ + val from: Entity<*, Topology> - /** - * The destination of the edge. - * - * This property is not guaranteed to have a runtime complexity of O(1), but must be at least - * O(n), with respect to the size of the topology. - */ - val to: Entity<*, Topology> + /** + * The destination of the edge. + * + * This property is not guaranteed to have a runtime complexity of O(1), but must be at least + * O(n), with respect to the size of the topology. + */ + val to: Entity<*, Topology> } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt index ac1b4ba5..7cf80702 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/MutableTopology.kt @@ -33,33 +33,33 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface MutableTopology : Topology, MutableSet> { - /** - * Create a directed, labeled edge between two nodes in the topology. - * - * @param from The source of the edge. - * @param to The destination of the edge. - * @param label The label of the edge. - * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. - * @return The edge that has been created. - */ - fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String? = null): Edge + /** + * Create a directed, labeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param label The label of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, label: T, tag: String? = null): Edge - /** - * Create a directed, unlabeled edge between two nodes in the topology. - * - * @param from The source of the edge. - * @param to The destination of the edge. - * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. - * @return The edge that has been created. - */ - fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, tag: String? = null): Edge = - connect(from, to, Unit, tag) + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param from The source of the edge. + * @param to The destination of the edge. + * @param tag The tag of the edge that uniquely identifies the relationship the edge represents. + * @return The edge that has been created. + */ + fun connect(from: Entity<*, Topology>, to: Entity<*, Topology>, tag: String? = null): Edge = + connect(from, to, Unit, tag) - /** - * Create a directed, unlabeled edge between two nodes in the topology. - * - * @param dest The destination of the edge. - * @return The edge that has been created. - */ - infix fun Entity<*, Topology>.to(dest: Entity<*, Topology>): Edge = connect(this, dest) + /** + * Create a directed, unlabeled edge between two nodes in the topology. + * + * @param dest The destination of the edge. + * @return The edge that has been created. + */ + infix fun Entity<*, Topology>.to(dest: Entity<*, Topology>): Edge = connect(this, dest) } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt index 1e5a404f..e277bc9f 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Topology.kt @@ -35,16 +35,16 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface Topology : TopologyContext, Cloneable, Set> { - /** - * The listeners of this topology. - */ - val listeners: MutableSet + /** + * The listeners of this topology. + */ + val listeners: MutableSet - /** - * Create a copy of the topology. - * - * @return A new [Topology] with a copy of the graph. - */ - public override fun clone(): Topology + /** + * Create a copy of the topology. + * + * @return A new [Topology] with a copy of the graph. + */ + public override fun clone(): Topology } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt index 44b1cb4e..8bdc37c0 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyBuilder.kt @@ -30,11 +30,11 @@ package com.atlarge.opendc.model.topology * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyBuilder : TopologyFactory { - /** - * Construct a [Topology] from the given block and return it. - * - * @param block The block to construct the topology. - * @return The topology that has been built. - */ - fun construct(block: MutableTopology.() -> Unit): MutableTopology = create().apply(block) + /** + * Construct a [Topology] from the given block and return it. + * + * @param block The block to construct the topology. + * @return The topology that has been built. + */ + fun construct(block: MutableTopology.() -> Unit): MutableTopology = create().apply(block) } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt index 2bf87a39..9d78b5eb 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyContext.kt @@ -33,18 +33,18 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyContext { - /** - * A unique identifier of an [Entity] within the topology. - */ - val Entity<*, Topology>.id: Int + /** + * A unique identifier of an [Entity] within the topology. + */ + val Entity<*, Topology>.id: Int - /** - * The set of ingoing edges of an [Entity]. - */ - val Entity<*, Topology>.ingoingEdges: Set> + /** + * The set of ingoing edges of an [Entity]. + */ + val Entity<*, Topology>.ingoingEdges: Set> - /** - * The set of outgoing edges of an [Entity]. - */ - val Entity<*, Topology>.outgoingEdges: Set> + /** + * The set of outgoing edges of an [Entity]. + */ + val Entity<*, Topology>.outgoingEdges: Set> } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt index 35cfa97a..ab2deeb7 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyFactory.kt @@ -31,10 +31,10 @@ package com.atlarge.opendc.model.topology * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyFactory { - /** - * Create a [MutableTopology] instance. - * - * @return A mutable topology. - */ - fun create(): MutableTopology + /** + * Create a [MutableTopology] instance. + * + * @return A mutable topology. + */ + fun create(): MutableTopology } diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt index 93108cc0..0b4d43f7 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/TopologyListener.kt @@ -33,31 +33,31 @@ import com.atlarge.opendc.simulator.Entity * @author Fabian Mastenbroek (f.s.mastenbroek@student.tudelft.nl) */ interface TopologyListener { - /** - * This method is invoked when an [Entity] is added to the [Topology]. - * - * @param node The entity that has been added to the [Topology]. - */ - fun Topology.onNodeAdded(node: Entity<*, Topology>) {} + /** + * This method is invoked when an [Entity] is added to the [Topology]. + * + * @param node The entity that has been added to the [Topology]. + */ + fun Topology.onNodeAdded(node: Entity<*, Topology>) {} - /** - * This method is invoked when an [Entity] is removed from the [Topology]. - * - * @param node The entity that has been removed from the [Topology]. - */ - fun Topology.onNodeRemoved(node: Entity<*, Topology>) {} + /** + * This method is invoked when an [Entity] is removed from the [Topology]. + * + * @param node The entity that has been removed from the [Topology]. + */ + fun Topology.onNodeRemoved(node: Entity<*, Topology>) {} - /** - * This method is invoked when an [Edge] is added to the [Topology]. - * - * @param edge The edge that has been added to the [Topology]. - */ - fun Topology.onEdgeAdded(edge: Edge<*>) {} + /** + * This method is invoked when an [Edge] is added to the [Topology]. + * + * @param edge The edge that has been added to the [Topology]. + */ + fun Topology.onEdgeAdded(edge: Edge<*>) {} - /** - * This method is invoked when an [Edge] is removed from the [Topology]. - * - * @param edge The entity that has been removed from the [Topology]. - */ - fun Topology.onEdgeRemoved(edge: Edge<*>) {} + /** + * This method is invoked when an [Edge] is removed from the [Topology]. + * + * @param edge The entity that has been removed from the [Topology]. + */ + fun Topology.onEdgeRemoved(edge: Edge<*>) {} } -- cgit v1.2.3 From 157d30beb52c75831e29a1a22c199b95d6d30b42 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Wed, 14 Feb 2018 12:32:57 +0100 Subject: refactor(#18): Create distinction between kernel and simulation This change creates a distinction between a kernel and a simulation. A single simulation is represented by a `Simulation` object which provides control over the simulation, while the `Kernel` interface allows users to create a new simulation using that kernel as backend. --- .../src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opendc-stdlib/src/main/kotlin/com') diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt index 1a5bbcaf..e0b54a28 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/model/topology/Bootstrap.kt @@ -6,7 +6,7 @@ import com.atlarge.opendc.simulator.Entity /** * Create a [Bootstrap] procedure for the given [Topology]. * - * @return A bootstrap procedure for the topology. + * @return A apply procedure for the topology. */ fun T.bootstrap(): Bootstrap = Bootstrap.create { ctx -> forEach { ctx.register(it) } -- cgit v1.2.3 From f8a4095d1824df095ea91253f914bc0512646684 Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Fri, 16 Feb 2018 15:25:19 +0100 Subject: refactor(#18): Provide access to process context in nested calls This change provides a method in the standard library to access the process context in nested suspending function calls. --- .../kotlin/com/atlarge/opendc/simulator/Helpers.kt | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt (limited to 'opendc-stdlib/src/main/kotlin/com') diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt new file mode 100644 index 00000000..acf3fe41 --- /dev/null +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt @@ -0,0 +1,44 @@ +package com.atlarge.opendc.simulator + +import kotlin.coroutines.experimental.intrinsics.* + +/** + * Try to find the [Context] instance associated with the [Process] in the call chain which has (indirectly) invoked the + * caller of this method. + * + * Note however that this method does not guarantee type-safety as this method allows the user to cast to a context + * with different generic type arguments. + * + * @return The context that has been found or `null` if this method is not called in a simulation context. + */ +suspend fun contextOrNull(): Context? = suspendCoroutineOrReturn { it.context[Context] } + +/** + * Find the [Context] instance associated with the [Process] in the call chain which has (indirectly) invoked the + * caller of this method. + * + * Note however that this method does not guarantee type-safety as this method allows the user to cast to a context + * with different generic type arguments. + * + * @throws IllegalStateException if the context cannot be found. + * @return The context that has been found. + */ +suspend fun context(): Context = + contextOrNull() ?: throw IllegalStateException("The suspending call does not have an associated process context") + +/** + * Try to find the untyped [Context] instance associated with the [Process] in the call chain which has (indirectly) + * invoked the caller of this method. + * + * @return The untyped context that has been found or `null` if this method is not called in a simulation context. + */ +suspend fun untypedContextOrNull(): Context<*, *>? = contextOrNull() + +/** + * Find the [Context] instance associated with the [Process] in the call chain which has (indirectly) invoked the + * caller of this method. + * + * @throws IllegalStateException if the context cannot be found. + * @return The untyped context that has been found. + */ +suspend fun untypedContext(): Context<*, *> = context() -- cgit v1.2.3 From 0f84a74536e404f707c4f4e370efbaad8d12b89a Mon Sep 17 00:00:00 2001 From: Fabian Mastenbroek Date: Sat, 17 Feb 2018 11:18:07 +0100 Subject: refactor(#18): Optimize imports --- opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'opendc-stdlib/src/main/kotlin/com') diff --git a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt index acf3fe41..0f6392ed 100644 --- a/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt +++ b/opendc-stdlib/src/main/kotlin/com/atlarge/opendc/simulator/Helpers.kt @@ -1,6 +1,6 @@ package com.atlarge.opendc.simulator -import kotlin.coroutines.experimental.intrinsics.* +import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn /** * Try to find the [Context] instance associated with the [Process] in the call chain which has (indirectly) invoked the -- cgit v1.2.3