diff options
| author | shedaniel <daniel@shedaniel.me> | 2023-05-29 12:38:01 +0800 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2023-05-29 12:38:24 +0800 |
| commit | 4b8675eda54b16c5b5f4a03eed9eb31ea5cadd4f (patch) | |
| tree | 78dc2bef419ecaf493480335fdf58c2ff4b58a4e | |
| parent | 50833c4668b5e7688d172767659eb8fee10f77e6 (diff) | |
| download | RoughlyEnoughItems-4b8675eda54b16c5b5f4a03eed9eb31ea5cadd4f.tar.gz RoughlyEnoughItems-4b8675eda54b16c5b5f4a03eed9eb31ea5cadd4f.tar.bz2 RoughlyEnoughItems-4b8675eda54b16c5b5f4a03eed9eb31ea5cadd4f.zip | |
Improve search performance
18 files changed, 569 insertions, 353 deletions
diff --git a/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java b/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java index f94266447..7fb37e351 100644 --- a/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java +++ b/api/src/main/java/me/shedaniel/rei/api/client/search/SearchFilter.java @@ -26,6 +26,7 @@ package me.shedaniel.rei.api.client.search; import me.shedaniel.rei.api.common.entry.EntryStack; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import org.jetbrains.annotations.ApiStatus; import java.util.Collection; import java.util.function.Predicate; @@ -80,4 +81,9 @@ public interface SearchFilter extends Predicate<EntryStack<?>> { */ default void prepareFilter(Collection<EntryStack<?>> stacks) { } + + @ApiStatus.Experimental + default boolean test(EntryStack<?> stack, long hashExact) { + return this.test(stack); + } } diff --git a/forge/build.gradle b/forge/build.gradle index 2aa93e09e..88fbffa0d 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -76,9 +76,9 @@ dependencies { // modRuntime("curse.maven:immersive-engineering-231951:3721708") // modRuntime("curse.maven:autoreglib-250363:3326041") // modRuntime("curse.maven:ars-nouveau-401955:3814106") - // modRuntime("curse.maven:patchouli-306770:3809917") + // modRuntime("curse.maven:patchouli-306770:3843443") // modRuntime("curse.maven:curios-309927:3748873") - // modRuntime("software.bernie.geckolib:geckolib-1.18-forge:3.0.22") + // modRuntime("software.bernie.geckolib:geckolib-forge-1.18:3.0.57") // modRuntime("curse.maven:little-logistics-570050:3818773") // modRuntime("curse.maven:refined-storage-243076:3623324") // modRuntime("appeng:appliedenergistics2:10.0.1") diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java index b18ddf9d2..3252a2dd8 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/entrylist/EntryListSearchManager.java @@ -24,6 +24,7 @@ package me.shedaniel.rei.impl.client.gui.widget.entrylist; import com.google.common.base.Stopwatch; +import com.google.common.collect.Iterators; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import me.shedaniel.rei.api.client.config.ConfigManager; @@ -36,10 +37,14 @@ import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.search.AsyncSearchManager; +import me.shedaniel.rei.impl.client.search.collapsed.CollapsedEntriesCache; import me.shedaniel.rei.impl.common.InternalLogger; +import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl; import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsedStack; import me.shedaniel.rei.impl.common.entry.type.collapsed.CollapsibleEntryRegistryImpl; +import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; import org.apache.logging.log4j.Level; @@ -50,10 +55,10 @@ import java.util.function.BooleanSupplier; import java.util.function.Consumer; public class EntryListSearchManager { - private static final Comparator<? super EntryStack<?>> ENTRY_NAME_COMPARER = Comparator.comparing(stack -> stack.asFormatStrippedText().getString()); - private static final Comparator<? super EntryStack<?>> ENTRY_GROUP_COMPARER = Comparator.comparingInt(stack -> { - if (stack.getType() == VanillaEntryTypes.ITEM) { - CreativeModeTab group = ((ItemStack) stack.getValue()).getItem().getItemCategory(); + private static final Comparator<? super HashedEntryStackWrapper> ENTRY_NAME_COMPARER = Comparator.comparing(stack -> stack.unwrap().asFormatStrippedText().getString()); + private static final Comparator<? super HashedEntryStackWrapper> ENTRY_GROUP_COMPARER = Comparator.comparingInt(stack -> { + if (stack.unwrap().getType() == VanillaEntryTypes.ITEM) { + CreativeModeTab group = ((ItemStack) stack.unwrap().getValue()).getItem().getItemCategory(); if (group != null) return group.getId(); } @@ -62,7 +67,7 @@ public class EntryListSearchManager { public static final EntryListSearchManager INSTANCE = new EntryListSearchManager(); - private AsyncSearchManager searchManager = new AsyncSearchManager(EntryRegistry.getInstance()::getPreFilteredList, () -> { + private final AsyncSearchManager searchManager = new AsyncSearchManager(((EntryRegistryImpl) EntryRegistry.getInstance())::getPreFilteredComplexList, () -> { boolean checkCraftable = ConfigManager.getInstance().isCraftableOnlyEnabled(); LongSet workingItems = checkCraftable ? new LongOpenHashSet() : null; if (checkCraftable) { @@ -70,8 +75,8 @@ public class EntryListSearchManager { workingItems.add(EntryStacks.hashExact(stack)); } } - return checkCraftable ? stack -> workingItems.contains(EntryStacks.hashExact(stack)) : stack -> true; - }, EntryStack::normalize); + return checkCraftable ? stack -> workingItems.contains(stack.hashExact()) : stack -> true; + }, HashedEntryStackWrapper::normalize); public void update(String searchTerm, boolean ignoreLastSearch, Consumer<List</*EntryStack<?> | CollapsedStack*/ Object>> update) { Stopwatch stopwatch = Stopwatch.createStarted(); @@ -80,21 +85,21 @@ public class EntryListSearchManager { if (searchManager.isDirty()) { searchManager.getAsync((list, filter) -> { if (!filter.getFilter().equals(searchTerm)) return; - if (searchManager.filter() == null || searchManager.filter() != filter) return; + if (searchManager.filter == null || searchManager.filter != filter) return; InternalLogger.getInstance().log(ConfigObject.getInstance().doDebugSearchTimeRequired() ? Level.INFO : Level.TRACE, "Search \"%s\" Used [%s]: %s", filter.getFilter(), Thread.currentThread().toString(), stopwatch.toString()); - List</*EntryStack<?> | CollapsedStack*/ Object> finalList = collapse(copyAndOrder(list), () -> searchManager.filter() != null && searchManager.filter() == filter); + List</*EntryStack<?> | CollapsedStack*/ Object> finalList = collapse(copyAndOrder(list), () -> searchManager.filter != null && searchManager.filter == filter); InternalLogger.getInstance().log(ConfigObject.getInstance().doDebugSearchTimeRequired() ? Level.INFO : Level.TRACE, "Search \"%s\" Used and Applied [%s]: %s", filter.getFilter(), Thread.currentThread().toString(), stopwatch.stop().toString()); Minecraft.getInstance().submit(() -> { - if (searchManager.filter() == null || searchManager.filter() != filter) return; + if (searchManager.filter == null || searchManager.filter != filter) return; update.accept(finalList); }); }); } } - private List<EntryStack<?>> copyAndOrder(List<EntryStack<?>> list) { + private List<HashedEntryStackWrapper> copyAndOrder(List<HashedEntryStackWrapper> list) { list = new ArrayList<>(list); EntryPanelOrdering ordering = ConfigObject.getInstance().getItemListOrdering(); if (ordering == EntryPanelOrdering.NAME) @@ -108,7 +113,7 @@ public class EntryListSearchManager { return list; } - private List</*EntryStack<?> | CollapsedStack*/ Object> collapse(List<EntryStack<?>> stacks, BooleanSupplier isValid) { + private List</*EntryStack<?> | CollapsedStack*/ Object> collapse(List<HashedEntryStackWrapper> stacks, BooleanSupplier isValid) { CollapsibleEntryRegistryImpl collapsibleRegistry = (CollapsibleEntryRegistryImpl) CollapsibleEntryRegistry.getInstance(); Map<CollapsibleEntryRegistryImpl.Entry, @Nullable CollapsedStack> entries = new HashMap<>(); @@ -116,20 +121,46 @@ public class EntryListSearchManager { entries.put(entry, null); } + if (entries.isEmpty()) return (List<Object>) (List<?>) new AbstractList<EntryStack<?>>() { + + @Override + public int size() { + return stacks.size(); + } + + @Override + public EntryStack<?> get(int i) { + return stacks.get(i).unwrap(); + } + + @Override + public Iterator<EntryStack<?>> iterator() { + return Iterators.transform(stacks.iterator(), HashedEntryStackWrapper::unwrap); + } + }; if (!isValid.getAsBoolean()) return List.of(); - List</*EntryStack<?> | CollapsedStack*/ Object> list = new ArrayList<>(); + List</*EntryStack<?> | CollapsedStack*/ Object> list = new ArrayList<>(stacks.size() + 10); int i = 0; - for (EntryStack<?> stack : stacks) { - long hashExact = EntryStacks.hashExact(stack); + for (HashedEntryStackWrapper wrapper : stacks) { + long hashExact = wrapper.hashExact(); + EntryStack<?> stack = wrapper.unwrap(); boolean matchedAny = false; + Set<ResourceLocation> locations = CollapsedEntriesCache.getInstance().getEntries(hashExact); for (Map.Entry<CollapsibleEntryRegistryImpl.Entry, @Nullable CollapsedStack> mapEntry : entries.entrySet()) { CollapsibleEntryRegistryImpl.Entry entry = mapEntry.getKey(); + boolean matches; + + if (!entry.canCache()) { + matches = entry.getMatcher().matches(stack, hashExact); + } else { + matches = locations != null && locations.contains(entry.getId()); + } - if (entry.getMatcher().matches(stack, hashExact)) { + if (matches) { CollapsedStack collapsed = mapEntry.getValue(); if (collapsed == null) { diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchFieldSyntaxHighlighter.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchFieldSyntaxHighlighter.java index 9391660c6..e039ad7e9 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchFieldSyntaxHighlighter.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/gui/widget/search/OverlaySearchFieldSyntaxHighlighter.java @@ -54,9 +54,9 @@ public class OverlaySearchFieldSyntaxHighlighter implements Consumer<String> { } @Override - public void addPart(Argument<?, ?> argument, boolean usingGrammar, Collection<IntRange> grammarRanges, int index) { + public void addPart(Argument.Builder<?, ?> argument, boolean usingGrammar, Collection<IntRange> grammarRanges, int index) { if (usingGrammar) { - int argIndex = ArgumentTypesRegistry.ARGUMENT_TYPE_LIST.indexOf(argument.getArgument()) * 2 + 1; + int argIndex = ArgumentTypesRegistry.ARGUMENT_TYPE_LIST.indexOf(argument.getType()) * 2 + 1; for (int i = argument.start(); i < argument.end(); i++) { highlighted[i] = (byte) argIndex; } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java index 9d418453c..30028d56d 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/AsyncSearchManager.java @@ -30,10 +30,8 @@ import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.impl.client.search.argument.Argument; -import me.shedaniel.rei.impl.client.search.argument.type.ArgumentType; import me.shedaniel.rei.impl.client.util.ThreadCreator; -import org.jetbrains.annotations.Nullable; +import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import java.util.AbstractMap; import java.util.ArrayList; @@ -46,32 +44,26 @@ import java.util.function.Supplier; import java.util.function.UnaryOperator; public class AsyncSearchManager { - private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-AsyncSearchManager").asService(); - private final Supplier<List<EntryStack<?>>> stacksProvider; - private final Supplier<Predicate<EntryStack<?>>> additionalPredicateSupplier; - private final UnaryOperator<EntryStack<?>> transformer; - private ExecutorTuple executor; - private SearchFilter filter; - private Map.Entry<List<EntryStack<?>>, SearchFilter> last; + private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-AsyncSearchManager").asService(Math.min(3, Runtime.getRuntime().availableProcessors())); + private final Supplier<List<HashedEntryStackWrapper>> stacksProvider; + private final Supplier<Predicate<HashedEntryStackWrapper>> additionalPredicateSupplier; + private final UnaryOperator<HashedEntryStackWrapper> transformer; + private volatile ExecutorTuple executor; + private volatile Map.Entry<List<HashedEntryStackWrapper>, SearchFilter> last; + public volatile SearchFilter filter; - public AsyncSearchManager(Supplier<List<EntryStack<?>>> stacksProvider, Supplier<Predicate<EntryStack<?>>> additionalPredicateSupplier, UnaryOperator<EntryStack<?>> transformer) { + public AsyncSearchManager(Supplier<List<HashedEntryStackWrapper>> stacksProvider, Supplier<Predicate<HashedEntryStackWrapper>> additionalPredicateSupplier, UnaryOperator<HashedEntryStackWrapper> transformer) { this.stacksProvider = stacksProvider; this.additionalPredicateSupplier = additionalPredicateSupplier; this.transformer = transformer; } public void markDirty() { - synchronized (AsyncSearchManager.this) { - this.last = null; - } - } - - @Nullable - public SearchFilter filter() { - return this.filter; + this.last = null; } - private record ExecutorTuple(SearchFilter filter, CompletableFuture<Map.Entry<List<EntryStack<?>>, SearchFilter>> future) { + private record ExecutorTuple(SearchFilter filter, + CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> future) { } public void updateFilter(String filter) { @@ -85,12 +77,10 @@ public class AsyncSearchManager { } public boolean isDirty() { - synchronized (AsyncSearchManager.this) { - return this.last == null || this.last.getValue() != this.filter; - } + return this.last == null || this.last.getValue() != this.filter; } - public Future<?> getAsync(BiConsumer<List<EntryStack<?>>, SearchFilter> consumer) { + public Future<?> getAsync(BiConsumer<List<HashedEntryStackWrapper>, SearchFilter> consumer) { if (this.executor == null || this.executor.filter() != filter || isDirty()) { if (this.executor != null) { this.executor.future().cancel(Platform.isFabric()); @@ -107,7 +97,7 @@ public class AsyncSearchManager { }, EXECUTOR_SERVICE))).future(); } - public List<EntryStack<?>> getNow() { + public List<HashedEntryStackWrapper> getNow() { try { return get(Runnable::run).get().getKey(); } catch (ExecutionException e) { @@ -117,18 +107,14 @@ public class AsyncSearchManager { } } - public CompletableFuture<Map.Entry<List<EntryStack<?>>, SearchFilter>> get(Executor executor) { + public CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> get(Executor executor) { if (isDirty()) { - Map.Entry<List<EntryStack<?>>, SearchFilter> last; - synchronized (AsyncSearchManager.this) { - last = this.last; - } + Map.Entry<List<HashedEntryStackWrapper>, SearchFilter> last; + last = this.last; return get(this.filter, this.additionalPredicateSupplier.get(), this.transformer, this.stacksProvider.get(), last, this, executor) .thenApply(entry -> { - synchronized (AsyncSearchManager.this) { - this.last = entry; - } + this.last = entry; return entry; }); } @@ -136,39 +122,20 @@ public class AsyncSearchManager { return CompletableFuture.completedFuture(last); } - public static CompletableFuture<Map.Entry<List<EntryStack<?>>, SearchFilter>> get(SearchFilter filter, Predicate<EntryStack<?>> additionalPredicate, - UnaryOperator<EntryStack<?>> transformer, List<EntryStack<?>> stacks, Map.Entry<List<EntryStack<?>>, SearchFilter> last, + public static CompletableFuture<Map.Entry<List<HashedEntryStackWrapper>, SearchFilter>> get(SearchFilter filter, Predicate<HashedEntryStackWrapper> additionalPredicate, + UnaryOperator<HashedEntryStackWrapper> transformer, List<HashedEntryStackWrapper> stacks, Map.Entry<List<HashedEntryStackWrapper>, SearchFilter> last, AsyncSearchManager manager, Executor executor) { int searchPartitionSize = ConfigObject.getInstance().getAsyncSearchPartitionSize(); boolean shouldAsync = ConfigObject.getInstance().shouldAsyncSearch() && stacks.size() > searchPartitionSize * 4; if (!stacks.isEmpty()) { - CompletableFuture<Void> preparationFuture = CompletableFuture.completedFuture(null); - - if (last == null || last.getValue() != filter) { - Runnable prepare = () -> { - if (manager.filter == filter) { - List<ArgumentType<?, ?>> argumentTypes = ((SearchProviderImpl.SearchFilterImpl) filter).getArgumentTypes(); - Argument.prepareFilter(stacks, argumentTypes, () -> manager.filter() != null && manager.filter() == filter, executor); - } else { - throw new CancellationException(); - } - }; - if (shouldAsync) { - preparationFuture = CompletableFuture.runAsync(prepare, executor); - } else { - prepare.run(); - preparationFuture = CompletableFuture.completedFuture(null); - } - } - if (shouldAsync) { - List<CompletableFuture<List<EntryStack<?>>>> futures = Lists.newArrayList(); - for (Iterable<EntryStack<?>> partitionStacks : CollectionUtils.partition(stacks, Math.max(searchPartitionSize, stacks.size() * 3 / Runtime.getRuntime().availableProcessors()))) { + List<CompletableFuture<List<HashedEntryStackWrapper>>> futures = Lists.newArrayList(); + for (Iterable<HashedEntryStackWrapper> partitionStacks : CollectionUtils.partition(stacks, Math.max(searchPartitionSize, stacks.size() * 3 / Runtime.getRuntime().availableProcessors()))) { futures.add(CompletableFuture.supplyAsync(() -> { - List<EntryStack<?>> filtered = Lists.newArrayList(); - for (EntryStack<?> stack : partitionStacks) { - if (stack != null && filter.test(stack) && additionalPredicate.test(stack)) { + List<HashedEntryStackWrapper> filtered = Lists.newArrayList(); + for (HashedEntryStackWrapper stack : partitionStacks) { + if (stack != null && filter.test(stack.unwrap(), stack.hashExact()) && additionalPredicate.test(stack)) { filtered.add(transformer.apply(stack)); } if (manager.filter != filter) throw new CancellationException(); @@ -176,19 +143,16 @@ public class AsyncSearchManager { return filtered; }, executor)); } - return preparationFuture.thenCompose($ -> CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) - .orTimeout(30, TimeUnit.SECONDS)) + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .orTimeout(30, TimeUnit.SECONDS) .thenApplyAsync($ -> { - List<EntryStack<?>> list = new ArrayList<>(); + List<HashedEntryStackWrapper> list = new ArrayList<>(); - if (manager.filter == filter) { - for (CompletableFuture<List<EntryStack<?>>> future : futures) { - List<EntryStack<?>> now = future.getNow(null); - if (now != null) list.addAll(now); - } - } else { - throw new CancellationException(); + for (CompletableFuture<List<HashedEntryStackWrapper>> future : futures) { + List<HashedEntryStackWrapper> now = future.getNow(null); + if (now != null) list.addAll(now); } + if (manager.filter != filter) throw new CancellationException(); return list; }, executor) @@ -196,10 +160,10 @@ public class AsyncSearchManager { return new AbstractMap.SimpleImmutableEntry<>(result, filter); }); } else { - List<EntryStack<?>> list = new ArrayList<>(); + List<HashedEntryStackWrapper> list = new ArrayList<>(); - for (EntryStack<?> stack : stacks) { - if (filter.test(stack) && additionalPredicate.test(stack)) { + for (HashedEntryStackWrapper stack : stacks) { + if (filter.test(stack.unwrap(), stack.hashExact()) && additionalPredicate.test(stack)) { list.add(transformer.apply(stack)); } if (manager.filter != filter) throw new CancellationException(); diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java index 06057497a..c19d3f0c1 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/SearchProviderImpl.java @@ -28,12 +28,15 @@ import me.shedaniel.rei.api.client.search.SearchFilter; import me.shedaniel.rei.api.client.search.SearchProvider; import me.shedaniel.rei.api.client.search.method.InputMethod; import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.search.argument.AlternativeArgument; import me.shedaniel.rei.impl.client.search.argument.Argument; import me.shedaniel.rei.impl.client.search.argument.CompoundArgument; import me.shedaniel.rei.impl.client.search.argument.type.ArgumentType; import me.shedaniel.rei.impl.client.util.CrashReportUtils; import me.shedaniel.rei.impl.common.InternalLogger; +import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.minecraft.CrashReport; import net.minecraft.CrashReportCategory; @@ -73,9 +76,9 @@ public class SearchProviderImpl implements SearchProvider { } @Override - public boolean test(EntryStack<?> stack) { + public boolean test(EntryStack<?> stack, long hashExact) { try { - return Argument.matches(stack, arguments.get(), inputMethod); + return Argument.matches(stack, hashExact, arguments.get(), inputMethod); } catch (Throwable throwable) { CrashReport report = CrashReportUtils.essential(throwable, "Testing entry with search filter"); CrashReportCategory category = report.addCategory("Search entry details"); @@ -89,8 +92,13 @@ public class SearchProviderImpl implements SearchProvider { } @Override + public boolean test(EntryStack<?> stack) { + return this.test(stack, EntryStacks.hashExact(stack)); + } + + @Override public void prepareFilter(Collection<EntryStack<?>> stacks) { - Argument.prepareFilter(stacks, argumentTypes.get()); + Argument.cache.prepareFilter(CollectionUtils.map(stacks, HashedEntryStackWrapper::new), argumentTypes.get()); } @Override diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java index 02af1c414..195210322 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/AlternativeArgument.java @@ -24,6 +24,7 @@ package me.shedaniel.rei.impl.client.search.argument; import com.google.common.collect.ForwardingList; +import me.shedaniel.rei.api.common.util.CollectionUtils; import org.jetbrains.annotations.ApiStatus; import java.util.ArrayList; @@ -50,9 +51,9 @@ public class AlternativeArgument extends ForwardingList<Argument<?, ?>> { } public static class Builder { - private List<Argument<?, ?>> arguments; + private List<Argument.Builder<?, ?>> arguments; - public <T, R> Builder add(Argument<T, R> argument) { + public <T, R> Builder add(Argument.Builder<T, R> argument) { if (arguments == null) { this.arguments = new ArrayList<>(); } @@ -67,8 +68,8 @@ public class AlternativeArgument extends ForwardingList<Argument<?, ?>> { public AlternativeArgument build() { if (arguments == null) return AlternativeArgument.EMPTY; - if (arguments.size() == 1) return new AlternativeArgument(Collections.singletonList(arguments.get(0))); - return new AlternativeArgument(arguments); + if (arguments.size() == 1) return new AlternativeArgument(List.of(arguments.get(0).build())); + return new AlternativeArgument(CollectionUtils.map(arguments, Argument.Builder::build)); } } } diff --git a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java index 50165f8eb..7b8dc7d18 100644 --- a/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java +++ b/runtime/src/main/java/me/shedaniel/rei/impl/client/search/argument/Argument.java @@ -26,92 +26,78 @@ package me.shedaniel.rei.impl.client.search.argument; import com.google.common.base.MoreObjects; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; -import it.unimi.dsi.fastutil.Pair; -import it.unimi.dsi.fastutil.ints.IntIntMutablePair; -import it.unimi.dsi.fastutil.ints.IntIntPair; import it.unimi.dsi.fastutil.ints.IntList; -import it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; -import it.unimi.dsi.fastutil.shorts.Short2ObjectMaps; -import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; -import me.shedaniel.rei.api.client.config.ConfigObject; import me.shedaniel.rei.api.client.gui.config.SearchMode; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.client.search.method.CharacterUnpackingInputMethod; import me.shedaniel.rei.api.client.search.method.InputMethod; import me.shedaniel.rei.api.common.entry.EntryStack; -import me.shedaniel.rei.api.common.util.CollectionUtils; -import me.shedaniel.rei.api.common.util.EntryStacks; import me.shedaniel.rei.impl.client.search.IntRange; import me.shedaniel.rei.impl.client.search.argument.type.ArgumentType; import me.shedaniel.rei.impl.client.search.argument.type.ArgumentTypesRegistry; +import me.shedaniel.rei.impl.client.search.collapsed.CollapsedEntriesCache; import me.shedaniel.rei.impl.client.search.result.ArgumentApplicableResult; -import me.shedaniel.rei.impl.client.util.ThreadCreator; -import me.shedaniel.rei.impl.common.InternalLogger; +import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl; import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.minecraft.Util; import net.minecraft.client.Minecraft; import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.Level; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.BooleanSupplier; import java.util.regex.Matcher; import java.util.regex.Pattern; @ApiStatus.Internal @Environment(EnvType.CLIENT) public class Argument<T, R> { - private static final ExecutorService EXECUTOR_SERVICE = new ThreadCreator("REI-ArgumentCache").asService(); - private static final Short2ObjectMap<Long2ObjectMap<Object>> SEARCH_CACHE = Short2ObjectMaps.synchronize(new Short2ObjectOpenHashMap<>()); private static final Object NO_CACHE = new Object(); - private static final AtomicReference<String> lastLanguage = new AtomicReference<>(); - private ArgumentType<T, R> argumentType; - private String text; - private T filterData; - private boolean regular; + private static final AtomicReference<String> LAST_LANGUAGE = new AtomicReference<>(); + public static ArgumentCache cache = new ArgumentCache(); + private final ArgumentType<T, R> argumentType; + private final String text; + private final T filterData; + private final boolean regular; private final int start; private final int end; private static final Pattern SPLIT_PATTERN = Pattern.compile("(?:\"([^\"]*)\")|([^\\s]+)"); - public Argument(ArgumentTy |
