diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java b/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java index 9dfad3b9af4b..a71bb105df3c 100644 --- a/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java +++ b/platform/indexing-impl/src/com/intellij/psi/impl/search/LowLevelSearchUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -32,12 +32,17 @@ import com.intellij.psi.impl.source.tree.LeafElement; import com.intellij.psi.impl.source.tree.TreeElement; import com.intellij.psi.search.TextOccurenceProcessor; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.ConcurrencyUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.StringSearcher; +import gnu.trove.TIntArrayList; import gnu.trove.TIntProcedure; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; public class LowLevelSearchUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.search.LowLevelSearchUtil"); @@ -224,6 +229,7 @@ public class LowLevelSearchUtil { LOG.error(msg); } + private static final ConcurrentMap> cache = ContainerUtil.createConcurrentWeakMap(); public static boolean processTextOccurrences(@NotNull CharSequence text, int startOffset, int endOffset, @@ -231,15 +237,31 @@ public class LowLevelSearchUtil { @Nullable ProgressIndicator progress, @NotNull TIntProcedure processor) { if (endOffset > text.length()) { - throw new AssertionError("end>length"); + throw new IllegalArgumentException("end: " + endOffset + " > length: "+text.length()); } - for (int index = startOffset; index < endOffset; index++) { - if (progress != null) progress.checkCanceled(); - //noinspection AssignmentToForLoopParameter - index = searcher.scan(text, index, endOffset); - if (index < 0) break; - if (checkJavaIdentifier(text, startOffset, endOffset, searcher, index)) { - if (!processor.execute(index)) return false; + Map cachedMap = cache.get(text); + int[] cachedOccurrences = cachedMap == null ? null : cachedMap.get(searcher); + if (cachedOccurrences == null) { + TIntArrayList occurrences = new TIntArrayList(); + for (int index = 0; index < text.length(); index++) { + if (progress != null) progress.checkCanceled(); + //noinspection AssignmentToForLoopParameter + index = searcher.scan(text, index, text.length()); + if (index < 0) break; + if (checkJavaIdentifier(text, 0, text.length(), searcher, index)) { + occurrences.add(index); + } + } + cachedOccurrences = occurrences.toNativeArray(); + if (cachedMap == null) { + cachedMap = ConcurrencyUtil.cacheOrGet(cache, text, ContainerUtil.createConcurrentSoftMap()); + } + cachedMap.put(searcher, cachedOccurrences); + } + for (int index : cachedOccurrences) { + if (index >= endOffset) break; + if (index >= startOffset && !processor.execute(index)) { + return false; } } return true;