package net.minecraft.util.parsing.packrat; import net.minecraft.Util; import org.jetbrains.annotations.Nullable; public abstract class CachedParseState implements ParseState { private CachedParseState.PositionCache[] positionCache = new CachedParseState.PositionCache[256]; private final ErrorCollector errorCollector; private final Scope scope = new Scope(); private CachedParseState.SimpleControl[] controlCache = new CachedParseState.SimpleControl[16]; private int nextControlToReturn; private final CachedParseState.Silent silent = new CachedParseState.Silent(); protected CachedParseState(ErrorCollector errorCollector) { this.errorCollector = errorCollector; } @Override public Scope scope() { return this.scope; } @Override public ErrorCollector errorCollector() { return this.errorCollector; } @Nullable @Override public T parse(NamedRule rule) { int i = this.mark(); CachedParseState.PositionCache positionCache = this.getCacheForPosition(i); int j = positionCache.findKeyIndex(rule.name()); if (j != -1) { CachedParseState.CacheEntry cacheEntry = positionCache.getValue(j); if (cacheEntry != null) { if (cacheEntry == CachedParseState.CacheEntry.NEGATIVE) { return null; } this.restore(cacheEntry.markAfterParse); return cacheEntry.value; } } else { j = positionCache.allocateNewEntry(rule.name()); } T object = rule.value().parse(this); CachedParseState.CacheEntry cacheEntry2; if (object == null) { cacheEntry2 = CachedParseState.CacheEntry.negativeEntry(); } else { int k = this.mark(); cacheEntry2 = new CachedParseState.CacheEntry<>(object, k); } positionCache.setValue(j, cacheEntry2); return object; } private CachedParseState.PositionCache getCacheForPosition(int position) { int i = this.positionCache.length; if (position >= i) { int j = Util.growByHalf(i, position + 1); CachedParseState.PositionCache[] positionCaches = new CachedParseState.PositionCache[j]; System.arraycopy(this.positionCache, 0, positionCaches, 0, i); this.positionCache = positionCaches; } CachedParseState.PositionCache positionCache = this.positionCache[position]; if (positionCache == null) { positionCache = new CachedParseState.PositionCache(); this.positionCache[position] = positionCache; } return positionCache; } @Override public Control acquireControl() { int i = this.controlCache.length; if (this.nextControlToReturn >= i) { int j = Util.growByHalf(i, this.nextControlToReturn + 1); CachedParseState.SimpleControl[] simpleControls = new CachedParseState.SimpleControl[j]; System.arraycopy(this.controlCache, 0, simpleControls, 0, i); this.controlCache = simpleControls; } int j = this.nextControlToReturn++; CachedParseState.SimpleControl simpleControl = this.controlCache[j]; if (simpleControl == null) { simpleControl = new CachedParseState.SimpleControl(); this.controlCache[j] = simpleControl; } else { simpleControl.reset(); } return simpleControl; } @Override public void releaseControl() { this.nextControlToReturn--; } @Override public ParseState silent() { return this.silent; } record CacheEntry(@Nullable T value, int markAfterParse) { public static final CachedParseState.CacheEntry NEGATIVE = new CachedParseState.CacheEntry(null, -1); public static CachedParseState.CacheEntry negativeEntry() { return (CachedParseState.CacheEntry)NEGATIVE; } } static class PositionCache { public static final int ENTRY_STRIDE = 2; private static final int NOT_FOUND = -1; private Object[] atomCache = new Object[16]; private int nextKey; public int findKeyIndex(Atom atom) { for (int i = 0; i < this.nextKey; i += 2) { if (this.atomCache[i] == atom) { return i; } } return -1; } public int allocateNewEntry(Atom entry) { int i = this.nextKey; this.nextKey += 2; int j = i + 1; int k = this.atomCache.length; if (j >= k) { int l = Util.growByHalf(k, j + 1); Object[] objects = new Object[l]; System.arraycopy(this.atomCache, 0, objects, 0, k); this.atomCache = objects; } this.atomCache[i] = entry; return i; } @Nullable public CachedParseState.CacheEntry getValue(int index) { return (CachedParseState.CacheEntry)this.atomCache[index + 1]; } public void setValue(int index, CachedParseState.CacheEntry value) { this.atomCache[index + 1] = value; } } class Silent implements ParseState { private final ErrorCollector silentCollector = new ErrorCollector.Nop<>(); @Override public ErrorCollector errorCollector() { return this.silentCollector; } @Override public Scope scope() { return CachedParseState.this.scope(); } @Nullable @Override public T parse(NamedRule rule) { return CachedParseState.this.parse(rule); } @Override public S input() { return CachedParseState.this.input(); } @Override public int mark() { return CachedParseState.this.mark(); } @Override public void restore(int cursor) { CachedParseState.this.restore(cursor); } @Override public Control acquireControl() { return CachedParseState.this.acquireControl(); } @Override public void releaseControl() { CachedParseState.this.releaseControl(); } @Override public ParseState silent() { return this; } } static class SimpleControl implements Control { private boolean hasCut; @Override public void cut() { this.hasCut = true; } @Override public boolean hasCut() { return this.hasCut; } public void reset() { this.hasCut = false; } } }