blob: b84d83f303987de26d267aade394fe4f48820150 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2018 SAP AG 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:
* SAP AG - initial API and implementation
******************************************************************************/
package org.eclipse.ocl.examples.impactanalyzer.instanceScope;
import java.util.Set;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.ocl.ecore.OCLExpression;
import org.eclipse.ocl.examples.impactanalyzer.util.SemanticIdentity;
/**
* A navigation step that branches in several paths and combines the results into one. As hashCode and equals
* depend on the subordinate steps, steps of this class register as {@link HashCodeChangeListener} on each
* contained step and propagate the event correspondingly. The hash code combination for the subordinate
* steps, once computed, is cached and updated when subordinate steps send hash code change events.
*/
public abstract class CompositeNavigationStep extends AbstractNavigationStep implements HashCodeChangeListener {
private final NavigationStep[] steps;
private int cachedXorOfStepHashCodes;
private final SemanticIdentity semanticIdentity;
public CompositeNavigationStep(EClass sourceType, EClass targetType, OCLExpression debugInfo, NavigationStep... steps) {
super(sourceType, targetType, debugInfo);
this.steps = steps;
for (NavigationStep step : steps) {
cachedXorOfStepHashCodes ^= step.hashCode();
step.addHashCodeChangeListener(this);
}
semanticIdentity = new CompositeNavigationStepIdentity();
}
private class CompositeNavigationStepIdentity extends SemanticIdentity {
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || hashCode() != o.hashCode()) {
return false;
}
if(o instanceof CompositeNavigationStep){
NavigationStep[] otherSteps = ((CompositeNavigationStepIdentity) o).getNavigationStep().getSteps();
if(otherSteps.length != steps.length){
return false;
}
for(int i = 0; i < steps.length; i++){
SemanticIdentity thisSubStepIdentity = steps[i].getSemanticIdentity();
SemanticIdentity otherSubStepIdentity = otherSteps[i].getSemanticIdentity();
if(!thisSubStepIdentity.equals(otherSubStepIdentity)){
return false;
}
}
return true;
}else{
return false;
}
}
@Override
public int calculateHashCode() {
int hashCode = getSemanticIdentityOfSuper().hashCode();
hashCode = hashCode ^ cachedXorOfStepHashCodes;
return hashCode;
}
public CompositeNavigationStep getNavigationStep() {
return CompositeNavigationStep.this;
}
@Override
public NavigationStep getStep() {
return getNavigationStep();
}
}
private SemanticIdentity getSemanticIdentityOfSuper(){
return super.getSemanticIdentity();
}
protected SemanticIdentity getSemanticIdentityOfAbstractNavigationStep(){
return super.getSemanticIdentity();
}
public NavigationStep[] getSteps() {
return steps;
}
public void beforeHashCodeChange(NavigationStep step, int token) {
fireBeforeHashCodeChange(token);
cachedXorOfStepHashCodes ^= step.hashCode();
}
public void afterHashCodeChange(NavigationStep step, int token) {
cachedXorOfStepHashCodes ^= step.hashCode();
fireAfterHashCodeChange(token);
}
/**
* The default size in particular for atomic navigation steps is <tt>1</tt>.
*/
@Override
protected int size(Set<NavigationStep> visited) {
int result = 0;
if (!visited.contains(this)) {
visited.add(this);
result++;
for (NavigationStep step : steps) {
result += ((AbstractNavigationStep) step).size(visited);
}
}
return result;
}
@Override
protected int distinctSize(Set<SemanticIdentity> visited) {
int result = 0;
if (!visited.contains(this.getSemanticIdentity())) {
visited.add(this.getSemanticIdentity());
result++;
for (NavigationStep step : steps) {
result += ((AbstractNavigationStep) step).distinctSize(visited);
}
}
return result;
}
@Override
public SemanticIdentity getSemanticIdentity() {
return semanticIdentity;
}
public InstanceScopeAnalysis getInstanceScopeAnalysis() {
return null;
}
}