/*
* Copyright (c) 2009-2011, IETR/INSA of Rennes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.df.transform;
import java.util.ArrayList;
import java.util.List;
import net.sf.orcc.df.Connection;
import net.sf.orcc.df.DfFactory;
import net.sf.orcc.df.Entity;
import net.sf.orcc.df.Network;
import net.sf.orcc.df.Port;
import net.sf.orcc.df.util.DfVisitor;
import net.sf.orcc.graph.Edge;
import net.sf.orcc.graph.Vertex;
import net.sf.orcc.ir.ExprVar;
import net.sf.orcc.ir.Expression;
import net.sf.orcc.ir.Use;
import net.sf.orcc.ir.Var;
import net.sf.orcc.ir.util.IrUtil;
import net.sf.orcc.util.SwitchUtil;
import net.sf.orcc.util.Void;
import net.sf.orcc.util.util.EcoreHelper;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.util.EcoreUtil;
/**
* This class defines a transformation that flattens a given network in-place.
* The network must have been instantiated first, otherwise this transformation
* will not flatten anything.
*
* @author Matthieu Wipliez
* @author Ghislain Roquier
* @author Herve Yviquel
*
*/
public class NetworkFlattener extends DfVisitor<Void> {
@Override
public Void caseNetwork(Network network) {
// make a copy because we modify the "entities" list in the loop
// and we want to avoid concurrent modification
List<Vertex> children = new ArrayList<Vertex>(network.getChildren());
for (Vertex entity : children) {
Network subNetwork = entity.getAdapter(Network.class);
if (subNetwork == null) {
// cannot flatten anything else than a network
continue;
}
// flatten this sub-network
new NetworkFlattener().doSwitch(subNetwork);
moveEntitiesAndConnections(network, subNetwork);
propagateVariables(subNetwork.getParameters());
propagateVariables(subNetwork.getVariables());
linkOutgoingConnections(network, subNetwork);
linkIncomingConnections(network, subNetwork);
// remove entity from network
network.remove(entity);
// remove connections to clean up incoming/outgoing of instances
subNetwork.removeEdges(subNetwork.getConnections());
}
return SwitchUtil.DONE;
}
/**
* Adds edges in the network between predecessors of the sub-network and
* successors of its input ports.
*
* @param network
* the network
* @param subNetwork
* the sub network
*/
private void linkIncomingConnections(Network network, Network subNetwork) {
List<Edge> incomingEdges = new ArrayList<Edge>(subNetwork.getIncoming());
for (Edge edge : incomingEdges) {
Connection connection = (Connection) edge;
List<Edge> outgoingEdges = connection.getTargetPort().getOutgoing();
for (Edge outgoingEdge : outgoingEdges) {
Connection outgoingConnection = (Connection) outgoingEdge;
Connection incoming = DfFactory.eINSTANCE.createConnection(
edge.getSource(), connection.getSourcePort(),
outgoingEdge.getTarget(),
outgoingConnection.getTargetPort(),
EcoreUtil.copyAll(connection.getAttributes()));
network.getConnections().add(incoming);
}
}
}
/**
* Adds edges in the network between successors of the sub-network and
* predecessors of its output ports.
*
* @param network
* the network
* @param subNetwork
* the sub network
*/
private void linkOutgoingConnections(Network network, Network subNetwork) {
List<Edge> outgoingEdges = new ArrayList<Edge>(subNetwork.getOutgoing());
for (Edge edge : outgoingEdges) {
Connection connection = (Connection) edge;
List<Edge> incomingEdges = connection.getSourcePort().getIncoming();
for (Edge incomingEdge : incomingEdges) {
Connection incomingConnection = (Connection) incomingEdge;
Connection incoming = DfFactory.eINSTANCE.createConnection(
incomingEdge.getSource(),
incomingConnection.getSourcePort(), edge.getTarget(),
connection.getTargetPort(),
EcoreUtil.copyAll(connection.getAttributes()));
network.getConnections().add(incoming);
}
}
}
private void moveEntitiesAndConnections(Network network, Network subNetwork) {
// Rename subNetwork entities
for (Vertex vertex : subNetwork.getChildren()) {
Entity entity = vertex.getAdapter(Entity.class);
String name = subNetwork.getSimpleName() + "_"
+ entity.getSimpleName();
vertex.setLabel(name);
}
// move entities/instances and vertices in this network
List<Vertex> vertices = new ArrayList<Vertex>(subNetwork.getChildren());
for (Vertex vertex : vertices) {
network.add(vertex);
}
// move connections between entities in this network
List<Connection> connections = new ArrayList<Connection>();
for (Connection connection : subNetwork.getConnections()) {
Vertex source = connection.getSource();
Vertex target = connection.getTarget();
if (!(source instanceof Port) && !(target instanceof Port)) {
connections.add(connection);
}
}
// move connections
network.getConnections().addAll(connections);
}
/**
* Propagate the values of the given variables to their uses
*
* @param variables
* the variables to propagate
*/
private void propagateVariables(EList<Var> variables) {
for (Var var : variables) {
for (Use use : var.getUses()) {
Expression oldExpr = EcoreHelper.getContainerOfType(use,
ExprVar.class);
Expression initialValue = var.getInitialValue();
if (initialValue != null) {
EcoreUtil.replace(oldExpr, IrUtil.copy(initialValue));
}
}
}
}
}