282 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
	
		
			6.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.util.parsing.packrat;
 | |
| 
 | |
| import com.google.common.annotations.VisibleForTesting;
 | |
| import java.util.Arrays;
 | |
| import java.util.HashMap;
 | |
| import java.util.Map;
 | |
| import net.minecraft.Util;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| public final class Scope {
 | |
| 	private static final int NOT_FOUND = -1;
 | |
| 	private static final Object FRAME_START_MARKER = new Object() {
 | |
| 		public String toString() {
 | |
| 			return "frame";
 | |
| 		}
 | |
| 	};
 | |
| 	private static final int ENTRY_STRIDE = 2;
 | |
| 	private Object[] stack = new Object[128];
 | |
| 	private int topEntryKeyIndex = 0;
 | |
| 	private int topMarkerKeyIndex = 0;
 | |
| 
 | |
| 	public Scope() {
 | |
| 		this.stack[0] = FRAME_START_MARKER;
 | |
| 		this.stack[1] = null;
 | |
| 	}
 | |
| 
 | |
| 	private int valueIndex(Atom<?> name) {
 | |
| 		for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= 2) {
 | |
| 			Object object = this.stack[i];
 | |
| 
 | |
| 			assert object instanceof Atom;
 | |
| 
 | |
| 			if (object == name) {
 | |
| 				return i + 1;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	public int valueIndexForAny(Atom<?>... names) {
 | |
| 		for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= 2) {
 | |
| 			Object object = this.stack[i];
 | |
| 
 | |
| 			assert object instanceof Atom;
 | |
| 
 | |
| 			for (Atom<?> atom : names) {
 | |
| 				if (atom == object) {
 | |
| 					return i + 1;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	private void ensureCapacity(int requiredCapacity) {
 | |
| 		int i = this.stack.length;
 | |
| 		int j = this.topEntryKeyIndex + 1;
 | |
| 		int k = j + requiredCapacity * 2;
 | |
| 		if (k >= i) {
 | |
| 			int l = Util.growByHalf(i, k + 1);
 | |
| 			Object[] objects = new Object[l];
 | |
| 			System.arraycopy(this.stack, 0, objects, 0, i);
 | |
| 			this.stack = objects;
 | |
| 		}
 | |
| 
 | |
| 		assert this.validateStructure();
 | |
| 	}
 | |
| 
 | |
| 	private void setupNewFrame() {
 | |
| 		this.topEntryKeyIndex += 2;
 | |
| 		this.stack[this.topEntryKeyIndex] = FRAME_START_MARKER;
 | |
| 		this.stack[this.topEntryKeyIndex + 1] = this.topMarkerKeyIndex;
 | |
| 		this.topMarkerKeyIndex = this.topEntryKeyIndex;
 | |
| 	}
 | |
| 
 | |
| 	public void pushFrame() {
 | |
| 		this.ensureCapacity(1);
 | |
| 		this.setupNewFrame();
 | |
| 
 | |
| 		assert this.validateStructure();
 | |
| 	}
 | |
| 
 | |
| 	private int getPreviousMarkerIndex(int markerIndex) {
 | |
| 		return (Integer)this.stack[markerIndex + 1];
 | |
| 	}
 | |
| 
 | |
| 	public void popFrame() {
 | |
| 		assert this.topMarkerKeyIndex != 0;
 | |
| 
 | |
| 		this.topEntryKeyIndex = this.topMarkerKeyIndex - 2;
 | |
| 		this.topMarkerKeyIndex = this.getPreviousMarkerIndex(this.topMarkerKeyIndex);
 | |
| 
 | |
| 		assert this.validateStructure();
 | |
| 	}
 | |
| 
 | |
| 	public void splitFrame() {
 | |
| 		int i = this.topMarkerKeyIndex;
 | |
| 		int j = (this.topEntryKeyIndex - this.topMarkerKeyIndex) / 2;
 | |
| 		this.ensureCapacity(j + 1);
 | |
| 		this.setupNewFrame();
 | |
| 		int k = i + 2;
 | |
| 		int l = this.topEntryKeyIndex;
 | |
| 
 | |
| 		for (int m = 0; m < j; m++) {
 | |
| 			l += 2;
 | |
| 			Object object = this.stack[k];
 | |
| 
 | |
| 			assert object != null;
 | |
| 
 | |
| 			this.stack[l] = object;
 | |
| 			this.stack[l + 1] = null;
 | |
| 			k += 2;
 | |
| 		}
 | |
| 
 | |
| 		this.topEntryKeyIndex = l;
 | |
| 
 | |
| 		assert this.validateStructure();
 | |
| 	}
 | |
| 
 | |
| 	public void clearFrameValues() {
 | |
| 		for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= 2) {
 | |
| 			assert this.stack[i] instanceof Atom;
 | |
| 
 | |
| 			this.stack[i + 1] = null;
 | |
| 		}
 | |
| 
 | |
| 		assert this.validateStructure();
 | |
| 	}
 | |
| 
 | |
| 	public void mergeFrame() {
 | |
| 		int i = this.getPreviousMarkerIndex(this.topMarkerKeyIndex);
 | |
| 		int j = i;
 | |
| 		int k = this.topMarkerKeyIndex;
 | |
| 
 | |
| 		while (k < this.topEntryKeyIndex) {
 | |
| 			j += 2;
 | |
| 			k += 2;
 | |
| 			Object object = this.stack[k];
 | |
| 
 | |
| 			assert object instanceof Atom;
 | |
| 
 | |
| 			Object object2 = this.stack[k + 1];
 | |
| 			Object object3 = this.stack[j];
 | |
| 			if (object3 != object) {
 | |
| 				this.stack[j] = object;
 | |
| 				this.stack[j + 1] = object2;
 | |
| 			} else if (object2 != null) {
 | |
| 				this.stack[j + 1] = object2;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		this.topEntryKeyIndex = j;
 | |
| 		this.topMarkerKeyIndex = i;
 | |
| 
 | |
| 		assert this.validateStructure();
 | |
| 	}
 | |
| 
 | |
| 	public <T> void put(Atom<T> atom, @Nullable T value) {
 | |
| 		int i = this.valueIndex(atom);
 | |
| 		if (i != -1) {
 | |
| 			this.stack[i] = value;
 | |
| 		} else {
 | |
| 			this.ensureCapacity(1);
 | |
| 			this.topEntryKeyIndex += 2;
 | |
| 			this.stack[this.topEntryKeyIndex] = atom;
 | |
| 			this.stack[this.topEntryKeyIndex + 1] = value;
 | |
| 		}
 | |
| 
 | |
| 		assert this.validateStructure();
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public <T> T get(Atom<T> atom) {
 | |
| 		int i = this.valueIndex(atom);
 | |
| 		return (T)(i != -1 ? this.stack[i] : null);
 | |
| 	}
 | |
| 
 | |
| 	public <T> T getOrThrow(Atom<T> atom) {
 | |
| 		int i = this.valueIndex(atom);
 | |
| 		if (i == -1) {
 | |
| 			throw new IllegalArgumentException("No value for atom " + atom);
 | |
| 		} else {
 | |
| 			return (T)this.stack[i];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public <T> T getOrDefault(Atom<T> atom, T defaultValue) {
 | |
| 		int i = this.valueIndex(atom);
 | |
| 		return (T)(i != -1 ? this.stack[i] : defaultValue);
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	@SafeVarargs
 | |
| 	public final <T> T getAny(Atom<? extends T>... atoms) {
 | |
| 		int i = this.valueIndexForAny(atoms);
 | |
| 		return (T)(i != -1 ? this.stack[i] : null);
 | |
| 	}
 | |
| 
 | |
| 	@SafeVarargs
 | |
| 	public final <T> T getAnyOrThrow(Atom<? extends T>... atoms) {
 | |
| 		int i = this.valueIndexForAny(atoms);
 | |
| 		if (i == -1) {
 | |
| 			throw new IllegalArgumentException("No value for atoms " + Arrays.toString(atoms));
 | |
| 		} else {
 | |
| 			return (T)this.stack[i];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public String toString() {
 | |
| 		StringBuilder stringBuilder = new StringBuilder();
 | |
| 		boolean bl = true;
 | |
| 
 | |
| 		for (int i = 0; i <= this.topEntryKeyIndex; i += 2) {
 | |
| 			Object object = this.stack[i];
 | |
| 			Object object2 = this.stack[i + 1];
 | |
| 			if (object == FRAME_START_MARKER) {
 | |
| 				stringBuilder.append('|');
 | |
| 				bl = true;
 | |
| 			} else {
 | |
| 				if (!bl) {
 | |
| 					stringBuilder.append(',');
 | |
| 				}
 | |
| 
 | |
| 				bl = false;
 | |
| 				stringBuilder.append(object).append(':').append(object2);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return stringBuilder.toString();
 | |
| 	}
 | |
| 
 | |
| 	@VisibleForTesting
 | |
| 	public Map<Atom<?>, ?> lastFrame() {
 | |
| 		HashMap<Atom<?>, Object> hashMap = new HashMap();
 | |
| 
 | |
| 		for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= 2) {
 | |
| 			Object object = this.stack[i];
 | |
| 			Object object2 = this.stack[i + 1];
 | |
| 			hashMap.put((Atom)object, object2);
 | |
| 		}
 | |
| 
 | |
| 		return hashMap;
 | |
| 	}
 | |
| 
 | |
| 	public boolean hasOnlySingleFrame() {
 | |
| 		for (int i = this.topEntryKeyIndex; i > 0; i--) {
 | |
| 			if (this.stack[i] == FRAME_START_MARKER) {
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (this.stack[0] != FRAME_START_MARKER) {
 | |
| 			throw new IllegalStateException("Corrupted stack");
 | |
| 		} else {
 | |
| 			return true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private boolean validateStructure() {
 | |
| 		assert this.topMarkerKeyIndex >= 0;
 | |
| 
 | |
| 		assert this.topEntryKeyIndex >= this.topMarkerKeyIndex;
 | |
| 
 | |
| 		for (int i = 0; i <= this.topEntryKeyIndex; i += 2) {
 | |
| 			Object object = this.stack[i];
 | |
| 			if (object != FRAME_START_MARKER && !(object instanceof Atom)) {
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		for (int ix = this.topMarkerKeyIndex; ix != 0; ix = this.getPreviousMarkerIndex(ix)) {
 | |
| 			Object object = this.stack[ix];
 | |
| 			if (object != FRAME_START_MARKER) {
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return true;
 | |
| 	}
 | |
| }
 |