Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize TooltipItemFilter; ItemFilter limited cache #565

Merged
merged 2 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 62 additions & 10 deletions src/main/java/codechicken/nei/SearchTokenParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -86,6 +88,47 @@ public boolean matches(ItemStack item) {
}
}

private static class ItemFilterCache implements ItemFilter {

public ItemFilter filter;
private final ItemStackMap<Boolean> 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<String, ItemFilter> filtersCache = new LinkedHashMap<>() {

private static final long serialVersionUID = 1042213947848622164L;

@Override
protected boolean removeEldestEntry(Map.Entry<String, ItemFilter> eldest) {
return size() > 20;
}
};

protected final List<ISearchParserProvider> searchProviders;
protected final ProvidersCache providersCache = new ProvidersCache();
protected final TCharCharMap prefixRedefinitions = new TCharCharHashMap();
Expand Down Expand Up @@ -134,17 +177,26 @@ && getRedefinedPrefix(provider.getPrefix()) == ch)
}

public ItemFilter getFilter(String filterText) {
final String[] parts = EnumChatFormatting.getTextWithoutFormattingCodes(filterText).toLowerCase().split("\\|");
final List<ItemFilter> 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<ItemFilter> 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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -53,6 +54,7 @@ private static class ResourcePackReloaded implements IResourceManagerReloadListe
@Override
public void onResourceManagerReload(IResourceManager p_110549_1_) {
renderingErrorItems.clear();
TooltipFilter.populateSearchMap();
}
}

Expand Down
64 changes: 25 additions & 39 deletions src/main/java/codechicken/nei/search/TooltipFilter.java
Original file line number Diff line number Diff line change
@@ -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<ItemStackKey, String> 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<String> itemSearchNames = new ItemStackMap<>();
private static final ReentrantLock lock = new ReentrantLock();

private final Pattern pattern;

Expand All @@ -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) {
Expand Down
Loading