More precisely,
+ *
{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+ *
for all {@code n < 64 * longs.length}.
+ *
+ *
This method is equivalent to + * {@code BitSet.valueOf(LongBuffer.wrap(longs))}. + * + * @param longs a long array containing a little-endian representation + * of a sequence of bits to be used as the initial bits of the + * new bit set + * @return a {@code BitSet} containing all the bits in the long array + * @since 1.7 + */ + public static BitSetRecyclable valueOf(long[] longs) { + int n; + for (n = longs.length; n > 0 && longs[n - 1] == 0; n--) + ; + return new BitSetRecyclable(Arrays.copyOf(longs, n)); + } + + /** + * Returns a new bit set containing all the bits in the given long + * buffer between its position and limit. + * + *
More precisely,
+ *
{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)}
+ *
for all {@code n < 64 * lb.remaining()}.
+ *
+ *
The long buffer is not modified by this method, and no + * reference to the buffer is retained by the bit set. + * + * @param lb a long buffer containing a little-endian representation + * of a sequence of bits between its position and limit, to be + * used as the initial bits of the new bit set + * @return a {@code BitSet} containing all the bits in the buffer in the + * specified range + * @since 1.7 + */ + public static BitSetRecyclable valueOf(LongBuffer lb) { + lb = lb.slice(); + int n; + for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--) + ; + long[] words = new long[n]; + lb.get(words); + return new BitSetRecyclable(words); + } + + /** + * Returns a new bit set containing all the bits in the given byte array. + * + *
More precisely,
+ *
{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+ *
for all {@code n < 8 * bytes.length}.
+ *
+ *
This method is equivalent to + * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}. + * + * @param bytes a byte array containing a little-endian + * representation of a sequence of bits to be used as the + * initial bits of the new bit set + * @return a {@code BitSet} containing all the bits in the byte array + * @since 1.7 + */ + public static BitSetRecyclable valueOf(byte[] bytes) { + return BitSetRecyclable.valueOf(ByteBuffer.wrap(bytes)); + } + + /** + * Returns a new bit set containing all the bits in the given byte + * buffer between its position and limit. + * + *
More precisely,
+ *
{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)}
+ *
for all {@code n < 8 * bb.remaining()}.
+ *
+ *
The byte buffer is not modified by this method, and no + * reference to the buffer is retained by the bit set. + * + * @param bb a byte buffer containing a little-endian representation + * of a sequence of bits between its position and limit, to be + * used as the initial bits of the new bit set + * @return a {@code BitSet} containing all the bits in the buffer in the + * specified range + * @since 1.7 + */ + public static BitSetRecyclable valueOf(ByteBuffer bb) { + bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN); + int n; + for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--) + ; + long[] words = new long[(n + 7) / 8]; + bb.limit(n); + int i = 0; + while (bb.remaining() >= 8) + words[i++] = bb.getLong(); + for (int remaining = bb.remaining(), j = 0; j < remaining; j++) + words[i] |= (bb.get() & 0xffL) << (8 * j); + return new BitSetRecyclable(words); + } + + /** + * Returns a new byte array containing all the bits in this bit set. + * + *
More precisely, if
+ *
{@code byte[] bytes = s.toByteArray();}
+ *
then {@code bytes.length == (s.length()+7)/8} and
+ *
{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+ *
for all {@code n < 8 * bytes.length}.
+ *
+ * @return a byte array containing a little-endian representation
+ * of all the bits in this bit set
+ * @since 1.7
+ */
+ public byte[] toByteArray() {
+ int n = wordsInUse;
+ if (n == 0)
+ return new byte[0];
+ int len = 8 * (n-1);
+ for (long x = words[n - 1]; x != 0; x >>>= 8)
+ len++;
+ byte[] bytes = new byte[len];
+ ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
+ for (int i = 0; i < n - 1; i++)
+ bb.putLong(words[i]);
+ for (long x = words[n - 1]; x != 0; x >>>= 8)
+ bb.put((byte) (x & 0xff));
+ return bytes;
+ }
+
+ /**
+ * Returns a new long array containing all the bits in this bit set.
+ *
+ *
More precisely, if
+ *
{@code long[] longs = s.toLongArray();}
+ *
then {@code longs.length == (s.length()+63)/64} and
+ *
{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+ *
for all {@code n < 64 * longs.length}.
+ *
+ * @return a long array containing a little-endian representation
+ * of all the bits in this bit set
+ * @since 1.7
+ */
+ public long[] toLongArray() {
+ return Arrays.copyOf(words, wordsInUse);
+ }
+
+ /**
+ * Ensures that the BitSet can hold enough words.
+ * @param wordsRequired the minimum acceptable number of words.
+ */
+ private void ensureCapacity(int wordsRequired) {
+ if (words.length < wordsRequired) {
+ // Allocate larger of doubled size or required size
+ int request = Math.max(2 * words.length, wordsRequired);
+ words = Arrays.copyOf(words, request);
+ sizeIsSticky = false;
+ }
+ }
+
+ /**
+ * Ensures that the BitSet can accommodate a given wordIndex,
+ * temporarily violating the invariants. The caller must
+ * restore the invariants before returning to the user,
+ * possibly using recalculateWordsInUse().
+ * @param wordIndex the index to be accommodated.
+ */
+ private void expandTo(int wordIndex) {
+ int wordsRequired = wordIndex+1;
+ if (wordsInUse < wordsRequired) {
+ ensureCapacity(wordsRequired);
+ wordsInUse = wordsRequired;
+ }
+ }
+
+ /**
+ * Checks that fromIndex ... toIndex is a valid range of bit indices.
+ */
+ private static void checkRange(int fromIndex, int toIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+ if (toIndex < 0)
+ throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
+ if (fromIndex > toIndex)
+ throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
+ " > toIndex: " + toIndex);
+ }
+
+ /**
+ * Sets the bit at the specified index to the complement of its
+ * current value.
+ *
+ * @param bitIndex the index of the bit to flip
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @since 1.4
+ */
+ public void flip(int bitIndex) {
+ if (bitIndex < 0)
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+ int wordIndex = wordIndex(bitIndex);
+ expandTo(wordIndex);
+
+ words[wordIndex] ^= (1L << bitIndex);
+
+ recalculateWordsInUse();
+ checkInvariants();
+ }
+
+ /**
+ * Sets each bit from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to the complement of its current
+ * value.
+ *
+ * @param fromIndex index of the first bit to flip
+ * @param toIndex index after the last bit to flip
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+ * or {@code toIndex} is negative, or {@code fromIndex} is
+ * larger than {@code toIndex}
+ * @since 1.4
+ */
+ public void flip(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+
+ if (fromIndex == toIndex)
+ return;
+
+ int startWordIndex = wordIndex(fromIndex);
+ int endWordIndex = wordIndex(toIndex - 1);
+ expandTo(endWordIndex);
+
+ long firstWordMask = WORD_MASK << fromIndex;
+ long lastWordMask = WORD_MASK >>> -toIndex;
+ if (startWordIndex == endWordIndex) {
+ // Case 1: One word
+ words[startWordIndex] ^= (firstWordMask & lastWordMask);
+ } else {
+ // Case 2: Multiple words
+ // Handle first word
+ words[startWordIndex] ^= firstWordMask;
+
+ // Handle intermediate words, if any
+ for (int i = startWordIndex+1; i < endWordIndex; i++)
+ words[i] ^= WORD_MASK;
+
+ // Handle last word
+ words[endWordIndex] ^= lastWordMask;
+ }
+
+ recalculateWordsInUse();
+ checkInvariants();
+ }
+
+ /**
+ * Sets the bit at the specified index to {@code true}.
+ *
+ * @param bitIndex a bit index
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @since JDK1.0
+ */
+ public void set(int bitIndex) {
+ if (bitIndex < 0)
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+ int wordIndex = wordIndex(bitIndex);
+ expandTo(wordIndex);
+
+ words[wordIndex] |= (1L << bitIndex); // Restores invariants
+
+ checkInvariants();
+ }
+
+ /**
+ * Sets the bit at the specified index to the specified value.
+ *
+ * @param bitIndex a bit index
+ * @param value a boolean value to set
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @since 1.4
+ */
+ public 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} is negative,
+ * or {@code toIndex} is negative, or {@code fromIndex} is
+ * larger than {@code toIndex}
+ * @since 1.4
+ */
+ public void set(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+
+ if (fromIndex == toIndex)
+ return;
+
+ // Increase capacity if necessary
+ int startWordIndex = wordIndex(fromIndex);
+ int endWordIndex = wordIndex(toIndex - 1);
+ expandTo(endWordIndex);
+
+ long firstWordMask = WORD_MASK << fromIndex;
+ long lastWordMask = WORD_MASK >>> -toIndex;
+ if (startWordIndex == endWordIndex) {
+ // Case 1: One word
+ words[startWordIndex] |= (firstWordMask & lastWordMask);
+ } else {
+ // Case 2: Multiple words
+ // Handle first word
+ words[startWordIndex] |= firstWordMask;
+
+ // Handle intermediate words, if any
+ for (int i = startWordIndex+1; i < endWordIndex; i++)
+ words[i] = WORD_MASK;
+
+ // Handle last word (restores invariants)
+ words[endWordIndex] |= lastWordMask;
+ }
+
+ checkInvariants();
+ }
+
+ /**
+ * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to the specified value.
+ *
+ * @param fromIndex index of the first bit to be set
+ * @param toIndex index after the last bit to be set
+ * @param value value to set the selected bits to
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+ * or {@code toIndex} is negative, or {@code fromIndex} is
+ * larger than {@code toIndex}
+ * @since 1.4
+ */
+ public void set(int fromIndex, int toIndex, boolean value) {
+ if (value)
+ set(fromIndex, toIndex);
+ else
+ clear(fromIndex, toIndex);
+ }
+
+ /**
+ * Sets the bit specified by the index to {@code false}.
+ *
+ * @param bitIndex the index of the bit to be cleared
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ * @since JDK1.0
+ */
+ public void clear(int bitIndex) {
+ if (bitIndex < 0)
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+ int wordIndex = wordIndex(bitIndex);
+ if (wordIndex >= wordsInUse)
+ return;
+
+ words[wordIndex] &= ~(1L << bitIndex);
+
+ recalculateWordsInUse();
+ checkInvariants();
+ }
+
+ /**
+ * 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} is negative,
+ * or {@code toIndex} is negative, or {@code fromIndex} is
+ * larger than {@code toIndex}
+ * @since 1.4
+ */
+ public void clear(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+
+ if (fromIndex == toIndex)
+ return;
+
+ int startWordIndex = wordIndex(fromIndex);
+ if (startWordIndex >= wordsInUse)
+ return;
+
+ int endWordIndex = wordIndex(toIndex - 1);
+ if (endWordIndex >= wordsInUse) {
+ toIndex = length();
+ endWordIndex = wordsInUse - 1;
+ }
+
+ long firstWordMask = WORD_MASK << fromIndex;
+ long lastWordMask = WORD_MASK >>> -toIndex;
+ if (startWordIndex == endWordIndex) {
+ // Case 1: One word
+ words[startWordIndex] &= ~(firstWordMask & lastWordMask);
+ } else {
+ // Case 2: Multiple words
+ // Handle first word
+ words[startWordIndex] &= ~firstWordMask;
+
+ // Handle intermediate words, if any
+ for (int i = startWordIndex+1; i < endWordIndex; i++)
+ words[i] = 0;
+
+ // Handle last word
+ words[endWordIndex] &= ~lastWordMask;
+ }
+
+ recalculateWordsInUse();
+ checkInvariants();
+ }
+
+ /**
+ * Sets all of the bits in this BitSet to {@code false}.
+ *
+ * @since 1.4
+ */
+ public void clear() {
+ while (wordsInUse > 0)
+ words[--wordsInUse] = 0;
+ }
+
+ /**
+ * Returns the value of the bit with the specified index. The value
+ * is {@code true} if the bit with the index {@code bitIndex}
+ * is currently set in this {@code BitSet}; otherwise, the result
+ * is {@code false}.
+ *
+ * @param bitIndex the bit index
+ * @return the value of the bit with the specified index
+ * @throws IndexOutOfBoundsException if the specified index is negative
+ */
+ public boolean get(int bitIndex) {
+ if (bitIndex < 0)
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+ checkInvariants();
+
+ int wordIndex = wordIndex(bitIndex);
+ return (wordIndex < wordsInUse)
+ && ((words[wordIndex] & (1L << bitIndex)) != 0);
+ }
+
+ /**
+ * Returns a new {@code BitSet} composed of bits from this {@code BitSet}
+ * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
+ *
+ * @param fromIndex index of the first bit to include
+ * @param toIndex index after the last bit to include
+ * @return a new {@code BitSet} from a range of this {@code BitSet}
+ * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+ * or {@code toIndex} is negative, or {@code fromIndex} is
+ * larger than {@code toIndex}
+ * @since 1.4
+ */
+ public BitSetRecyclable get(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+
+ checkInvariants();
+
+ int len = length();
+
+ // If no set bits in range return empty bitset
+ if (len <= fromIndex || fromIndex == toIndex)
+ return new BitSetRecyclable(0);
+
+ // An optimization
+ if (toIndex > len)
+ toIndex = len;
+
+ BitSetRecyclable result = new BitSetRecyclable(toIndex - fromIndex);
+ int targetWords = wordIndex(toIndex - fromIndex - 1) + 1;
+ int sourceIndex = wordIndex(fromIndex);
+ boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0);
+
+ // Process all words but the last word
+ for (int i = 0; i < targetWords - 1; i++, sourceIndex++)
+ result.words[i] = wordAligned ? words[sourceIndex] :
+ (words[sourceIndex] >>> fromIndex) |
+ (words[sourceIndex+1] << -fromIndex);
+
+ // Process the last word
+ long lastWordMask = WORD_MASK >>> -toIndex;
+ result.words[targetWords - 1] =
+ ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK)
+ ? /* straddles source words */
+ ((words[sourceIndex] >>> fromIndex) |
+ (words[sourceIndex+1] & lastWordMask) << -fromIndex)
+ :
+ ((words[sourceIndex] & lastWordMask) >>> fromIndex);
+
+ // Set wordsInUse correctly
+ result.wordsInUse = targetWords;
+ result.recalculateWordsInUse();
+ result.checkInvariants();
+
+ return result;
+ }
+
+ /**
+ * Returns the index of the first bit that is set to {@code true}
+ * that occurs on or after the specified starting index. If no such
+ * bit exists then {@code -1} is returned.
+ *
+ *
To iterate over the {@code true} bits in a {@code BitSet}, + * use the following loop: + * + *
{@code + * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) { + * // operate on index i here + * if (i == Integer.MAX_VALUE) { + * break; // or (i+1) would overflow + * } + * }}+ * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the next set bit, or {@code -1} if there + * is no such bit + * @throws IndexOutOfBoundsException if the specified index is negative + * @since 1.4 + */ + public int nextSetBit(int fromIndex) { + if (fromIndex < 0) + throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); + + checkInvariants(); + + int u = wordIndex(fromIndex); + if (u >= wordsInUse) + return -1; + + long word = words[u] & (WORD_MASK << fromIndex); + + while (true) { + if (word != 0) + return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); + if (++u == wordsInUse) + return -1; + word = words[u]; + } + } + + /** + * Returns the index of the first bit that is set to {@code false} + * that occurs on or after the specified starting index. + * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the next clear bit + * @throws IndexOutOfBoundsException if the specified index is negative + * @since 1.4 + */ + public int nextClearBit(int fromIndex) { + // Neither spec nor implementation handle bitsets of maximal length. + // See 4816253. + if (fromIndex < 0) + throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); + + checkInvariants(); + + int u = wordIndex(fromIndex); + if (u >= wordsInUse) + return fromIndex; + + long word = ~words[u] & (WORD_MASK << fromIndex); + + while (true) { + if (word != 0) + return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); + if (++u == wordsInUse) + return wordsInUse * BITS_PER_WORD; + word = ~words[u]; + } + } + + /** + * Returns the index of the nearest bit that is set to {@code true} + * that occurs on or before the specified starting index. + * If no such bit exists, or if {@code -1} is given as the + * starting index, then {@code -1} is returned. + * + *
To iterate over the {@code true} bits in a {@code BitSet}, + * use the following loop: + * + *
{@code + * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) { + * // operate on index i here + * }}+ * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the previous set bit, or {@code -1} if there + * is no such bit + * @throws IndexOutOfBoundsException if the specified index is less + * than {@code -1} + * @since 1.7 + */ + public int previousSetBit(int fromIndex) { + if (fromIndex < 0) { + if (fromIndex == -1) + return -1; + throw new IndexOutOfBoundsException( + "fromIndex < -1: " + fromIndex); + } + + checkInvariants(); + + int u = wordIndex(fromIndex); + if (u >= wordsInUse) + return length() - 1; + + long word = words[u] & (WORD_MASK >>> -(fromIndex+1)); + + while (true) { + if (word != 0) + return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word); + if (u-- == 0) + return -1; + word = words[u]; + } + } + + /** + * Returns the index of the nearest bit that is set to {@code false} + * that occurs on or before the specified starting index. + * If no such bit exists, or if {@code -1} is given as the + * starting index, then {@code -1} is returned. + * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the previous clear bit, or {@code -1} if there + * is no such bit + * @throws IndexOutOfBoundsException if the specified index is less + * than {@code -1} + * @since 1.7 + */ + public int previousClearBit(int fromIndex) { + if (fromIndex < 0) { + if (fromIndex == -1) + return -1; + throw new IndexOutOfBoundsException( + "fromIndex < -1: " + fromIndex); + } + + checkInvariants(); + + int u = wordIndex(fromIndex); + if (u >= wordsInUse) + return fromIndex; + + long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1)); + + while (true) { + if (word != 0) + return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word); + if (u-- == 0) + return -1; + word = ~words[u]; + } + } + + /** + * Returns the "logical size" of this {@code BitSet}: the index of + * the highest set bit in the {@code BitSet} plus one. Returns zero + * if the {@code BitSet} contains no set bits. + * + * @return the logical size of this {@code BitSet} + * @since 1.2 + */ + public int length() { + if (wordsInUse == 0) + return 0; + + return BITS_PER_WORD * (wordsInUse - 1) + + (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1])); + } + + /** + * Returns true if this {@code BitSet} contains no bits that are set + * to {@code true}. + * + * @return boolean indicating whether this {@code BitSet} is empty + * @since 1.4 + */ + public boolean isEmpty() { + return wordsInUse == 0; + } + + /** + * Returns true if the specified {@code BitSet} has any bits set to + * {@code true} that are also set to {@code true} in this {@code BitSet}. + * + * @param set {@code BitSet} to intersect with + * @return boolean indicating whether this {@code BitSet} intersects + * the specified {@code BitSet} + * @since 1.4 + */ + public boolean intersects(BitSetRecyclable set) { + for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) + if ((words[i] & set.words[i]) != 0) + return true; + return false; + } + + /** + * Returns the number of bits set to {@code true} in this {@code BitSet}. + * + * @return the number of bits set to {@code true} in this {@code BitSet} + * @since 1.4 + */ + public int cardinality() { + int sum = 0; + for (int i = 0; i < wordsInUse; i++) + sum += Long.bitCount(words[i]); + return sum; + } + + /** + * Performs a logical AND of this target bit set with the + * argument bit set. This bit set is modified so that each bit in it + * has the value {@code true} if and only if it both initially + * had the value {@code true} and the corresponding bit in the + * bit set argument also had the value {@code true}. + * + * @param set a bit set + */ + public void and(BitSetRecyclable set) { + if (this == set) + return; + + while (wordsInUse > set.wordsInUse) + words[--wordsInUse] = 0; + + // Perform logical AND on words in common + for (int i = 0; i < wordsInUse; i++) + words[i] &= set.words[i]; + + recalculateWordsInUse(); + checkInvariants(); + } + + /** + * Performs a logical OR of this bit set with the bit set + * argument. This bit set is modified so that a bit in it has the + * value {@code true} if and only if it either already had the + * value {@code true} or the corresponding bit in the bit set + * argument has the value {@code true}. + * + * @param set a bit set + */ + public void or(BitSetRecyclable set) { + if (this == set) + return; + + int wordsInCommon = Math.min(wordsInUse, set.wordsInUse); + + if (wordsInUse < set.wordsInUse) { + ensureCapacity(set.wordsInUse); + wordsInUse = set.wordsInUse; + } + + // Perform logical OR on words in common + for (int i = 0; i < wordsInCommon; i++) + words[i] |= set.words[i]; + + // Copy any remaining words + if (wordsInCommon < set.wordsInUse) + System.arraycopy(set.words, wordsInCommon, + words, wordsInCommon, + wordsInUse - wordsInCommon); + + // recalculateWordsInUse() is unnecessary + checkInvariants(); + } + + /** + * Performs a logical XOR of this bit set with the bit set + * argument. This bit set is modified so that a bit in it has the + * value {@code true} if and only if one of the following + * statements holds: + *
The hash code is defined to be the result of the following + * calculation: + *
{@code + * public int hashCode() { + * long h = 1234; + * long[] words = toLongArray(); + * for (int i = words.length; --i >= 0; ) + * h ^= words[i] * (i + 1); + * return (int)((h >> 32) ^ h); + * }}+ * Note that the hash code changes if the set of bits is altered. + * + * @return the hash code value for this bit set + */ + public int hashCode() { + long h = 1234; + for (int i = wordsInUse; --i >= 0; ) + h ^= words[i] * (i + 1); + + return (int)((h >> 32) ^ h); + } + + /** + * Returns the number of bits of space actually in use by this + * {@code BitSet} to represent bit values. + * The maximum element in the set is the size - 1st element. + * + * @return the number of bits currently in this bit set + */ + public int size() { + return words.length * BITS_PER_WORD; + } + + /** + * Compares this object against the specified object. + * The result is {@code true} if and only if the argument is + * not {@code null} and is a {@code Bitset} object that has + * exactly the same set of bits set to {@code true} as this bit + * set. That is, for every nonnegative {@code int} index {@code k}, + *
((BitSet)obj).get(k) == this.get(k)+ * must be true. The current sizes of the two bit sets are not compared. + * + * @param obj the object to compare with + * @return {@code true} if the objects are the same; + * {@code false} otherwise + * @see #size() + */ + public boolean equals(Object obj) { + if (!(obj instanceof BitSetRecyclable)) + return false; + if (this == obj) + return true; + + BitSetRecyclable set = (BitSetRecyclable) obj; + + checkInvariants(); + set.checkInvariants(); + + if (wordsInUse != set.wordsInUse) + return false; + + // Check words in use by both BitSets + for (int i = 0; i < wordsInUse; i++) + if (words[i] != set.words[i]) + return false; + + return true; + } + + /** + * Cloning this {@code BitSet} produces a new {@code BitSet} + * that is equal to it. + * The clone of the bit set is another bit set that has exactly the + * same bits set to {@code true} as this bit set. + * + * @return a clone of this bit set + * @see #size() + */ + public Object clone() { + if (! sizeIsSticky) + trimToSize(); + + try { + BitSetRecyclable result = (BitSetRecyclable) super.clone(); + result.words = words.clone(); + result.checkInvariants(); + return result; + } catch (CloneNotSupportedException e) { + throw new InternalError(e); + } + } + + /** + * Attempts to reduce internal storage used for the bits in this bit set. + * Calling this method may, but is not required to, affect the value + * returned by a subsequent call to the {@link #size()} method. + */ + private void trimToSize() { + if (wordsInUse != words.length) { + words = Arrays.copyOf(words, wordsInUse); + checkInvariants(); + } + } + + /** + * Save the state of the {@code BitSet} instance to a stream (i.e., + * serialize it). + */ + private void writeObject(ObjectOutputStream s) + throws IOException { + + checkInvariants(); + + if (! sizeIsSticky) + trimToSize(); + + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("bits", words); + s.writeFields(); + } + + /** + * Reconstitute the {@code BitSet} instance from a stream (i.e., + * deserialize it). + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException { + + ObjectInputStream.GetField fields = s.readFields(); + words = (long[]) fields.get("bits", null); + + // Assume maximum length then find real length + // because recalculateWordsInUse assumes maintenance + // or reduction in logical size + wordsInUse = words.length; + recalculateWordsInUse(); + sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic + checkInvariants(); + } + + /** + * Returns a string representation of this bit set. For every index + * for which this {@code BitSet} contains a bit in the set + * state, the decimal representation of that index is included in + * the result. Such indices are listed in order from lowest to + * highest, separated by ", " (a comma and a space) and + * surrounded by braces, resulting in the usual mathematical + * notation for a set of integers. + * + *
Example: + *
+ * BitSet drPepper = new BitSet();+ * Now {@code drPepper.toString()} returns "{@code {}}". + *
+ * drPepper.set(2);+ * Now {@code drPepper.toString()} returns "{@code {2}}". + *
+ * drPepper.set(4); + * drPepper.set(10);+ * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}". + * + * @return a string representation of this bit set + */ + public String toString() { + checkInvariants(); + + int numBits = (wordsInUse > 128) ? + cardinality() : wordsInUse * BITS_PER_WORD; + StringBuilder b = new StringBuilder(6*numBits + 2); + b.append('{'); + + int i = nextSetBit(0); + if (i != -1) { + b.append(i); + while (true) { + if (++i < 0) break; + if ((i = nextSetBit(i)) < 0) break; + int endOfRun = nextClearBit(i); + do { b.append(", ").append(i); } + while (++i != endOfRun); + } + } + + b.append('}'); + return b.toString(); + } + + public BitSetRecyclable resetWords(long[] words) { + int n; + for (n = words.length; n > 0 && words[n - 1] == 0; n--) + ; + long[] longs = Arrays.copyOf(words, n); + this.words = longs; + this.wordsInUse = longs.length; + checkInvariants(); + return this; + } + + private Handle