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.KotlinSignature;
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, R> R dfsFromNode(@NotNull N node, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
041            doDfs(node, neighbors, visited, handler);
042            return handler.result();
043        }
044    
045        public static <N> void dfsFromNode(
046                @NotNull N node,
047                @NotNull Neighbors<N> neighbors,
048                @NotNull Visited<N> visited
049        ) {
050            dfsFromNode(node, neighbors, visited, new AbstractNodeHandler<N, Void>() {
051                @Override
052                public Void result() {
053                    return null;
054                }
055            });
056        }
057    
058        public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited) {
059            TopologicalOrder<N> handler = new TopologicalOrder<N>();
060            for (N node : nodes) {
061                doDfs(node, neighbors, visited, handler);
062            }
063            return handler.result();
064        }
065    
066        public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors) {
067            return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
068        }
069    
070        private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
071            if (!visited.checkAndMarkVisited(current)) return;
072            if (!handler.beforeChildren(current)) return;
073    
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            @KotlinSignature("fun beforeChildren(current: N): Boolean")
082            boolean beforeChildren(N current);
083    
084            @KotlinSignature("fun afterChildren(current: N): Unit")
085            void afterChildren(N current);
086    
087            R result();
088        }
089    
090        public interface Neighbors<N> {
091            @KotlinSignature("fun getNeighbors(current: N): Iterable<N>")
092            @NotNull
093            Iterable<? extends N> getNeighbors(N current);
094        }
095    
096        public interface Visited<N> {
097            boolean checkAndMarkVisited(N current);
098        }
099    
100        public static abstract class AbstractNodeHandler<N, R> implements NodeHandler<N, R> {
101            @Override
102            public boolean beforeChildren(N current) {
103                return true;
104            }
105    
106            @Override
107            public void afterChildren(N current) {
108            }
109        }
110    
111        public static class VisitedWithSet<N> implements Visited<N> {
112            private final Set<N> visited;
113    
114            public VisitedWithSet() {
115                this(new HashSet<N>());
116            }
117    
118            public VisitedWithSet(@NotNull Set<N> visited) {
119                this.visited = visited;
120            }
121    
122            @Override
123            public boolean checkAndMarkVisited(N current) {
124                return visited.add(current);
125            }
126        }
127    
128        public static abstract class CollectingNodeHandler<N, R, C extends Iterable<R>> extends AbstractNodeHandler<N, C> {
129            @NotNull
130            protected final C result;
131    
132            protected CollectingNodeHandler(@NotNull C result) {
133                this.result = result;
134            }
135    
136            @Override
137            @NotNull
138            public C result() {
139                return result;
140            }
141        }
142    
143        public static abstract class NodeHandlerWithListResult<N, R> extends CollectingNodeHandler<N, R, LinkedList<R>> {
144            protected NodeHandlerWithListResult() {
145                super(new LinkedList<R>());
146            }
147        }
148    
149        public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
150            @Override
151            public void afterChildren(N current) {
152                result.addFirst(current);
153            }
154        }
155    }