DFS utility class factored out of CommonSupertypes

This commit is contained in:
Andrey Breslav
2012-09-11 19:08:52 +04:00
parent 6a0e4d1593
commit ab18b12165
3 changed files with 204 additions and 67 deletions
+1
View File
@@ -10,6 +10,7 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
<orderEntry type="library" name="javax.inject" level="project" />
<orderEntry type="module" module-name="util" />
</component>
</module>
@@ -16,6 +16,8 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
@@ -24,11 +26,11 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.utils.DFS;
import java.util.*;
import static org.jetbrains.jet.lang.types.Variance.IN_VARIANCE;
import static org.jetbrains.jet.lang.types.Variance.OUT_VARIANCE;
import static org.jetbrains.jet.lang.types.Variance.*;
/**
* @author abreslav
@@ -91,33 +93,8 @@ public class CommonSupertypes {
List<TypeConstructor> order = null;
for (JetType type : types) {
Set<TypeConstructor> visited = new HashSet<TypeConstructor>();
order = dfs(type, visited, new DfsNodeHandler<List<TypeConstructor>>() {
public LinkedList<TypeConstructor> list = new LinkedList<TypeConstructor>();
@Override
public void beforeChildren(JetType current) {
TypeConstructor constructor = current.getConstructor();
Set<JetType> instances = constructorToAllInstances.get(constructor);
if (instances == null) {
instances = new HashSet<JetType>();
constructorToAllInstances.put(constructor, instances);
}
instances.add(current);
}
@Override
public void afterChildren(JetType current) {
list.addFirst(current.getConstructor());
}
@Override
public List<TypeConstructor> result() {
return list;
}
});
Set<TypeConstructor> visited = Sets.newHashSet();
order = topologicallySortSuperclassesAndRecordAllInstances(type, constructorToAllInstances, visited);
if (commonSuperclasses == null) {
commonSuperclasses = visited;
@@ -144,6 +121,55 @@ public class CommonSupertypes {
return result;
}
private static List<TypeConstructor> topologicallySortSuperclassesAndRecordAllInstances(
@NotNull JetType type,
@NotNull final Map<TypeConstructor, Set<JetType>> constructorToAllInstances,
@NotNull final Set<TypeConstructor> visited
) {
return DFS.dfs(
Collections.singletonList(type),
new DFS.Neighbors<JetType>() {
@NotNull
@Override
public Iterable<JetType> getNeighbors(JetType current) {
TypeSubstitutor substitutor = TypeSubstitutor.create(current);
List<JetType> result = Lists.newArrayList();
for (JetType supertype : current.getConstructor().getSupertypes()) {
if (visited.contains(supertype.getConstructor())) {
continue;
}
result.add(substitutor.safeSubstitute(supertype, INVARIANT));
}
return result;
}
},
new DFS.Visited<JetType>() {
@Override
public boolean checkAndMarkVisited(JetType current) {
return visited.add(current.getConstructor());
}
},
new DFS.NodeHandlerWithListResult<JetType, TypeConstructor>() {
@Override
public void beforeChildren(JetType current) {
TypeConstructor constructor = current.getConstructor();
Set<JetType> instances = constructorToAllInstances.get(constructor);
if (instances == null) {
instances = new HashSet<JetType>();
constructorToAllInstances.put(constructor, instances);
}
instances.add(current);
}
@Override
public void afterChildren(JetType current) {
result.addFirst(current.getConstructor());
}
}
);
}
// constructor - type constructor of a supertype to be instantiated
// types - instantiations of constructor occurring as supertypes of classes we are trying to intersect
@NotNull
@@ -251,42 +277,4 @@ public class CommonSupertypes {
markAll(type.getConstructor(), markerSet);
}
}
private static <R> R dfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<R> handler) {
doDfs(current, visited, handler);
return handler.result();
}
private static void doDfs(@NotNull JetType current, @NotNull Set<TypeConstructor> visited, @NotNull DfsNodeHandler<?> handler) {
if (!visited.add(current.getConstructor())) {
return;
}
handler.beforeChildren(current);
// Map<TypeConstructor, TypeProjection> substitutionContext = TypeUtils.buildSubstitutionContext(current);
TypeSubstitutor substitutor = TypeSubstitutor.create(current);
for (JetType supertype : current.getConstructor().getSupertypes()) {
TypeConstructor supertypeConstructor = supertype.getConstructor();
if (visited.contains(supertypeConstructor)) {
continue;
}
JetType substitutedSupertype = substitutor.safeSubstitute(supertype, Variance.INVARIANT);
dfs(substitutedSupertype, visited, handler);
}
handler.afterChildren(current);
}
private static class DfsNodeHandler<R> {
public void beforeChildren(JetType current) {
}
public void afterChildren(JetType current) {
}
public R result() {
return null;
}
}
}
@@ -0,0 +1,148 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.utils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
*/
public class DFS {
public static <N, R> R dfs(@NotNull Collection<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
for (N node : nodes) {
doDfs(node, neighbors, visited, handler);
}
return handler.result();
}
public static <N, R> R dfs(
@NotNull Collection<N> nodes,
@NotNull Neighbors<N> neighbors,
@NotNull NodeHandler<N, R> handler
) {
return dfs(nodes, neighbors, new VisitedWithSet<N>(), handler);
}
public static <N, R> R dfsFromNode(@NotNull N node, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, R> handler) {
doDfs(node, neighbors, visited, handler);
return handler.result();
}
public static <N> void dfsFromNode(
@NotNull N node,
@NotNull Neighbors<N> neighbors,
@NotNull Visited<N> visited
) {
dfsFromNode(node, neighbors, visited, new AbstractNodeHandler<N, Void>() {
@Override
public Void result() {
return null;
}
});
}
public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited) {
TopologicalOrder<N> handler = new TopologicalOrder<N>();
for (N node : nodes) {
doDfs(node, neighbors, visited, handler);
}
return handler.result();
}
public static <N> List<N> topologicalOrder(@NotNull Iterable<N> nodes, @NotNull Neighbors<N> neighbors) {
return topologicalOrder(nodes, neighbors, new VisitedWithSet<N>());
}
private static <N> void doDfs(@NotNull N current, @NotNull Neighbors<N> neighbors, @NotNull Visited<N> visited, @NotNull NodeHandler<N, ?> handler) {
if (!visited.checkAndMarkVisited(current)) {
return;
}
handler.beforeChildren(current);
for (N neighbor : neighbors.getNeighbors(current)) {
doDfs(neighbor, neighbors, visited, handler);
}
handler.afterChildren(current);
}
public interface NodeHandler<N, R> {
void beforeChildren(N current);
void afterChildren(N current);
R result();
}
public interface Neighbors<N> {
@NotNull
Iterable<N> getNeighbors(N current);
}
public interface Visited<N> {
boolean checkAndMarkVisited(N current);
}
public static abstract class AbstractNodeHandler<N, R> implements NodeHandler<N, R> {
@Override
public void beforeChildren(N current) {
}
@Override
public void afterChildren(N current) {
}
}
public static class VisitedWithSet<N> implements Visited<N> {
private final Set<N> visited;
public VisitedWithSet() {
this(Sets.<N>newHashSet());
}
public VisitedWithSet(@NotNull Set<N> visited) {
this.visited = visited;
}
@Override
public boolean checkAndMarkVisited(N current) {
return visited.add(current);
}
}
public static abstract class NodeHandlerWithListResult<N, R> extends AbstractNodeHandler<N, List<R>> {
protected final LinkedList<R> result = Lists.newLinkedList();
@Override
public List<R> result() {
return result;
}
}
public static class TopologicalOrder<N> extends NodeHandlerWithListResult<N, N> {
@Override
public void afterChildren(N current) {
result.addFirst(current);
}
}
}