blob: 45ffac493af2ab8e9b17a76da6347fa8eb804e60 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 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.internal.conflict;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Predicate;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.compare.Diff;
import org.eclipse.emf.compare.Match;
import org.eclipse.emf.compare.internal.SubMatchIterator;
/**
* A custom iterator that will walk a Match->submatch tree, and allow iteration over the Diffs of these
* Matches.
* <p>
* Since we're walking over Matches but returning Diffs, this is not a good candidate for guava's filters.
* We're providing the custom {@link DiffTreeIterator#setFilter(Predicate)} and
* {@link DiffTreeIterator#setPruningFilter(Predicate)} to allow for filtering or pruning the the iteration.
* </p>
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public class DiffTreeIterator implements Iterator<Diff> {
/**
* The tree iterator that will walk over our Match tree. Some of the paths can be pruned through the use
* of a {@link #pruningFilter}.
*/
private final TreeIterator<Match> subMatchIterator;
/** An iterator over the differences of the current Match. */
private Iterator<Diff> diffIterator;
/** Current match. */
private Match current;
/** The Diff that will be returned by the next call to {@link #next()}. */
private Diff nextDiff;
/** Only Diffs that meet this criterion will be returned by this iterator. */
private Predicate<? super Diff> filter = x -> true;
/**
* This particular filter can be used in order to prune a given Match and all of its differences and
* sub-differences.
*/
private Predicate<? super Match> pruningFilter = x -> false;
/**
* Constructs our iterator given the root of the Match tree to iterate over.
*
* @param start
* Starting match of the tree we'll iterate over.
*/
public DiffTreeIterator(Match start) {
this.current = start;
this.subMatchIterator = new SubMatchIterator(start);
this.diffIterator = start.getDifferences().iterator();
}
/**
* Sets the criterion that Diffs must meet to be returned by this iterator.
*
* @param filter
* The filter differences must meet.
*/
public void setFilter(Predicate<? super Diff> filter) {
this.filter = filter;
}
/**
* Sets the pruning filter for this iterator. Any Match that meets this criterion will be pruned along
* with all of its differences and sub-differences.
*
* @param pruningFilter
* The pruning filter for this iterator.
*/
public void setPruningFilter(Predicate<? super Match> pruningFilter) {
this.pruningFilter = pruningFilter;
}
/**
* {@inheritDoc}
*
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
if (nextDiff != null) {
return true;
}
if (!diffIterator.hasNext()) {
computeNextMatch();
}
while (nextDiff == null && diffIterator.hasNext()) {
final Diff next = diffIterator.next();
if (filter.test(next)) {
nextDiff = next;
}
}
return nextDiff != null;
}
/**
* Computes the next match within the sub-match tree, pruning those that may meet {@link #pruningFilter}.
*/
private void computeNextMatch() {
final Match old = current;
while (current == old && subMatchIterator.hasNext()) {
final Match next = subMatchIterator.next();
if (pruningFilter.test(next)) {
subMatchIterator.prune();
} else {
current = next;
diffIterator = current.getDifferences().iterator();
}
}
}
/**
* {@inheritDoc}
*
* @see java.util.Iterator#next()
*/
public Diff next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
final Diff next = nextDiff;
nextDiff = null;
return next;
}
/**
* {@inheritDoc}
*
* @see java.util.Iterator#remove()
*/
public void remove() {
diffIterator.remove();
}
}