mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+2
-2
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+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);
|
||||
|
||||
+6
-43
@@ -17,14 +17,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.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,46 +45,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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
val reachableNodes = ReachableNodes(LinearGraphUtils.asLiteLinearGraph(graph))
|
||||
reachableNodes.walk(headNodeIndexes, true) { node: Int ->
|
||||
result.set(node, true)
|
||||
true
|
||||
}
|
||||
return result
|
||||
synchronized(visited) {
|
||||
visited.setAll(false)
|
||||
DfsWalk(startNodes, graph, visited).walk(goDown, consumer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.vcs.log.graph.utils;
|
||||
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.vcs.log.graph.api.LiteLinearGraph;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
public class BfsUtil {
|
||||
public static int getCorrespondingParent(@NotNull LiteLinearGraph graph, int startNode, int endNode, @NotNull Flags visited) {
|
||||
List<Integer> candidates = graph.getNodes(startNode, LiteLinearGraph.NodeFilter.DOWN);
|
||||
if (candidates.size() == 1) return candidates.get(0);
|
||||
if (candidates.contains(endNode)) return endNode;
|
||||
|
||||
List<Queue<Integer>> queues = new ArrayList<>(candidates.size());
|
||||
for (int candidate : candidates) {
|
||||
queues.add(ContainerUtil.newLinkedList(candidate));
|
||||
}
|
||||
|
||||
int emptyCount;
|
||||
visited.setAll(false);
|
||||
do {
|
||||
emptyCount = 0;
|
||||
for (Queue<Integer> queue : queues) {
|
||||
if (queue.isEmpty()) {
|
||||
emptyCount++;
|
||||
}
|
||||
else {
|
||||
boolean found = runNextBfsStep(graph, queue, visited, endNode);
|
||||
if (found) {
|
||||
return candidates.get(queues.indexOf(queue));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (emptyCount < queues.size());
|
||||
|
||||
return candidates.get(0);
|
||||
}
|
||||
|
||||
private static boolean runNextBfsStep(@NotNull LiteLinearGraph graph, @NotNull Queue<Integer> queue, @NotNull Flags visited, int target) {
|
||||
while (!queue.isEmpty()) {
|
||||
Integer node = queue.poll();
|
||||
if (!visited.get(node)) {
|
||||
visited.set(node, true);
|
||||
List<Integer> next = graph.getNodes(node, LiteLinearGraph.NodeFilter.DOWN);
|
||||
if (next.contains(target)) return true;
|
||||
queue.addAll(next);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.vcs.log.graph.utils
|
||||
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.vcs.log.graph.api.LiteLinearGraph
|
||||
|
||||
class BfsWalk(val start: Int, private val graph: LiteLinearGraph, private val visited: Flags) {
|
||||
private val queue = ContainerUtil.newLinkedList(start)
|
||||
|
||||
fun isFinished() = queue.isEmpty()
|
||||
|
||||
fun step(): List<Int> {
|
||||
while (!queue.isEmpty()) {
|
||||
val node = queue.poll()
|
||||
if (!visited.get(node)) {
|
||||
visited.set(node, true)
|
||||
val next = graph.getNodes(node, LiteLinearGraph.NodeFilter.DOWN)
|
||||
queue.addAll(next)
|
||||
return next
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
fun walk() {
|
||||
while (!isFinished()) {
|
||||
step()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
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 +33,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.
|
||||
@@ -87,46 +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()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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 LinearGraph.getReachableNodes(headNodes: Set<Int>?): UnsignedBitSet {
|
||||
if (headNodes == null) {
|
||||
val nodesVisibility = UnsignedBitSet()
|
||||
nodesVisibility.set(0, nodesCount() - 1, true)
|
||||
return nodesVisibility
|
||||
}
|
||||
|
||||
val result = UnsignedBitSet()
|
||||
DfsWalk(headNodes, this).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 LiteLinearGraph.getCorrespondingParent(startNode: Int, endNode: Int, visited: Flags): Int {
|
||||
val candidates = 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, this, 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]
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.intellij.vcs.log.graph.utils.Flags;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Objects;
|
||||
|
||||
public class BitSetFlags implements Flags {
|
||||
|
||||
@@ -65,4 +66,23 @@ public class BitSetFlags implements Flags {
|
||||
if (index < 0) throw new IndexOutOfBoundsException("index is " + index + " which is less then zero");
|
||||
if (index >= mySize) throw new IndexOutOfBoundsException("index is " + index + " and set size is " + mySize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BitSetFlags flags = (BitSetFlags)o;
|
||||
return mySize == flags.mySize &&
|
||||
myBitSet.equals(flags.myBitSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mySize, myBitSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myBitSet + ", size = " + mySize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// 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.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.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
|
||||
|
||||
class BfsTests {
|
||||
|
||||
private fun assertCorrespondingParent(startNode: Int, endNode: Int, expectedParent: Int, graphBuilder: TestGraphBuilder.() -> Unit) {
|
||||
val graph = graph(graphBuilder)
|
||||
val actualParent = LinearGraphUtils.asLiteLinearGraph(graph).getCorrespondingParent(startNode, endNode, BitSetFlags(graph.nodesCount()))
|
||||
assertEquals(expectedParent, actualParent,
|
||||
"Incorrect parent found when walking from ${startNode} to ${endNode} in ${graph.asString(true)}")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `one parent`() {
|
||||
assertCorrespondingParent(0, 5, 1) {
|
||||
0(1)
|
||||
1(2)
|
||||
2(3, 4)
|
||||
3(5)
|
||||
4(5)
|
||||
5()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `target parent`() {
|
||||
assertCorrespondingParent(0, 2, 2) {
|
||||
0(1, 2)
|
||||
1(3)
|
||||
2(3)
|
||||
3()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `merge commit`() {
|
||||
assertCorrespondingParent(0, 4, 2) {
|
||||
0(1, 2)
|
||||
1(3)
|
||||
2(3, 4)
|
||||
3()
|
||||
4()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test visited`() {
|
||||
val graph = graph {
|
||||
0(3)
|
||||
1(3)
|
||||
2(4)
|
||||
3(4)
|
||||
4(5, 6)
|
||||
5(7)
|
||||
6(8)
|
||||
7()
|
||||
8()
|
||||
}
|
||||
val nodesCount = graph.nodesCount()
|
||||
val visited = BitSetFlags(nodesCount)
|
||||
|
||||
BfsWalk(0, LinearGraphUtils.asLiteLinearGraph(graph), visited).walk()
|
||||
assertEquals(BitSetFlags(nodesCount).setAll(0, 3, 4, 5, 6, 7, 8), visited)
|
||||
visited.setAll(false)
|
||||
|
||||
BfsWalk(3, LinearGraphUtils.asLiteLinearGraph(graph), visited).walk()
|
||||
assertEquals(BitSetFlags(nodesCount).setAll(3, 4, 5, 6, 7, 8), visited)
|
||||
visited.setAll(false)
|
||||
|
||||
BfsWalk(5, LinearGraphUtils.asLiteLinearGraph(graph), visited).walk()
|
||||
assertEquals(BitSetFlags(nodesCount).setAll(5, 7), visited)
|
||||
visited.setAll(false)
|
||||
|
||||
BfsWalk(8, LinearGraphUtils.asLiteLinearGraph(graph), visited).walk()
|
||||
assertEquals(BitSetFlags(nodesCount).setAll(8), visited)
|
||||
visited.setAll(false)
|
||||
}
|
||||
|
||||
private fun BitSetFlags.setAll(vararg values: Int): BitSetFlags {
|
||||
values.forEach { this[it] = true }
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -202,7 +198,7 @@ internal class FileHistoryRefiner(private val visibleLinearGraph: LinearGraph,
|
||||
namesData.getPathInParentRevision(previousCommit, permanentCommitsInfo.getCommitId(parentIndex), previousPath.filePath)
|
||||
}
|
||||
val path = findPathWithoutConflict(previousNodeId, pathGetter)
|
||||
path ?: pathGetter(getCorrespondingParent(permanentLinearGraph, previousNodeId, currentNodeId, visibilityBuffer))
|
||||
path ?: pathGetter(permanentLinearGraph.getCorrespondingParent(previousNodeId, currentNodeId, visibilityBuffer))
|
||||
}
|
||||
else {
|
||||
val pathGetter = { parentIndex: Int ->
|
||||
@@ -210,7 +206,7 @@ internal class FileHistoryRefiner(private val visibleLinearGraph: LinearGraph,
|
||||
}
|
||||
val path = findPathWithoutConflict(currentNodeId, pathGetter)
|
||||
// since in reality there is no edge between the nodes, but the whole path, we need to know, which parent is affected by this path
|
||||
path ?: pathGetter(getCorrespondingParent(permanentLinearGraph, currentNodeId, previousNodeId, visibilityBuffer))
|
||||
path ?: pathGetter(permanentLinearGraph.getCorrespondingParent(currentNodeId, previousNodeId, visibilityBuffer))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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