All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.it.unimi.dsi.bits.LongArrayBitVector Maven / Gradle / Ivy

Go to download

The DSI utilities are a mishmash of classes accumulated during the last twenty years in projects developed at the DSI (Dipartimento di Scienze dell'Informazione, i.e., Information Sciences Department), now DI (Dipartimento di Informatica, i.e., Informatics Department), of the Universita` degli Studi di Milano.

There is a newer version: 2.7.3
Show newest version
package it.unimi.dsi.bits;

/*
 * DSI utilities
 *
 * Copyright (C) 2007-2019 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 java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;

import it.unimi.dsi.fastutil.longs.LongArrays;
import it.unimi.dsi.fastutil.longs.LongBigList;

/** 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 = false; 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(final 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() { final 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(final long value, final int width) { if (width == 0) return this; if (CHECKS) if( 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(final long from, final 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 int from = word(index); final long maskedFirstWord = bits[from] & -(1L << index); if (maskedFirstWord != 0) return from * (long)BITS_PER_WORD + Long.numberOfTrailingZeros(maskedFirstWord); final long words = numWords(length); for (int i = from + 1; i < words; i++) if (bits[i] != 0) return i * (long)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 * (long)BITS_PER_WORD + Fast.mostSignificantBit(maskedFirstWord); for (int i = from; i-- != 0;) if (bits[i] != 0) return i * (long)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); final long maskedFirstWord = bits[from] | (1L << index) - 1; if (maskedFirstWord != 0xFFFFFFFFFFFFFFFFL) { final long result = from * (long)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 * (long)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 * (long)BITS_PER_WORD + Fast.mostSignificantBit(~maskedFirstWord); for (int i = from; i-- != 0;) if (bits[i] != 0xFFFFFFFFFFFFFFFFL) return i * (long)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) { final 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) { final 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) { final 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 { final 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(final long value) { bitVector.append(value, width); return true; } @Override public long getLong(final long index) { final long start = index * width; return bitVector.getLong(start, start + width); } @Override public void clear() { bitVector.clear(); } @Override public long set(final long index, final 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(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy