[vcs-log-graph] introduce GraphUtil and move methods there

This commit is contained in:
Julia Beliaeva
2018-11-09 20:42:56 +03:00
parent 9c4312ab8c
commit 0fe79a3700
8 changed files with 78 additions and 84 deletions
@@ -20,7 +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.impl.facade.CascadeController;
import com.intellij.vcs.log.graph.impl.facade.LinearGraphController;
import com.intellij.vcs.log.graph.impl.facade.ReachableNodes;
import com.intellij.vcs.log.graph.utils.GraphUtilKt;
import com.intellij.vcs.log.graph.utils.UnsignedBitSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,7 +35,7 @@ public class BranchFilterController extends CascadeController {
@NotNull PermanentGraphInfo<?> permanentGraphInfo,
@Nullable Set<Integer> idsOfVisibleBranches) {
super(delegateLinearGraphController, permanentGraphInfo);
myVisibility = ReachableNodes.getReachableNodes(myPermanentGraphInfo.getLinearGraph(), idsOfVisibleBranches);
myVisibility = GraphUtilKt.getReachableNodes(myPermanentGraphInfo.getLinearGraph(), idsOfVisibleBranches);
myCollapsedGraph = update();
}
@@ -24,7 +24,7 @@ import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo;
import com.intellij.vcs.log.graph.impl.facade.CascadeController;
import com.intellij.vcs.log.graph.impl.facade.GraphChanges;
import com.intellij.vcs.log.graph.impl.facade.LinearGraphController;
import com.intellij.vcs.log.graph.impl.facade.ReachableNodes;
import com.intellij.vcs.log.graph.utils.GraphUtilKt;
import com.intellij.vcs.log.graph.utils.UnsignedBitSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,7 +38,7 @@ public class CollapsedController extends CascadeController {
@NotNull final PermanentGraphInfo<?> permanentGraphInfo,
@Nullable Set<Integer> idsOfVisibleBranches) {
super(delegateLinearGraphController, permanentGraphInfo);
UnsignedBitSet initVisibility = ReachableNodes.getReachableNodes(permanentGraphInfo.getLinearGraph(), idsOfVisibleBranches);
UnsignedBitSet initVisibility = GraphUtilKt.getReachableNodes(permanentGraphInfo.getLinearGraph(), idsOfVisibleBranches);
myCollapsedGraph = CollapsedGraph.newInstance(getDelegateController().getCompiledGraph(), initVisibility);
}
@@ -17,11 +17,9 @@
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.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.*
@@ -52,22 +50,4 @@ class ReachableNodes(private val graph: LiteLinearGraph) {
DfsWalk(startNodes, graph, visited).walk(goDown, consumer)
}
}
companion object {
@JvmStatic
fun getReachableNodes(graph: LinearGraph, headNodeIndexes: Set<Int>?): UnsignedBitSet {
if (headNodeIndexes == null) {
val nodesVisibility = UnsignedBitSet()
nodesVisibility.set(0, graph.nodesCount() - 1, true)
return nodesVisibility
}
val result = UnsignedBitSet()
DfsWalk(headNodeIndexes, graph).walk(true) { node: Int ->
result.set(node, true)
true
}
return result
}
}
}
@@ -41,28 +41,4 @@ class BfsWalk(val start: Int, private val graph: LiteLinearGraph, private val vi
step()
}
}
}
object BfsUtil {
fun getCorrespondingParent(graph: LiteLinearGraph, startNode: Int, endNode: Int, visited: Flags): Int {
val candidates = graph.getNodes(startNode, LiteLinearGraph.NodeFilter.DOWN)
if (candidates.size == 1) return candidates[0]
if (candidates.contains(endNode)) return endNode
val bfsWalks = candidates.mapTo(mutableListOf()) { BfsWalk(it, graph, visited) }
visited.setAll(false)
do {
for (walk in bfsWalks) {
if (walk.step().contains(endNode)) {
return walk.start
}
}
bfsWalks.removeIf { it.isFinished() }
}
while (bfsWalks.isNotEmpty())
return candidates[0]
}
}
}
@@ -16,7 +16,6 @@
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
@@ -136,29 +135,4 @@ private fun isDown(stack: IntStack): Boolean {
val previousNode = getPreviousNode(stack)
if (previousNode == Dfs.NextNode.NODE_NOT_FOUND) return true
return previousNode < currentNode
}
fun LiteLinearGraph.isAncestor(lowerNode: Int, upperNode: Int): Boolean {
val visited = BitSetFlags(nodesCount(), false)
val result = Ref.create(false)
walk(lowerNode) { currentNode ->
visited.set(currentNode, true)
if (currentNode == upperNode) {
result.set(true)
return@walk Dfs.NextNode.EXIT
}
if (currentNode > upperNode) {
for (nextNode in getNodes(currentNode, LiteLinearGraph.NodeFilter.UP)) {
if (!visited.get(nextNode)) {
return@walk nextNode
}
}
}
Dfs.NextNode.NODE_NOT_FOUND
}
return result.get()
}
}
@@ -0,0 +1,68 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.vcs.log.graph.utils
import com.intellij.openapi.util.Ref
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
fun getReachableNodes(graph: LinearGraph, headNodes: Set<Int>?): UnsignedBitSet {
if (headNodes == null) {
val nodesVisibility = UnsignedBitSet()
nodesVisibility.set(0, graph.nodesCount() - 1, true)
return nodesVisibility
}
val result = UnsignedBitSet()
DfsWalk(headNodes, graph).walk(true) { node: Int ->
result.set(node, true)
true
}
return result
}
fun LiteLinearGraph.isAncestor(lowerNode: Int, upperNode: Int): Boolean {
val visited = BitSetFlags(nodesCount(), false)
val result = Ref.create(false)
walk(lowerNode) { currentNode ->
visited.set(currentNode, true)
if (currentNode == upperNode) {
result.set(true)
return@walk Dfs.NextNode.EXIT
}
if (currentNode > upperNode) {
for (nextNode in getNodes(currentNode, LiteLinearGraph.NodeFilter.UP)) {
if (!visited.get(nextNode)) {
return@walk nextNode
}
}
}
Dfs.NextNode.NODE_NOT_FOUND
}
return result.get()
}
fun getCorrespondingParent(graph: LiteLinearGraph, startNode: Int, endNode: Int, visited: Flags): Int {
val candidates = graph.getNodes(startNode, LiteLinearGraph.NodeFilter.DOWN)
if (candidates.size == 1) return candidates[0]
if (candidates.contains(endNode)) return endNode
val bfsWalks = candidates.mapTo(mutableListOf()) { BfsWalk(it, graph, visited) }
visited.setAll(false)
do {
for (walk in bfsWalks) {
if (walk.step().contains(endNode)) {
return walk.start
}
}
bfsWalks.removeIf { it.isFinished() }
}
while (bfsWalks.isNotEmpty())
return candidates[0]
}
@@ -4,9 +4,9 @@ package com.intellij.vcs.log.graph.impl
import com.intellij.vcs.log.graph.TestGraphBuilder
import com.intellij.vcs.log.graph.asString
import com.intellij.vcs.log.graph.graph
import com.intellij.vcs.log.graph.utils.BfsUtil
import com.intellij.vcs.log.graph.utils.BfsWalk
import com.intellij.vcs.log.graph.utils.LinearGraphUtils
import com.intellij.vcs.log.graph.utils.getCorrespondingParent
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags
import org.junit.Test
import kotlin.test.assertEquals
@@ -15,8 +15,8 @@ class BfsTests {
private fun assertCorrespondingParent(startNode: Int, endNode: Int, expectedParent: Int, graphBuilder: TestGraphBuilder.() -> Unit) {
val graph = graph(graphBuilder)
val actualParent = BfsUtil.getCorrespondingParent(LinearGraphUtils.asLiteLinearGraph(graph), startNode, endNode,
BitSetFlags(graph.nodesCount()))
val actualParent = getCorrespondingParent(LinearGraphUtils.asLiteLinearGraph(graph), startNode, endNode,
BitSetFlags(graph.nodesCount()))
assertEquals(expectedParent, actualParent,
"Incorrect parent found when walking from ${startNode} to ${endNode} in ${graph.asString(true)}")
}
@@ -19,12 +19,8 @@ import com.intellij.vcs.log.graph.api.permanent.PermanentCommitsInfo
import com.intellij.vcs.log.graph.api.permanent.PermanentGraphInfo
import com.intellij.vcs.log.graph.collapsing.CollapsedGraph
import com.intellij.vcs.log.graph.impl.facade.*
import com.intellij.vcs.log.graph.utils.BfsUtil.getCorrespondingParent
import com.intellij.vcs.log.graph.utils.Dfs
import com.intellij.vcs.log.graph.utils.LinearGraphUtils
import com.intellij.vcs.log.graph.utils.*
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags
import com.intellij.vcs.log.graph.utils.isAncestor
import com.intellij.vcs.log.graph.utils.walk
import gnu.trove.*
import java.util.*
import java.util.function.BiConsumer