diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/impl/BuildTargetIndexImpl.java b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/BuildTargetIndexImpl.java index 7c54fe178e92..67d198e11e05 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/impl/BuildTargetIndexImpl.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/impl/BuildTargetIndexImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -20,8 +20,6 @@ import com.intellij.util.graph.CachingSemiGraph; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.GraphGenerator; import gnu.trove.THashMap; -import gnu.trove.TIntArrayList; -import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.builders.*; import org.jetbrains.jps.incremental.CompileContext; @@ -83,8 +81,7 @@ public class BuildTargetIndexImpl implements BuildTargetIndex { myDependencies.put(target, realDependencies); } - GraphGenerator> - graph = GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph>() { + GraphGenerator> graph = GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph>() { @Override public Collection> getNodes() { return realTargets; @@ -96,24 +93,12 @@ public class BuildTargetIndexImpl implements BuildTargetIndex { } })); - final DFSTBuilder> builder = new DFSTBuilder>(graph); - final TIntArrayList sccs = builder.getSCCs(); - - myTargetChunks = new ArrayList(sccs.size()); - sccs.forEach(new TIntProcedure() { - int myTNumber = 0; - public boolean execute(int size) { - final Set> chunkNodes = new LinkedHashSet>(); - for (int j = 0; j < size; j++) { - final BuildTarget node = builder.getNodeByTNumber(myTNumber + j); - chunkNodes.add(node); - } - myTargetChunks.add(new BuildTargetChunk(chunkNodes)); - - myTNumber += size; - return true; - } - }); + DFSTBuilder> builder = new DFSTBuilder>(graph); + Collection>> components = builder.getComponents(); + myTargetChunks = new ArrayList(components.size()); + for (Collection> component : components) { + myTargetChunks.add(new BuildTargetChunk(ContainerUtil.newLinkedHashSet(component))); + } } private static Collection> includeTransitiveDependenciesOfDummyTargets(Collection> dependencies, diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/ArtifactSorter.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/ArtifactSorter.java index 9c4678791b77..7f49eb835201 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/ArtifactSorter.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/ArtifactSorter.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -21,8 +21,6 @@ import com.intellij.util.Processor; import com.intellij.util.graph.CachingSemiGraph; import com.intellij.util.graph.DFSTBuilder; import com.intellij.util.graph.GraphGenerator; -import gnu.trove.TIntArrayList; -import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.incremental.artifacts.JpsBuilderArtifactService; import org.jetbrains.jps.model.JpsModel; @@ -84,20 +82,13 @@ public class ArtifactSorter { final DFSTBuilder builder = new DFSTBuilder(graph); if (builder.isAcyclic() && result.isEmpty()) return Collections.emptyMap(); - final TIntArrayList sccs = builder.getSCCs(); - sccs.forEach(new TIntProcedure() { - int myTNumber = 0; - public boolean execute(int size) { - if (size > 1) { - for (int j = 0; j < size; j++) { - final JpsArtifact artifact = builder.getNodeByTNumber(myTNumber + j); - result.put(artifact, artifact); - } + for (Collection component : builder.getComponents()) { + if (component.size() > 1) { + for (JpsArtifact artifact : component) { + result.put(artifact, artifact); } - myTNumber += size; - return true; } - }); + } for (int i = 0; i < graph.getNodes().size(); i++) { final JpsArtifact artifact = builder.getNodeByTNumber(i); diff --git a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java index 75b0cce1b6e5..625c9ecb8854 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java +++ b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java @@ -45,7 +45,6 @@ import com.intellij.util.xmlb.JDOMXIncluder; import com.intellij.util.xmlb.XmlSerializationException; import gnu.trove.THashMap; import gnu.trove.THashSet; -import gnu.trove.TIntProcedure; import gnu.trove.TObjectIntHashMap; import org.jdom.Document; import org.jetbrains.annotations.NotNull; @@ -529,28 +528,17 @@ public class PluginManagerCore { final Graph graph = createPluginIdGraph(idToDescriptorMap); final DFSTBuilder builder = new DFSTBuilder(graph); if (!builder.isAcyclic()) { - final List cycles = new ArrayList(); - builder.getSCCs().forEach(new TIntProcedure() { - private int myTNumber; - @Override - public boolean execute(int size) { - if (size > 1) { - String cycle = ""; - for (int j = 0; j < size; j++) { - PluginId id = builder.getNodeByTNumber(myTNumber + j); - idToDescriptorMap.get(id).setEnabled(false); - cycle += id.getIdString() + " "; - } - cycles.add(cycle); - } - myTNumber += size; - return true; - } - }); - final String cyclePresentation; if (ApplicationManager.getApplication().isInternal()) { - cyclePresentation = StringUtil.join(cycles, ";"); + final StringBuilder cycles = new StringBuilder(); + for (Collection component : builder.getComponents()) { + if (cycles.length() > 0) cycles.append(';'); + for (PluginId id : component) { + idToDescriptorMap.get(id).setEnabled(false); + cycles.append(id.getIdString()).append(' '); + } + } + cyclePresentation = cycles.toString(); } else { final Couple circularDependency = builder.getCircularDependency(); diff --git a/platform/platform-impl/src/com/intellij/util/graph/impl/CycleFinder.java b/platform/platform-impl/src/com/intellij/util/graph/impl/CycleFinder.java index 38f58e4b46bf..8f71253c23ec 100644 --- a/platform/platform-impl/src/com/intellij/util/graph/impl/CycleFinder.java +++ b/platform/platform-impl/src/com/intellij/util/graph/impl/CycleFinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.graph.impl; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.graph.Graph; import org.jetbrains.annotations.NotNull; import java.util.*; /** - * User: anna - * Date: Feb 13, 2005 + * @author anna + * @since Feb 13, 2005 */ public class CycleFinder { private final Graph myGraph; @@ -33,59 +33,39 @@ public class CycleFinder { } @NotNull - public Set> getNodeCycles(final Node node){ + public Set> getNodeCycles(final Node node) { final Set> result = new HashSet<>(); - final Graph graphWithoutNode = new Graph() { + @Override public Collection getNodes() { final Collection nodes = myGraph.getNodes(); nodes.remove(node); return nodes; } + @Override public Iterator getIn(final Node n) { - final HashSet nodes = new HashSet<>(); - final Iterator in = myGraph.getIn(n); - while (in.hasNext()) { - nodes.add(in.next()); - } + final Set nodes = ContainerUtil.newHashSet(myGraph.getIn(n)); nodes.remove(node); return nodes.iterator(); } + @Override public Iterator getOut(final Node n) { - final HashSet nodes = new HashSet<>(); - final Iterator out = myGraph.getOut(n); - while (out.hasNext()) { - nodes.add(out.next()); - } + final Set nodes = ContainerUtil.newHashSet(myGraph.getOut(n)); nodes.remove(node); return nodes.iterator(); } - }; - final HashSet inNodes = new HashSet<>(); - final Iterator in = myGraph.getIn(node); - while (in.hasNext()) { - inNodes.add(in.next()); - } - final HashSet outNodes = new HashSet<>(); - final Iterator out = myGraph.getOut(node); - while (out.hasNext()) { - outNodes.add(out.next()); - } - - final HashSet retainNodes = new HashSet<>(inNodes); + final Set inNodes = ContainerUtil.newHashSet(myGraph.getIn(node)); + final Set outNodes = ContainerUtil.newHashSet(myGraph.getOut(node)); + final Set retainNodes = new HashSet<>(inNodes); retainNodes.retainAll(outNodes); for (Node node1 : retainNodes) { - ArrayList oneNodeCycle = new ArrayList<>(); - oneNodeCycle.add(node1); - oneNodeCycle.add(node); - result.add(oneNodeCycle); + result.add(ContainerUtil.newArrayList(node1, node)); } - inNodes.removeAll(retainNodes); outNodes.removeAll(retainNodes); @@ -94,13 +74,14 @@ public class CycleFinder { for (Node toNode : inNodes) { final List shortestPath = finder.findPath(fromNode, toNode); if (shortestPath != null) { - ArrayList path = new ArrayList<>(); + List path = new ArrayList<>(shortestPath.size() + 1); path.addAll(shortestPath); path.add(node); result.add(path); } } } + return result; } -} +} \ No newline at end of file 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 f3cbf030682f..f877fd2f579e 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 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -18,8 +18,6 @@ package com.intellij.util.graph.impl; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.util.Chunk; import com.intellij.util.graph.*; -import gnu.trove.TIntArrayList; -import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -69,32 +67,27 @@ public class GraphAlgorithmsImpl extends GraphAlgorithms { @Override public Graph> computeSCCGraph(@NotNull final Graph graph) { final DFSTBuilder builder = new DFSTBuilder<>(graph); - final TIntArrayList sccs = builder.getSCCs(); - final List> chunks = new ArrayList<>(sccs.size()); + final Collection> components = builder.getComponents(); + final List> chunks = new ArrayList<>(components.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; + for (Collection component : components) { + final Set chunkNodes = new LinkedHashSet<>(); + final Chunk chunk = new Chunk<>(chunkNodes); + chunks.add(chunk); + for (Node node : component) { + chunkNodes.add(node); + nodeToChunkMap.put(node, chunk); } - }); + } return GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph>() { + @Override public Collection> getNodes() { return chunks; } + @Override public Iterator> getIn(Chunk chunk) { final Set chunkNodes = chunk.getNodes(); final Set> ins = new LinkedHashSet<>(); @@ -144,4 +137,4 @@ public class GraphAlgorithmsImpl extends GraphAlgorithms { private static boolean containsCycle(List path) { return new HashSet(path).size() != path.size(); } -} +} \ No newline at end of file diff --git a/platform/util/src/com/intellij/util/graph/DFSTBuilder.java b/platform/util/src/com/intellij/util/graph/DFSTBuilder.java index 103cc1b89f51..afad35943393 100644 --- a/platform/util/src/com/intellij/util/graph/DFSTBuilder.java +++ b/platform/util/src/com/intellij/util/graph/DFSTBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -27,7 +27,7 @@ import org.jetbrains.annotations.NotNull; import java.util.*; /** - * @author dsl, ven + * @author dsl, ven */ public class DFSTBuilder { private final Graph myGraph; @@ -42,6 +42,7 @@ public class DFSTBuilder { private final Node[] myInvT; // number in (enumerate all nodes scc by scc) order -> node private final Node[] myAllNodes; + @SuppressWarnings("unchecked") public DFSTBuilder(@NotNull Graph graph) { myAllNodes = (Node[])graph.getNodes().toArray(); myGraph = graph; @@ -52,17 +53,13 @@ public class DFSTBuilder { new Tarjan().build(); } - @Deprecated - public void buildDFST() { - } - /** - * Tarjan strong-connect-components search algorithm. - * See e.g. https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
- * This implementation differs from the canonical one above by
+ * Tarjan's strongly connected components search algorithm + * (Wikipedia article).
+ * This implementation differs from the canonical one above by:
*
    - *
  • - being not recursive
  • - *
  • - computing also topological order during the same single pass
  • + *
  • being non-recursive
  • + *
  • also computing a topological order during the same single pass
  • *
*/ private class Tarjan { @@ -91,11 +88,10 @@ public class DFSTBuilder { @Override public String toString() { - final StringBuilder o = new StringBuilder(); - for (int id : out) { - o.append(myAllNodes[id] + ", "); - } - return myAllNodes[nodeI] + " -> [" + o + "]"; + StringBuilder o = new StringBuilder(); + o.append(myAllNodes[nodeI]).append(" -> ["); + for (int id : out) o.append(myAllNodes[id]).append(", "); + return o.append(']').toString(); } } @@ -149,7 +145,7 @@ public class DFSTBuilder { myNodeToNNumber.put(node, index.length - 1 - i); myInvN[index.length - 1 - i] = node; } - mySCCs.reverse(); // have to place sccs in topological order too + mySCCs.reverse(); // have to place SCCs in topological order too } private void strongConnect(@NotNull List> sccs) { @@ -174,7 +170,7 @@ public class DFSTBuilder { successor = i; // if unexplored children left, dfs there - while (pair.nextUnexploredIndex { return mySCCs; } + @NotNull + public Collection> getComponents() { + final TIntArrayList componentSizes = getSCCs(); + if (componentSizes.isEmpty()) return Collections.emptyList(); + + return new MyCollection>(componentSizes.size()) { + @Override + public Iterator> iterator() { + return new MyIterator>(componentSizes.size()) { + private int offset = 0; + + @Override + protected Collection get(int i) { + final int cSize = componentSizes.get(i), cOffset = offset; + if (cSize == 0) return Collections.emptyList(); + offset += cSize; + return new MyCollection(cSize) { + @Override + public Iterator iterator() { + return new MyIterator(cSize) { + @Override + public Node get(int i) { + return getNodeByTNumber(cOffset + i); + } + }; + } + }; + } + }; + } + }; + } + + private static abstract class MyCollection extends AbstractCollection { + private final int size; + + protected MyCollection(int size) { + this.size = size; + } + + @Override + public int size() { + return size; + } + } + + private static abstract class MyIterator implements Iterator { + private final int size; + private int i = 0; + + protected MyIterator(int size) { + this.size = size; + } + + @Override + public boolean hasNext() { + return i < size; + } + + @Override + public T next() { + if (i == size) throw new NoSuchElementException(); + return get(i++); + } + + protected abstract T get(int i); + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + @NotNull public List getSortedNodes() { List result = new ArrayList(myGraph.getNodes()); Collections.sort(result, comparator()); return result; } -} +} \ No newline at end of file