/* * Copyright 2010-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jetbrains.kotlin.utils; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import java.util.*; public class DFS { public static <N, R> R dfs(@NotNull Collection<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) { for (N node : nodes) { doDfs(node, neighbors, visited, handler); } return handler.result(); } public static <N, R> R dfs( @NotNull Collection<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull NodeHandler<N, R> handler ) { return dfs(nodes, neighbors, new VisitedWithSet<N>(), handler); } public static <N> Boolean ifAny( @NotNull Collection<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull final Function1<N, Boolean> predicate ) { final boolean[] result = new boolean[1]; return dfs(nodes, neighbors, new AbstractNodeHandler<N, Boolean>() { @Override public boolean beforeChildren(N current) { if (predicate.invoke(current)) { result[0] = true; } return !result[0]; } @Override public Boolean result() { return result[0]; } }); } public static <N, R> R dfsFromNode(@NotNull N node, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) { doDfs(node, neighbors, visited, handler); return handler.result(); } public static <N> void dfsFromNode( @NotNull N node, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited ) { dfsFromNode(node, neighbors, visited, new AbstractNodeHandler<N, Void>() { @Override public Void result() { return null; } }); } public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited) { TopologicalOrder<N> handler = new TopologicalOrder<N>(); for (N node : nodes) { doDfs(node, neighbors, visited, handler); } return handler.result(); } public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors) { return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>()); } private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) { if (!visited.checkAndMarkVisited(current)) return; if (!handler.beforeChildren(current)) return; for (N neighbor : neighbors.getNeighbors(current)) { doDfs(neighbor, neighbors, visited, handler); } handler.afterChildren(current); } public interface NodeHandler<N, R> { boolean beforeChildren(N current); void afterChildren(N current); R result(); } public interface Neighbors<N> { @NotNull Iterable<? extends N> getNeighbors(N current); } public interface Visited<N> { boolean checkAndMarkVisited(N current); } public static abstract class AbstractNodeHandler<N, R> implements NodeHandler<N, R> { @Override public boolean beforeChildren(N current) { return true; } @Override public void afterChildren(N current) { } } public static class VisitedWithSet<N> implements Visited<N> { private final Set<N> visited; public VisitedWithSet() { this(new HashSet<N>()); } public VisitedWithSet(@NotNull Set<N> visited) { this.visited = visited; } @Override public boolean checkAndMarkVisited(N current) { return visited.add(current); } } public static abstract class CollectingNodeHandler<N, R, C extends Iterable<R>> extends AbstractNodeHandler<N, C> { @NotNull protected final C result; protected CollectingNodeHandler(@NotNull C result) { this.result = result; } @Override @NotNull public C result() { return result; } } public static abstract class NodeHandlerWithListResult<N, R> extends CollectingNodeHandler<N, R, LinkedList<R>> { protected NodeHandlerWithListResult() { super(new LinkedList<R>()); } } public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> { @Override public void afterChildren(N current) { result.addFirst(current); } } }