/**
* Copyright (C) 2013-2014 Olaf Lessenich
* Copyright (C) 2014-2015 University of Passau, Germany
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Contributors:
* Olaf Lessenich <lessenic@fim.uni-passau.de>
* Georg Seibt <seibt@fim.uni-passau.de>
*/
package de.fosd.jdime.artifact;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* This class consists of {@code static} utility methods for operating on {@code Artifact} instances.
*/
public final class Artifacts {
/**
* An {@code Iterator} over the elements of an {@code Artifact} tree in breadth-first order.
*
* @param <T>
* the {@code Artifact} type
*/
private static final class BFSIterator<T extends Artifact<T>> implements Iterator<T> {
private Deque<T> wait;
/**
* Constructs a new {@link BFSIterator} over the given tree.
*
* @param treeRoot
* the root of the tree to traverse
*/
private BFSIterator(T treeRoot) {
wait = new ArrayDeque<>();
wait.addFirst(treeRoot);
}
@Override
public boolean hasNext() {
return !wait.isEmpty();
}
@Override
public T next() {
T next = wait.removeFirst();
next.getChildren().forEach(wait::addLast);
return next;
}
}
/**
* An {@code Iterator} over the elements of an {@code Artifact} tree in depth-first order.
*
* @param <T>
* the {@code Artifact} type
*/
private static final class DFSIterator<T extends Artifact<T>> implements Iterator<T> {
private Deque<T> wait;
/**
* Constructs a new {@code DFSIterator} over the given tree.
*
* @param treeRoot
* the root of the tree to traverse
*/
private DFSIterator(T treeRoot) {
wait = new ArrayDeque<>();
wait.addFirst(treeRoot);
}
@Override
public boolean hasNext() {
return !wait.isEmpty();
}
@Override
public T next() {
T next = wait.removeFirst();
if (next.getNumChildren() == 1) {
wait.addFirst(next.getChild(0));
} else if (next.getNumChildren() > 1) {
ArrayList<T> ch = new ArrayList<>(next.getChildren());
Collections.reverse(ch);
ch.forEach(wait::addFirst);
}
return next;
}
}
private Artifacts() {
// UTILITY CLASS
}
/**
* Returns the root of the tree {@code artifact} is a part of.
*
* @param artifact
* the {@link Artifact} for whose tree the root is to be returned
* @param <T>
* the {@code Artifact} type
* @return the root of the tree
*/
public static <T extends Artifact<T>> T root(T artifact) {
T root = artifact;
while (!root.isRoot()) {
root = root.getParent();
}
return root;
}
/**
* Returns the tree rooted in {@code treeRoot} in breadth-first order.
*
* @param treeRoot
* the root of the tree to return in breadth-first order
* @param <T>
* the {@code Artifact} type
* @return the nodes of the tree rooted in {@code treeRoot} in breadth-first order
*/
public static <T extends Artifact<T>> List<T> bfs(T treeRoot) {
return bfsStream(treeRoot).collect(Collectors.toList());
}
/**
* Returns a {@code Stream} consisting of the elements of the tree rooted in {@code treeRoot} in breadth-first order.
*
* @param treeRoot
* the root of the tree to return in breadth-first order
* @param <T>
* the {@code Artifact} type
* @return the nodes of the tree rooted in {@code treeRoot} in breadth-first order as a {@code Stream}
*/
public static <T extends Artifact<T>> Stream<T> bfsStream(T treeRoot) {
return StreamSupport.stream(bfsIterable(treeRoot).spliterator(), false);
}
/**
* Returns an {@code Iterable} returning the elements of the tree rooted in {@code treeRoot} in breadth-first order
* from the {@link Iterator#hasNext()} method of its {@code Iterator}.
*
* @param treeRoot
* the root of the tree to return in breadth-first order
* @param <T>
* the {@code Artifact} type
* @return an {@code Iterable} over the elements of the tree rooted in {@code treeRoot} in breadth-first order
*/
public static <T extends Artifact<T>> Iterable<T> bfsIterable(T treeRoot) {
return () -> new BFSIterator<>(treeRoot);
}
/**
* Returns the tree rooted in {@code treeRoot} in depth-first order.
*
* @param treeRoot
* the root of the tree to return in depth-first order
* @param <T>
* the {@code Artifact} type
* @return the nodes of the tree rooted in {@code treeRoot} in depth-first order
*/
public static <T extends Artifact<T>> List<T> dfs(T treeRoot) {
return dfsStream(treeRoot).collect(Collectors.toList());
}
/**
* Returns a {@code Stream} consisting of the elements of the tree rooted in {@code treeRoot} in depth-first order.
*
* @param treeRoot
* the root of the tree to return in depth-first order
* @param <T>
* the {@code Artifact} type
* @return the nodes of the tree rooted in {@code treeRoot} in depth-first order as a {@code Stream}
*/
public static <T extends Artifact<T>> Stream<T> dfsStream(T treeRoot) {
return StreamSupport.stream(dfsIterable(treeRoot).spliterator(), false);
}
/**
* Returns an {@code Iterable} returning the elements of the tree rooted in {@code treeRoot} in depth-first order
* from the {@link Iterator#hasNext()} method of its {@code Iterator}.
*
* @param treeRoot
* the root of the tree to return in depth-first order
* @param <T>
* the {@code Artifact} type
* @return an {@code Iterable} over the elements of the tree rooted in {@code treeRoot} in depth-first order
*/
public static <T extends Artifact<T>> Iterable<T> dfsIterable(T treeRoot) {
return () -> new DFSIterator<>(treeRoot);
}
}