/** * <copyright> * * Copyright (c) 2010-2016 Thales Global Services S.A.S. * 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: * Thales Global Services S.A.S. - initial API and implementation * * </copyright> */ package org.eclipse.emf.diffmerge.util.structures; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * A base implementation for endorelations providing a few services. * @param <T> the type of the elements * @author Olivier Constant */ public abstract class AbstractEndorelation<T> extends AbstractBinaryRelation<T, T> implements IEndorelation<T> { /** * Constructor * @param tester_p a potentially null equality tester for comparing elements * (null means default) */ protected AbstractEndorelation(IEqualityTester tester_p) { super(tester_p); } /** * @see org.eclipse.emf.diffmerge.util.structures.IEndorelation#getTransitiveClosure(Object) */ public List<T> getTransitiveClosure(T element_p) { return getTransitiveClosure(Collections.singleton(element_p)); } /** * @see org.eclipse.emf.diffmerge.util.structures.IEndorelation#getTransitiveClosure(Collection) */ public List<T> getTransitiveClosure(Collection<? extends T> elements_p) { // Implementation is iterative, not recursive, for scalability reasons. // We use LinkedLists instead of HashSets because we need to preserve a // partial order even though it has a cost in performance on contains(Object) List<T> result = new FLinkedList<T>(getEqualityTester()); List<T> toExplore = new FLinkedList<T>(getEqualityTester()); toExplore.addAll(elements_p); while (!toExplore.isEmpty()) { T current = toExplore.get(0); toExplore.remove(current); if (!result.contains(current)) { int index = minIndexOfMappingElements(current, result); result.add(index, current); toExplore.addAll(get(current)); } } result.removeAll(elements_p); return Collections.unmodifiableList(result); } /** * Return the index of the first element in the given list which is mapped to the given element, * or the index of the last+1 element if none * @param element_p a non-null element * @param elements_p a non-null list of elements * @return the min of indexes or elements_p.size() if there exists no mapped element * belonging to elements_p */ private int minIndexOfMappingElements(T element_p, List<T> elements_p) { final int size = elements_p.size(); int result = size; int currentIndex = 0; Iterator<T> it = elements_p.iterator(); while (result == size && it.hasNext()) { T current = it.next(); Collection<T> mapped = get(current); if (mapped.contains(element_p)) result = currentIndex; currentIndex++; } return result; } }