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 }