001 /*
002 * Copyright 2010-2013 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.jet.utils;
018
019 import org.jetbrains.annotations.NotNull;
020
021 import java.util.*;
022
023 public class DFS {
024 public static <N, R> R dfs(@NotNull Collection<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
025 for (N node : nodes) {
026 doDfs(node, neighbors, visited, handler);
027 }
028 return handler.result();
029 }
030
031 public static <N, R> R dfs(
032 @NotNull Collection<N> nodes,
033 @NotNull Neighbors<N> neighbors,
034 @NotNull NodeHandler<N, R> handler
035 ) {
036 return dfs(nodes, neighbors, new VisitedWithSet<N>(), handler);
037 }
038
039 public static <N, R> R dfsFromNode(@NotNull N node, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
040 doDfs(node, neighbors, visited, handler);
041 return handler.result();
042 }
043
044 public static <N> void dfsFromNode(
045 @NotNull N node,
046 @NotNull Neighbors<N> neighbors,
047 @NotNull Visited<N> visited
048 ) {
049 dfsFromNode(node, neighbors, visited, new AbstractNodeHandler<N, Void>() {
050 @Override
051 public Void result() {
052 return null;
053 }
054 });
055 }
056
057 public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited) {
058 TopologicalOrder<N> handler = new TopologicalOrder<N>();
059 for (N node : nodes) {
060 doDfs(node, neighbors, visited, handler);
061 }
062 return handler.result();
063 }
064
065 public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors) {
066 return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
067 }
068
069 private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
070 if (!visited.checkAndMarkVisited(current)) {
071 return;
072 }
073 handler.beforeChildren(current);
074 for (N neighbor : neighbors.getNeighbors(current)) {
075 doDfs(neighbor, neighbors, visited, handler);
076 }
077 handler.afterChildren(current);
078 }
079
080 public interface NodeHandler<N, R> {
081
082 void beforeChildren(N current);
083
084 void afterChildren(N current);
085
086 R result();
087 }
088
089 public interface Neighbors<N> {
090 @NotNull
091 Iterable<N> getNeighbors(N current);
092 }
093
094 public interface Visited<N> {
095 boolean checkAndMarkVisited(N current);
096 }
097
098 public static abstract class AbstractNodeHandler<N, R> implements NodeHandler<N, R> {
099 @Override
100 public void beforeChildren(N current) {
101 }
102
103 @Override
104 public void afterChildren(N current) {
105 }
106 }
107
108 public static class VisitedWithSet<N> implements Visited<N> {
109 private final Set<N> visited;
110
111 public VisitedWithSet() {
112 this(new HashSet<N>());
113 }
114
115 public VisitedWithSet(@NotNull Set<N> visited) {
116 this.visited = visited;
117 }
118
119 @Override
120 public boolean checkAndMarkVisited(N current) {
121 return visited.add(current);
122 }
123 }
124
125 public static abstract class NodeHandlerWithListResult<N, R> extends AbstractNodeHandler<N, List<R>> {
126 protected final LinkedList<R> result = new LinkedList<R>();
127
128 @Override
129 public List<R> result() {
130 return result;
131 }
132 }
133
134 public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
135 @Override
136 public void afterChildren(N current) {
137 result.addFirst(current);
138 }
139 }
140 }