222 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.level.lighting;
 | |
| 
 | |
| import it.unimi.dsi.fastutil.HashCommon;
 | |
| import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap;
 | |
| import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
 | |
| import java.util.NoSuchElementException;
 | |
| import net.minecraft.util.Mth;
 | |
| 
 | |
| public class SpatialLongSet extends LongLinkedOpenHashSet {
 | |
| 	private final SpatialLongSet.InternalMap map;
 | |
| 
 | |
| 	public SpatialLongSet(int expectedSize, float loadFactor) {
 | |
| 		super(expectedSize, loadFactor);
 | |
| 		this.map = new SpatialLongSet.InternalMap(expectedSize / 64, loadFactor);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public boolean add(long l) {
 | |
| 		return this.map.addBit(l);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public boolean rem(long l) {
 | |
| 		return this.map.removeBit(l);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public long removeFirstLong() {
 | |
| 		return this.map.removeFirstBit();
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public int size() {
 | |
| 		throw new UnsupportedOperationException();
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public boolean isEmpty() {
 | |
| 		return this.map.isEmpty();
 | |
| 	}
 | |
| 
 | |
| 	protected static class InternalMap extends Long2LongLinkedOpenHashMap {
 | |
| 		private static final int X_BITS = Mth.log2(60000000);
 | |
| 		private static final int Z_BITS = Mth.log2(60000000);
 | |
| 		private static final int Y_BITS = 64 - X_BITS - Z_BITS;
 | |
| 		private static final int Y_OFFSET = 0;
 | |
| 		private static final int Z_OFFSET = Y_BITS;
 | |
| 		private static final int X_OFFSET = Y_BITS + Z_BITS;
 | |
| 		private static final long OUTER_MASK = 3L << X_OFFSET | 3L | 3L << Z_OFFSET;
 | |
| 		private int lastPos = -1;
 | |
| 		private long lastOuterKey;
 | |
| 		private final int minSize;
 | |
| 
 | |
| 		public InternalMap(int minSize, float loadFactor) {
 | |
| 			super(minSize, loadFactor);
 | |
| 			this.minSize = minSize;
 | |
| 		}
 | |
| 
 | |
| 		static long getOuterKey(long value) {
 | |
| 			return value & ~OUTER_MASK;
 | |
| 		}
 | |
| 
 | |
| 		static int getInnerKey(long value) {
 | |
| 			int i = (int)(value >>> X_OFFSET & 3L);
 | |
| 			int j = (int)(value >>> 0 & 3L);
 | |
| 			int k = (int)(value >>> Z_OFFSET & 3L);
 | |
| 			return i << 4 | k << 2 | j;
 | |
| 		}
 | |
| 
 | |
| 		static long getFullKey(long value, int trailingZeros) {
 | |
| 			value |= (long)(trailingZeros >>> 4 & 3) << X_OFFSET;
 | |
| 			value |= (long)(trailingZeros >>> 2 & 3) << Z_OFFSET;
 | |
| 			return value | (long)(trailingZeros >>> 0 & 3) << 0;
 | |
| 		}
 | |
| 
 | |
| 		public boolean addBit(long value) {
 | |
| 			long l = getOuterKey(value);
 | |
| 			int i = getInnerKey(value);
 | |
| 			long m = 1L << i;
 | |
| 			int j;
 | |
| 			if (l == 0L) {
 | |
| 				if (this.containsNullKey) {
 | |
| 					return this.replaceBit(this.n, m);
 | |
| 				}
 | |
| 
 | |
| 				this.containsNullKey = true;
 | |
| 				j = this.n;
 | |
| 			} else {
 | |
| 				if (this.lastPos != -1 && l == this.lastOuterKey) {
 | |
| 					return this.replaceBit(this.lastPos, m);
 | |
| 				}
 | |
| 
 | |
| 				long[] ls = this.key;
 | |
| 				j = (int)HashCommon.mix(l) & this.mask;
 | |
| 
 | |
| 				for (long n = ls[j]; n != 0L; n = ls[j]) {
 | |
| 					if (n == l) {
 | |
| 						this.lastPos = j;
 | |
| 						this.lastOuterKey = l;
 | |
| 						return this.replaceBit(j, m);
 | |
| 					}
 | |
| 
 | |
| 					j = j + 1 & this.mask;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			this.key[j] = l;
 | |
| 			this.value[j] = m;
 | |
| 			if (this.size == 0) {
 | |
| 				this.first = this.last = j;
 | |
| 				this.link[j] = -1L;
 | |
| 			} else {
 | |
| 				this.link[this.last] = this.link[this.last] ^ (this.link[this.last] ^ j & 4294967295L) & 4294967295L;
 | |
| 				this.link[j] = (this.last & 4294967295L) << 32 | 4294967295L;
 | |
| 				this.last = j;
 | |
| 			}
 | |
| 
 | |
| 			if (this.size++ >= this.maxFill) {
 | |
| 				this.rehash(HashCommon.arraySize(this.size + 1, this.f));
 | |
| 			}
 | |
| 
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		private boolean replaceBit(int index, long value) {
 | |
| 			boolean bl = (this.value[index] & value) != 0L;
 | |
| 			this.value[index] = this.value[index] | value;
 | |
| 			return bl;
 | |
| 		}
 | |
| 
 | |
| 		public boolean removeBit(long value) {
 | |
| 			long l = getOuterKey(value);
 | |
| 			int i = getInnerKey(value);
 | |
| 			long m = 1L << i;
 | |
| 			if (l == 0L) {
 | |
| 				return this.containsNullKey ? this.removeFromNullEntry(m) : false;
 | |
| 			} else if (this.lastPos != -1 && l == this.lastOuterKey) {
 | |
| 				return this.removeFromEntry(this.lastPos, m);
 | |
| 			} else {
 | |
| 				long[] ls = this.key;
 | |
| 				int j = (int)HashCommon.mix(l) & this.mask;
 | |
| 
 | |
| 				for (long n = ls[j]; n != 0L; n = ls[j]) {
 | |
| 					if (l == n) {
 | |
| 						this.lastPos = j;
 | |
| 						this.lastOuterKey = l;
 | |
| 						return this.removeFromEntry(j, m);
 | |
| 					}
 | |
| 
 | |
| 					j = j + 1 & this.mask;
 | |
| 				}
 | |
| 
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private boolean removeFromNullEntry(long value) {
 | |
| 			if ((this.value[this.n] & value) == 0L) {
 | |
| 				return false;
 | |
| 			} else {
 | |
| 				this.value[this.n] = this.value[this.n] & ~value;
 | |
| 				if (this.value[this.n] != 0L) {
 | |
| 					return true;
 | |
| 				} else {
 | |
| 					this.containsNullKey = false;
 | |
| 					this.size--;
 | |
| 					this.fixPointers(this.n);
 | |
| 					if (this.size < this.maxFill / 4 && this.n > 16) {
 | |
| 						this.rehash(this.n / 2);
 | |
| 					}
 | |
| 
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private boolean removeFromEntry(int index, long value) {
 | |
| 			if ((this.value[index] & value) == 0L) {
 | |
| 				return false;
 | |
| 			} else {
 | |
| 				this.value[index] = this.value[index] & ~value;
 | |
| 				if (this.value[index] != 0L) {
 | |
| 					return true;
 | |
| 				} else {
 | |
| 					this.lastPos = -1;
 | |
| 					this.size--;
 | |
| 					this.fixPointers(index);
 | |
| 					this.shiftKeys(index);
 | |
| 					if (this.size < this.maxFill / 4 && this.n > 16) {
 | |
| 						this.rehash(this.n / 2);
 | |
| 					}
 | |
| 
 | |
| 					return true;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public long removeFirstBit() {
 | |
| 			if (this.size == 0) {
 | |
| 				throw new NoSuchElementException();
 | |
| 			} else {
 | |
| 				int i = this.first;
 | |
| 				long l = this.key[i];
 | |
| 				int j = Long.numberOfTrailingZeros(this.value[i]);
 | |
| 				this.value[i] = this.value[i] & ~(1L << j);
 | |
| 				if (this.value[i] == 0L) {
 | |
| 					this.removeFirstLong();
 | |
| 					this.lastPos = -1;
 | |
| 				}
 | |
| 
 | |
| 				return getFullKey(l, j);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void rehash(int i) {
 | |
| 			if (i > this.minSize) {
 | |
| 				super.rehash(i);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |