All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.intellij.vcs.log.graph.collapsing.CollapsedGraph Maven / Gradle / Ivy
/*
* 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.collapsing;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.graph.api.EdgeFilter;
import com.intellij.vcs.log.graph.api.LinearGraph;
import com.intellij.vcs.log.graph.api.elements.GraphEdge;
import com.intellij.vcs.log.graph.api.elements.GraphNode;
import com.intellij.vcs.log.graph.utils.UnsignedBitSet;
import com.intellij.vcs.log.graph.utils.UpdatableIntToIntMap;
import com.intellij.vcs.log.graph.utils.impl.ListIntToIntMap;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntIterator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class CollapsedGraph {
public static CollapsedGraph newInstance(@NotNull LinearGraph delegateGraph, @NotNull UnsignedBitSet matchedNodeId) {
return new CollapsedGraph(delegateGraph, matchedNodeId, matchedNodeId.clone(), new EdgeStorage());
}
public static CollapsedGraph updateInstance(@NotNull CollapsedGraph prevCollapsedGraph, @NotNull LinearGraph newDelegateGraph) {
UnsignedBitSet visibleNodesId = prevCollapsedGraph.myDelegateNodesVisibility.getNodeVisibilityById();
return new CollapsedGraph(newDelegateGraph, prevCollapsedGraph.myMatchedNodeId, visibleNodesId, prevCollapsedGraph.myEdgeStorage);
}
@NotNull private final LinearGraph myDelegatedGraph;
@NotNull private final UnsignedBitSet myMatchedNodeId;
@NotNull private final GraphNodesVisibility myDelegateNodesVisibility;
@NotNull private final UpdatableIntToIntMap myNodesMap;
@NotNull private final EdgeStorage myEdgeStorage;
@NotNull private final CompiledGraph myCompiledGraph;
@NotNull private final AtomicReference myCurrentModification = new AtomicReference(null);
private CollapsedGraph(@NotNull LinearGraph delegatedGraph,
@NotNull UnsignedBitSet matchedNodeId,
@NotNull UnsignedBitSet visibleNodesId,
@NotNull EdgeStorage edgeStorage) {
myDelegatedGraph = delegatedGraph;
myMatchedNodeId = matchedNodeId;
myDelegateNodesVisibility = new GraphNodesVisibility(delegatedGraph, visibleNodesId);
myNodesMap = ListIntToIntMap.newInstance(myDelegateNodesVisibility.asFlags());
myEdgeStorage = edgeStorage;
myCompiledGraph = new CompiledGraph();
}
@NotNull
public LinearGraph getDelegatedGraph() {
return myDelegatedGraph;
}
public boolean isNodeVisible(int delegateNodeIndex) {
return myDelegateNodesVisibility.isVisible(delegateNodeIndex);
}
@NotNull
public Modification startModification() {
Modification modification = new Modification();
if (myCurrentModification.compareAndSet(null, modification)) {
return modification;
}
throw new RuntimeException("Can not start a new modification while the other one is still running.");
}
@NotNull
public LinearGraph getCompiledGraph() {
assertNotUnderModification();
return myCompiledGraph;
}
public int convertToDelegateNodeIndex(int compiledNodeIndex) {
assertNotUnderModification();
return myNodesMap.getLongIndex(compiledNodeIndex);
}
@NotNull
public UnsignedBitSet getMatchedNodeId() {
return myMatchedNodeId;
}
// todo proper name
public boolean isMyCollapsedEdge(int upNodeIndex, int downNodeIndex) {
return new EdgeStorageWrapper(myEdgeStorage, myDelegatedGraph).hasEdge(upNodeIndex, downNodeIndex);
}
// everywhere in this class "nodeIndexes" means "node indexes in delegated graph"
public class Modification {
private static final int COLLECTING = 0;
private static final int APPLYING = 1;
private static final int DONE = 2;
@NotNull private final EdgeStorageWrapper myEdgesToAdd = EdgeStorageWrapper.createSimpleEdgeStorage();
@NotNull private final EdgeStorageWrapper myEdgesToRemove = EdgeStorageWrapper.createSimpleEdgeStorage();
@NotNull private final TIntHashSet myNodesToHide = new TIntHashSet();
@NotNull private final TIntHashSet myNodesToShow = new TIntHashSet();
private boolean myClearEdges = false;
private boolean myClearVisibility = false;
private volatile int myProgress = COLLECTING;
private int minAffectedNodeIndex = Integer.MAX_VALUE;
private int maxAffectedNodeIndex = Integer.MIN_VALUE;
private void touchIndex(int nodeIndex) {
assert myProgress == COLLECTING;
minAffectedNodeIndex = Math.min(minAffectedNodeIndex, nodeIndex);
maxAffectedNodeIndex = Math.max(maxAffectedNodeIndex, nodeIndex);
}
private void touchAll() {
assert myProgress == COLLECTING;
minAffectedNodeIndex = 0;
maxAffectedNodeIndex = getDelegatedGraph().nodesCount() - 1;
}
private void touchEdge(@NotNull GraphEdge edge) {
assert myProgress == COLLECTING;
if (edge.getUpNodeIndex() != null) touchIndex(edge.getUpNodeIndex());
if (edge.getDownNodeIndex() != null) touchIndex(edge.getDownNodeIndex());
}
public void showNode(int nodeIndex) {
assert myProgress == COLLECTING;
myNodesToShow.add(nodeIndex);
touchIndex(nodeIndex);
}
public void hideNode(int nodeIndex) {
assert myProgress == COLLECTING;
myNodesToHide.add(nodeIndex);
touchIndex(nodeIndex);
}
public void createEdge(@NotNull GraphEdge edge) {
assert myProgress == COLLECTING;
myEdgesToAdd.createEdge(edge);
touchEdge(edge);
}
public void removeEdge(@NotNull GraphEdge edge) { // todo add support for removing edge from delegate graph
assert myProgress == COLLECTING;
myEdgesToRemove.createEdge(edge);
touchEdge(edge);
}
public void removeAdditionalEdges() {
assert myProgress == COLLECTING;
myClearEdges = true;
touchAll();
}
public void resetNodesVisibility() {
assert myProgress == COLLECTING;
myClearVisibility = true;
touchAll();
}
// "package private" means "I'm not entirely happy about this method"
@NotNull
/*package private*/ EdgeStorageWrapper getEdgesToAdd() {
assert myProgress == COLLECTING;
return myEdgesToAdd;
}
/*package private*/
boolean isNodeHidden(int nodeIndex) {
assert myProgress == COLLECTING;
return myNodesToHide.contains(nodeIndex);
}
/*package private*/
boolean isNodeShown(int nodeIndex) {
assert myProgress == COLLECTING;
return myNodesToShow.contains(nodeIndex);
}
public void apply() {
assert myCurrentModification.get() == this;
myProgress = APPLYING;
if (myClearVisibility) {
myDelegateNodesVisibility.setNodeVisibilityById(myMatchedNodeId.clone());
}
if (myClearEdges) {
myEdgeStorage.removeAll();
}
TIntIterator toShow = myNodesToShow.iterator();
while (toShow.hasNext()) {
myDelegateNodesVisibility.show(toShow.next());
}
TIntIterator toHide = myNodesToHide.iterator();
while (toHide.hasNext()) {
myDelegateNodesVisibility.hide(toHide.next());
}
EdgeStorageWrapper edgeStorageWrapper = new EdgeStorageWrapper(myEdgeStorage, getDelegatedGraph());
for (GraphEdge edge : myEdgesToAdd.getEdges()) {
edgeStorageWrapper.createEdge(edge);
}
for (GraphEdge edge : myEdgesToRemove.getEdges()) {
edgeStorageWrapper.removeEdge(edge);
}
if (minAffectedNodeIndex != Integer.MAX_VALUE && maxAffectedNodeIndex != Integer.MIN_VALUE) {
myNodesMap.update(minAffectedNodeIndex, maxAffectedNodeIndex);
}
myProgress = DONE;
myCurrentModification.set(null);
}
}
private void assertNotUnderModification() {
Modification modification = myCurrentModification.get();
if (modification != null && modification.myProgress == Modification.APPLYING) {
throw new IllegalStateException("CompiledGraph is under modification");
}
}
private class CompiledGraph implements LinearGraph {
@NotNull private final EdgeStorageWrapper myEdgeStorageWrapper;
private CompiledGraph() {
myEdgeStorageWrapper = new EdgeStorageWrapper(myEdgeStorage, this);
}
@Override
public int nodesCount() {
assertNotUnderModification();
return myNodesMap.shortSize();
}
@NotNull
private GraphEdge createEdge(@NotNull GraphEdge delegateEdge, @Nullable Integer upNodeIndex, @Nullable Integer downNodeIndex) {
return new GraphEdge(upNodeIndex, downNodeIndex, delegateEdge.getTargetId(), delegateEdge.getType());
}
@Nullable
private Integer compiledNodeIndex(@Nullable Integer delegateNodeIndex) {
if (delegateNodeIndex == null) return null;
if (myDelegateNodesVisibility.isVisible(delegateNodeIndex)) {
return myNodesMap.getShortIndex(delegateNodeIndex);
}
else {
return -1;
}
}
private boolean isVisibleEdge(@Nullable Integer compiledUpNode, @Nullable Integer compiledDownNode) {
if (compiledUpNode != null && compiledUpNode == -1) return false;
if (compiledDownNode != null && compiledDownNode == -1) return false;
return true;
}
@NotNull
@Override
public List getAdjacentEdges(int nodeIndex, @NotNull EdgeFilter filter) {
assertNotUnderModification();
List result = ContainerUtil.newSmartList();
int delegateIndex = myNodesMap.getLongIndex(nodeIndex);
// add delegate edges
for (GraphEdge delegateEdge : myDelegatedGraph.getAdjacentEdges(delegateIndex, filter)) {
Integer compiledUpIndex = compiledNodeIndex(delegateEdge.getUpNodeIndex());
Integer compiledDownIndex = compiledNodeIndex(delegateEdge.getDownNodeIndex());
if (isVisibleEdge(compiledUpIndex, compiledDownIndex)) result.add(createEdge(delegateEdge, compiledUpIndex, compiledDownIndex));
}
result.addAll(myEdgeStorageWrapper.getAdjacentEdges(nodeIndex, filter));
return result;
}
@NotNull
@Override
public GraphNode getGraphNode(int nodeIndex) {
assertNotUnderModification();
int delegateIndex = myNodesMap.getLongIndex(nodeIndex);
GraphNode graphNode = myDelegatedGraph.getGraphNode(delegateIndex);
return new GraphNode(nodeIndex, graphNode.getType());
}
@Override
public int getNodeId(int nodeIndex) {
assertNotUnderModification();
int delegateIndex = myNodesMap.getLongIndex(nodeIndex);
return myDelegatedGraph.getNodeId(delegateIndex);
}
@Override
@Nullable
public Integer getNodeIndex(int nodeId) {
assertNotUnderModification();
Integer delegateIndex = myDelegatedGraph.getNodeIndex(nodeId);
if (delegateIndex == null) return null;
if (myDelegateNodesVisibility.isVisible(delegateIndex)) {
return myNodesMap.getShortIndex(delegateIndex);
}
else {
return null;
}
}
}
}