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    }