[file-history] move NodeVisitor and walk method to DfsUtil and add a comment for walk method

This commit is contained in:
Julia Beliaeva
2017-01-31 23:54:52 +03:00
parent 94938baefc
commit 0a6aa6a417
2 changed files with 67 additions and 55 deletions
@@ -16,7 +16,11 @@
package com.intellij.vcs.log.graph.utils;
import com.intellij.openapi.util.Pair;
import com.intellij.util.containers.IntStack;
import com.intellij.util.containers.Stack;
import com.intellij.vcs.log.graph.api.LiteLinearGraph;
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags;
import org.jetbrains.annotations.NotNull;
public class DfsUtil {
@@ -27,6 +31,66 @@ public class DfsUtil {
int fun(int currentNode);
}
public interface NodeVisitor {
void enterNode(int node);
void exitNode(int node);
}
/*
* Depth-first walk for a graph. For each node, walks both into upward and downward siblings.
* Tries to preserve direction of travel: when a node is entered from up-sibling, goes to the down-siblings first.
* Then goes to the other up-siblings.
* And when a node is entered from down-sibling, goes to the up-siblings first.
* Then goes to the other down-siblings.
* When a node is entered the first time, enterNode is called.
* When a node is passes in the same direction, exitNode is called.
* Nothing is called when a all the siblings of the node are visited.
*/
public static void walk(@NotNull LiteLinearGraph graph, int start, @NotNull NodeVisitor visitor) {
BitSetFlags visited = new BitSetFlags(graph.nodesCount(), false);
BitSetFlags visitedInSameDirection = new BitSetFlags(graph.nodesCount(), false);
Stack<Pair<Integer, Boolean>> stack = new Stack<>();
stack.push(new Pair<>(start, true)); // commit + direction of travel
while (!stack.empty()) {
int currentNode = stack.peek().first;
boolean down = stack.peek().second;
if (!visited.get(currentNode)) {
visited.set(currentNode, true);
visitor.enterNode(currentNode);
}
boolean found = false;
for (int nextNode : graph.getNodes(currentNode, down ? LiteLinearGraph.NodeFilter.DOWN : LiteLinearGraph.NodeFilter.UP)) {
if (!visited.get(nextNode)) {
stack.push(new Pair<>(nextNode, down));
found = true;
break;
}
}
if (!found) {
if (!visitedInSameDirection.get(currentNode)) {
visitedInSameDirection.set(currentNode, true);
visitor.exitNode(currentNode);
}
for (int nextNode : graph.getNodes(currentNode, down ? LiteLinearGraph.NodeFilter.UP : LiteLinearGraph.NodeFilter.DOWN)) {
if (!visited.get(nextNode)) {
stack.push(new Pair<>(nextNode, !down));
found = true;
break;
}
}
}
if (!found) {
stack.pop();
}
}
}
public static void walk(int startRowIndex, @NotNull NextNode nextNodeFun) {
IntStack stack = new IntStack();
stack.push(startRowIndex);
@@ -15,7 +15,6 @@
*/
package com.intellij.vcs.log.ui.history;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vfs.VirtualFile;
@@ -32,13 +31,12 @@ import com.intellij.vcs.log.data.index.IndexDataGetter;
import com.intellij.vcs.log.graph.PermanentGraph;
import com.intellij.vcs.log.graph.VisibleGraph;
import com.intellij.vcs.log.graph.api.LinearGraph;
import com.intellij.vcs.log.graph.api.LiteLinearGraph;
import com.intellij.vcs.log.graph.impl.facade.PermanentGraphImpl;
import com.intellij.vcs.log.graph.impl.facade.ReachableNodes;
import com.intellij.vcs.log.graph.impl.facade.VisibleGraphImpl;
import com.intellij.vcs.log.graph.impl.permanent.PermanentCommitsInfoImpl;
import com.intellij.vcs.log.graph.utils.DfsUtil;
import com.intellij.vcs.log.graph.utils.LinearGraphUtils;
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags;
import com.intellij.vcs.log.visible.VcsLogFilterer;
import com.intellij.vcs.log.visible.VisiblePack;
import com.intellij.vcsUtil.VcsUtil;
@@ -136,57 +134,7 @@ class FileHistoryFilterer extends VcsLogFilterer {
return 0;
}
private static void walk(@NotNull LiteLinearGraph graph, int start, @NotNull NodeVisitor visitor) {
BitSetFlags visited = new BitSetFlags(graph.nodesCount(), false);
BitSetFlags visitedInSameDirection = new BitSetFlags(graph.nodesCount(), false);
Stack<Pair<Integer, Boolean>> stack = new Stack<>();
stack.push(new Pair<>(start, true)); // commit + direction of travel
while (!stack.empty()) {
int currentNode = stack.peek().first;
boolean down = stack.peek().second;
if (!visited.get(currentNode)) {
visited.set(currentNode, true);
visitor.enterNode(currentNode);
}
boolean found = false;
for (int nextNode : graph.getNodes(currentNode, down ? LiteLinearGraph.NodeFilter.DOWN : LiteLinearGraph.NodeFilter.UP)) {
if (!visited.get(nextNode)) {
stack.push(new Pair<>(nextNode, down));
found = true;
break;
}
}
if (!found) {
if (!visitedInSameDirection.get(currentNode)) {
visitedInSameDirection.set(currentNode, true);
visitor.exitNode(currentNode);
}
for (int nextNode : graph.getNodes(currentNode, down ? LiteLinearGraph.NodeFilter.UP : LiteLinearGraph.NodeFilter.DOWN)) {
if (!visited.get(nextNode)) {
stack.push(new Pair<>(nextNode, !down));
found = true;
break;
}
}
}
if (!found) {
stack.pop();
}
}
}
public interface NodeVisitor {
void enterNode(int node);
void exitNode(int node);
}
private static class FileHistoryRefiner implements NodeVisitor {
private static class FileHistoryRefiner implements DfsUtil.NodeVisitor {
@NotNull private final VisibleGraph<Integer> myVisibleGraph;
@NotNull private final IndexDataGetter.FileNamesData myNamesData;
@NotNull private final Stack<FilePath> myPaths;
@@ -206,7 +154,7 @@ class FileHistoryFilterer extends VcsLogFilterer {
public boolean refine(@NotNull LinearGraph graph, int row, @NotNull FilePath startPath) {
myPaths.push(startPath);
walk(LinearGraphUtils.asLiteLinearGraph(graph), row, this);
DfsUtil.walk(LinearGraphUtils.asLiteLinearGraph(graph), row, this);
return myWasChanged;
}