That not fast
This commit is contained in:
@@ -1,563 +0,0 @@
|
||||
/*
|
||||
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
|
||||
* Copyright (C) 2012 - Javolution (http://javolution.org/)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software is
|
||||
* freely granted, provided that this notice is preserved.
|
||||
*/
|
||||
package io.akarin.api.internal.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.PrimitiveIterator;
|
||||
import java.util.Spliterator;
|
||||
import java.util.Spliterators;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import io.akarin.api.internal.utils.misc.MathLib;
|
||||
|
||||
/**
|
||||
* A high-performance bit-set integrated with the collection framework as a set of {@link Index indices}
|
||||
* and obeying the collection semantic for methods such as {@link #size} (cardinality) or {@link #equals}
|
||||
* (same set of indices).</p>
|
||||
*
|
||||
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
|
||||
* @version 7.0, September 13, 2015
|
||||
*/
|
||||
public class FastBitSet extends BitSet implements Cloneable, java.io.Serializable {
|
||||
|
||||
private static final long serialVersionUID = 0x700L; // Version.
|
||||
private static final long[] ALL_CLEARED = new long[0];
|
||||
|
||||
/** Holds the bits (64 bits per long). */
|
||||
private long[] bits;
|
||||
|
||||
/**
|
||||
* Creates a new bit-set (all bits cleared).
|
||||
*/
|
||||
public FastBitSet() {
|
||||
bits = ALL_CLEARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logical AND operation on this bit set and the
|
||||
* given bit set. This means it builds the intersection
|
||||
* of the two sets. The result is stored into this bit set.
|
||||
*
|
||||
* @param that the second bit set.
|
||||
*/
|
||||
public final void and(FastBitSet that) {
|
||||
long[] thatBits = that.toLongArray();
|
||||
int n = MathLib.min(this.bits.length, thatBits.length);
|
||||
for (int i = 0; i < n; i++) {
|
||||
this.bits[i] &= thatBits[i];
|
||||
}
|
||||
for (int i = n; i < bits.length; i++) {
|
||||
this.bits[i] = 0L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logical AND operation on this bit set and the
|
||||
* complement of the given bit set. This means it
|
||||
* selects every element in the first set, that isn't in the
|
||||
* second set. The result is stored into this bit set.
|
||||
*
|
||||
* @param that the second bit set
|
||||
*/
|
||||
public final void andNot(FastBitSet that) {
|
||||
long[] thatBits = that.toLongArray();
|
||||
int n = MathLib.min(this.bits.length, thatBits.length);
|
||||
for (int i = 0; i < n; i++) {
|
||||
this.bits[i] &= ~thatBits[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bits set to {@code true} (or the size of this
|
||||
* set).
|
||||
*
|
||||
* @return the number of bits being set.
|
||||
*/
|
||||
public final int cardinality() {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < bits.length; i++) {
|
||||
sum += MathLib.bitCount(bits[i]);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public final void clear() {
|
||||
bits = ALL_CLEARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified integer value from this set. That is
|
||||
* the corresponding bit is cleared.
|
||||
*
|
||||
* @param bitIndex a non-negative integer.
|
||||
* @throws IndexOutOfBoundsException if {@code index < 0}
|
||||
*/
|
||||
public final void clear(int bitIndex) {
|
||||
int longIndex = bitIndex >> 6;
|
||||
if (longIndex >= bits.length)
|
||||
return;
|
||||
bits[longIndex] &= ~(1L << bitIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits from the specified {@code fromIndex} (inclusive) to the
|
||||
* specified {@code toIndex} (exclusive) to {@code false}.
|
||||
*
|
||||
* @param fromIndex index of the first bit to be cleared.
|
||||
* @param toIndex index after the last bit to be cleared.
|
||||
* @throws IndexOutOfBoundsException if
|
||||
* {@code (fromIndex < 0) | (toIndex < fromIndex)}
|
||||
*/
|
||||
public final void clear(int fromIndex, int toIndex) {
|
||||
if ((fromIndex < 0) || (toIndex < fromIndex))
|
||||
throw new IndexOutOfBoundsException();
|
||||
int i = fromIndex >>> 6;
|
||||
if (i >= bits.length)
|
||||
return; // Ensures that i < _length
|
||||
int j = toIndex >>> 6;
|
||||
if (i == j) {
|
||||
bits[i] &= ((1L << fromIndex) - 1) | (-1L << toIndex);
|
||||
return;
|
||||
}
|
||||
bits[i] &= (1L << fromIndex) - 1;
|
||||
if (j < bits.length) {
|
||||
bits[j] &= -1L << toIndex;
|
||||
}
|
||||
for (int k = i + 1; (k < j) && (k < bits.length); k++) {
|
||||
bits[k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final FastBitSet clone() {
|
||||
FastBitSet copy = new FastBitSet();
|
||||
copy.bits = this.bits.clone();
|
||||
return copy;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// BitSet Operations.
|
||||
//
|
||||
|
||||
/**
|
||||
* Sets the bit at the index to the opposite value.
|
||||
*
|
||||
* @param bitIndex the index of the bit.
|
||||
* @throws IndexOutOfBoundsException if {@code bitIndex < 0}
|
||||
*/
|
||||
public final void flip(int bitIndex) {
|
||||
int i = bitIndex >> 6;
|
||||
ensureCapacity(i + 1);
|
||||
bits[i] ^= 1L << bitIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a range of bits to the opposite value.
|
||||
*
|
||||
* @param fromIndex the low index (inclusive).
|
||||
* @param toIndex the high index (exclusive).
|
||||
* @throws IndexOutOfBoundsException if
|
||||
* {@code (fromIndex < 0) | (toIndex < fromIndex)}
|
||||
*/
|
||||
public final void flip(int fromIndex, int toIndex) {
|
||||
if ((fromIndex < 0) || (toIndex < fromIndex))
|
||||
throw new IndexOutOfBoundsException();
|
||||
int i = fromIndex >>> 6;
|
||||
int j = toIndex >>> 6;
|
||||
ensureCapacity(j + 1);
|
||||
if (i == j) {
|
||||
bits[i] ^= (-1L << fromIndex) & ((1L << toIndex) - 1);
|
||||
return;
|
||||
}
|
||||
bits[i] ^= -1L << fromIndex;
|
||||
bits[j] ^= (1L << toIndex) - 1;
|
||||
for (int k = i + 1; k < j; k++) {
|
||||
bits[k] ^= -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true } if the specified integer is in
|
||||
* this bit set; {@code false } otherwise.
|
||||
*
|
||||
* @param bitIndex a non-negative integer.
|
||||
* @return the value of the bit at the specified index.
|
||||
* @throws IndexOutOfBoundsException if {@code bitIndex < 0}
|
||||
*/
|
||||
public final boolean get(int bitIndex) {
|
||||
int i = bitIndex >> 6;
|
||||
return (i >= bits.length) ? false : (bits[i] & (1L << bitIndex)) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new bit set composed of a range of bits from this one.
|
||||
*
|
||||
* @param fromIndex the low index (inclusive).
|
||||
* @param toIndex the high index (exclusive).
|
||||
* @return a context allocated bit set instance.
|
||||
* @throws IndexOutOfBoundsException if
|
||||
* {@code (fromIndex < 0) | (toIndex < fromIndex)}
|
||||
*/
|
||||
public final FastBitSet get(int fromIndex, int toIndex) {
|
||||
if (fromIndex < 0 || fromIndex > toIndex)
|
||||
throw new IndexOutOfBoundsException();
|
||||
FastBitSet bitSet = new FastBitSet();
|
||||
int length = MathLib.min(bits.length, (toIndex >>> 6) + 1);
|
||||
bitSet.bits = new long[length];
|
||||
System.arraycopy(bits, 0, bitSet.bits, 0, length);
|
||||
bitSet.clear(0, fromIndex);
|
||||
bitSet.clear(toIndex, length << 6);
|
||||
return bitSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified bit, returns <code>true</code>
|
||||
* if previously set. */
|
||||
public final boolean getAndSet(int bitIndex, boolean value) {
|
||||
int i = bitIndex >> 6;
|
||||
ensureCapacity(i + 1);
|
||||
boolean previous = (bits[i] & (1L << bitIndex)) != 0;
|
||||
if (value) {
|
||||
bits[i] |= 1L << bitIndex;
|
||||
} else {
|
||||
bits[i] &= ~(1L << bitIndex);
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
|
||||
public int getAny(int index) {
|
||||
return get(index) ? index : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this bit set shares at least one
|
||||
* common bit with the specified bit set.
|
||||
*
|
||||
* @param that the bit set to check for intersection
|
||||
* @return {@code true} if the sets intersect; {@code false} otherwise.
|
||||
*/
|
||||
public final boolean intersects(FastBitSet that) {
|
||||
long[] thatBits = that.toLongArray();
|
||||
int i = MathLib.min(this.bits.length, thatBits.length);
|
||||
while (--i >= 0) {
|
||||
if ((bits[i] & thatBits[i]) != 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logical number of bits actually used by this bit
|
||||
* set. It returns the index of the highest set bit plus one.
|
||||
*
|
||||
* <p> Note: This method does not return the number of set bits
|
||||
* which is returned by {@link #size} </p>
|
||||
*
|
||||
* @return the index of the highest set bit plus one.
|
||||
*/
|
||||
public final int length() {
|
||||
trim();
|
||||
if (bits.length == 0) return 0;
|
||||
return (bits.length << 6) - MathLib.numberOfLeadingZeros(bits[bits.length -1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the next {@code false} bit, from the specified bit
|
||||
* (inclusive).
|
||||
*
|
||||
* @param fromIndex the start location.
|
||||
* @return the first {@code false} bit.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex < 0}
|
||||
*/
|
||||
public final int nextClearBit(int fromIndex) {
|
||||
int offset = fromIndex >> 6;
|
||||
long mask = 1L << fromIndex;
|
||||
while (offset < bits.length) {
|
||||
long h = bits[offset];
|
||||
do {
|
||||
if ((h & mask) == 0) { return fromIndex; }
|
||||
mask <<= 1;
|
||||
fromIndex++;
|
||||
} while (mask != 0);
|
||||
mask = 1;
|
||||
offset++;
|
||||
}
|
||||
return fromIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the next {@code true} bit, from the specified bit
|
||||
* (inclusive). If there is none, {@code -1} is returned.
|
||||
* The following code will iterates through the bit set:[code]
|
||||
* for (int i=nextSetBit(0); i >= 0; i = nextSetBit(i+1)) {
|
||||
* ...
|
||||
* }[/code]
|
||||
*
|
||||
* @param fromIndex the start location.
|
||||
* @return the first {@code false} bit.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex < 0}
|
||||
*/
|
||||
public final int nextSetBit(int fromIndex) {
|
||||
int offset = fromIndex >> 6;
|
||||
long mask = 1L << fromIndex;
|
||||
while (offset < bits.length) {
|
||||
long h = bits[offset];
|
||||
do {
|
||||
if ((h & mask) != 0)
|
||||
return fromIndex;
|
||||
mask <<= 1;
|
||||
fromIndex++;
|
||||
} while (mask != 0);
|
||||
mask = 1;
|
||||
offset++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logical OR operation on this bit set and the one specified.
|
||||
* In other words, builds the union of the two sets.
|
||||
* The result is stored into this bit set.
|
||||
*
|
||||
* @param that the second bit set.
|
||||
*/
|
||||
public final void or(FastBitSet that) {
|
||||
long[] thatBits = (that instanceof FastBitSet) ? ((FastBitSet) that).bits
|
||||
: that.toLongArray();
|
||||
ensureCapacity(thatBits.length);
|
||||
for (int i = thatBits.length; --i >= 0;) {
|
||||
bits[i] |= thatBits[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the previous {@code false} bit,
|
||||
* from the specified bit (inclusive).
|
||||
*
|
||||
* @param fromIndex the start location.
|
||||
* @return the first {@code false} bit.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex < -1}
|
||||
*/
|
||||
public final int previousClearBit(int fromIndex) {
|
||||
int offset = fromIndex >> 6;
|
||||
long mask = 1L << fromIndex;
|
||||
while (offset >= 0) {
|
||||
long h = bits[offset];
|
||||
do {
|
||||
if ((h & mask) == 0)
|
||||
return fromIndex;
|
||||
mask >>= 1;
|
||||
fromIndex--;
|
||||
} while (mask != 0);
|
||||
mask = 1L << 63;
|
||||
offset--;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the previous {@code true} bit, from the
|
||||
* specified bit (inclusive). If there is none, {@code -1} is returned.
|
||||
* The following code will iterates through the bit set:[code]
|
||||
* for (int i = length(); (i = previousSetBit(i-1)) >= 0; ) {
|
||||
* ...
|
||||
* }[/code]
|
||||
*
|
||||
* @param fromIndex the start location.
|
||||
* @return the first {@code false} bit.
|
||||
* @throws IndexOutOfBoundsException if {@code fromIndex < -1}
|
||||
*/
|
||||
public final int previousSetBit(int fromIndex) {
|
||||
int offset = fromIndex >> 6;
|
||||
long mask = 1L << fromIndex;
|
||||
while (offset >= 0) {
|
||||
long h = bits[offset];
|
||||
do {
|
||||
if ((h & mask) != 0)
|
||||
return fromIndex;
|
||||
mask >>= 1;
|
||||
fromIndex--;
|
||||
} while (mask != 0);
|
||||
mask = 1L << 63;
|
||||
offset--;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int removeAny(int index) {
|
||||
return getAndSet(index, false) ? index : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified integer to this set (corresponding bit is set to
|
||||
* {@code true}.
|
||||
*
|
||||
* @param bitIndex a non-negative integer.
|
||||
* @throws IndexOutOfBoundsException if {@code bitIndex < 0}
|
||||
*/
|
||||
public final void set(int bitIndex) {
|
||||
int i = bitIndex >> 6;
|
||||
ensureCapacity(i + 1);
|
||||
bits[i] |= 1L << bitIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bit at the given index to the specified value.
|
||||
*
|
||||
* @param bitIndex the position to set.
|
||||
* @param value the value to set it to.
|
||||
* @throws IndexOutOfBoundsException if {@code bitIndex < 0}
|
||||
*/
|
||||
public final void set(int bitIndex, boolean value) {
|
||||
if (value) {
|
||||
set(bitIndex);
|
||||
} else {
|
||||
clear(bitIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits from the specified {@code fromIndex} (inclusive) to the
|
||||
* specified {@code toIndex} (exclusive) to {@code true}.
|
||||
*
|
||||
* @param fromIndex index of the first bit to be set.
|
||||
* @param toIndex index after the last bit to be set.
|
||||
* @throws IndexOutOfBoundsException if
|
||||
* {@code (fromIndex < 0) | (toIndex < fromIndex)}
|
||||
*/
|
||||
public final void set(int fromIndex, int toIndex) {
|
||||
if ((fromIndex < 0) || (toIndex < fromIndex))
|
||||
throw new IndexOutOfBoundsException();
|
||||
int i = fromIndex >>> 6;
|
||||
int j = toIndex >>> 6;
|
||||
ensureCapacity(j + 1);
|
||||
if (i == j) {
|
||||
bits[i] |= (-1L << fromIndex) & ((1L << toIndex) - 1);
|
||||
return;
|
||||
}
|
||||
bits[i] |= -1L << fromIndex;
|
||||
bits[j] |= (1L << toIndex) - 1;
|
||||
for (int k = i + 1; k < j; k++) {
|
||||
bits[k] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bits between from (inclusive) and to (exclusive) to the
|
||||
* specified value.
|
||||
*
|
||||
* @param fromIndex the start range (inclusive).
|
||||
* @param toIndex the end range (exclusive).
|
||||
* @param value the value to set it to.
|
||||
* @throws IndexOutOfBoundsException if {@code bitIndex < 0}
|
||||
*/
|
||||
public final void set(int fromIndex, int toIndex, boolean value) {
|
||||
if (value) {
|
||||
set(fromIndex, toIndex);
|
||||
} else {
|
||||
clear(fromIndex, toIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public final int size() {
|
||||
return cardinality();
|
||||
}
|
||||
|
||||
/** Returns the minimal length <code>long[]</code> representation of this bitset.
|
||||
*
|
||||
* @return Array of longs representing this bitset
|
||||
*/
|
||||
public final long[] toLongArray() {
|
||||
trim();
|
||||
return bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the logical XOR operation on this bit set and the one specified.
|
||||
* In other words, builds the symmetric remainder of the two sets
|
||||
* (the elements that are in one set, but not in the other).
|
||||
* The result is stored into this bit set.
|
||||
*
|
||||
* @param that the second bit set.
|
||||
*/
|
||||
public final void xor(FastBitSet that) {
|
||||
long[] thatBits = (that instanceof FastBitSet) ? ((FastBitSet) that).bits
|
||||
: that.toLongArray();
|
||||
ensureCapacity(thatBits.length);
|
||||
for (int i = thatBits.length; --i >= 0;) {
|
||||
bits[i] ^= thatBits[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Checks capacity.
|
||||
private void ensureCapacity(int capacity) {
|
||||
if (bits.length < capacity) {
|
||||
bits = Arrays.copyOf(bits, MathLib.max(bits.length * 2, capacity));
|
||||
}
|
||||
}
|
||||
|
||||
// Removes trailing zeros.
|
||||
private void trim() {
|
||||
int n = bits.length;
|
||||
while ((--n >= 0) && (bits[n] == 0L)) {}
|
||||
if (++n != bits.length) { // Trim.
|
||||
bits = Arrays.copyOf(bits, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a stream of indices for which this {@code BitSet}
|
||||
* contains a bit in the set state. The indices are returned
|
||||
* in order, from lowest to highest. The size of the stream
|
||||
* is the number of bits in the set state, equal to the value
|
||||
* returned by the {@link #cardinality()} method.
|
||||
*
|
||||
* <p>The bit set must remain constant during the execution of the
|
||||
* terminal stream operation. Otherwise, the result of the terminal
|
||||
* stream operation is undefined.
|
||||
*
|
||||
* @return a stream of integers representing set indices
|
||||
* @since 1.8
|
||||
*/
|
||||
public IntStream stream() {
|
||||
class BitSetIterator implements PrimitiveIterator.OfInt {
|
||||
int next = nextSetBit(0);
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return next != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextInt() {
|
||||
if (next != -1) {
|
||||
int ret = next;
|
||||
next = nextSetBit(next+1);
|
||||
return ret;
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return StreamSupport.intStream(
|
||||
() -> Spliterators.spliterator(
|
||||
new BitSetIterator(), cardinality(),
|
||||
Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED),
|
||||
Spliterator.SIZED | Spliterator.SUBSIZED |
|
||||
Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED,
|
||||
false);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,8 @@ package net.minecraft.server;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterators;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Iterator;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -24,7 +26,7 @@ public class RegistryID<K> implements Registry {
|
||||
this.b = (K[]) (new Object[i]);
|
||||
this.c = new int[i];
|
||||
this.d = (K[]) (new Object[i]);
|
||||
this.usedIds = new io.akarin.api.internal.utils.FastBitSet(); // Akarin - 1.13 backport
|
||||
this.usedIds = new BitSet(); // Akarin - 1.13 backport
|
||||
}
|
||||
|
||||
public int getId(@Nullable K k0) {
|
||||
|
||||
Reference in New Issue
Block a user