mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[util] easier iteration over DFSTBuilder
This commit is contained in:
@@ -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<BuildTarget<?>>
|
||||
graph = GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<BuildTarget<?>>() {
|
||||
GraphGenerator<BuildTarget<?>> graph = GraphGenerator.create(CachingSemiGraph.create(new GraphGenerator.SemiGraph<BuildTarget<?>>() {
|
||||
@Override
|
||||
public Collection<BuildTarget<?>> getNodes() {
|
||||
return realTargets;
|
||||
@@ -96,24 +93,12 @@ public class BuildTargetIndexImpl implements BuildTargetIndex {
|
||||
}
|
||||
}));
|
||||
|
||||
final DFSTBuilder<BuildTarget<?>> builder = new DFSTBuilder<BuildTarget<?>>(graph);
|
||||
final TIntArrayList sccs = builder.getSCCs();
|
||||
|
||||
myTargetChunks = new ArrayList<BuildTargetChunk>(sccs.size());
|
||||
sccs.forEach(new TIntProcedure() {
|
||||
int myTNumber = 0;
|
||||
public boolean execute(int size) {
|
||||
final Set<BuildTarget<?>> chunkNodes = new LinkedHashSet<BuildTarget<?>>();
|
||||
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<BuildTarget<?>> builder = new DFSTBuilder<BuildTarget<?>>(graph);
|
||||
Collection<Collection<BuildTarget<?>>> components = builder.getComponents();
|
||||
myTargetChunks = new ArrayList<BuildTargetChunk>(components.size());
|
||||
for (Collection<BuildTarget<?>> component : components) {
|
||||
myTargetChunks.add(new BuildTargetChunk(ContainerUtil.newLinkedHashSet(component)));
|
||||
}
|
||||
}
|
||||
|
||||
private static Collection<BuildTarget<?>> includeTransitiveDependenciesOfDummyTargets(Collection<BuildTarget<?>> dependencies,
|
||||
|
||||
+6
-15
@@ -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<JpsArtifact> builder = new DFSTBuilder<JpsArtifact>(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<JpsArtifact> 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);
|
||||
|
||||
@@ -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<PluginId> graph = createPluginIdGraph(idToDescriptorMap);
|
||||
final DFSTBuilder<PluginId> builder = new DFSTBuilder<PluginId>(graph);
|
||||
if (!builder.isAcyclic()) {
|
||||
final List<String> cycles = new ArrayList<String>();
|
||||
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<PluginId> 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<PluginId> circularDependency = builder.getCircularDependency();
|
||||
|
||||
@@ -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<Node> {
|
||||
private final Graph<Node> myGraph;
|
||||
@@ -33,59 +33,39 @@ public class CycleFinder<Node> {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<List<Node>> getNodeCycles(final Node node){
|
||||
public Set<List<Node>> getNodeCycles(final Node node) {
|
||||
final Set<List<Node>> result = new HashSet<>();
|
||||
|
||||
|
||||
final Graph<Node> graphWithoutNode = new Graph<Node>() {
|
||||
@Override
|
||||
public Collection<Node> getNodes() {
|
||||
final Collection<Node> nodes = myGraph.getNodes();
|
||||
nodes.remove(node);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Node> getIn(final Node n) {
|
||||
final HashSet<Node> nodes = new HashSet<>();
|
||||
final Iterator<Node> in = myGraph.getIn(n);
|
||||
while (in.hasNext()) {
|
||||
nodes.add(in.next());
|
||||
}
|
||||
final Set<Node> nodes = ContainerUtil.newHashSet(myGraph.getIn(n));
|
||||
nodes.remove(node);
|
||||
return nodes.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Node> getOut(final Node n) {
|
||||
final HashSet<Node> nodes = new HashSet<>();
|
||||
final Iterator<Node> out = myGraph.getOut(n);
|
||||
while (out.hasNext()) {
|
||||
nodes.add(out.next());
|
||||
}
|
||||
final Set<Node> nodes = ContainerUtil.newHashSet(myGraph.getOut(n));
|
||||
nodes.remove(node);
|
||||
return nodes.iterator();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
final HashSet<Node> inNodes = new HashSet<>();
|
||||
final Iterator<Node> in = myGraph.getIn(node);
|
||||
while (in.hasNext()) {
|
||||
inNodes.add(in.next());
|
||||
}
|
||||
final HashSet<Node> outNodes = new HashSet<>();
|
||||
final Iterator<Node> out = myGraph.getOut(node);
|
||||
while (out.hasNext()) {
|
||||
outNodes.add(out.next());
|
||||
}
|
||||
|
||||
final HashSet<Node> retainNodes = new HashSet<>(inNodes);
|
||||
final Set<Node> inNodes = ContainerUtil.newHashSet(myGraph.getIn(node));
|
||||
final Set<Node> outNodes = ContainerUtil.newHashSet(myGraph.getOut(node));
|
||||
final Set<Node> retainNodes = new HashSet<>(inNodes);
|
||||
retainNodes.retainAll(outNodes);
|
||||
for (Node node1 : retainNodes) {
|
||||
ArrayList<Node> 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<Node> {
|
||||
for (Node toNode : inNodes) {
|
||||
final List<Node> shortestPath = finder.findPath(fromNode, toNode);
|
||||
if (shortestPath != null) {
|
||||
ArrayList<Node> path = new ArrayList<>();
|
||||
List<Node> path = new ArrayList<>(shortestPath.size() + 1);
|
||||
path.addAll(shortestPath);
|
||||
path.add(node);
|
||||
result.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 <Node> Graph<Chunk<Node>> computeSCCGraph(@NotNull final Graph<Node> graph) {
|
||||
final DFSTBuilder<Node> builder = new DFSTBuilder<>(graph);
|
||||
final TIntArrayList sccs = builder.getSCCs();
|
||||
|
||||
final List<Chunk<Node>> chunks = new ArrayList<>(sccs.size());
|
||||
final Collection<Collection<Node>> components = builder.getComponents();
|
||||
final List<Chunk<Node>> chunks = new ArrayList<>(components.size());
|
||||
final Map<Node, Chunk<Node>> nodeToChunkMap = new LinkedHashMap<>();
|
||||
sccs.forEach(new TIntProcedure() {
|
||||
int myTNumber = 0;
|
||||
public boolean execute(int size) {
|
||||
final Set<Node> chunkNodes = new LinkedHashSet<>();
|
||||
final Chunk<Node> 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<Node> component : components) {
|
||||
final Set<Node> chunkNodes = new LinkedHashSet<>();
|
||||
final Chunk<Node> 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<Chunk<Node>>() {
|
||||
@Override
|
||||
public Collection<Chunk<Node>> getNodes() {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Chunk<Node>> getIn(Chunk<Node> chunk) {
|
||||
final Set<Node> chunkNodes = chunk.getNodes();
|
||||
final Set<Chunk<Node>> ins = new LinkedHashSet<>();
|
||||
@@ -144,4 +137,4 @@ public class GraphAlgorithmsImpl extends GraphAlgorithms {
|
||||
private static boolean containsCycle(List<?> path) {
|
||||
return new HashSet<Object>(path).size() != path.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Node> {
|
||||
private final Graph<Node> myGraph;
|
||||
@@ -42,6 +42,7 @@ public class DFSTBuilder<Node> {
|
||||
private final Node[] myInvT; // number in (enumerate all nodes scc by scc) order -> node
|
||||
private final Node[] myAllNodes;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public DFSTBuilder(@NotNull Graph<Node> graph) {
|
||||
myAllNodes = (Node[])graph.getNodes().toArray();
|
||||
myGraph = graph;
|
||||
@@ -52,17 +53,13 @@ public class DFSTBuilder<Node> {
|
||||
new Tarjan().build();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void buildDFST() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tarjan strong-connect-components search algorithm.
|
||||
* See e.g. <a href="https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm">https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm</a><br>
|
||||
* This implementation differs from the canonical one above by<br>
|
||||
* Tarjan's strongly connected components search algorithm
|
||||
* (<a href="https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm">Wikipedia article</a>).<br>
|
||||
* This implementation differs from the canonical one above by:<br>
|
||||
* <ul>
|
||||
* <li>- being not recursive</li>
|
||||
* <li>- computing also topological order during the same single pass</li>
|
||||
* <li>being non-recursive</li>
|
||||
* <li>also computing a topological order during the same single pass</li>
|
||||
* </ul>
|
||||
*/
|
||||
private class Tarjan {
|
||||
@@ -91,11 +88,10 @@ public class DFSTBuilder<Node> {
|
||||
|
||||
@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<Node> {
|
||||
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<List<Node>> sccs) {
|
||||
@@ -174,7 +170,7 @@ public class DFSTBuilder<Node> {
|
||||
successor = i;
|
||||
|
||||
// if unexplored children left, dfs there
|
||||
while (pair.nextUnexploredIndex<pair.out.length) {
|
||||
while (pair.nextUnexploredIndex < pair.out.length) {
|
||||
int nextI = pair.out[pair.nextUnexploredIndex++];
|
||||
if (index[nextI] == -1) {
|
||||
frames.push(new Frame(nextI));
|
||||
@@ -249,10 +245,83 @@ public class DFSTBuilder<Node> {
|
||||
return mySCCs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<Collection<Node>> getComponents() {
|
||||
final TIntArrayList componentSizes = getSCCs();
|
||||
if (componentSizes.isEmpty()) return Collections.emptyList();
|
||||
|
||||
return new MyCollection<Collection<Node>>(componentSizes.size()) {
|
||||
@Override
|
||||
public Iterator<Collection<Node>> iterator() {
|
||||
return new MyIterator<Collection<Node>>(componentSizes.size()) {
|
||||
private int offset = 0;
|
||||
|
||||
@Override
|
||||
protected Collection<Node> get(int i) {
|
||||
final int cSize = componentSizes.get(i), cOffset = offset;
|
||||
if (cSize == 0) return Collections.emptyList();
|
||||
offset += cSize;
|
||||
return new MyCollection<Node>(cSize) {
|
||||
@Override
|
||||
public Iterator<Node> iterator() {
|
||||
return new MyIterator<Node>(cSize) {
|
||||
@Override
|
||||
public Node get(int i) {
|
||||
return getNodeByTNumber(cOffset + i);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static abstract class MyCollection<T> extends AbstractCollection<T> {
|
||||
private final int size;
|
||||
|
||||
protected MyCollection(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class MyIterator<T> implements Iterator<T> {
|
||||
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<Node> getSortedNodes() {
|
||||
List<Node> result = new ArrayList<Node>(myGraph.getNodes());
|
||||
Collections.sort(result, comparator());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user