diff --git a/src/main/java/codechicken/nei/SearchTokenParser.java b/src/main/java/codechicken/nei/SearchTokenParser.java index c9722a5e8..ad406afc1 100644 --- a/src/main/java/codechicken/nei/SearchTokenParser.java +++ b/src/main/java/codechicken/nei/SearchTokenParser.java @@ -3,8 +3,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -86,6 +88,47 @@ public boolean matches(ItemStack item) { } } + private static class ItemFilterCache implements ItemFilter { + + public ItemFilter filter; + private final ItemStackMap states = new ItemStackMap<>(); + private final ReentrantLock lock = new ReentrantLock(); + + public ItemFilterCache(ItemFilter filter) { + this.filter = filter; + } + + @Override + public boolean matches(ItemStack item) { + lock.lock(); + + try { + Boolean match = states.get(item); + + if (match == null) { + states.put(item, match = this.filter.matches(item)); + } + + return match; + } catch (Throwable th) { + th.printStackTrace(); + return false; + } finally { + lock.unlock(); + } + } + } + + private static final LinkedHashMap filtersCache = new LinkedHashMap<>() { + + private static final long serialVersionUID = 1042213947848622164L; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > 20; + } + }; + protected final List searchProviders; protected final ProvidersCache providersCache = new ProvidersCache(); protected final TCharCharMap prefixRedefinitions = new TCharCharHashMap(); @@ -134,17 +177,26 @@ && getRedefinedPrefix(provider.getPrefix()) == ch) } public ItemFilter getFilter(String filterText) { - final String[] parts = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase().split("\\|"); - final List searchTokens = Arrays.stream(parts).map(this::parseSearchText).filter(s -> s != null) - .collect(Collectors.toCollection(ArrayList::new)); - - if (searchTokens.isEmpty()) { - return new EverythingItemFilter(); - } else if (searchTokens.size() == 1) { - return new IsRegisteredItemFilter(searchTokens.get(0)); - } else { - return new IsRegisteredItemFilter(new AnyMultiItemFilter(searchTokens)); + + if (!filtersCache.containsKey(filterText)) { + final String[] parts = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase() + .split("\\|"); + final List searchTokens = Arrays.stream(parts).map(this::parseSearchText).filter(s -> s != null) + .collect(Collectors.toCollection(ArrayList::new)); + + if (searchTokens.isEmpty()) { + filtersCache.put(filterText, new EverythingItemFilter()); + } else if (searchTokens.size() == 1) { + filtersCache.put(filterText, new IsRegisteredItemFilter(new ItemFilterCache(searchTokens.get(0)))); + } else { + filtersCache.put( + filterText, + new IsRegisteredItemFilter(new ItemFilterCache(new AnyMultiItemFilter(searchTokens)))); + } + } + + return filtersCache.get(filterText); } public Pattern getSplitPattern() { diff --git a/src/main/java/codechicken/nei/guihook/GuiContainerManager.java b/src/main/java/codechicken/nei/guihook/GuiContainerManager.java index 5fa7f785f..e0137df79 100644 --- a/src/main/java/codechicken/nei/guihook/GuiContainerManager.java +++ b/src/main/java/codechicken/nei/guihook/GuiContainerManager.java @@ -44,6 +44,7 @@ import codechicken.nei.NEIClientConfig; import codechicken.nei.NEIClientUtils; import codechicken.nei.recipe.StackInfo; +import codechicken.nei.search.TooltipFilter; import codechicken.nei.util.ReadableNumberConverter; public class GuiContainerManager { @@ -53,6 +54,7 @@ private static class ResourcePackReloaded implements IResourceManagerReloadListe @Override public void onResourceManagerReload(IResourceManager p_110549_1_) { renderingErrorItems.clear(); + TooltipFilter.populateSearchMap(); } } diff --git a/src/main/java/codechicken/nei/search/TooltipFilter.java b/src/main/java/codechicken/nei/search/TooltipFilter.java index af2439061..f75980545 100644 --- a/src/main/java/codechicken/nei/search/TooltipFilter.java +++ b/src/main/java/codechicken/nei/search/TooltipFilter.java @@ -1,48 +1,21 @@ package codechicken.nei.search; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumChatFormatting; import codechicken.nei.ItemList; +import codechicken.nei.ItemStackMap; import codechicken.nei.api.ItemFilter; import codechicken.nei.guihook.GuiContainerManager; public class TooltipFilter implements ItemFilter { - // lookup optimisation - private static final ConcurrentHashMap itemSearchNames = new ConcurrentHashMap<>(); - - private static class ItemStackKey { - - public final ItemStack stack; - - public ItemStackKey(ItemStack stack) { - this.stack = stack; - } - - @Override - public int hashCode() { - if (this.stack == null) return 1; - int hashCode = 1; - hashCode = 31 * hashCode + stack.stackSize; - hashCode = 31 * hashCode + Item.getIdFromItem(stack.getItem()); - hashCode = 31 * hashCode + stack.getItemDamage(); - hashCode = 31 * hashCode + (!stack.hasTagCompound() ? 0 : stack.getTagCompound().hashCode()); - return hashCode; - } - - @Override - public boolean equals(Object o) { - if (o == this) return true; - if (!(o instanceof ItemStackKey)) return false; - return ItemStack.areItemStacksEqual(this.stack, ((ItemStackKey) o).stack); - } - } + private static final ItemStackMap itemSearchNames = new ItemStackMap<>(); + private static final ReentrantLock lock = new ReentrantLock(); private final Pattern pattern; @@ -56,17 +29,30 @@ public boolean matches(ItemStack itemStack) { } public static void populateSearchMap() { - new Thread("NEI populate Tooltip Filter") { - - @Override - public void run() { - ItemList.items.parallelStream().forEach(TooltipFilter::getSearchTooltip); - } - }.start(); + itemSearchNames.clear(); + new Thread( + () -> ItemList.items.parallelStream().forEach(TooltipFilter::getSearchTooltip), + "NEI populate Tooltip Filter").start(); } protected static String getSearchTooltip(ItemStack stack) { - return itemSearchNames.computeIfAbsent(new ItemStackKey(stack), key -> getTooltip(key.stack)); + lock.lock(); + + try { + String tooltip = itemSearchNames.get(stack); + + if (tooltip == null) { + tooltip = getTooltip(stack.copy()); + itemSearchNames.put(stack, tooltip); + } + + return tooltip; + } catch (Throwable th) { + th.printStackTrace(); + return ""; + } finally { + lock.unlock(); + } } private static String getTooltip(ItemStack itemstack) {