blob: cff3029716dbbba765e72d2324dbf93a5575a50c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Willink Transformations and others.
* 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:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.pivot.qvtcorebase.utilities;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.VariableExp;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.pivot.qvtbase.utilities.TreeIterable;
import org.eclipse.qvtd.pivot.qvtcorebase.Assignment;
import org.eclipse.qvtd.pivot.qvtcorebase.PropertyAssignment;
import org.eclipse.qvtd.pivot.qvtcorebase.VariableAssignment;
/**
* AssignmentComparator supports sorting an assignment list into VariableAssignments first, least dependent first, alphabetical order.
*/
public class AssignmentComparator implements Comparator<@NonNull Assignment>
{
private final @NonNull List<@NonNull Assignment> assignments;
private @Nullable Map<@NonNull Variable, @NonNull Set<@NonNull Variable>> variable2referencedVariables = null;
public AssignmentComparator(@NonNull List<@NonNull Assignment> assignments) {
this.assignments = assignments;
}
@Override
public int compare(@NonNull Assignment o1, @NonNull Assignment o2) {
if (o1 instanceof PropertyAssignment) {
if (o2 instanceof PropertyAssignment) {
Property p1 = ((PropertyAssignment)o1).getTargetProperty();
Property p2 = ((PropertyAssignment)o2).getTargetProperty();
String n1 = p1.getName();
String n2 = p2.getName();
int diff = ClassUtil.safeCompareTo(n1, n2);
if (diff != 0) {
return diff;
}
n1 = p1.toString();
n2 = p2.toString();
return ClassUtil.safeCompareTo(n1, n2);
}
else {
return 1;
}
}
else if (o1 instanceof VariableAssignment) {
if (o2 instanceof PropertyAssignment) {
return -1;
}
else if (o2 instanceof VariableAssignment) {
Map<@NonNull Variable, @NonNull Set<@NonNull Variable>> variable2referencedVariables2 = variable2referencedVariables;
if (variable2referencedVariables2 == null) {
variable2referencedVariables2 = variable2referencedVariables = computeReferencedVariableClosure();
}
Variable v1 = ((VariableAssignment)o1).getTargetVariable();
Variable v2 = ((VariableAssignment)o2).getTargetVariable();
Set<@NonNull Variable> r1 = variable2referencedVariables2.get(v1);
Set<@NonNull Variable> r2 = variable2referencedVariables2.get(v2);
assert (r1 != null) && (r2 != null);
int diff = r1.size() - r2.size();
if (diff != 0) {
return diff;
}
String n1 = v1.getName();
String n2 = v2.getName();
return ClassUtil.safeCompareTo(n1, n2);
}
}
return 0;
}
private @NonNull Map<@NonNull Variable, @NonNull Set<@NonNull Variable>> computeReferencedVariableClosure() {
Map<@NonNull Variable, @NonNull Set<@NonNull Variable>> variable2referencedVariables2;
variable2referencedVariables2 = new HashMap<@NonNull Variable, @NonNull Set<@NonNull Variable>>();
//
// Compute the direct references of each variable
//
for (@NonNull Assignment assignment : assignments) {
if (assignment instanceof VariableAssignment) {
VariableAssignment variableAssignment = (VariableAssignment)assignment;
Variable variable = ClassUtil.nonNullState(variableAssignment.getTargetVariable());
Set<@NonNull Variable> referencedVariables = new HashSet<@NonNull Variable>();
for (EObject eObject : new TreeIterable(ClassUtil.nonNullState(variableAssignment.getValue()), true)) {
if (eObject instanceof VariableExp) {
VariableDeclaration referredVariable = ((VariableExp)eObject).getReferredVariable();
if (referredVariable instanceof Variable) {
referencedVariables.add((Variable)referredVariable);
}
}
else if (eObject instanceof Variable) {
referencedVariables.add((Variable)eObject);
}
}
variable2referencedVariables2.put(variable, referencedVariables);
}
}
//
// Aggregate the closure
//
while (true) {
boolean more = false;
for (@NonNull Variable variable : variable2referencedVariables2.keySet()) {
Set<@NonNull Variable> referencedVariables = variable2referencedVariables2.get(variable);
assert referencedVariables != null;
for (@NonNull Variable referencedVariable : new ArrayList<@NonNull Variable>(referencedVariables)) {
Set<@NonNull Variable> referencedReferencedVariables = variable2referencedVariables2.get(referencedVariable);
if ((referencedReferencedVariables != null) && referencedVariables.addAll(referencedReferencedVariables)) {
more = true;
}
}
}
if (!more) {
break;
}
}
return variable2referencedVariables2;
}
}