| /******************************************************************************* |
| * Copyright (c) 2012, 2014 Obeo 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: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.emf.compare.match.eobject; |
| |
| import java.util.Map; |
| |
| import org.eclipse.emf.compare.Comparison; |
| import org.eclipse.emf.compare.match.eobject.ProximityEObjectMatcher.DistanceFunction; |
| import org.eclipse.emf.compare.match.eobject.internal.AccessBasedLRUCache; |
| import org.eclipse.emf.ecore.EObject; |
| |
| /** |
| * This class wraps a DistanceFunction and cache its result. Any call to distance(a,b) will be cached and the |
| * same value will be returned to distance(b,a). |
| * |
| * @author <a href="mailto:cedric.brun@obeo.fr">Cedric Brun</a> |
| * @since 3.1 |
| */ |
| public class CachingDistance implements DistanceFunction { |
| |
| /** |
| * The wrapped function. |
| */ |
| private DistanceFunction wrapped; |
| |
| /** |
| * The cache keeping the previous results. |
| */ |
| private Map<Pair, Double> distanceCache; |
| |
| /** |
| * Create a new caching distance. |
| * |
| * @param wrapped |
| * actual distance function to cache results from. |
| */ |
| public CachingDistance(DistanceFunction wrapped) { |
| this.wrapped = wrapped; |
| distanceCache = new AccessBasedLRUCache<Pair, Double>(10000, 1000, .75F); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public double distance(Comparison inProgress, EObject a, EObject b) { |
| Pair key = new Pair(a, b); |
| Double previousResult = distanceCache.get(key); |
| if (previousResult == null) { |
| double dist = wrapped.distance(inProgress, a, b); |
| distanceCache.put(key, Double.valueOf(dist)); |
| // cache it |
| return dist; |
| } |
| return previousResult.doubleValue(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean areIdentic(Comparison inProgress, EObject a, EObject b) { |
| return wrapped.areIdentic(inProgress, a, b); |
| } |
| |
| /** |
| * A class used as a key for two EObjects. Pair(a,b) and Pair(b,a) should be equals and have the same |
| * hashcodes |
| */ |
| class Pair { |
| // CHECKSTYLE:OFF |
| EObject a; |
| |
| EObject b; |
| |
| public Pair(EObject a, EObject b) { |
| super(); |
| this.a = a; |
| this.b = b; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + getOuterType().hashCode(); |
| int first = a.hashCode(); |
| int second = b.hashCode(); |
| if (first > second) { |
| int tmp = first; |
| first = second; |
| second = tmp; |
| } |
| result = prime * result + first; |
| result = prime * result + second; |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (getClass() != obj.getClass()) { |
| return false; |
| } |
| Pair other = (Pair)obj; |
| if (!getOuterType().equals(other.getOuterType())) { |
| return false; |
| } |
| return (a == other.a && b == other.b) || (b == other.a && a == other.b); |
| |
| } |
| |
| private CachingDistance getOuterType() { |
| return CachingDistance.this; |
| } |
| |
| } |
| // CHECKSTYLE:ON |
| |
| } |