228 lines
5.6 KiB
Java
228 lines
5.6 KiB
Java
package net.minecraft.util.parsing.packrat;
|
|
|
|
import net.minecraft.Util;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public abstract class CachedParseState<S> implements ParseState<S> {
|
|
private CachedParseState.PositionCache[] positionCache = new CachedParseState.PositionCache[256];
|
|
private final ErrorCollector<S> errorCollector;
|
|
private final Scope scope = new Scope();
|
|
private CachedParseState.SimpleControl[] controlCache = new CachedParseState.SimpleControl[16];
|
|
private int nextControlToReturn;
|
|
private final CachedParseState<S>.Silent silent = new CachedParseState.Silent();
|
|
|
|
protected CachedParseState(ErrorCollector<S> errorCollector) {
|
|
this.errorCollector = errorCollector;
|
|
}
|
|
|
|
@Override
|
|
public Scope scope() {
|
|
return this.scope;
|
|
}
|
|
|
|
@Override
|
|
public ErrorCollector<S> errorCollector() {
|
|
return this.errorCollector;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public <T> T parse(NamedRule<S, T> rule) {
|
|
int i = this.mark();
|
|
CachedParseState.PositionCache positionCache = this.getCacheForPosition(i);
|
|
int j = positionCache.findKeyIndex(rule.name());
|
|
if (j != -1) {
|
|
CachedParseState.CacheEntry<T> 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<T> 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<S> silent() {
|
|
return this.silent;
|
|
}
|
|
|
|
record CacheEntry<T>(@Nullable T value, int markAfterParse) {
|
|
public static final CachedParseState.CacheEntry<?> NEGATIVE = new CachedParseState.CacheEntry(null, -1);
|
|
|
|
public static <T> CachedParseState.CacheEntry<T> negativeEntry() {
|
|
return (CachedParseState.CacheEntry<T>)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 <T> CachedParseState.CacheEntry<T> getValue(int index) {
|
|
return (CachedParseState.CacheEntry<T>)this.atomCache[index + 1];
|
|
}
|
|
|
|
public void setValue(int index, CachedParseState.CacheEntry<?> value) {
|
|
this.atomCache[index + 1] = value;
|
|
}
|
|
}
|
|
|
|
class Silent implements ParseState<S> {
|
|
private final ErrorCollector<S> silentCollector = new ErrorCollector.Nop<>();
|
|
|
|
@Override
|
|
public ErrorCollector<S> errorCollector() {
|
|
return this.silentCollector;
|
|
}
|
|
|
|
@Override
|
|
public Scope scope() {
|
|
return CachedParseState.this.scope();
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public <T> T parse(NamedRule<S, T> 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<S> 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;
|
|
}
|
|
}
|
|
}
|