make smart pointers occupy less memory:

create ManualRangeMarker-s (now immutable) only for non-committed documents
store only PSI ranges in the pointers
This commit is contained in:
peter
2015-08-20 21:44:19 +02:00
parent 63aa506d25
commit c014fe6eb4
6 changed files with 103 additions and 255 deletions
@@ -23,27 +23,23 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A range marker that has to be manually updated with {@link #getUpdatedRange(DocumentEvent)} and {@link #applyState(ManualRangeMarker)}.
* A range marker that has to be manually updated with {@link #getUpdatedRange(DocumentEvent)}.
* Can hold PSI-based range and be updated when the document is committed.
*/
public class ManualRangeMarker {
private static int ourCount = 0;
private ProperTextRange myRange;
private boolean myValid = true;
private final ProperTextRange myRange;
private final boolean myGreedyLeft;
private final boolean myGreedyRight;
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") private final int myHash = ourCount++;
private PersistentRangeMarker.LinesCols myLinesCols;
private final PersistentRangeMarker.LinesCols myLinesCols;
public ManualRangeMarker(@NotNull FrozenDocument document, @NotNull ProperTextRange range, boolean greedyLeft, boolean greedyRight, boolean surviveOnExternalChange) {
this(range, greedyLeft, greedyRight, surviveOnExternalChange ? PersistentRangeMarker.storeLinesAndCols(range, document) : null);
}
private ManualRangeMarker(ProperTextRange range,
boolean greedyLeft,
boolean greedyRight,
PersistentRangeMarker.LinesCols linesCols) {
private ManualRangeMarker(@NotNull ProperTextRange range,
boolean greedyLeft,
boolean greedyRight,
@Nullable PersistentRangeMarker.LinesCols linesCols) {
myRange = range;
myGreedyLeft = greedyLeft;
myGreedyRight = greedyRight;
@@ -52,67 +48,32 @@ public class ManualRangeMarker {
@Nullable
public ManualRangeMarker getUpdatedRange(@NotNull DocumentEvent event) {
Pair<ProperTextRange, PersistentRangeMarker.LinesCols> pair = getUpdatedState(event);
return pair == null ? null : new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, pair.second);
}
@Nullable
private Pair<ProperTextRange, PersistentRangeMarker.LinesCols> getUpdatedState(@NotNull DocumentEvent event) {
if (event instanceof RetargetRangeMarkers) {
int start = ((RetargetRangeMarkers)event).getStartOffset();
if (myRange.getStartOffset() >= start && myRange.getEndOffset() <= ((RetargetRangeMarkers)event).getEndOffset()) {
ProperTextRange range = myRange.shiftRight(((RetargetRangeMarkers)event).getMoveDestinationOffset() - start);
return Pair.create(range, myLinesCols == null ? null : PersistentRangeMarker.storeLinesAndCols(range, event.getDocument()));
return new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, myLinesCols == null ? null : PersistentRangeMarker.storeLinesAndCols(range, event.getDocument()));
}
}
if (myLinesCols != null) {
return PersistentRangeMarker
Pair<ProperTextRange, PersistentRangeMarker.LinesCols> pair = PersistentRangeMarker
.applyChange(event, myRange, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight, myLinesCols);
return pair == null ? null : new ManualRangeMarker(pair.first, myGreedyLeft, myGreedyRight, pair.second);
}
ProperTextRange range = RangeMarkerImpl.applyChange(event, myRange.getStartOffset(), myRange.getEndOffset(), myGreedyLeft, myGreedyRight);
return range == null ? null : new Pair<ProperTextRange, PersistentRangeMarker.LinesCols>(range, null);
return range == null ? null : new ManualRangeMarker(range, myGreedyLeft, myGreedyRight, null);
}
public void applyState(@Nullable ManualRangeMarker updated) {
if (updated == null || !updated.myValid) {
myValid = false;
}
if (!myValid) return;
myRange = updated.myRange;
myLinesCols = updated.myLinesCols;
}
public boolean isGreedyLeft() {
return myGreedyLeft;
}
public boolean isGreedyRight() {
return myGreedyRight;
}
public boolean isSurviveOnExternalChange() {
return myLinesCols != null;
}
@Nullable
@NotNull
public ProperTextRange getRange() {
return myValid ? myRange : null;
}
public boolean isValid() {
return myValid;
return myRange;
}
@Override
public String toString() {
return "ManualRangeMarker" + (myValid ? myRange.toString() : " invalid");
return "ManualRangeMarker" + myRange;
}
@Override
public int hashCode() {
return myHash;
}
}
@@ -317,6 +317,12 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
final boolean synchronously) {
if (myProject.isDisposed()) return false;
assert !(document instanceof DocumentWindow);
VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document);
if (virtualFile != null) {
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject)).fastenBelts(virtualFile);
}
myIsCommitInProgress = true;
boolean success = true;
try {
@@ -635,9 +641,6 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
if (document instanceof DocumentImpl && !myUncommittedInfos.containsKey(document)) {
myUncommittedInfos.put(document, new UncommittedInfo((DocumentImpl)document));
if (isRelevant) {
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject)).fastenBelts(virtualFile);
}
}
final FileViewProvider viewProvider = getCachedViewProvider(document);
@@ -769,7 +772,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
UncommittedInfo info = myUncommittedInfos.remove(document);
if (info != null) {
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject)).updatePointers(document, info.myFrozen, info.myEvents);
Disposer.dispose(info);
info.removeListener();
}
return info;
}
@@ -845,7 +848,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
@VisibleForTesting
public void clearUncommittedDocuments() {
for (UncommittedInfo info : myUncommittedInfos.values()) {
Disposer.dispose(info);
info.removeListener();
}
myUncommittedInfos.clear();
myUncommittedDocuments.clear();
@@ -892,7 +895,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
return mySynchronizer;
}
private static class UncommittedInfo extends DocumentAdapter implements PrioritizedInternalDocumentListener, Disposable {
private static class UncommittedInfo extends DocumentAdapter implements PrioritizedInternalDocumentListener {
final DocumentImpl myOriginal;
final FrozenDocument myFrozen;
final List<DocumentEvent> myEvents = ContainerUtil.newArrayList();
@@ -900,7 +903,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
public UncommittedInfo(DocumentImpl original) {
myOriginal = original;
myFrozen = original.freeze();
myOriginal.addDocumentListener(this, this);
myOriginal.addDocumentListener(this);
}
@Override
@@ -918,8 +921,8 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
myEvents.add(new RetargetRangeMarkers(myOriginal, start, end, base));
}
@Override
public void dispose() {
public void removeListener() {
myOriginal.removeDocumentListener(this);
}
}
@@ -123,7 +123,8 @@ class AnchorElementInfo extends SelfElementInfo {
// switch to tree
myStubElementTypeAndId = pack(-1, null);
PsiElement anchor = AnchorElementInfoFactory.getAnchor(element);
setRange((anchor == null ? element : anchor).getTextRange(), document);
TextRange range = (anchor == null ? element : anchor).getTextRange();
setRange(ProperTextRange.create(range));
}
}
@@ -24,65 +24,39 @@ import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.Trinity;
import com.intellij.util.NullableFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.WeakHashMap;
import com.intellij.util.containers.WeakValueHashMap;
import gnu.trove.TLongObjectHashMap;
import gnu.trove.TLongObjectProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author peter
*/
class MarkerCache {
private final Set<ManualRangeMarker> myMarkerSet = Collections.newSetFromMap(new WeakHashMap<ManualRangeMarker, Boolean>());
private WeakValueHashMap<RangeKey, ManualRangeMarker> myByRange = new WeakValueHashMap<RangeKey, ManualRangeMarker>();
private volatile Trinity<Integer, Map<RangeKey, ManualRangeMarker>, FrozenDocument> myUpdatedRanges;
private final SmartPointerManagerImpl.FilePointersList myPointers;
private volatile Trinity<Integer, TLongObjectHashMap<ManualRangeMarker>, FrozenDocument> myUpdatedRanges;
@Nullable
private static RangeKey keyOf(@NotNull ManualRangeMarker marker) {
ProperTextRange range = marker.getRange();
return range == null ? null : new RangeKey(range, marker.isGreedyLeft(), marker.isGreedyRight(), marker.isSurviveOnExternalChange());
MarkerCache(SmartPointerManagerImpl.FilePointersList pointers) {
myPointers = pointers;
}
@NotNull
synchronized ManualRangeMarker obtainMarker(@NotNull ProperTextRange range, @NotNull FrozenDocument frozen, boolean greedyLeft, boolean greedyRight, boolean persistent) {
WeakValueHashMap<RangeKey, ManualRangeMarker> byRange = getByRangeCache();
RangeKey key = new RangeKey(range, greedyLeft, greedyRight, persistent);
ManualRangeMarker marker = byRange.get(key);
if (marker == null) {
marker = new ManualRangeMarker(frozen, range, greedyLeft, greedyRight, persistent);
myMarkerSet.add(marker);
byRange.put(key, marker);
myUpdatedRanges = null;
}
return marker;
private static long keyOf(@NotNull ProperTextRange range, boolean forInjected) {
long start = range.getStartOffset();
assert start >= 0;
assert start < Integer.MAX_VALUE;
long packed = (start + 1) | ((long)range.getEndOffset() << 32);
assert packed > 0;
return forInjected ? -packed : packed;
}
private WeakValueHashMap<RangeKey, ManualRangeMarker> getByRangeCache() {
if (myByRange == null) {
myByRange = new WeakValueHashMap<RangeKey, ManualRangeMarker>();
for (ManualRangeMarker marker : myMarkerSet) {
RangeKey key = keyOf(marker);
if (key != null) {
myByRange.put(key, marker);
}
}
}
return myByRange;
}
private Map<RangeKey, ManualRangeMarker> getUpdatedMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
if (myMarkerSet.isEmpty()) return Collections.emptyMap();
private TLongObjectHashMap<ManualRangeMarker> getUpdatedMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
int eventCount = events.size();
assert eventCount > 0;
Trinity<Integer, Map<RangeKey, ManualRangeMarker>, FrozenDocument> cache = myUpdatedRanges;
Trinity<Integer, TLongObjectHashMap<ManualRangeMarker>, FrozenDocument> cache = myUpdatedRanges;
if (cache != null && cache.first.intValue() == eventCount) return cache.second;
//noinspection SynchronizeOnThis
@@ -90,17 +64,19 @@ class MarkerCache {
cache = myUpdatedRanges;
if (cache != null && cache.first.intValue() == eventCount) return cache.second;
Map<RangeKey, ManualRangeMarker> answer = ContainerUtil.newHashMap();
TLongObjectHashMap<ManualRangeMarker> answer;
if (cache != null && cache.first < eventCount) {
// apply only the new events
answer.putAll(cache.second);
answer = cache.second.clone();
frozen = applyEvents(cache.third, events.subList(cache.first, eventCount), answer);
}
else {
for (ManualRangeMarker marker : myMarkerSet) {
RangeKey key = keyOf(marker);
if (key != null) {
answer.put(key, marker);
answer = new TLongObjectHashMap<ManualRangeMarker>();
for (SelfElementInfo info : getInfos()) {
ProperTextRange range = info.getPsiRange();
if (range != null) {
boolean forInjected = info.isForInjected();
answer.put(keyOf(range, forInjected), new ManualRangeMarker(frozen, range, forInjected, forInjected, !forInjected));
}
}
frozen = applyEvents(frozen, events, answer);
@@ -112,10 +88,10 @@ class MarkerCache {
}
private static FrozenDocument applyEvents(@NotNull FrozenDocument frozen,
@NotNull List<DocumentEvent> events,
Map<RangeKey, ManualRangeMarker> map) {
@NotNull List<DocumentEvent> events,
final TLongObjectHashMap<ManualRangeMarker> map) {
for (DocumentEvent event : events) {
DocumentEvent corrected;
final DocumentEvent corrected;
if ((event instanceof RetargetRangeMarkers)) {
RetargetRangeMarkers retarget = (RetargetRangeMarkers)event;
corrected = new RetargetRangeMarkers(frozen, retarget.getStartOffset(), retarget.getEndOffset(), retarget.getMoveDestinationOffset());
@@ -126,102 +102,55 @@ class MarkerCache {
event.isWholeTextReplaced());
}
for (Map.Entry<RangeKey, ManualRangeMarker> entry : map.entrySet()) {
ManualRangeMarker currentRange = entry.getValue();
if (currentRange != null) {
entry.setValue(currentRange.getUpdatedRange(corrected));
map.forEachEntry(new TLongObjectProcedure<ManualRangeMarker>() {
@Override
public boolean execute(long key, ManualRangeMarker currentRange) {
if (currentRange != null) {
map.put(key, currentRange.getUpdatedRange(corrected));
}
return true;
}
}
});
}
return frozen;
}
synchronized void updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events, @NotNull List<SmartPsiElementPointerImpl> pointers) {
List<SelfElementInfo> infos = ContainerUtil.findAll(ContainerUtil.map(pointers, new NullableFunction<SmartPsiElementPointerImpl, SmartPointerElementInfo>() {
@Nullable
@Override
public SmartPointerElementInfo fun(SmartPsiElementPointerImpl pointer) {
return pointer.getElementInfo();
}
}), SelfElementInfo.class);
synchronized void updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
TLongObjectHashMap<ManualRangeMarker> updated = getUpdatedMarkers(frozen, events);
Map<RangeKey, ManualRangeMarker> updated = getUpdatedMarkers(frozen, events);
Map<ManualRangeMarker, ManualRangeMarker> newStates = ContainerUtil.newHashMap();
for (SelfElementInfo info : infos) {
ManualRangeMarker marker = info.getRangeMarker();
RangeKey key = marker == null ? null : keyOf(marker);
if (key != null) {
newStates.put(marker, updated.get(key));
for (SelfElementInfo info : getInfos()) {
ProperTextRange range = info.getPsiRange();
if (range != null) {
ManualRangeMarker newRange = updated.get(keyOf(range, info.isForInjected()));
info.setRange(newRange == null ? null : newRange.getRange());
}
}
myMarkerSet.clear();
for (Map.Entry<ManualRangeMarker, ManualRangeMarker> entry : newStates.entrySet()) {
ManualRangeMarker marker = entry.getKey();
marker.applyState(entry.getValue());
if (marker.isValid()) {
myMarkerSet.add(marker); //re-add only alive markers
}
}
myByRange = null;
myUpdatedRanges = null;
}
for (SelfElementInfo info : infos) {
info.updateValidity();
}
@NotNull
private List<SelfElementInfo> getInfos() {
return ContainerUtil.findAll(ContainerUtil.map(myPointers.getAlivePointers(), new NullableFunction<SmartPsiElementPointerImpl, SmartPointerElementInfo>() {
@Override
public SmartPointerElementInfo fun(SmartPsiElementPointerImpl pointer) {
return pointer.getElementInfo();
}
}), SelfElementInfo.class);
}
@Nullable
ProperTextRange getUpdatedRange(@NotNull ManualRangeMarker marker, @NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
ManualRangeMarker updated = getUpdatedMarkers(frozen, events).get(keyOf(marker));
ProperTextRange getUpdatedRange(SelfElementInfo info, @NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
ProperTextRange range = info.getPsiRange();
if (range == null) return null;
ManualRangeMarker updated = getUpdatedMarkers(frozen, events).get(keyOf(range, info.isForInjected()));
return updated == null ? null : updated.getRange();
}
@TestOnly
synchronized int getMarkerCount() {
return myMarkerSet.size();
}
private static class RangeKey {
final int start;
final int end;
final int flags;
RangeKey(ProperTextRange range, boolean greedyLeft, boolean greedyRight, boolean persistent) {
start = range.getStartOffset();
end = range.getEndOffset();
flags = (persistent ? 4 : 0) + (greedyLeft ? 2 : 0) + (greedyRight ? 1 : 0);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RangeKey)) return false;
RangeKey key = (RangeKey)o;
if (start != key.start) return false;
if (end != key.end) return false;
if (flags != key.flags) return false;
return true;
}
@Override
public int hashCode() {
int result = start;
result = 31 * result + end;
result = 31 * result + flags;
return result;
}
@Override
public String toString() {
return "RangeKey{" +
"start=" + start +
", end=" + end +
", flags=" + flags +
'}';
synchronized void rangeChanged(@NotNull ProperTextRange range, boolean forInjected) {
if (myUpdatedRanges != null && !myUpdatedRanges.second.contains(keyOf(range, forInjected))) {
myUpdatedRanges = null;
}
}
@@ -17,11 +17,8 @@ package com.intellij.psi.impl.smartPointers;
import com.intellij.lang.Language;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.impl.FrozenDocument;
import com.intellij.openapi.editor.impl.ManualRangeMarker;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
@@ -37,7 +34,6 @@ import java.util.List;
* User: cdr
*/
public class SelfElementInfo extends SmartPointerElementInfo {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.smartPointers.SelfElementInfo");
private static final FileDocumentManager ourFileDocManager = FileDocumentManager.getInstance();
@NotNull private final VirtualFile myVirtualFile;
private final Class myType;
@@ -45,7 +41,6 @@ public class SelfElementInfo extends SmartPointerElementInfo {
private final Language myLanguage;
private final MarkerCache myMarkerCache;
private final boolean myForInjected;
@Nullable private ManualRangeMarker myRangeMarker;
@Nullable private ProperTextRange myPsiRange;
private final PsiDocumentManagerBase myPsiDocManager;
@@ -65,17 +60,18 @@ public class SelfElementInfo extends SmartPointerElementInfo {
myPsiRange = range;
myMarkerCache = ((SmartPointerManagerImpl)SmartPointerManager.getInstance(project)).getMarkerCache(myVirtualFile);
myPsiDocManager = (PsiDocumentManagerBase)PsiDocumentManager.getInstance(myProject);
setRange(range);
}
Document document = myPsiDocManager.getCachedDocument(containingFile);
if (document != null) {
setRange(range, document);
void setRange(@Nullable ProperTextRange range) {
myPsiRange = range;
if (range != null) {
myMarkerCache.rangeChanged(range, myForInjected);
}
}
void setRange(@NotNull TextRange range, @NotNull Document document) {
myPsiRange = null;
FrozenDocument frozenDocument = myPsiDocManager.getLastCommittedDocument(document);
myRangeMarker = myMarkerCache.obtainMarker(ProperTextRange.create(range), frozenDocument, myForInjected, myForInjected, !myForInjected);
boolean isForInjected() {
return myForInjected;
}
@Override
@@ -83,23 +79,6 @@ public class SelfElementInfo extends SmartPointerElementInfo {
return ourFileDocManager.getCachedDocument(myVirtualFile);
}
// before change
@Override
public void fastenBelt() {
if (myRangeMarker != null) return; // already tracks changes
if (myPsiRange == null) return; // invalid
Document document = ourFileDocManager.getDocument(myVirtualFile);
if (document == null || !myPsiDocManager.isCommitted(document)) {
// we only have PSI range and now they say the document is uncommitted, so this PSI range is useless
// so, just invalidate
myPsiRange = null;
return;
}
setRange(myPsiRange, document);
}
@Override
public PsiElement restoreElement() {
Segment segment = getPsiRange();
@@ -112,8 +91,8 @@ public class SelfElementInfo extends SmartPointerElementInfo {
}
@Nullable
protected Segment getPsiRange() {
return myRangeMarker != null ? myRangeMarker.getRange() : myPsiRange;
protected ProperTextRange getPsiRange() {
return myPsiRange;
}
@Override
@@ -149,21 +128,9 @@ public class SelfElementInfo extends SmartPointerElementInfo {
@Override
public void cleanup() {
myRangeMarker = null;
myPsiRange = null;
}
void updateValidity() {
if (myPsiRange != null) {
LOG.error("Non-fastened smart pointer " + this + " " + myRangeMarker);
myPsiRange = null;
myRangeMarker = null;
}
if (myRangeMarker != null && !myRangeMarker.isValid()) {
myRangeMarker = null;
}
}
@Nullable
public static PsiFile restoreFileFromVirtual(@NotNull final VirtualFile virtualFile, @NotNull final Project project, @Nullable final Language language) {
return ApplicationManager.getApplication().runReadAction(new NullableComputable<PsiFile>() {
@@ -252,16 +219,15 @@ public class SelfElementInfo extends SmartPointerElementInfo {
@Override
@Nullable
public Segment getRange() {
if (myRangeMarker != null) {
if (myPsiRange != null) {
Document document = getDocumentToSynchronize();
if (document != null) {
PsiDocumentManagerBase documentManager = myPsiDocManager;
List<DocumentEvent> events = documentManager.getEventsSinceCommit(document);
if (!events.isEmpty()) {
return myMarkerCache.getUpdatedRange(myRangeMarker, documentManager.getLastCommittedDocument(document), events);
return myMarkerCache.getUpdatedRange(this, documentManager.getLastCommittedDocument(document), events);
}
}
return myRangeMarker.getRange();
}
return myPsiRange;
}
@@ -272,8 +238,4 @@ public class SelfElementInfo extends SmartPointerElementInfo {
return myProject;
}
@Nullable
ManualRangeMarker getRangeMarker() {
return myRangeMarker;
}
}
@@ -230,14 +230,6 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
}
}
@TestOnly
public int getMarkerCount(@NotNull Document document) {
synchronized (lock) {
VirtualFile file = FileDocumentManager.getInstance().getFile(document);
return file == null ? 0 : getMarkerCache(file).getMarkerCount();
}
}
@Override
public boolean pointToTheSameElement(@NotNull SmartPsiElementPointer pointer1, @NotNull SmartPsiElementPointer pointer2) {
return SmartPsiElementPointerImpl.pointsToTheSameElementAs(pointer1, pointer2);
@@ -248,7 +240,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
FilePointersList list = file == null ? null : getPointers(file);
if (list == null) return;
list.markerCache.updateMarkers(frozen, events, list.getAlivePointers());
list.markerCache.updateMarkers(frozen, events);
}
private static class PointerReference extends WeakReference<SmartPointerEx> {
@@ -265,11 +257,11 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
}
}
private static class FilePointersList {
static class FilePointersList {
private int nextAvailableIndex;
private int size;
private PointerReference[] references = new PointerReference[10];
private final MarkerCache markerCache = new MarkerCache();
private final MarkerCache markerCache = new MarkerCache(this);
private void add(@NotNull PointerReference reference) {
if (nextAvailableIndex >= references.length || nextAvailableIndex > size*2) { // overflow or too many dead refs
@@ -316,7 +308,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
}
@NotNull
private List<SmartPsiElementPointerImpl> getAlivePointers() {
List<SmartPsiElementPointerImpl> getAlivePointers() {
return ContainerUtil.mapNotNull(references, new Function<PointerReference, SmartPsiElementPointerImpl>() {
@Override
public SmartPsiElementPointerImpl fun(PointerReference reference) {