diff --git a/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java b/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java index 84d62846383a..bf4cce63dc53 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java +++ b/java/compiler/openapi/src/com/intellij/compiler/ModuleCompilerUtil.java @@ -27,12 +27,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Pair; import com.intellij.util.Chunk; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.graph.CachingSemiGraph; -import com.intellij.util.graph.DFSTBuilder; -import com.intellij.util.graph.Graph; -import com.intellij.util.graph.GraphGenerator; -import gnu.trove.TIntArrayList; -import gnu.trove.TIntProcedure; +import com.intellij.util.graph.*; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -92,47 +87,7 @@ public final class ModuleCompilerUtil { } public static Graph> toChunkGraph(final Graph graph) { - final DFSTBuilder builder = new DFSTBuilder(graph); - final TIntArrayList sccs = builder.getSCCs(); - - final List> chunks = new ArrayList>(sccs.size()); - final Map> nodeToChunkMap = new LinkedHashMap>(); - sccs.forEach(new TIntProcedure() { - int myTNumber = 0; - public boolean execute(int size) { - final Set chunkNodes = new LinkedHashSet(); - final Chunk chunk = new Chunk(chunkNodes); - chunks.add(chunk); - for (int j = 0; j < size; j++) { - final Node node = builder.getNodeByTNumber(myTNumber + j); - chunkNodes.add(node); - nodeToChunkMap.put(node, chunk); - } - - myTNumber += size; - return true; - } - }); - - return GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph>() { - public Collection> getNodes() { - return chunks; - } - - public Iterator> getIn(Chunk chunk) { - final Set chunkNodes = chunk.getNodes(); - final Set> ins = new LinkedHashSet>(); - for (final Node node : chunkNodes) { - for (Iterator nodeIns = graph.getIn(node); nodeIns.hasNext();) { - final Node in = nodeIns.next(); - if (!chunk.containsNode(in)) { - ins.add(nodeToChunkMap.get(in)); - } - } - } - return ins.iterator(); - } - })); + return GraphAlgorithms.getInstance().computeSCCGraph(graph); } public static void sortModules(final Project project, final List modules) { diff --git a/platform/platform-impl/src/com/intellij/util/graph/GraphAlgorithms.java b/platform/platform-api/src/com/intellij/util/graph/GraphAlgorithms.java similarity index 87% rename from platform/platform-impl/src/com/intellij/util/graph/GraphAlgorithms.java rename to platform/platform-api/src/com/intellij/util/graph/GraphAlgorithms.java index 90cd66bf0049..0b224cdc1ad7 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/GraphAlgorithms.java +++ b/platform/platform-api/src/com/intellij/util/graph/GraphAlgorithms.java @@ -17,6 +17,8 @@ package com.intellij.util.graph; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.util.Chunk; +import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,4 +48,8 @@ public abstract class GraphAlgorithms { @NotNull public abstract Graph invertEdgeDirections(@NotNull Graph graph); + + public abstract Graph> computeSCCGraph(final Graph graph); + + public abstract Graph createGraphByInArcs(MultiMap inArcs); } diff --git a/platform/platform-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java b/platform/platform-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java index a8a45f15bf4a..d324549a4196 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java +++ b/platform/platform-impl/src/com/intellij/util/graph/impl/GraphAlgorithmsImpl.java @@ -16,8 +16,11 @@ package com.intellij.util.graph.impl; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.util.graph.Graph; -import com.intellij.util.graph.GraphAlgorithms; +import com.intellij.util.Chunk; +import com.intellij.util.containers.MultiMap; +import com.intellij.util.graph.*; +import gnu.trove.TIntArrayList; +import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -63,6 +66,69 @@ public class GraphAlgorithmsImpl extends GraphAlgorithms { }; } + @Override + public Graph> computeSCCGraph(final Graph graph) { + final DFSTBuilder builder = new DFSTBuilder(graph); + final TIntArrayList sccs = builder.getSCCs(); + + final List> chunks = new ArrayList>(sccs.size()); + final Map> nodeToChunkMap = new LinkedHashMap>(); + sccs.forEach(new TIntProcedure() { + int myTNumber = 0; + public boolean execute(int size) { + final Set chunkNodes = new LinkedHashSet(); + final Chunk chunk = new Chunk(chunkNodes); + chunks.add(chunk); + for (int j = 0; j < size; j++) { + final Node node = builder.getNodeByTNumber(myTNumber + j); + chunkNodes.add(node); + nodeToChunkMap.put(node, chunk); + } + + myTNumber += size; + return true; + } + }); + + return GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph>() { + public Collection> getNodes() { + return chunks; + } + + public Iterator> getIn(Chunk chunk) { + final Set chunkNodes = chunk.getNodes(); + final Set> ins = new LinkedHashSet>(); + for (final Node node : chunkNodes) { + for (Iterator nodeIns = graph.getIn(node); nodeIns.hasNext(); ) { + final Node in = nodeIns.next(); + if (!chunk.containsNode(in)) { + ins.add(nodeToChunkMap.get(in)); + } + } + } + return ins.iterator(); + } + })); + } + + @Override + public Graph createGraphByInArcs(final MultiMap inArcs) { + final Set nodes = new LinkedHashSet(); + nodes.addAll(inArcs.keySet()); + nodes.addAll(inArcs.values()); + return new GraphGenerator(new CachingSemiGraph(new GraphGenerator.SemiGraph() { + @Override + public Collection getNodes() { + return nodes; + } + + @Override + public Iterator getIn(Node n) { + return inArcs.get(n).iterator(); + } + })); + } + @NotNull @Override public List> removePathsWithCycles(@NotNull List> paths) { diff --git a/platform/platform-impl/testSrc/com/intellij/util/graph/ChunkGraphTest.java b/platform/platform-impl/testSrc/com/intellij/util/graph/ChunkGraphTest.java new file mode 100644 index 000000000000..ff28347037a3 --- /dev/null +++ b/platform/platform-impl/testSrc/com/intellij/util/graph/ChunkGraphTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package com.intellij.util.graph; + +import com.intellij.util.Chunk; + +import java.util.*; + +/** + * @author Eugene Zhuravlev + * Date: Sep 27, 2004 + */ +@SuppressWarnings({"HardCodedStringLiteral"}) +public class ChunkGraphTest extends GraphTestCase { + + public void testGraph1() { + final Map arcs = new HashMap(); + arcs.put("a", "b"); + arcs.put("b", "c"); + arcs.put("c", "bd"); + arcs.put("d", "e"); + arcs.put("e", "d"); + + final Graph> graph = getAlgorithmsInstance().computeSCCGraph(initGraph(arcs)); + + final List> expectedNodes = new ArrayList>(); + Chunk A = new Chunk("a"); + expectedNodes.add(A); + Chunk BC = new Chunk(toSet("b", "c")); + expectedNodes.add(BC); + Chunk DE = new Chunk(toSet("d", "e")); + expectedNodes.add(DE); + + checkVertices(expectedNodes, graph.getNodes().iterator()); + + final Map, Set>> expectedArcs = new HashMap, Set>>(); + expectedArcs.put(A, toSet()); + expectedArcs.put(BC, toSet(A)); + expectedArcs.put(DE, toSet(BC)); + + checkArcs(expectedArcs, graph); + } + + public void testGraph2() { + final Map arcs = new HashMap(); + arcs.put("a", "b"); + arcs.put("b", "ac"); + arcs.put("c", "ad"); + arcs.put("d", ""); + + final Graph> graph = getAlgorithmsInstance().computeSCCGraph(initGraph(arcs)); + + final List> expectedNodes = new ArrayList>(); + Chunk ABC = new Chunk(toSet("a", "b", "c")); + expectedNodes.add(ABC); + Chunk D = new Chunk("d"); + expectedNodes.add(D); + + checkVertices(expectedNodes, graph.getNodes().iterator()); + + final Map, Set>> expectedArcs = new HashMap, Set>>(); + expectedArcs.put(ABC, toSet()); + expectedArcs.put(D, toSet(ABC)); + + checkArcs(expectedArcs, graph); + } + + private static void checkArcs(Map, Set>> expectedArcs, Graph> graph) { + for (Chunk chunk : graph.getNodes()) { + final List> ins = new ArrayList>(); + final Iterator> insIterator = graph.getIn(chunk); + while (insIterator.hasNext()) { + ins.add(insIterator.next()); + } + final Set> expectedIns = expectedArcs.get(chunk); + assertTrue(expectedIns.size() == ins.size()); + assertTrue(expectedIns.equals(new HashSet>(ins))); + } + } + + private static Set toSet(T... strings) { + return new HashSet(Arrays.asList(strings)); + } + + private static Set> toSet() { + return new HashSet>(); + } + + private static Set> toSet(Chunk c) { + return Collections.singleton(c); + } + + + private static void checkVertices(List> expected, Iterator> nodes) { + List> realNodes = new ArrayList>(); + while (nodes.hasNext()) { + realNodes.add(nodes.next()); + } + assertTrue(expected.size() == realNodes.size()); + assertTrue(new HashSet>(expected).equals(new HashSet>(realNodes))); + } +} diff --git a/platform/platform-impl/testSrc/com/intellij/util/graph/GraphTestCase.java b/platform/platform-impl/testSrc/com/intellij/util/graph/GraphTestCase.java index ab14963613fb..a4df60b5b24c 100644 --- a/platform/platform-impl/testSrc/com/intellij/util/graph/GraphTestCase.java +++ b/platform/platform-impl/testSrc/com/intellij/util/graph/GraphTestCase.java @@ -15,6 +15,7 @@ */ package com.intellij.util.graph; +import com.intellij.util.graph.impl.GraphAlgorithmsImpl; import junit.framework.TestCase; import java.util.*; @@ -23,6 +24,10 @@ import java.util.*; * @author nik */ public abstract class GraphTestCase extends TestCase { + protected static GraphAlgorithmsImpl getAlgorithmsInstance() { + return new GraphAlgorithmsImpl(); + } + protected static Graph initGraph(final Map graph) { final Map> out = new HashMap>(); final Map> in = new HashMap>(); diff --git a/platform/platform-impl/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java b/platform/platform-impl/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java index 4750a7c0fa49..daf7f42780af 100644 --- a/platform/platform-impl/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java +++ b/platform/platform-impl/testSrc/com/intellij/util/graph/KShortestPathsFinderTest.java @@ -150,8 +150,7 @@ public class KShortestPathsFinderTest extends GraphTestCase { private static void doTest(Map graph, final String start, final String finish, final int k, String... expectedPaths) { final Graph generator = initGraph(graph); - final KShortestPathsFinder finder = new KShortestPathsFinder(generator, start, finish, new EmptyProgressIndicator()); - final List> paths = finder.findShortestPaths(k); + final List> paths = getAlgorithmsInstance().findKShortestPaths(generator, start, finish, k, new EmptyProgressIndicator()); List pathStrings = new ArrayList(); Set sizes = new HashSet(); for (List path : paths) { diff --git a/platform/platform-impl/testSrc/com/intellij/util/graph/SearchCyclesTest.java b/platform/platform-impl/testSrc/com/intellij/util/graph/SearchCyclesTest.java index 2fce8b661cbe..4a68f16f3e78 100644 --- a/platform/platform-impl/testSrc/com/intellij/util/graph/SearchCyclesTest.java +++ b/platform/platform-impl/testSrc/com/intellij/util/graph/SearchCyclesTest.java @@ -16,11 +16,13 @@ package com.intellij.util.graph; -import com.intellij.util.graph.impl.CycleFinder; import com.intellij.openapi.util.text.StringUtil; import com.intellij.testFramework.UsefulTestCase; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * User: anna @@ -81,8 +83,7 @@ public class SearchCyclesTest extends GraphTestCase { } private static void doTest(HashMap graph, final String node, String... expected) { - Graph stringGraph = initGraph(graph); - final Set> nodeCycles = new CycleFinder(stringGraph).getNodeCycles(node); + final Set> nodeCycles = getAlgorithmsInstance().findCycles(initGraph(graph), node); checkResult(expected, nodeCycles); } diff --git a/platform/platform-impl/testSrc/com/intellij/util/graph/ShortestPathTest.java b/platform/platform-impl/testSrc/com/intellij/util/graph/ShortestPathTest.java index d5db1b8bc39b..45573649708a 100644 --- a/platform/platform-impl/testSrc/com/intellij/util/graph/ShortestPathTest.java +++ b/platform/platform-impl/testSrc/com/intellij/util/graph/ShortestPathTest.java @@ -17,7 +17,6 @@ package com.intellij.util.graph; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.graph.impl.ShortestPathFinder; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -90,7 +89,6 @@ public class ShortestPathTest extends GraphTestCase { @Nullable private static List getShortestPath(Map graph, final String from, final String to) { - Graph graphGenerator = initGraph(graph); - return new ShortestPathFinder(graphGenerator).findPath(from, to); + return getAlgorithmsInstance().findShortestPath(initGraph(graph), from, to); } }