001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.utils;
018
019 import kotlin.jvm.functions.Function1;
020 import org.jetbrains.annotations.NotNull;
021
022 import java.util.*;
023
024 public class DFS {
025 public static <N, R> R dfs(@NotNull Collection<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
026 for (N node : nodes) {
027 doDfs(node, neighbors, visited, handler);
028 }
029 return handler.result();
030 }
031
032 public static <N, R> R dfs(
033 @NotNull Collection<N> nodes,
034 @NotNull Neighbors<N> neighbors,
035 @NotNull NodeHandler<N, R> handler
036 ) {
037 return dfs(nodes, neighbors, new VisitedWithSet<N>(), handler);
038 }
039
040 public static <N> Boolean ifAny(
041 @NotNull Collection<N> nodes,
042 @NotNull Neighbors<N> neighbors,
043 @NotNull final Function1<N, Boolean> predicate
044 ) {
045 final boolean[] result = new boolean[1];
046
047 return dfs(nodes, neighbors, new AbstractNodeHandler<N, Boolean>() {
048 @Override
049 public boolean beforeChildren(N current) {
050 if (predicate.invoke(current)) {
051 result[0] = true;
052 }
053
054 return !result[0];
055 }
056
057 @Override
058 public Boolean result() {
059 return result[0];
060 }
061 });
062 }
063
064 public static <N, R> R dfsFromNode(@NotNull N node, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
065 doDfs(node, neighbors, visited, handler);
066 return handler.result();
067 }
068
069 public static <N> void dfsFromNode(
070 @NotNull N node,
071 @NotNull Neighbors<N> neighbors,
072 @NotNull Visited<N> visited
073 ) {
074 dfsFromNode(node, neighbors, visited, new AbstractNodeHandler<N, Void>() {
075 @Override
076 public Void result() {
077 return null;
078 }
079 });
080 }
081
082 public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited) {
083 TopologicalOrder<N> handler = new TopologicalOrder<N>();
084 for (N node : nodes) {
085 doDfs(node, neighbors, visited, handler);
086 }
087 return handler.result();
088 }
089
090 public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors) {
091 return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
092 }
093
094 private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
095 if (!visited.checkAndMarkVisited(current)) return;
096 if (!handler.beforeChildren(current)) return;
097
098 for (N neighbor : neighbors.getNeighbors(current)) {
099 doDfs(neighbor, neighbors, visited, handler);
100 }
101 handler.afterChildren(current);
102 }
103
104 public interface NodeHandler<N, R> {
105 boolean beforeChildren(N current);
106
107 void afterChildren(N current);
108
109 R result();
110 }
111
112 public interface Neighbors<N> {
113 @NotNull
114 Iterable<? extends N> getNeighbors(N current);
115 }
116
117 public interface Visited<N> {
118 boolean checkAndMarkVisited(N current);
119 }
120
121 public static abstract class AbstractNodeHandler<N, R> implements NodeHandler<N, R> {
122 @Override
123 public boolean beforeChildren(N current) {
124 return true;
125 }
126
127 @Override
128 public void afterChildren(N current) {
129 }
130 }
131
132 public static class VisitedWithSet<N> implements Visited<N> {
133 private final Set<N> visited;
134
135 public VisitedWithSet() {
136 this(new HashSet<N>());
137 }
138
139 public VisitedWithSet(@NotNull Set<N> visited) {
140 this.visited = visited;
141 }
142
143 @Override
144 public boolean checkAndMarkVisited(N current) {
145 return visited.add(current);
146 }
147 }
148
149 public static abstract class CollectingNodeHandler<N, R, C extends Iterable<R>> extends AbstractNodeHandler<N, C> {
150 @NotNull
151 protected final C result;
152
153 protected CollectingNodeHandler(@NotNull C result) {
154 this.result = result;
155 }
156
157 @Override
158 @NotNull
159 public C result() {
160 return result;
161 }
162 }
163
164 public static abstract class NodeHandlerWithListResult<N, R> extends CollectingNodeHandler<N, R, LinkedList<R>> {
165 protected NodeHandlerWithListResult() {
166 super(new LinkedList<R>());
167 }
168 }
169
170 public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
171 @Override
172 public void afterChildren(N current) {
173 result.addFirst(current);
174 }
175 }
176 }