/*
* Copyright 2000-2014 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.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.DfsUtil;
import com.intellij.vcs.log.graph.utils.Flags;
import com.intellij.vcs.log.graph.utils.LinearGraphUtils;
import com.intellij.vcs.log.graph.utils.UnsignedBitSet;
import com.intellij.vcs.log.graph.utils.impl.BitSetFlags;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class ReachableNodes {
@NotNull private final LiteLinearGraph myGraph;
@NotNull private final DfsUtil myDfsUtil = new DfsUtil();
@NotNull private final Flags myTempFlags;
public ReachableNodes(@NotNull LiteLinearGraph graph) {
myGraph = graph;
myTempFlags = new BitSetFlags(graph.nodesCount());
}
@NotNull
public static UnsignedBitSet getReachableNodes(@NotNull LinearGraph permanentGraph, @Nullable Set<Integer> headNodeIndexes) {
if (headNodeIndexes == null) {
UnsignedBitSet nodesVisibility = new UnsignedBitSet();
nodesVisibility.set(0, permanentGraph.nodesCount() - 1, true);
return nodesVisibility;
}
final UnsignedBitSet result = new UnsignedBitSet();
ReachableNodes getter = new ReachableNodes(LinearGraphUtils.asLiteLinearGraph(permanentGraph));
getter.walk(headNodeIndexes, new Consumer<Integer>() {
@Override
public void consume(Integer node) {
result.set(node, true);
}
});
return result;
}
public Set<Integer> getContainingBranches(int nodeIndex, @NotNull final Collection<Integer> branchNodeIndexes) {
final Set<Integer> result = new HashSet<>();
walk(Collections.singletonList(nodeIndex), false, new Consumer<Integer>() {
@Override
public void consume(Integer integer) {
if (branchNodeIndexes.contains(integer)) result.add(integer);
}
});
return result;
}
public void walk(@NotNull Collection<Integer> headIds, @NotNull final Consumer<Integer> consumer) {
walk(headIds, true, consumer);
}
private void walk(@NotNull Collection<Integer> startNodes, final boolean goDown, @NotNull final Consumer<Integer> consumer) {
synchronized (myTempFlags) {
myTempFlags.setAll(false);
for (int start : startNodes) {
if (start < 0) continue;
if (myTempFlags.get(start)) continue;
myTempFlags.set(start, true);
consumer.consume(start);
myDfsUtil.nodeDfsIterator(start, new DfsUtil.NextNode() {
@Override
public int fun(int currentNode) {
for (int downNode : myGraph.getNodes(currentNode, goDown ? LiteLinearGraph.NodeFilter.DOWN : LiteLinearGraph.NodeFilter.UP)) {
if (!myTempFlags.get(downNode)) {
myTempFlags.set(downNode, true);
consumer.consume(downNode);
return downNode;
}
}
return NODE_NOT_FOUND;
}
});
}
}
}
}