Java tutorial
/******************************************************************************* * Copyright (c) 2013-2014 Synflow SAS. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Matthieu Wipliez - initial API and implementation and/or initial documentation *******************************************************************************/ package com.synflow.cx.internal.scheduler; import static com.synflow.models.util.SwitchUtil.visit; import java.util.List; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.Switch; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.synflow.cx.cx.Branch; import com.synflow.cx.cx.CxExpression; import com.synflow.cx.cx.Enter; import com.synflow.cx.cx.Leave; import com.synflow.cx.cx.StatementWrite; import com.synflow.cx.cx.VarRef; import com.synflow.cx.instantiation.IInstantiator; import com.synflow.models.dpn.Action; import com.synflow.models.dpn.Actor; import com.synflow.models.dpn.DpnFactory; import com.synflow.models.dpn.Port; import com.synflow.models.node.Node; import com.synflow.models.util.Void; /** * This class tracks the reads/writes in a current task, and is used to compute the cycle-accurate * behavior. * * @author Matthieu * */ public class Schedule { /** * Returns <code>true</code> if the given list of objects is empty (or contains only Enter/Leave * objects). * * @param eObjects * a list of objects (like <code>transition.getBody()</code> or * <code>transition.getScheduler()</code>). * @return true if the list is assimilated to empty */ public static boolean isEmpty(List<EObject> eObjects) { // returns true if iterable is empty or it just contains Enter/Leave instances return Iterables.all(eObjects, new Predicate<EObject>() { @Override public boolean apply(EObject eObject) { return eObject instanceof Enter || eObject instanceof Leave; } }); } protected final Actor actor; protected final IInstantiator instantiator; private ICycleListener listener; private Node node; private boolean usePeek; public Schedule(IInstantiator instantiator, Actor actor) { this.instantiator = instantiator; this.actor = actor; node = new Node(DpnFactory.eINSTANCE.createActionEmpty()); } /** * Creates a new schedule whose reads/writes are copied from the given schedule. * * @param schedule * an existing schedule */ public Schedule(Schedule schedule) { this(schedule.instantiator, schedule.actor); DpnFactory.eINSTANCE.addPatterns(getAction(), schedule.getAction()); this.listener = schedule.listener; } public void addListener(ICycleListener listener) { this.listener = listener; } /** * Returns the current action holding the peek/input/output patterns. * * @return an action */ protected final Action getAction() { return getAction(node); } /** * Returns the action associated with the given node. * * @param node * a node * @return an action */ protected Action getAction(Node node) { return (Action) node.getContent(); } public Node getNode() { return node; } /** * Returns <code>true</code> if the port has been read in the current cycle. * * @param port * an input port * @return a boolean */ protected boolean hasBeenRead(Port port) { return getAction().getInputPattern().contains(port); } /** * Returns <code>true</code> if the port has been written in the current cycle. * * @param port * an output port * @return a boolean */ protected boolean hasBeenWritten(Port port) { return getAction().getOutputPattern().contains(port); } /** * Adds peeks to reads. * * @param action */ public final void promotePeeks(Action action) { action.getInputPattern().add(action.getPeekPattern()); } /** * Registers a read from the given port. * * @param ref * reference to an input port */ public void read(VarRef ref) { Port port = instantiator.getPort(actor, ref); if (hasBeenRead(port)) { startNewCycle(); } if (usePeek) { getAction().getPeekPattern().add(port); } else { getAction().getInputPattern().add(port); } } public void removeListener(ICycleListener listener) { this.listener = null; } public void setNode(Node node) { this.node = node; } /** * Starts a new cycle, clears the current node's children, and updates its content to a new * empty action. */ public void startNewCycle() { // if the node had any child branches, clear them up node.clearChildren(); node.setContent(DpnFactory.eINSTANCE.createActionEmpty()); if (listener != null) { listener.newCycleStarted(); } } @Override public String toString() { return getAction().toString(); } /** * Visits the given branch (condition and body) with the given void switch, and then promote * peeks. * * @param voidSwitch * an EMF Void Switch * @param branch * a Branch */ public void visitBranch(Switch<Void> voidSwitch, Branch branch) { visitCondition(voidSwitch, branch.getCondition()); visit(voidSwitch, branch.getBody()); promotePeeks(getAction()); } /** * Visits the given condition with the given void switch. * * @param voidSwitch * an EMF Void Switch * @param condition * a CxExpression (may be <code>null</code>) */ public void visitCondition(Switch<Void> voidSwitch, CxExpression condition) { if (condition != null) { // condition may be absent (for else statements) usePeek = true; visit(voidSwitch, condition); usePeek = false; } } /** * Visits a write to the given port. * * @param voidSwitch * an EMF Void Switch * @param stmt * a write statement */ public void write(Switch<Void> voidSwitch, StatementWrite stmt) { // first check for existing writes Port port = instantiator.getPort(actor, stmt.getPort()); if (hasBeenWritten(port)) { startNewCycle(); } // only then visit the value visit(voidSwitch, stmt.getValue()); // and records the fact that we are doing a write getAction().getOutputPattern().add(port); } }