mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[vcs-log-graph] introduce DfsWalk class and use it instead of ReachableNodes
This commit is contained in:
+4
-3
@@ -20,6 +20,7 @@ import com.intellij.vcs.log.graph.api.elements.GraphElement;
|
||||
import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo;
|
||||
import com.intellij.vcs.log.graph.collapsing.CollapsedGraph;
|
||||
import com.intellij.vcs.log.graph.collapsing.DottedFilterEdgesGenerator;
|
||||
import com.intellij.vcs.log.graph.utils.DfsWalk;
|
||||
import com.intellij.vcs.log.graph.utils.LinearGraphUtils;
|
||||
import com.intellij.vcs.log.graph.utils.UnsignedBitSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -44,13 +45,13 @@ public class FilteredController extends CascadeController {
|
||||
|
||||
UnsignedBitSet initVisibility = new UnsignedBitSet();
|
||||
if (visibleHeadsIds != null) {
|
||||
ReachableNodes getter = new ReachableNodes(LinearGraphUtils.asLiteLinearGraph(myPermanentGraphInfo.getLinearGraph()));
|
||||
getter.walkDown(visibleHeadsIds, node -> {
|
||||
new DfsWalk(visibleHeadsIds, myPermanentGraphInfo.getLinearGraph()).walk(true, node -> {
|
||||
if (matchedIds.contains(node)) initVisibility.set(node, true);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
else {
|
||||
for (Integer matchedId: matchedIds) initVisibility.set(matchedId, true);
|
||||
for (Integer matchedId : matchedIds) initVisibility.set(matchedId, true);
|
||||
}
|
||||
|
||||
myCollapsedGraph = CollapsedGraph.newInstance(delegateLinearGraphController.getCompiledGraph(), initVisibility);
|
||||
|
||||
+8
-25
@@ -19,12 +19,14 @@ package com.intellij.vcs.log.graph.impl.facade
|
||||
import com.intellij.util.Consumer
|
||||
import com.intellij.vcs.log.graph.api.LinearGraph
|
||||
import com.intellij.vcs.log.graph.api.LiteLinearGraph
|
||||
import com.intellij.vcs.log.graph.utils.*
|
||||
import com.intellij.vcs.log.graph.utils.DfsWalk
|
||||
import com.intellij.vcs.log.graph.utils.Flags
|
||||
import com.intellij.vcs.log.graph.utils.UnsignedBitSet
|
||||
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags
|
||||
import java.util.*
|
||||
|
||||
class ReachableNodes(private val graph: LiteLinearGraph) {
|
||||
private val flags: Flags = BitSetFlags(graph.nodesCount())
|
||||
private val visited: Flags = BitSetFlags(graph.nodesCount())
|
||||
|
||||
fun getContainingBranches(nodeIndex: Int, branchNodeIndexes: Collection<Int>): Set<Int> {
|
||||
val result = HashSet<Int>()
|
||||
@@ -45,27 +47,9 @@ class ReachableNodes(private val graph: LiteLinearGraph) {
|
||||
}
|
||||
|
||||
fun walk(startNodes: Collection<Int>, goDown: Boolean, consumer: (Int) -> Boolean) {
|
||||
synchronized(flags) {
|
||||
|
||||
flags.setAll(false)
|
||||
for (start in startNodes) {
|
||||
if (start < 0) continue
|
||||
if (flags.get(start)) continue
|
||||
flags.set(start, true)
|
||||
if (!consumer(start)) return
|
||||
|
||||
walk(start) nextNode@{ currentNode ->
|
||||
for (downNode in graph.getNodes(currentNode, if (goDown) LiteLinearGraph.NodeFilter.DOWN else LiteLinearGraph.NodeFilter.UP)) {
|
||||
if (!flags.get(downNode)) {
|
||||
flags.set(downNode, true)
|
||||
if (!consumer(downNode)) return@nextNode Dfs.NextNode.EXIT
|
||||
return@nextNode downNode
|
||||
}
|
||||
}
|
||||
|
||||
Dfs.NextNode.NODE_NOT_FOUND
|
||||
}
|
||||
}
|
||||
synchronized(visited) {
|
||||
visited.setAll(false)
|
||||
DfsWalk(startNodes, graph, visited).walk(goDown, consumer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,8 +63,7 @@ class ReachableNodes(private val graph: LiteLinearGraph) {
|
||||
}
|
||||
|
||||
val result = UnsignedBitSet()
|
||||
val reachableNodes = ReachableNodes(LinearGraphUtils.asLiteLinearGraph(graph))
|
||||
reachableNodes.walk(headNodeIndexes, true) { node: Int ->
|
||||
DfsWalk(headNodeIndexes, graph).walk(true) { node: Int ->
|
||||
result.set(node, true)
|
||||
true
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.vcs.log.graph.utils
|
||||
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.util.containers.IntStack
|
||||
import com.intellij.vcs.log.graph.api.LinearGraph
|
||||
import com.intellij.vcs.log.graph.api.LiteLinearGraph
|
||||
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags
|
||||
|
||||
@@ -33,6 +34,54 @@ object Dfs {
|
||||
}
|
||||
}
|
||||
|
||||
private fun walk(start: Int, stack: IntStack, nextNodeFun: (Int) -> Int) {
|
||||
stack.push(start)
|
||||
|
||||
while (!stack.empty()) {
|
||||
val nextNode = nextNodeFun(stack.peek())
|
||||
if (nextNode == Dfs.NextNode.EXIT) return
|
||||
if (nextNode != Dfs.NextNode.NODE_NOT_FOUND) {
|
||||
stack.push(nextNode)
|
||||
}
|
||||
else {
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
stack.clear()
|
||||
}
|
||||
|
||||
fun walk(start: Int, nextNodeFun: (Int) -> Int) {
|
||||
walk(start, IntStack(), nextNodeFun)
|
||||
}
|
||||
|
||||
class DfsWalk(private val startNodes: Collection<Int>, private val graph: LiteLinearGraph, private val visited: Flags) {
|
||||
private val stack = IntStack()
|
||||
|
||||
constructor(startNodes: Collection<Int>, linearGraph: LinearGraph) :
|
||||
this(startNodes, LinearGraphUtils.asLiteLinearGraph(linearGraph), BitSetFlags(linearGraph.nodesCount()))
|
||||
|
||||
fun walk(goDown: Boolean, consumer: (Int) -> Boolean) {
|
||||
for (start in startNodes) {
|
||||
if (start < 0) continue
|
||||
if (visited.get(start)) continue
|
||||
visited.set(start, true)
|
||||
if (!consumer(start)) return
|
||||
|
||||
walk(start, stack) nextNode@{ currentNode ->
|
||||
for (downNode in graph.getNodes(currentNode, if (goDown) LiteLinearGraph.NodeFilter.DOWN else LiteLinearGraph.NodeFilter.UP)) {
|
||||
if (!visited.get(downNode)) {
|
||||
visited.set(downNode, true)
|
||||
if (!consumer(downNode)) return@nextNode Dfs.NextNode.EXIT
|
||||
return@nextNode downNode
|
||||
}
|
||||
}
|
||||
|
||||
Dfs.NextNode.NODE_NOT_FOUND
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@@ -113,20 +162,3 @@ fun LiteLinearGraph.isAncestor(lowerNode: Int, upperNode: Int): Boolean {
|
||||
|
||||
return result.get()
|
||||
}
|
||||
|
||||
fun walk(startRowIndex: Int, nextNodeFun: (Int) -> Int) {
|
||||
val stack = IntStack()
|
||||
stack.push(startRowIndex)
|
||||
|
||||
while (!stack.empty()) {
|
||||
val nextNode = nextNodeFun(stack.peek())
|
||||
if (nextNode == Dfs.NextNode.EXIT) return
|
||||
if (nextNode != Dfs.NextNode.NODE_NOT_FOUND) {
|
||||
stack.push(nextNode)
|
||||
}
|
||||
else {
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
stack.clear()
|
||||
}
|
||||
|
||||
@@ -5,16 +5,14 @@ import com.intellij.openapi.util.Ref
|
||||
import com.intellij.vcs.log.data.DataPack
|
||||
import com.intellij.vcs.log.graph.api.LinearGraph
|
||||
import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo
|
||||
import com.intellij.vcs.log.graph.impl.facade.ReachableNodes
|
||||
import com.intellij.vcs.log.graph.impl.facade.VisibleGraphImpl
|
||||
import com.intellij.vcs.log.graph.utils.LinearGraphUtils
|
||||
import com.intellij.vcs.log.graph.utils.DfsWalk
|
||||
import com.intellij.vcs.log.visible.VisiblePack
|
||||
|
||||
fun LinearGraph.findAncestorNode(startNodeId: Int, condition: (Int) -> Boolean): Int? {
|
||||
val resultNodeId = Ref<Int>()
|
||||
|
||||
val reachableNodes = ReachableNodes(LinearGraphUtils.asLiteLinearGraph(this))
|
||||
reachableNodes.walk(setOf(startNodeId), true) { currentNodeId ->
|
||||
DfsWalk(setOf(startNodeId), this).walk(true) { currentNodeId: Int ->
|
||||
if (condition(currentNodeId)) {
|
||||
resultNodeId.set(currentNodeId)
|
||||
false // stop walk, we have found it
|
||||
|
||||
Reference in New Issue
Block a user