mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
simplify: use JobLauncher instead of manually breaking work in chunks
This commit is contained in:
+45
-74
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
package com.intellij.ide.util.gotoByName;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.concurrency.JobLauncher;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -32,14 +33,13 @@ import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.gotoByName.ChooseByNameIdea");
|
||||
private WeakReference<PsiElement> myContext;
|
||||
private final Reference<PsiElement> myContext;
|
||||
|
||||
public DefaultChooseByNameItemProvider(PsiElement context) {
|
||||
myContext = new WeakReference<PsiElement>(context);
|
||||
@@ -60,10 +60,11 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
String matchingPattern = convertToMatchingPattern(base, namePattern);
|
||||
List<MatchResult> namesList = new ArrayList<MatchResult>();
|
||||
String[] names = base.getNames(everywhere);
|
||||
processNamesByPattern(base, names, matchingPattern, new CollectConsumer<MatchResult>(namesList));
|
||||
CollectConsumer<MatchResult> collect = new SynchronizedCollectConsumer<MatchResult>(namesList);
|
||||
processNamesByPattern(base, names, matchingPattern, indicator, collect);
|
||||
|
||||
indicator.checkCanceled();
|
||||
sortNamesList(matchingPattern, namesList);
|
||||
sortNamesList(matchingPattern, (List<MatchResult>)collect.getResult());
|
||||
|
||||
indicator.checkCanceled();
|
||||
|
||||
@@ -71,7 +72,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
final Map<Object, MatchResult> qualifierMatchResults = new THashMap<Object, MatchResult>();
|
||||
|
||||
Comparator<Object> weightComparator = new Comparator<Object>() {
|
||||
Comparator<Object> modelComparator = model instanceof Comparator ? (Comparator<Object>)model : new PathProximityComparator(model, myContext.get());
|
||||
Comparator<Object> modelComparator = model instanceof Comparator ? (Comparator<Object>)model : new PathProximityComparator(myContext.get());
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
@@ -90,7 +91,7 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
for (MatchResult result : namesList) {
|
||||
indicator.checkCanceled();
|
||||
String name = result.elementName;
|
||||
|
||||
|
||||
boolean needSeparator = sortedByMatchingDegree && !result.startMatch && afterStartMatch;
|
||||
|
||||
// use interruptible call if possible
|
||||
@@ -115,14 +116,14 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
continue;
|
||||
}
|
||||
|
||||
if (needSeparator && !startMiddleMatchVariants(consumer, qualifierMiddleMatched)) return false;
|
||||
if (needSeparator && !startMiddleMatchVariants(qualifierMiddleMatched, consumer)) return false;
|
||||
if (!consumer.process(element)) return false;
|
||||
needSeparator = false;
|
||||
afterStartMatch = result.startMatch;
|
||||
}
|
||||
}
|
||||
else if (elements.length == 1 && matchQualifier(elements[0], base, patternsAndMatchers) != null) {
|
||||
if (needSeparator && !startMiddleMatchVariants(consumer, qualifierMiddleMatched)) return false;
|
||||
if (needSeparator && !startMiddleMatchVariants(qualifierMiddleMatched, consumer)) return false;
|
||||
if (!consumer.process(elements[0])) return false;
|
||||
afterStartMatch = result.startMatch;
|
||||
}
|
||||
@@ -130,7 +131,8 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
return ContainerUtil.process(qualifierMiddleMatched, consumer);
|
||||
}
|
||||
|
||||
private static boolean startMiddleMatchVariants(Processor<Object> consumer, List<Object> qualifierMiddleMatched) {
|
||||
private static boolean startMiddleMatchVariants(@NotNull List<Object> qualifierMiddleMatched,
|
||||
@NotNull Processor<Object> consumer) {
|
||||
if (!consumer.process(ChooseByNameBase.NON_PREFIX_SEPARATOR)) return false;
|
||||
if (!ContainerUtil.process(qualifierMiddleMatched, consumer)) return false;
|
||||
qualifierMiddleMatched.clear();
|
||||
@@ -179,8 +181,8 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
}
|
||||
|
||||
private static MatchResult matchQualifier(@NotNull Object element,
|
||||
@NotNull final ChooseByNameBase base,
|
||||
@NotNull List<Pair<String, MinusculeMatcher>> patternsAndMatchers) {
|
||||
@NotNull final ChooseByNameBase base,
|
||||
@NotNull List<Pair<String, MinusculeMatcher>> patternsAndMatchers) {
|
||||
final String name = base.getModel().getFullName(element);
|
||||
if (name == null) return null;
|
||||
|
||||
@@ -237,72 +239,41 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
@Override
|
||||
public List<String> filterNames(@NotNull ChooseByNameBase base, @NotNull String[] names, @NotNull String pattern) {
|
||||
final List<String> filtered = new ArrayList<String>();
|
||||
processNamesByPattern(base, names, convertToMatchingPattern(base, pattern), new Consumer<MatchResult>() {
|
||||
processNamesByPattern(base, names, convertToMatchingPattern(base, pattern), ProgressIndicatorProvider.getGlobalProgressIndicator(), new Consumer<MatchResult>() {
|
||||
@Override
|
||||
public void consume(MatchResult result) {
|
||||
filtered.add(result.elementName);
|
||||
synchronized (filtered) {
|
||||
filtered.add(result.elementName);
|
||||
}
|
||||
}
|
||||
});
|
||||
return filtered;
|
||||
synchronized (filtered) {
|
||||
return filtered;
|
||||
}
|
||||
}
|
||||
|
||||
private static void processNamesByPattern(@NotNull final ChooseByNameBase base,
|
||||
@NotNull final String[] names,
|
||||
final String pattern,
|
||||
final Consumer<MatchResult> consumer
|
||||
) {
|
||||
@NotNull final String pattern,
|
||||
final ProgressIndicator indicator,
|
||||
@NotNull final Consumer<MatchResult> consumer) {
|
||||
final MinusculeMatcher matcher = buildPatternMatcher(pattern, NameUtil.MatchingCaseSensitivity.NONE);
|
||||
int chunks = Math.min(Runtime.getRuntime().availableProcessors(), 4);
|
||||
final AtomicReferenceArray<ArrayList<MatchResult>> arr = new AtomicReferenceArray<ArrayList<MatchResult>>(chunks);
|
||||
Future<?>[] futures = new Future[arr.length() - 1];
|
||||
for(int i = 0; i < futures.length; ++i) {
|
||||
final int finalI = i;
|
||||
futures[i] = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
arr.set(finalI, matchNamesByPatternInChunk(base, finalI, arr.length(), names, pattern, matcher));
|
||||
}
|
||||
});
|
||||
}
|
||||
arr.set(futures.length, matchNamesByPatternInChunk(base, futures.length, arr.length(), names, pattern, matcher));
|
||||
|
||||
for(int i = arr.length() - 1; i >= 0; --i) {
|
||||
if (i < futures.length) {
|
||||
try {
|
||||
futures[i].get();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
Processor<String> processor = new Processor<String>() {
|
||||
@Override
|
||||
public boolean process(String name) {
|
||||
ProgressManager.checkCanceled();
|
||||
MatchResult result = matches(base, pattern, matcher, name);
|
||||
if (result != null) {
|
||||
consumer.consume(result);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (MatchResult result: arr.get(i)) consumer.consume(result);
|
||||
}
|
||||
};
|
||||
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(Arrays.asList(names), indicator, false, false, processor);
|
||||
}
|
||||
|
||||
private static ArrayList<MatchResult> matchNamesByPatternInChunk(@NotNull final ChooseByNameBase base,
|
||||
int index,
|
||||
int totalWorkers,
|
||||
@NotNull String[] names,
|
||||
String pattern,
|
||||
MinusculeMatcher matcher
|
||||
|
||||
) {
|
||||
ArrayList<MatchResult> namesList = new ArrayList<MatchResult>();
|
||||
|
||||
int perThreadWork = (names.length / totalWorkers + 1);
|
||||
int max = Math.min(perThreadWork * (index + 1), names.length);
|
||||
|
||||
for (int i = perThreadWork * index; i < max; ++i) {
|
||||
ProgressManager.checkCanceled();
|
||||
MatchResult result = matches(base, pattern, matcher, names[i]);
|
||||
if (result != null) {
|
||||
namesList.add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return namesList;
|
||||
}
|
||||
|
||||
private static String convertToMatchingPattern(ChooseByNameBase base, String pattern) {
|
||||
@NotNull
|
||||
private static String convertToMatchingPattern(@NotNull ChooseByNameBase base, @NotNull String pattern) {
|
||||
pattern = removeModelSpecificMarkup(base, pattern);
|
||||
|
||||
if (!base.canShowListForEmptyPattern()) {
|
||||
@@ -312,7 +283,8 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
return addSearchAnywherePatternDecorationIfNeeded(base, pattern);
|
||||
}
|
||||
|
||||
private static String addSearchAnywherePatternDecorationIfNeeded(ChooseByNameBase base, String pattern) {
|
||||
@NotNull
|
||||
private static String addSearchAnywherePatternDecorationIfNeeded(@NotNull ChooseByNameBase base, @NotNull String pattern) {
|
||||
String trimmedPattern;
|
||||
if (base.isSearchInAnyPlace() && !(trimmedPattern = pattern.trim()).isEmpty() && trimmedPattern.length() > 1) {
|
||||
pattern = "*" + pattern;
|
||||
@@ -320,7 +292,8 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
return pattern;
|
||||
}
|
||||
|
||||
private static String removeModelSpecificMarkup(ChooseByNameBase base, String pattern) {
|
||||
@NotNull
|
||||
private static String removeModelSpecificMarkup(@NotNull ChooseByNameBase base, @NotNull String pattern) {
|
||||
if (base.getModel() instanceof GotoClassModel2 && pattern.startsWith("@")) {
|
||||
pattern = pattern.substring(1);
|
||||
}
|
||||
@@ -329,9 +302,9 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
|
||||
@Nullable
|
||||
private static MatchResult matches(@NotNull ChooseByNameBase base,
|
||||
@NotNull String pattern,
|
||||
@NotNull MinusculeMatcher matcher,
|
||||
@Nullable String name) {
|
||||
@NotNull String pattern,
|
||||
@NotNull MinusculeMatcher matcher,
|
||||
@Nullable String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -353,11 +326,9 @@ public class DefaultChooseByNameItemProvider implements ChooseByNameItemProvider
|
||||
}
|
||||
|
||||
private static class PathProximityComparator implements Comparator<Object> {
|
||||
private final ChooseByNameModel myModel;
|
||||
@NotNull private final PsiProximityComparator myProximityComparator;
|
||||
|
||||
private PathProximityComparator(@NotNull ChooseByNameModel model, @Nullable final PsiElement context) {
|
||||
myModel = model;
|
||||
private PathProximityComparator(@Nullable final PsiElement context) {
|
||||
myProximityComparator = new PsiProximityComparator(context);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user