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 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)) return;
071 if (!handler.beforeChildren(current)) return;
072
073 for (N neighbor : neighbors.getNeighbors(current)) {
074 doDfs(neighbor, neighbors, visited, handler);
075 }
076 handler.afterChildren(current);
077 }
078
079 public interface NodeHandler<N, R> {
080 boolean beforeChildren(N current);
081
082 void afterChildren(N current);
083
084 R result();
085 }
086
087 public interface Neighbors<N> {
088 @NotNull
089 Iterable<? extends N> getNeighbors(N current);
090 }
091
092 public interface Visited<N> {
093 boolean checkAndMarkVisited(N current);
094 }
095
096 public static abstract class AbstractNodeHandler<N, R> implements NodeHandler<N, R> {
097 @Override
098 public boolean beforeChildren(N current) {
099 return true;
100 }
101
102 @Override
103 public void afterChildren(N current) {
104 }
105 }
106
107 public static class VisitedWithSet<N> implements Visited<N> {
108 private final Set<N> visited;
109
110 public VisitedWithSet() {
111 this(new HashSet<N>());
112 }
113
114 public VisitedWithSet(@NotNull Set<N> visited) {
115 this.visited = visited;
116 }
117
118 @Override
119 public boolean checkAndMarkVisited(N current) {
120 return visited.add(current);
121 }
122 }
123
124 public static abstract class CollectingNodeHandler<N, R, C extends Iterable<R>> extends AbstractNodeHandler<N, C> {
125 @NotNull
126 protected final C result;
127
128 protected CollectingNodeHandler(@NotNull C result) {
129 this.result = result;
130 }
131
132 @Override
133 @NotNull
134 public C result() {
135 return result;
136 }
137 }
138
139 public static abstract class NodeHandlerWithListResult<N, R> extends CollectingNodeHandler<N, R, LinkedList<R>> {
140 protected NodeHandlerWithListResult() {
141 super(new LinkedList<R>());
142 }
143 }
144
145 public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
146 @Override
147 public void afterChildren(N current) {
148 result.addFirst(current);
149 }
150 }
151 }