blob: 8c5f60ca6c8d0d63da71cc115bcddd8e1f66a99d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 EclipseSource Services GmbH 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:
* Martin Fleck - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.compare.merge;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.merge.IMerger.Registry;
/**
* A computer implementation to cache the relationship of diffs. Note that the "all" relationships are not
* cached because they would O(n^2) memory in the general case.
*
* @since 3.5
* @author Martin Fleck <mfleck@eclipsesource.com>
* @see IMerger2
*/
public class CachingDiffRelationshipComputer extends DiffRelationshipComputer {
/** Direct merge dependencies: right to left. */
protected Map<Diff, Set<Diff>> directMergeDependenciesR2L = new ConcurrentHashMap<>();
/** Direct merge dependencies: left to right. */
protected Map<Diff, Set<Diff>> directMergeDependenciesL2R = new ConcurrentHashMap<>();
/** Direct resulting merges: right to left. */
protected Map<Diff, Set<Diff>> directResultingMergesR2L = new ConcurrentHashMap<>();
/** Direct resulting merges: left to right. */
protected Map<Diff, Set<Diff>> directResultingMergesL2R = new ConcurrentHashMap<>();
/** Direct resulting rejections: right to left. */
protected Map<Diff, Set<Diff>> directResultingRejectionsR2L = new ConcurrentHashMap<>();
/** Direct resulting rejections: left to right. */
protected Map<Diff, Set<Diff>> directResultingRejectionsL2R = new ConcurrentHashMap<>();
/**
* Creates a new computer with the given registry.
*
* @param registry
* merger registry
*/
public CachingDiffRelationshipComputer(IMerger.Registry registry) {
this(registry, IMergeCriterion.NONE);
}
/**
* Creates a new computer with the given registry and merge criterion.
*
* @param registry
* merger registry
* @param criterion
* merge criterion used to get the merger from the registry, use {@link IMergeCriterion#NONE}
* if no special criterion should be set.
*/
public CachingDiffRelationshipComputer(IMerger.Registry registry, IMergeCriterion criterion) {
super(registry, criterion);
}
/**
* {@inheritDoc} WARNING: Setting the merger registry invalidates previously cached results, if another
* registry was set previously!
*/
@Override
public void setMergerRegistry(Registry mergerRegistry) {
if (getMergerRegistry() != mergerRegistry) {
super.setMergerRegistry(mergerRegistry);
invalidate();
}
}
/**
* {@inheritDoc} WARNING: Setting the merge criterion invalidates previously cached results, if another
* criterion was set previously.
*/
@Override
public void setMergeCriterion(IMergeCriterion mergeCriterion) {
if (getMergeCriterion() != mergeCriterion) {
super.setMergeCriterion(mergeCriterion);
invalidate();
}
}
/**
* Caches the given direct merge dependencies.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @param directMergeDependencies
* direct merge dependencies of diff
*/
protected void setCachedDirectMergeDependencies(Diff diff, boolean mergeRightToLeft,
Set<Diff> directMergeDependencies) {
if (mergeRightToLeft) {
directMergeDependenciesR2L.put(diff, directMergeDependencies);
} else {
directMergeDependenciesL2R.put(diff, directMergeDependencies);
}
}
/**
* Returns the cached direct merge dependencies.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return cached direct merge dependencies
*/
protected Set<Diff> getCachedDirectMergeDependencies(Diff diff, boolean mergeRightToLeft) {
if (mergeRightToLeft) {
return directMergeDependenciesR2L.get(diff);
} else {
return directMergeDependenciesL2R.get(diff);
}
}
/**
* Computes direct merge dependencies for the given diff.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return a non-null set of direct merge dependencies
*/
protected Set<Diff> computeDirectMergeDependencies(Diff diff, boolean mergeRightToLeft) {
return super.getDirectMergeDependencies(diff, mergeRightToLeft);
}
/**
* Returns the cached direct merge dependencies, if present. Otherwise, the direct merge dependencies are
* retrieved and cached using the given merger.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return cached direct merge dependencies
* @see IMerger2#getDirectMergeDependencies(Diff, boolean)
*/
@Override
public Set<Diff> getDirectMergeDependencies(Diff diff, boolean mergeRightToLeft) {
Set<Diff> directMergeDependencies = getCachedDirectMergeDependencies(diff, mergeRightToLeft);
if (directMergeDependencies == null) {
directMergeDependencies = computeDirectMergeDependencies(diff, mergeRightToLeft);
setCachedDirectMergeDependencies(diff, mergeRightToLeft, asEmptySet(directMergeDependencies));
}
return directMergeDependencies;
}
/**
* Caches the given direct resulting merges.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @param directResultingMerges
* direct resulting merges
*/
protected void setCachedDirectResultingMerges(Diff diff, boolean mergeRightToLeft,
Set<Diff> directResultingMerges) {
if (mergeRightToLeft) {
directResultingMergesR2L.put(diff, directResultingMerges);
} else {
directResultingMergesL2R.put(diff, directResultingMerges);
}
}
/**
* Returns the cached direct resulting merges.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return cached direct resulting merges
*/
protected Set<Diff> getCachedDirectResultingMerges(Diff diff, boolean mergeRightToLeft) {
if (mergeRightToLeft) {
return directResultingMergesR2L.get(diff);
} else {
return directResultingMergesL2R.get(diff);
}
}
/**
* Computes direct resulting merges for the given diff.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return a non-null set of all resulting merges
*/
protected Set<Diff> computeDirectResultingMerges(Diff diff, boolean mergeRightToLeft) {
return super.getDirectResultingMerges(diff, mergeRightToLeft);
}
/**
* Returns the cached direct resulting merges, if present. Otherwise, the direct resulting merges are
* retrieved and cached using the given merger.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return cached direct resulting merges
* @see IMerger2#getDirectResultingMerges(Diff, boolean)
*/
@Override
public Set<Diff> getDirectResultingMerges(Diff diff, boolean mergeRightToLeft) {
Set<Diff> directResultingMerges = getCachedDirectResultingMerges(diff, mergeRightToLeft);
if (directResultingMerges == null) {
directResultingMerges = computeDirectResultingMerges(diff, mergeRightToLeft);
setCachedDirectResultingMerges(diff, mergeRightToLeft, asEmptySet(directResultingMerges));
}
return directResultingMerges;
}
/**
* Caches the given direct resulting rejections.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @param directResultingRejections
* direct resulting rejections
*/
protected void setCachedDirectResultingRejections(Diff diff, boolean mergeRightToLeft,
Set<Diff> directResultingRejections) {
if (mergeRightToLeft) {
directResultingRejectionsR2L.put(diff, directResultingRejections);
} else {
directResultingRejectionsL2R.put(diff, directResultingRejections);
}
}
/**
* Returns the cached direct resulting rejections.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return cached direct resulting rejections
*/
protected Set<Diff> getCachedDirectResultingRejections(Diff diff, boolean mergeRightToLeft) {
if (mergeRightToLeft) {
return directResultingRejectionsR2L.get(diff);
} else {
return directResultingRejectionsL2R.get(diff);
}
}
/**
* Computes the direct resulting rejections.
*
* @param diff
* diff
* @param mergeRightToLeft
* merge direction
* @return a non-null set of direct resulting rejections
*/
protected Set<Diff> computeDirectResultingRejections(Diff diff, boolean mergeRightToLeft) {
return super.getDirectResultingRejections(diff, mergeRightToLeft);
}
@Override
public Set<Diff> getDirectResultingRejections(Diff diff, boolean mergeRightToLeft) {
Set<Diff> directResultingRejections = getCachedDirectResultingRejections(diff, mergeRightToLeft);
if (directResultingRejections == null) {
directResultingRejections = computeDirectResultingRejections(diff, mergeRightToLeft);
setCachedDirectResultingRejections(diff, mergeRightToLeft, asEmptySet(directResultingRejections));
}
return directResultingRejections;
}
/**
* Returns the argument or the empty set if the argument is empty.
*
* @param diffs
* the diffs to transform.
* @return the diffs or the empty set.
*/
private Set<Diff> asEmptySet(Set<Diff> diffs) {
if (diffs.isEmpty()) {
return Collections.emptySet();
} else {
return diffs;
}
}
/**
* Computes the cached relationships for the give diff.
*
* @param diff
* the diff for which to cmpute the cached relationship.
*/
public void computeCache(Diff diff) {
IMerger2 merger = getMerger(diff);
if (merger != null) {
directMergeDependenciesR2L.put(diff, asEmptySet(merger.getDirectMergeDependencies(diff, true)));
directMergeDependenciesL2R.put(diff, asEmptySet(merger.getDirectMergeDependencies(diff, false)));
directResultingRejectionsR2L.put(diff,
asEmptySet(merger.getDirectResultingRejections(diff, true)));
directResultingRejectionsL2R.put(diff,
asEmptySet(merger.getDirectResultingRejections(diff, false)));
directResultingMergesR2L.put(diff, asEmptySet(merger.getDirectResultingMerges(diff, true)));
directResultingMergesL2R.put(diff, asEmptySet(merger.getDirectResultingMerges(diff, false)));
}
}
/**
* Invalidates the complete cache, so that relationships will be re-calculated any diff the next time a
* respective method is called.
*/
public void invalidate() {
directMergeDependenciesR2L.clear();
directMergeDependenciesL2R.clear();
directResultingRejectionsR2L.clear();
directResultingRejectionsL2R.clear();
directResultingMergesR2L.clear();
directResultingMergesL2R.clear();
}
}