blob: e118c3344d1036a5c5f838848e46dec6065dbfe4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvts2qvts.merger;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.NavigationEdge;
import org.eclipse.qvtd.pivot.qvtschedule.Node;
import org.eclipse.qvtd.pivot.qvtschedule.Role;
import org.eclipse.qvtd.pivot.qvtschedule.utilities.QVTscheduleUtil;
/**
* An EdgeMerger gathers the contributions for an edge in a merged region and supports
* optimization of the to be created merged region.
*/
class EdgeMerger
{
protected final @NonNull RegionMerger regionMerger;
protected final @NonNull NodeMerger mergedSourceNodeMerger;
protected final @NonNull NodeMerger mergedTargetNodeMerger;
protected final @NonNull List<@NonNull Edge> originalEdges = new ArrayList<>();
private @NonNull Role edgeRole;
private @Nullable Edge mergedEdge = null;
public EdgeMerger(@NonNull RegionMerger regionMerger, @NonNull Edge originalEdge) {
assert !originalEdge.isSecondary();
this.regionMerger = regionMerger;
mergedSourceNodeMerger = regionMerger.getNodeMerger(originalEdge.getEdgeSource());
mergedTargetNodeMerger = regionMerger.getNodeMerger(originalEdge.getEdgeTarget());
originalEdges.add(originalEdge);
edgeRole = QVTscheduleUtil.getEdgeRole(originalEdge);
regionMerger.mapOriginalEdge(originalEdge, this);
mergedSourceNodeMerger.addOutgoingEdgeMerger(this, mergedTargetNodeMerger);
mergedTargetNodeMerger.addIncomingEdgeMerger(this, mergedSourceNodeMerger);
}
public void addOriginalEdge(@NonNull Edge originalEdge) {
assert !originalEdge.isSecondary();
assert !originalEdges.contains(originalEdge);
originalEdges.add(originalEdge);
edgeRole = QVTscheduleUtil.mergeToMoreKnownPhase(edgeRole, QVTscheduleUtil.getEdgeRole(originalEdge));
regionMerger.mapOriginalEdge(originalEdge, this);
}
public @Nullable Edge createMergedEdge(@NonNull Node sourceNodeMerger, @NonNull Node targetNodeMerger) {
Edge mergedEdge2 = mergedEdge;
assert mergedEdge2 == null;
for (@NonNull Edge originalEdge : originalEdges) {
mergedEdge2 = mergedEdge = originalEdge.createEdge(edgeRole, sourceNodeMerger, targetNodeMerger);
break;
}
if (mergedEdge2 == null) {
return null;
}
return mergedEdge2;
}
public void destroy() {
mergedSourceNodeMerger.removeOutgoingEdgeMerger(this, mergedTargetNodeMerger);
mergedTargetNodeMerger.removeIncomingEdgeMerger(this, mergedSourceNodeMerger);
for (@NonNull Edge originalEdge : originalEdges) {
regionMerger.unmapOriginalEdge(originalEdge, this);
}
}
public @NonNull Edge getMergedEdge() {
return ClassUtil.nonNullState(mergedEdge);
}
public @NonNull Iterable<@NonNull Edge> getOriginalEdges() {
return originalEdges;
}
public @NonNull Node getOriginalSource() {
return getPrimaryEdge().getEdgeSource();
}
public @NonNull Node getOriginalTarget() {
return getPrimaryEdge().getEdgeTarget();
}
private @NonNull Edge getPrimaryEdge() {
return originalEdges.get(0);
}
public @Nullable Property getProperty() {
Edge primaryEdge = getPrimaryEdge(); // FIXME check all original edges
if (primaryEdge instanceof NavigationEdge) {
return QVTscheduleUtil.getReferredProperty((NavigationEdge)primaryEdge);
}
else {
return null;
}
}
public @NonNull NodeMerger getSource() {
return mergedSourceNodeMerger;
}
public @NonNull NodeMerger getTarget() {
return mergedTargetNodeMerger;
}
private boolean isCast() {
return getPrimaryEdge().isCast();
}
public boolean isConstant() {
return getPrimaryEdge().isConstant(); // FIXME check all original edges
}
public boolean isFoldable() {
return isCast() && mergedTargetNodeMerger.isNew() && !mergedSourceNodeMerger.isNew();
}
public boolean isLoaded() {
return getPrimaryEdge().isLoaded(); // FIXME check all original edges
}
public boolean isNew() {
return getPrimaryEdge().isNew(); // FIXME check all original edges
}
public boolean isOld() {
return getPrimaryEdge().isOld(); // FIXME check all original edges
}
public boolean isUnconditional() {
return getPrimaryEdge().isUnconditional(); // FIXME check all original edges
}
/**
* Return an originalEdge that is the same as mergedEdge or null if none.
*/
public @Nullable Edge sameEdge(@NonNull Edge mergedEdge) {
if (mergedEdge instanceof NavigationEdge) {
Property mergedProperty = QVTscheduleUtil.getReferredProperty((NavigationEdge)mergedEdge);
for (@NonNull Edge originalEdge : originalEdges) {
if (originalEdge instanceof NavigationEdge) {
Property originalProperty = QVTscheduleUtil.getReferredProperty((NavigationEdge)originalEdge);
if (originalProperty == mergedProperty) {
return originalEdge;
}
}
}
}
else {
Class<? extends @NonNull Edge> mergedClass = mergedEdge.getClass();
for (@NonNull Edge originalEdge : originalEdges) {
Class<? extends @NonNull Edge> originalClass = originalEdge.getClass();
if (originalClass == mergedClass) {
return originalEdge;
}
}
}
return null;
}
@Override
public String toString() {
return mergedEdge != null? mergedEdge.toString() : getPrimaryEdge().toString();
}
}