| /******************************************************************************* |
| * Copyright (c) 2012, 2014 Obeo. |
| * 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.utils; |
| |
| import com.google.common.base.Function; |
| |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.emf.compare.Comparison; |
| import org.eclipse.emf.compare.Diff; |
| import org.eclipse.emf.compare.internal.utils.ComparisonUtil; |
| |
| /** |
| * This utility class will be used to provide similarity implementations. |
| * |
| * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> |
| * @deprecated Not intendended to be used by clients |
| */ |
| @Deprecated |
| public final class DiffUtil { |
| /** This utility class does not need to be instantiated. */ |
| private DiffUtil() { |
| // Hides default constructor |
| } |
| |
| /** |
| * Computes the dice coefficient between the two given String's bigrams. |
| * <p> |
| * This implementation is case sensitive. |
| * </p> |
| * |
| * @param first |
| * First of the two Strings to compare. |
| * @param second |
| * Second of the two Strings to compare. |
| * @return The dice coefficient of the two given String's bigrams, ranging from 0 to 1. |
| */ |
| public static double diceCoefficient(String first, String second) { |
| return org.eclipse.emf.compare.internal.utils.DiffUtil.diceCoefficient(first, second); |
| } |
| |
| /** |
| * This will compute the longest common subsequence between the two given Lists, ignoring any object that |
| * is included in {@code ignoredElements}. We will use |
| * {@link EqualityHelper#matchingValues(Comparison, Object, Object)} in order to try and match the values |
| * from both lists two-by-two. This can thus be used both for reference values or attribute values. If |
| * there are two subsequences of the same "longest" length, the first (according to the second argument) |
| * will be returned. |
| * <p> |
| * Take note that this might be slower than |
| * {@link #longestCommonSubsequence(Comparison, EqualityHelper, List, List)} and should only be used when |
| * elements should be removed from the potential LCS. This is mainly aimed at merge operations during |
| * three-way comparisons as some objects might be in conflict and thus shifting the computed insertion |
| * indices. |
| * </p> |
| * <p> |
| * Please see {@link #longestCommonSubsequence(Comparison, EqualityHelper, List, List)} for a more |
| * complete description. |
| * </p> |
| * |
| * @param comparison |
| * This will be used in order to retrieve the Match for EObjects when comparing them. |
| * @param ignoredElements |
| * Specifies elements that should be excluded from the subsequences. |
| * @param sequence1 |
| * First of the two sequences to consider. |
| * @param sequence2 |
| * Second of the two sequences to consider. |
| * @param <E> |
| * Type of the sequences content. |
| * @return The LCS of the two given sequences. Will never be the same instance as one of the input |
| * sequences. |
| * @see #longestCommonSubsequence(Comparison, EqualityHelper, List, List). |
| */ |
| public static <E> List<E> longestCommonSubsequence(Comparison comparison, Iterable<E> ignoredElements, |
| List<E> sequence1, List<E> sequence2) { |
| return org.eclipse.emf.compare.internal.utils.DiffUtil.longestCommonSubsequence(comparison, |
| ignoredElements, sequence1, sequence2); |
| } |
| |
| /** |
| * This will compute the longest common subsequence between the two given Lists. We will use |
| * {@link EqualityHelper#matchingValues(Comparison, Object, Object)} in order to try and match the values |
| * from both lists two-by-two. This can thus be used both for reference values or attribute values. If |
| * there are two subsequences of the same "longest" length, the first (according to the second argument) |
| * will be returned. |
| * <p> |
| * For example, it the two given sequence are, in this order, <code>{"a", "b", "c", "d", "e"}</code> and |
| * <code>{"c", "z", "d", "a", "b"}</code>, there are two "longest" subsequences : <code>{"a", "b"}</code> |
| * and <code>{"c", "d"}</code>. The first of those two subsequences in the second list is |
| * <code>{"c", "d"}</code>. On the other hand, the LCS of <code>{"a", "b", "c", "d", "e"}</code> and |
| * <code>{"y", "c", "d", "e", "b"}</code> is <code>{"c", "d", "e"}</code>. |
| * </p> |
| * <p> |
| * The following algorithm has been inferred from the wikipedia article on the Longest Common Subsequence, |
| * http://en.wikipedia.org/wiki/Longest_common_subsequence_problem at the time of writing. It is |
| * decomposed in two : we first compute the LCS matrix, then we backtrack through the input to determine |
| * the LCS. Evaluation will be shortcut after the first part if the LCS is one of the two input sequences. |
| * </p> |
| * <p> |
| * Note : we are not using Iterables as input in order to make use of the random access cost of |
| * ArrayLists. This might also be converted to directly use arrays. This implementation will not play well |
| * with LinkedLists or any List which needs to iterate over the values for each call to |
| * {@link List#get(int)}, i.e any list which is not instanceof RandomAccess or does not satisfy its |
| * contract. |
| * </p> |
| * |
| * @param comparison |
| * This will be used in order to retrieve the Match for EObjects when comparing them. |
| * @param sequence1 |
| * First of the two sequences to consider. |
| * @param sequence2 |
| * Second of the two sequences to consider. |
| * @param <E> |
| * Type of the sequences content. |
| * @return The LCS of the two given sequences. Will never be the same instance as one of the input |
| * sequences. |
| */ |
| public static <E> List<E> longestCommonSubsequence(Comparison comparison, List<E> sequence1, |
| List<E> sequence2) { |
| return org.eclipse.emf.compare.internal.utils.DiffUtil.longestCommonSubsequence(comparison, sequence1, |
| sequence2); |
| } |
| |
| /** |
| * This will try and determine the index at which a given element from the {@code source} list should be |
| * inserted in the {@code target} list. We expect {@code newElement} to be an element from the |
| * {@code source} or to have a Match that allows us to map it to one of the {@code source} list's |
| * elements. |
| * <p> |
| * The expected insertion index will always be relative to the Longest Common Subsequence (LCS) between |
| * the two given lists, ignoring all elements from that LCS that have changed between the target list and |
| * the common origin of the two. If there are more than one "longest" subsequence between the two lists, |
| * the insertion index will be relative to the first that comes in the {@code target} list. |
| * </p> |
| * <p> |
| * Note : we are not using Iterables as input in order to make use of the random access cost of |
| * ArrayLists. This might also be converted to directly use arrays. This implementation will not play well |
| * with LinkedLists or any List which needs to iterate over the values for each call to |
| * {@link List#get(int)}, i.e any list which is not instanceof RandomAccess or does not satisfy its |
| * contract. |
| * </p> |
| * |
| * @param comparison |
| * This will be used in order to retrieve the Match for EObjects when comparing them. |
| * @param ignoredElements |
| * If there are elements from {@code target} that should be ignored when searching for an |
| * insertion index, set them here. Can be {@code null} or an empty list. |
| * @param source |
| * The List from which one element has to be added to the {@code target} list. |
| * @param target |
| * The List into which one element from {@code source} has to be added. |
| * @param newElement |
| * The element from {@code source} that needs to be added into {@code target}. |
| * @param <E> |
| * Type of the sequences content. |
| * @return The index at which {@code newElement} should be inserted in {@code target}. |
| * @see #longestCommonSubsequence(Comparison, List, List) |
| * @noreference This method is not intended to be referenced by clients. |
| */ |
| public static <E> int findInsertionIndex(Comparison comparison, Iterable<E> ignoredElements, |
| List<E> source, List<E> target, E newElement) { |
| return org.eclipse.emf.compare.internal.utils.DiffUtil.findInsertionIndex(comparison, ignoredElements, |
| source, target, newElement); |
| } |
| |
| /** |
| * This will try and determine the index at which a given element from the {@code source} list should be |
| * inserted in the {@code target} list. We expect {@code newElement} to be an element from the |
| * {@code source} or to have a Match that allows us to map it to one of the {@code source} list's |
| * elements. |
| * <p> |
| * The expected insertion index will always be relative to the Longest Common Subsequence (LCS) between |
| * the two given lists. If there are more than one "longest" subsequence between the two lists, the |
| * insertion index will be relative to the first that comes in the {@code target} list. |
| * </p> |
| * <p> |
| * For example, assume {@code source} is <code>{"1", "2", "4", "6", "8", "3", "0", "7", "5"}</code> and |
| * {@code target} is <code>{"8", "1", "2", "9", "3", "4", "7"}</code>; I try to merge the addition of |
| * {@code "0"} in the right list. The returned "insertion index" will be {@code 5} : just after |
| * {@code "3"}. There are two subsequence of the same "longest" length 4 : |
| * <code>{"1", "2", "3", "7"}</code> and <code>{"1", "2", "4", "7"}</code>. However, the first of those |
| * two in {@code target} is <code>{"1", "2", "3", "7"}</code>. The closest element before {@code "0"} in |
| * this LCS in {@code source} is {@code "3"}. |
| * </p> |
| * <p> |
| * Note : we are not using Iterables as input in order to make use of the random access cost of |
| * ArrayLists. This might also be converted to directly use arrays. This implementation will not play well |
| * with LinkedLists or any List which needs to iterate over the values for each call to |
| * {@link List#get(int)}, i.e any list which is not instanceof RandomAccess or does not satisfy its |
| * contract. |
| * </p> |
| * |
| * @param comparison |
| * This will be used in order to retrieve the Match for EObjects when comparing them. |
| * @param source |
| * The List from which one element has to be added to the {@code target} list. |
| * @param target |
| * The List into which one element from {@code source} has to be added. |
| * @param newElement |
| * The element from {@code source} that needs to be added into {@code target}. |
| * @param <E> |
| * Type of the sequences content. |
| * @return The index at which {@code newElement} should be inserted in {@code target}. |
| * @see #longestCommonSubsequence(Comparison, List, List) |
| */ |
| public static <E> int findInsertionIndex(Comparison comparison, List<E> source, List<E> target, |
| E newElement) { |
| return org.eclipse.emf.compare.internal.utils.DiffUtil.findInsertionIndex(comparison, source, target, |
| newElement); |
| } |
| |
| /** |
| * This is the main entry point for |
| * {@link #findInsertionIndex(Comparison, EqualityHelper, Iterable, List, List, Object)}. It will use |
| * default algorithms to determine the source and target lists as well as the list of elements that should |
| * be ignored when computing the insertion index. |
| * |
| * @param comparison |
| * This will be used in order to retrieve the Match for EObjects when comparing them. |
| * @param diff |
| * The diff which merging will trigger the need for an insertion index in its target list. |
| * @param rightToLeft |
| * {@code true} if the merging will be done into the left list, so that we should consider the |
| * right model as the source and the left as the target. |
| * @return The index at which this {@code diff}'s value should be inserted into the 'target' list, as |
| * inferred from {@code rightToLeft}. |
| * @see #findInsertionIndex(Comparison, Iterable, List, List, Object) |
| */ |
| public static int findInsertionIndex(Comparison comparison, Diff diff, boolean rightToLeft) { |
| return org.eclipse.emf.compare.internal.utils.DiffUtil.findInsertionIndex(comparison, diff, |
| rightToLeft); |
| } |
| |
| /** |
| * When merging a {@link Diff}, returns the sub diffs of this given diff, and all associated diffs (see |
| * {@link DiffUtil#getAssociatedDiffs(Iterable, boolean, Diff)}) of these sub diffs. |
| * <p> |
| * If the diff is an {@link org.eclipse.emf.compare.AttributeChange}, a |
| * {@link org.eclipse.emf.compare.FeatureMapChange} or a @{code ResourceAttachmentChange}, this method |
| * will return an empty iterable. |
| * </p> |
| * <p> |
| * If the diff is a {@link org.eclipse.emf.compare.ReferenceChange} this method will return all |
| * differences contained in the match that contains the value of the reference change, and all associated |
| * diffs of these differences. |
| * </p> |
| * |
| * @param leftToRight |
| * the direction of merge. |
| * @return an iterable containing the sub diffs of this given diff, and all associated diffs of these sub |
| * diffs. |
| * @since 3.0 |
| */ |
| public static Function<Diff, Iterable<Diff>> getSubDiffs(final boolean leftToRight) { |
| return ComparisonUtil.getSubDiffs(leftToRight); |
| } |
| |
| /** |
| * When merging a {@link Diff}, returns the associated diffs of the sub diffs of the diff, and all sub |
| * diffs (see {@link DiffUtil#getSubDiffs(boolean)}) of these associated diffs. |
| * <p> |
| * The associated diffs of a diff are : |
| * <p> |
| * - {@link Diff#getRequiredBy()} if the source of the diff is the left side and the direction of the |
| * merge is right to left. |
| * </p> |
| * <p> |
| * - {@link Diff#getRequiredBy()} if the source of the diff is the right side and the direction of the |
| * merge is left to right. |
| * </p> |
| * <p> |
| * - {@link Diff#getRequires()} if the source of the diff is the left side and the direction of the merge |
| * is left to right. |
| * </p> |
| * <p> |
| * - {@link Diff#getRequires()} if the source of the diff is the right side and the direction of the merge |
| * is right to left. |
| * </p> |
| * </p> |
| * |
| * @param diffRoot |
| * the given diff. |
| * @param subDiffs |
| * the iterable of sub diffs for which we want the associated diffs. |
| * @param leftToRight |
| * the direction of merge. |
| * @return an empty list. |
| * @since 3.0 |
| * @deprecated |
| */ |
| @Deprecated |
| public static Iterable<Diff> getAssociatedDiffs(final Diff diffRoot, Iterable<Diff> subDiffs, |
| boolean leftToRight) { |
| return Collections.emptyList(); |
| } |
| } |