blob: 2e286d399e20eacdcb7921bcf007da29376d8550 [file] [log] [blame]
/*
* 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.newgraph.render.cell;
import com.intellij.util.containers.SLRUMap;
import com.intellij.vcs.log.newgraph.gpaph.Edge;
import com.intellij.vcs.log.newgraph.gpaph.MutableGraph;
import com.intellij.vcs.log.newgraph.gpaph.Node;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class EdgesInRow {
private final static int CACHE_SIZE = 100;
private final static int WALK_SIZE = 1000;
@NotNull
private final MutableGraph myGraph;
@NotNull
private final SLRUMap<Integer, Set<Edge>> cache = new SLRUMap<Integer, Set<Edge>>(CACHE_SIZE, CACHE_SIZE * 2);
public EdgesInRow(@NotNull MutableGraph graph) {
myGraph = graph;
}
@NotNull
public Set<Edge> getEdgesInRow(int visibleRowIndex) {
Set<Edge> edges = cache.get(visibleRowIndex);
if (edges != null) {
return edges;
}
return calculateEdgesAround(visibleRowIndex);
}
public void invalidate() {
cache.clear();
}
@NotNull
private Set<Edge> calculateEdgesAround(int visibleRowIndex) {
int startIndex = Math.max(visibleRowIndex - CACHE_SIZE / 2, 0);
int endIndex = Math.min(visibleRowIndex + CACHE_SIZE / 2, myGraph.getCountVisibleNodes() - 1);
List<Set<Edge>> uCorrectEdges = getUCorrectEdges(startIndex, endIndex);
List<Set<Edge>> dCorrectEdges = getDCorrectEdges(startIndex, endIndex);
assert uCorrectEdges.size() == dCorrectEdges.size();
for (int i = 0; i < uCorrectEdges.size(); i++)
uCorrectEdges.get(i).addAll(dCorrectEdges.get(i));
for (int i = 0; i < uCorrectEdges.size(); i++)
cache.put(startIndex + i, uCorrectEdges.get(i));
return uCorrectEdges.get(visibleRowIndex - startIndex);
}
// [start, end]
@NotNull
private List<Set<Edge>> getUCorrectEdges(int startIndex, int endIndex) {
int startCalculateIndex = Math.max(startIndex - WALK_SIZE, 0);
List<Set<Edge>> result = new ArrayList<Set<Edge>>(endIndex - startIndex + 1);
Node currentNode = myGraph.getNode(startCalculateIndex);
Set<Edge> edgesInCurrentRow = new HashSet<Edge>();
if (startCalculateIndex >= startIndex)
result.add(new HashSet<Edge>(edgesInCurrentRow));
for (int i = startCalculateIndex + 1; i <= endIndex; i++) {
Node nextNode = myGraph.getNode(i);
oneDownStep(edgesInCurrentRow, currentNode, nextNode);
if (i >= startIndex)
result.add(new HashSet<Edge>(edgesInCurrentRow));
currentNode = nextNode;
}
return result;
}
private static void oneDownStep(Set<Edge> edgesInCurrentRow, Node currentNode, Node nextNode) {
edgesInCurrentRow.addAll(currentNode.getDownEdges());
edgesInCurrentRow.removeAll(nextNode.getUpEdges());
}
// [start, end]
@NotNull
private List<Set<Edge>> getDCorrectEdges(int startIndex, int endIndex) {
int endCalculateIndex = Math.min(endIndex + WALK_SIZE, myGraph.getCountVisibleNodes() - 1);
List<Set<Edge>> result = new ArrayList<Set<Edge>>(endIndex - startIndex + 1);
Node currentNode = myGraph.getNode(endCalculateIndex);
Set<Edge> edgesInCurrentRow = new HashSet<Edge>();
if (endCalculateIndex <= endIndex)
result.add(new HashSet<Edge>(edgesInCurrentRow));
for (int i = endCalculateIndex - 1; i >= startIndex; i--) {
Node prevNode = myGraph.getNode(i);
oneUpStep(edgesInCurrentRow, currentNode, prevNode);
if (i <= endIndex)
result.add(new HashSet<Edge>(edgesInCurrentRow));
currentNode = prevNode;
}
Collections.reverse(result);
return result;
}
private static void oneUpStep(Set<Edge> edgesInCurrentRow, Node currentNode, Node prevNode) {
edgesInCurrentRow.addAll(currentNode.getUpEdges());
edgesInCurrentRow.removeAll(prevNode.getDownEdges());
}
}