src.it.unimi.dsi.bits.LongArrayBitVector Maven / Gradle / Ivy
Show all versions of dsiutils Show documentation
package it.unimi.dsi.bits;
/*
* DSI utilities
*
* Copyright (C) 2007-2018 Sebastiano Vigna
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see .
*
*/
import it.unimi.dsi.fastutil.longs.LongArrays;
import it.unimi.dsi.fastutil.longs.LongBigList;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
/** A bit vector implementation based on arrays of longs.
*
* The main goal of this class is to be fast and flexible. It implements a lightweight,
* fast, open, optimized, reuse-oriented version of bit vectors. Instances of this class
* represent a bit vector an array of longs that is enlarged as needed when new entries
* are created (by dividing the current length by the golden ratio), but is
* never made smaller (even on a {@link #clear()}). Use
* {@link #trim()} for that purpose.
*
*
Besides usual methods for setting and getting bits, this class provides views
* that make it possible to access comfortably the bit vector in different ways: for instance,
* {@link #asLongBigList(int)} provide access as a list of longs, whereas
* {@link #asLongSet()} provides access in setwise form.
*
*
When enlarging the underlying array (e.g., for {@link #append(long, int)} operations or
* add operations on the {@linkplain #asLongBigList(int) big list view}), or when
* invoking {@link #ensureCapacity(long)}, this class calls
* {@link LongArrays#grow(long[], int, int)}, which could enlarge the array more than
* expected. On the contrary, {@link #length(long)} (and the corresponding method in the
* {@linkplain #asLongBigList(int) big list view}) sizes the underlying array in an exact manner.
*
*
Bit numbering follows the right-to-left convention: bit k (counted from the
* right) of word w is bit 64w + k of the overall bit vector.
*
*
If {@link #CHECKS} is true at compile time, boundary checks for all bit operations
* will be compiled in. For maximum speed, you may want to recompile this class with {@link #CHECKS}
* set to false. {@link #CHECKS} is public, so you can check from your code whether you're
* being provided a version with checks or not.
*
*
Warning: A few optional methods have still to be implemented (e.g.,
* adding an element at an arbitrary position using the list view).
*
*
Warning: In some cases, you might want to cache locally the result
* of {@link #bits()} to speed up computations on immutable bit vectors (this is what happens, for instance,
* in static ranking structures). This class, however, does its own serialisation
* of the bit vector: as a result, all cached references to the result of {@link #bits()}
* must be marked as transient and rebuilt at deserialisation
* time, or you will end up saving the bits twice.
*/
public class LongArrayBitVector extends AbstractBitVector implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
public final static int LOG2_BITS_PER_WORD = 6;
public final static int BITS_PER_WORD = 1 << LOG2_BITS_PER_WORD;
public final static int WORD_MASK = BITS_PER_WORD - 1;
public final static int LAST_BIT = BITS_PER_WORD - 1;
public final static long ALL_ONES = 0xFFFFFFFFFFFFFFFFL;
public final static long LAST_BIT_MASK = 1L << LAST_BIT;
/** Whether this class has been compiled with index checks or not. */
public final static boolean CHECKS = true;
private static final boolean ASSERTS = false;
/** The number of bits in this vector. */
protected long length;
/** The backing array of this vector. Bit 0 of the first element contains bit 0 of the bit vector,
* bit 1 of the second element contains bit {@link #BITS_PER_WORD} of the bit vector and so on. */
protected transient long[] bits;
/** Returns the number of words that are necessary to hold the given number of bits.
*
* @param size a number of bits.
* @return the number of words that are necessary to hold the given number of bits.
*/
protected final static int numWords(final long size) {
if (ASSERTS) assert (size + WORD_MASK) >>> LOG2_BITS_PER_WORD <= Integer.MAX_VALUE;
return (int)((size + WORD_MASK) >>> LOG2_BITS_PER_WORD);
}
/** Return the index of the word that holds a bit of specified index.
*
* @param index the index of a bit, or -1.
* @return the index of the word that holds the bit of given index, or -1
* if index
is -1.
*/
protected final static int word(final long index) {
if (ASSERTS) assert index >>> LOG2_BITS_PER_WORD <= Integer.MAX_VALUE;
return (int)(index >>> LOG2_BITS_PER_WORD);
}
/** Returns the inside-word index of the bit that would hold the bit of specified index.
*
*
Note that bit 0 is positioned in word 0, index 0, bit 1 in word 0, index 1, …,
* bit {@link #BITS_PER_WORD} in word 0, index 0, bit {@link #BITS_PER_WORD} + 1 in word 1, index 1,
* and so on.
*
* @param index the index of a bit.
* @return the inside-word index of the bit that would hold the bit of specified index.
*/
protected final static int bit(final long index) {
return (int)(index & WORD_MASK);
}
/** Returns a mask having a 1 exactly at the bit {@link #bit(long) bit(index)}.
*
* @param index the index of a bit
* @return a mask having a 1 exactly at the bit {@link #bit(long) bit(index)}.
*/
protected final static long mask(final long index) {
return 1L << index;
}
protected LongArrayBitVector(final long capacity) {
if (capacity > (long)Integer.MAX_VALUE * Long.SIZE) throw new IndexOutOfBoundsException("In this implementations bit vectors can be at most 2^37 - 64 bits long");
this.bits = capacity > 0 ? new long[numWords(capacity)] : LongArrays.EMPTY_ARRAY;
}
/** Creates a new empty bit vector of given capacity. The
* resulting vector will be able to contain capacity
* bits without reallocations of the backing array.
*
*
Note that this constructor creates an empty bit vector.
* If you want a cleared bit vector of a specified size, please
* use the {@link #ofLength(long)} factory method.
*
* @param capacity the capacity (in bits) of the new bit vector.
* @return a new bit vector of given capacity.
*/
public static LongArrayBitVector getInstance(final long capacity) {
return new LongArrayBitVector(capacity);
}
/** Creates a new empty bit vector. No allocation is actually performed.
* @return a new bit vector with no capacity.
*/
public static LongArrayBitVector getInstance() {
return new LongArrayBitVector(0);
}
/** Creates a new empty bit vector of given length.
*
* @param length the size (in bits) of the new bit vector.
*/
public static LongArrayBitVector ofLength(final long length) {
final LongArrayBitVector bv = new LongArrayBitVector(length);
bv.length = length;
return bv;
}
/** Creates a new bit vector with given bits.
*
* @param bit a list of bits that will be set in the newly created bit vector.
*/
public static LongArrayBitVector of(final int... bit) {
final LongArrayBitVector bitVector = new LongArrayBitVector(bit.length);
for(int b : bit) {
if (b != 0 && b != 1) throw new IllegalArgumentException("Illegal bit value: " + b);
bitVector.add(b);
}
return bitVector;
}
@Override
public long[] bits() {
return bits;
}
@Override
public long length() {
return length;
}
/** Ensures that this bit vector can hold the specified number of bits.
*
*
This method uses {@link LongArrays#grow(long[], int, int)} to
* ensure that there is enough space for the given number of bits. As a
* consequence, the actual length of the long array allocated might be
* larger than expected.
*
* @param numBits the number of bits that this vector must be able to contain.
* @return this bit vector.
*/
public LongArrayBitVector ensureCapacity(final long numBits) {
if (numBits > (long)Integer.MAX_VALUE * Long.SIZE) throw new IndexOutOfBoundsException("In this implementations bit vectors can be at most 2^37 - 64 bits long");
bits = LongArrays.grow(bits, numWords(numBits), numWords(length));
return this;
}
@Override
public LongArrayBitVector length(final long newLength) {
bits = LongArrays.ensureCapacity(bits, numWords(newLength), numWords(length));
final long oldLength = length;
if (newLength < oldLength) fill(newLength, oldLength, false);
length = newLength;
return this;
}
@Override
public void fill(final boolean value) {
final int fullWords = (int)(length / Long.SIZE);
Arrays.fill(bits, 0, fullWords, value ? 0xFFFFFFFFFFFFFFFFL : 0L);
if (length % Long.SIZE != 0) {
if (value) bits[fullWords] = (1L << length % Long.SIZE) - 1;
else bits[fullWords] = 0;
}
}
@Override
public void fill(final long from, final long to, final boolean value) {
if (to / Long.SIZE == from / Long.SIZE) {
if (value) bits[(int)(from / Long.SIZE)] |= (1L << to - from) - 1 << from;
else bits[(int)(from / Long.SIZE)] &= ~((1L << to - from) - 1 << from);
return;
}
Arrays.fill(bits, (int)((from + Long.SIZE - 1) / Long.SIZE), (int)(to / Long.SIZE), value ? -1L : 0L);
if (from % Long.SIZE != 0) {
if (value) bits[(int)(from / Long.SIZE)] |= -1L << from % Long.SIZE;
else bits[(int)(from / Long.SIZE)] &= (1L << from % Long.SIZE) - 1;
}
if (to % Long.SIZE != 0) {
if (value) bits[(int)(to / Long.SIZE)] |= (1L << to % Long.SIZE) - 1;
else bits[(int)(to / Long.SIZE)] &= -1L << to % Long.SIZE;
}
}
@Override
public void flip() {
final int fullWords = (int)(length / Long.SIZE);
for(int i = fullWords; i-- != 0;) bits[i] ^= 0xFFFFFFFFFFFFFFFFL;
if (length % Long.SIZE != 0) bits[fullWords] ^= (1L << length % Long.SIZE) - 1;
}
@Override
public void flip(final long from, final long to) {
if (to / Long.SIZE == from / Long.SIZE) {
bits[(int)(from / Long.SIZE)] ^= (1L << to - from) - 1 << from;
return;
}
final int start = (int)((from + Long.SIZE - 1) / Long.SIZE);
for(int i = (int)(to / Long.SIZE); i-- != start;) bits[i] ^= 0xFFFFFFFFFFFFFFFFL;
if (from % Long.SIZE != 0) bits[(int)(from / Long.SIZE)] ^= -1L << from % Long.SIZE;
if (to % Long.SIZE != 0) bits[(int)(to / Long.SIZE)] ^= (1L << to % Long.SIZE) - 1;
}
/** Reduces as must as possible the size of the backing array.
*
* @return true if some trimming was actually necessary.
*/
public boolean trim() {
if (bits.length == numWords(length)) return false;
bits = LongArrays.setLength(bits, numWords(length));
return true;
}
/** Sets the size of this bit vector to 0.
*
Note that this method does not try to reallocate that backing array.
* If you want to force that behaviour, call {@link #trim()} afterwards.
*/
@Override
public void clear() {
Arrays.fill(bits, 0, word(length - 1) + 1, 0);
length = 0;
}
@Override
public LongArrayBitVector copy(final long from, final long to) {
BitVectors.ensureFromTo(length, from, to);
final LongArrayBitVector copy = new LongArrayBitVector(to - from);
if ((copy.length = to - from) == 0) return copy;
final int numWords = numWords(to - from);
final int startWord = word(from);
final int startBit = bit(from);
if (startBit == 0) {
// If we're copying from the first bit, we just copy the array.
System.arraycopy(bits, startWord, copy.bits, 0, numWords);
final int endBit = bit(to);
if (endBit > 0) copy.bits[numWords - 1] &= (1L << endBit) - 1;
}
else if (startWord == word(to - 1)) {
// Same word, startBit > 0
copy.bits[0] = bits[startWord] >>> startBit & ((1L << to - from) - 1);
}
else {
final int bitsPerWordMinusStartBit = BITS_PER_WORD - startBit;
final long[] bits = this.bits;
final long[] copyBits = copy.bits;
copyBits[0] = bits[startWord] >>> startBit;
for(int word = 1; word < numWords; word++) {
copyBits[word - 1] |= bits[word + startWord] << bitsPerWordMinusStartBit;
copyBits[word] = bits[word + startWord] >>> startBit;
}
final int endBit = bit(to - from);
if (endBit == 0) copyBits[numWords - 1] |= bits[numWords + startWord] << bitsPerWordMinusStartBit;
else {
if (endBit > bitsPerWordMinusStartBit) copyBits[numWords - 1] |= bits[numWords + startWord] << bitsPerWordMinusStartBit;
copyBits[numWords - 1] &= (1L << endBit) - 1;
}
}
return copy;
}
@Override
public LongArrayBitVector copy() {
LongArrayBitVector copy = new LongArrayBitVector(length);
copy.length = length;
System.arraycopy(bits, 0, copy.bits, 0, numWords(length));
return copy;
}
/** Returns this bit vector.
*
* @return this bit vector.
*/
@Override
public LongArrayBitVector fast() {
return this;
}
/** Returns a copy of the given bit vector.
*
*
This method uses {@link BitVector#getLong(long, long)} on {@link Long#SIZE} boundaries to copy at high speed.
*
* @param bv a bit vector.
* @return an instance of this class containing a copy of the given vector.
*/
public static LongArrayBitVector copy(final BitVector bv) {
final long length = bv.length();
final LongArrayBitVector copy = new LongArrayBitVector(length);
final long fullBits = length - length % Long.SIZE;
for(long i = 0; i < fullBits; i += Long.SIZE) copy.bits[(int)(i / Long.SIZE)] = bv.getLong(i, i + Long.SIZE);
if (length % Long.SIZE != 0) copy.bits[(int)(fullBits / Long.SIZE)] = bv.getLong(fullBits, length);
copy.length = length;
return copy;
}
@Override
public boolean getBoolean(final long index) {
if (CHECKS) ensureRestrictedIndex(index);
return (bits[word(index)] & mask(index)) != 0;
}
@Override
public boolean set(final long index, final boolean value) {
if (CHECKS) ensureRestrictedIndex(index);
final int word = word(index);
final long mask = mask(index);
final boolean oldValue = (bits[word] & mask) != 0;
if (value != oldValue) bits[word] ^= mask;
return oldValue;
}
@Override
public void set(final long index) {
if (CHECKS) ensureRestrictedIndex(index);
bits[word(index)] |= mask(index);
}
@Override
public void clear(final long index) {
if (CHECKS) ensureRestrictedIndex(index);
bits[word(index)] &= ~mask(index);
}
@Override
public void add(final long index, final boolean value) {
if (CHECKS) ensureIndex(index);
if (length == (long)bits.length << LOG2_BITS_PER_WORD) bits = LongArrays.grow(bits, numWords(length + 1));
length++;
if (index == length - 1) set(index, value);
else {
final int word = word(index);
final int bit = bit(index);
boolean carry = (bits[word] & LAST_BIT_MASK) != 0, nextCarry;
long t = bits[word];
if (bit == LAST_BIT) t &= ~LAST_BIT_MASK;
else t = (t & - (1L << bit)) << 1 | t & (1L << bit) - 1;
if (value) t |= 1L << bit;
bits[word] = t;
final int numWords = numWords(length);
for(int i = word + 1; i < numWords; i++) {
nextCarry = (bits[i] & LAST_BIT_MASK) != 0;
bits[i] <<= 1;
if (carry) bits[i] |= 1;
carry = nextCarry;
}
}
return;
}
@Override
public boolean removeBoolean(final long index) {
if (CHECKS) ensureRestrictedIndex(index);
final boolean oldValue = getBoolean(index);
final long[] bits = this.bits;
final int word = word(index);
final int bit = bit(index);
bits[word] = (bits[word] & - (1L << bit) << 1) >>> 1 | bits[word] & (1L << bit) - 1;
final int numWords = numWords(length--);
for(int i = word + 1; i < numWords; i++) {
if ((bits[i] & 1) != 0) bits[i - 1] |= LAST_BIT_MASK;
bits[i] >>>= 1;
}
return oldValue;
}
@Override
public LongArrayBitVector append(long value, int width) {
if (width == 0) return this;
if (CHECKS && width < Long.SIZE && (value & -1L << width) != 0) throw new IllegalArgumentException("The specified value (" + value + ") is larger than the maximum value for the given width (" + width + ")");
final long length = this.length;
final int startWord = word(length);
final int startBit = bit(length);
ensureCapacity(length + width);
if (startBit + width <= Long.SIZE) bits[startWord] |= value << startBit;
else {
bits[startWord] |= value << startBit;
bits[startWord + 1] = value >>> BITS_PER_WORD - startBit;
}
this.length += width;
return this;
}
@Override
public long getLong(long from, long to) {
if (CHECKS) BitVectors.ensureFromTo(length, from, to);
final long l = Long.SIZE - (to - from);
final int startWord = word(from);
final int startBit = bit(from);
if (l == Long.SIZE) return 0;
if (startBit <= l) return bits[startWord] << l - startBit >>> l;
return bits[startWord] >>> startBit | bits[startWord + 1] << Long.SIZE + l - startBit >>> l;
}
@Override
public long count() {
long c = 0;
for(int i = numWords(length); i-- != 0;) c += Long.bitCount(bits[i]);
return c;
}
@Override
public long nextOne(final long index) {
if (index >= length) return -1;
final long[] bits = this.bits;
final long words = numWords(length);
final int from = word(index);
final long maskedFirstWord = bits[from] & -(1L << index);
if (maskedFirstWord != 0) return from * BITS_PER_WORD + Long.numberOfTrailingZeros(maskedFirstWord);
for (int i = from + 1; i < words; i++)
if (bits[i] != 0) return i * BITS_PER_WORD + Long.numberOfTrailingZeros(bits[i]);
return -1;
}
@Override
public long previousOne(final long index) {
if (index == 0) return -1;
final long[] bits = this.bits;
final int from = word(index - 1);
final long mask = 1L << index - 1;
final long maskedFirstWord = bits[from] & (mask | mask - 1);
if (maskedFirstWord != 0) return from * BITS_PER_WORD + Fast.mostSignificantBit(maskedFirstWord);
for (int i = from; i-- != 0;)
if (bits[i] != 0) return i * BITS_PER_WORD + Fast.mostSignificantBit(bits[i]);
return -1;
}
@Override
public long nextZero(final long index) {
if (index >= length) return -1;
final long[] bits = this.bits;
final long words = numWords(length);
final int from = word(index);
long maskedFirstWord = bits[from] | (1L << index) - 1;
if (maskedFirstWord != 0xFFFFFFFFFFFFFFFFL) {
final long result = from * BITS_PER_WORD + Long.numberOfTrailingZeros(~maskedFirstWord);
return result >= length ? -1 : result;
}
for (int i = from + 1; i < words; i++)
if (bits[i] != 0xFFFFFFFFFFFFFFFFL) {
final long result = i * BITS_PER_WORD + Long.numberOfTrailingZeros(~bits[i]);
return result >= length ? -1 : result;
}
return -1;
}
@Override
public long previousZero(final long index) {
if (index == 0) return -1;
final long[] bits = this.bits;
final int from = word(index - 1);
long maskedFirstWord = bits[from] | -1L << index;
if (from == word(length - 1)) maskedFirstWord |= -1L << length % Long.SIZE;
if (maskedFirstWord != 0xFFFFFFFFFFFFFFFFL)
return from * BITS_PER_WORD + Fast.mostSignificantBit(~maskedFirstWord);
for (int i = from; i-- != 0;)
if (bits[i] != 0xFFFFFFFFFFFFFFFFL)
return i * BITS_PER_WORD + Fast.mostSignificantBit(~bits[i]);
return -1;
}
@Override
public long longestCommonPrefixLength(final BitVector v) {
if (v instanceof LongArrayBitVector) return longestCommonPrefixLength((LongArrayBitVector)v);
return super.longestCommonPrefixLength(v);
}
public long longestCommonPrefixLength(final LongArrayBitVector v) {
final long minLength = Math.min(v.length(), length());
final long words = (minLength + BITS_PER_WORD - 1) >> LOG2_BITS_PER_WORD;
final long[] bits = this.bits;
final long[] vBits = v.bits;
for (int i = 0; i < words; i++)
if (bits[i] != vBits[i])
return Math.min(minLength, (i << LOG2_BITS_PER_WORD) + Long.numberOfTrailingZeros(bits[i] ^ vBits[i]));
return minLength;
}
@Override
public BitVector and(final BitVector v) {
if (v instanceof LongArrayBitVector) {
LongArrayBitVector l = (LongArrayBitVector)v;
int words = Math.min(numWords(length()), numWords(l.length()));
while(words-- != 0) bits[words] &= l.bits[words];
}
else super.and(v);
return this;
}
@Override
public BitVector or(final BitVector v) {
if (v instanceof LongArrayBitVector) {
LongArrayBitVector l = (LongArrayBitVector)v;
int words = Math.min(numWords(length()), numWords(l.length()));
while(words-- != 0) bits[words] |= l.bits[words];
}
else super.or(v);
return this;
}
@Override
public BitVector xor(final BitVector v) {
if (v instanceof LongArrayBitVector) {
LongArrayBitVector l = (LongArrayBitVector)v;
int words = Math.min(numWords(length()), numWords(l.length()));
while(words-- != 0) bits[words] ^= l.bits[words];
}
else super.xor(v);
return this;
}
/** Wraps the given array of longs in a bit vector for the given number of bits.
*
*
Note that all bits in array
beyond that of index
* size
must be unset, or an exception will be thrown.
*
* @param array an array of longs.
* @param size the number of bits of the newly created bit vector.
* @return a bit vector of size size
using array
as backing array.
*/
public static LongArrayBitVector wrap(final long[] array, final long size) {
if (size > (long)array.length << LOG2_BITS_PER_WORD) throw new IllegalArgumentException("The provided array is too short (" + array.length + " elements) for the given size (" + size + ")");
final LongArrayBitVector result = new LongArrayBitVector(0);
result.length = size;
result.bits = array;
final int arrayLength = array.length;
final int lastWord = (int)(size / Long.SIZE);
if (lastWord < arrayLength && (array[lastWord] & ~ ((1L << size % Long.SIZE) - 1)) != 0) throw new IllegalArgumentException("Garbage beyond size in bit array");
for(int i = lastWord + 1; i < arrayLength; i++) if (array[i] != 0) throw new IllegalArgumentException("Garbage beyond size in bit array");
return result;
}
/** Wraps the given array of longs in a bit vector.
*
* @param array an array of longs.
* @return a bit vector of size array.length * Long.SIZE
using array
as backing array.
*/
public static LongArrayBitVector wrap(final long[] array) {
return wrap(array, (long)array.length * Long.SIZE);
}
/** Returns a cloned copy of this bit vector.
*
*
This method is functionally equivalent to {@link #copy()},
* except that {@link #copy()} trims the backing array.
*
* @return a copy of this bit vector.
*/
@Override
public LongArrayBitVector clone() throws CloneNotSupportedException {
LongArrayBitVector copy = (LongArrayBitVector)super.clone();
copy.bits = bits.clone();
return copy;
}
public LongArrayBitVector replace(final LongArrayBitVector bv) {
ensureCapacity(bv.length);
final long[] bits = this.bits;
final long[] bvBits = bv.bits;
final int bvFirstFreeWord = word(bv.length - 1) + 1;
for(int i = bvFirstFreeWord; i-- != 0;) bits[i] = bvBits[i];
final int thisFirstFreeWord = word(length - 1) + 1;
if (bvFirstFreeWord < thisFirstFreeWord) Arrays.fill(this.bits, bvFirstFreeWord, thisFirstFreeWord, 0);
this.length = bv.length;
return this;
}
@Override
public LongArrayBitVector replace(final BitVector bv) {
final long bvLength = bv.length();
ensureCapacity(bvLength);
final long[] bits = this.bits;
final long fullBits = bvLength - bvLength % Long.SIZE;
for(long i = 0; i < fullBits; i += Long.SIZE) bits[(int)(i / Long.SIZE)] = bv.getLong(i, i + Long.SIZE);
final int bvFirstFreeWord = word(bvLength - 1) + 1;
final int thisFirstFreeWord = word(length - 1) + 1;
if (bvLength % Long.SIZE != 0) bits[(int)(fullBits / Long.SIZE)] = bv.getLong(fullBits, bvLength);
if (bvFirstFreeWord < thisFirstFreeWord) Arrays.fill(this.bits, bvFirstFreeWord, thisFirstFreeWord, 0);
this.length = bvLength;
return this;
}
@Override
public int hashCode() {
long h = 0x9e3779b97f4a7c13L ^ length;
final int numWords = numWords(length);
for(int i = 0; i < numWords; i++) h ^= (h << 5) + bits[i] + (h >>> 2);
if (ASSERTS) assert (int)((h >>> 32) ^ h) == super.hashCode();
return (int)((h >>> 32) ^ h);
}
@Override
public boolean equals(final Object o) {
if (o instanceof LongArrayBitVector) return equals((LongArrayBitVector) o);
return super.equals(o);
}
public boolean equals(final LongArrayBitVector v) {
if (length != v.length()) return false;
int i = numWords(length);
while(i-- != 0) if (bits[i] != v.bits[i]) return false;
return true;
}
public boolean equals(final LongArrayBitVector v, final long start, final long end) {
int startWord = (int)(start >>> LongArrayBitVector.LOG2_BITS_PER_WORD);
final int endWord = (int)(end >>> LongArrayBitVector.LOG2_BITS_PER_WORD);
final int startBit = (int)(start & LongArrayBitVector.WORD_MASK);
final int endBit = (int)(end & LongArrayBitVector.WORD_MASK);
final long[] aBits = bits();
final long[] bBits = v.bits();
if (startWord == endWord) return ((aBits[startWord] ^ bBits[startWord]) & ((1L << (endBit - startBit)) - 1) << startBit) == 0;
if (((aBits[startWord] ^ bBits[startWord++]) & (-1L << startBit)) != 0) return false;
while(startWord < endWord) if (aBits[startWord] != bBits[startWord++]) return false;
return ((aBits[endWord] ^ bBits[endWord]) & (1L << endBit) - 1) == 0;
}
/** A list-of-integers view of a bit vector.
*
*
This class implements in the obvious way a view
* of a bit vector as a list of integers of given width. The vector is enlarged as needed (i.e., when
* adding new elements), but it is never shrunk.
*/
protected static class LongBigListView extends AbstractBitVector.LongBigListView {
private static final long serialVersionUID = 1L;
@SuppressWarnings("hiding")
private final LongArrayBitVector bitVector;
public LongBigListView(final LongArrayBitVector bitVector, final int width) {
super(bitVector, width);
this.bitVector = bitVector;
}
@Override
public boolean add(long value) {
bitVector.append(value, width);
return true;
}
@Override
public long getLong(long index) {
final long start = index * width;
return bitVector.getLong(start, start + width);
}
@Override
public void clear() {
bitVector.clear();
}
@Override
public long set(long index, long value) {
if (width == 0) return 0;
if (width != Long.SIZE && value > fullMask) throw new IllegalArgumentException("Value too large: " + value);
final long bits[] = bitVector.bits;
final long start = index * width;
final int startWord = word(start);
final int endWord = word(start + width - 1);
final int startBit = bit(start);
final long oldValue;
if (startWord == endWord) {
oldValue = bits[startWord] >>> startBit & fullMask;
bits[startWord] &= ~ (fullMask << startBit);
bits[startWord] |= value << startBit;
if (ASSERTS) assert value == (bits[startWord] >>> startBit & fullMask);
}
else {
// Here startBit > 0.
oldValue = bits[startWord] >>> startBit | bits[endWord] << (BITS_PER_WORD - startBit) & fullMask;
bits[startWord] &= (1L << startBit) - 1;
bits[startWord] |= value << startBit;
bits[endWord] &= - (1L << width - BITS_PER_WORD + startBit);
bits[endWord] |= value >>> BITS_PER_WORD - startBit;
if (ASSERTS) assert value == (bits[startWord] >>> startBit | bits[endWord] << (BITS_PER_WORD - startBit) & fullMask);
}
return oldValue;
}
}
@Override
public LongBigList asLongBigList(final int width) {
return new LongBigListView(this, width);
}
private void writeObject(final ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
final int numWords = numWords(length);
for(int i = 0; i < numWords; i++) s.writeLong(bits[i]);
}
private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
final int numWords = numWords(length);
bits = new long[numWords];
for(int i = 0; i < numWords; i++) bits[i] = s.readLong();
}
}