jtulach@1399: /* jtulach@1399: * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved. jtulach@1399: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jtulach@1399: * jtulach@1399: * This code is free software; you can redistribute it and/or modify it jtulach@1399: * under the terms of the GNU General Public License version 2 only, as jtulach@1399: * published by the Free Software Foundation. Oracle designates this jtulach@1399: * particular file as subject to the "Classpath" exception as provided jtulach@1399: * by Oracle in the LICENSE file that accompanied this code. jtulach@1399: * jtulach@1399: * This code is distributed in the hope that it will be useful, but WITHOUT jtulach@1399: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jtulach@1399: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jtulach@1399: * version 2 for more details (a copy is included in the LICENSE file that jtulach@1399: * accompanied this code). jtulach@1399: * jtulach@1399: * You should have received a copy of the GNU General Public License version jtulach@1399: * 2 along with this work; if not, write to the Free Software Foundation, jtulach@1399: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jtulach@1399: * jtulach@1399: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jtulach@1399: * or visit www.oracle.com if you need additional information or have any jtulach@1399: * questions. jtulach@1399: */ jtulach@1399: jtulach@1399: package java.util; jtulach@1399: jtulach@1399: import java.io.*; jtulach@1399: jtulach@1399: /** jtulach@1399: * This class implements a vector of bits that grows as needed. Each jtulach@1399: * component of the bit set has a {@code boolean} value. The jtulach@1399: * bits of a {@code BitSet} are indexed by nonnegative integers. jtulach@1399: * Individual indexed bits can be examined, set, or cleared. One jtulach@1399: * {@code BitSet} may be used to modify the contents of another jtulach@1399: * {@code BitSet} through logical AND, logical inclusive OR, and jtulach@1399: * logical exclusive OR operations. jtulach@1399: * jtulach@1399: *

By default, all bits in the set initially have the value jtulach@1399: * {@code false}. jtulach@1399: * jtulach@1399: *

Every bit set has a current size, which is the number of bits jtulach@1399: * of space currently in use by the bit set. Note that the size is jtulach@1399: * related to the implementation of a bit set, so it may change with jtulach@1399: * implementation. The length of a bit set relates to logical length jtulach@1399: * of a bit set and is defined independently of implementation. jtulach@1399: * jtulach@1399: *

Unless otherwise noted, passing a null parameter to any of the jtulach@1399: * methods in a {@code BitSet} will result in a jtulach@1399: * {@code NullPointerException}. jtulach@1399: * jtulach@1399: *

A {@code BitSet} is not safe for multithreaded use without jtulach@1399: * external synchronization. jtulach@1399: * jtulach@1399: * @author Arthur van Hoff jtulach@1399: * @author Michael McCloskey jtulach@1399: * @author Martin Buchholz jtulach@1399: * @since JDK1.0 jtulach@1399: */ jtulach@1399: public class BitSet implements Cloneable, java.io.Serializable { jtulach@1399: /* jtulach@1399: * BitSets are packed into arrays of "words." Currently a word is jtulach@1399: * a long, which consists of 64 bits, requiring 6 address bits. jtulach@1399: * The choice of word size is determined purely by performance concerns. jtulach@1399: */ jtulach@1399: private final static int ADDRESS_BITS_PER_WORD = 6; jtulach@1399: private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; jtulach@1399: private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1; jtulach@1399: jtulach@1399: /* Used to shift left or right for a partial word mask */ jtulach@1399: private static final long WORD_MASK = 0xffffffffffffffffL; jtulach@1399: jtulach@1399: /** jtulach@1399: * @serialField bits long[] jtulach@1399: * jtulach@1399: * The bits in this BitSet. The ith bit is stored in bits[i/64] at jtulach@1399: * bit position i % 64 (where bit position 0 refers to the least jtulach@1399: * significant bit and 63 refers to the most significant bit). jtulach@1399: */ jtulach@1399: private static final ObjectStreamField[] serialPersistentFields = { jtulach@1399: new ObjectStreamField("bits", long[].class), jtulach@1399: }; jtulach@1399: jtulach@1399: /** jtulach@1399: * The internal field corresponding to the serialField "bits". jtulach@1399: */ jtulach@1399: private long[] words; jtulach@1399: jtulach@1399: /** jtulach@1399: * The number of words in the logical size of this BitSet. jtulach@1399: */ jtulach@1399: private transient int wordsInUse = 0; jtulach@1399: jtulach@1399: /** jtulach@1399: * Whether the size of "words" is user-specified. If so, we assume jtulach@1399: * the user knows what he's doing and try harder to preserve it. jtulach@1399: */ jtulach@1399: private transient boolean sizeIsSticky = false; jtulach@1399: jtulach@1399: /* use serialVersionUID from JDK 1.0.2 for interoperability */ jtulach@1399: private static final long serialVersionUID = 7997698588986878753L; jtulach@1399: jtulach@1399: /** jtulach@1399: * Given a bit index, return word index containing it. jtulach@1399: */ jtulach@1399: private static int wordIndex(int bitIndex) { jtulach@1399: return bitIndex >> ADDRESS_BITS_PER_WORD; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Every public method must preserve these invariants. jtulach@1399: */ jtulach@1399: private void checkInvariants() { jtulach@1399: assert(wordsInUse == 0 || words[wordsInUse - 1] != 0); jtulach@1399: assert(wordsInUse >= 0 && wordsInUse <= words.length); jtulach@1399: assert(wordsInUse == words.length || words[wordsInUse] == 0); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the field wordsInUse to the logical size in words of the bit set. jtulach@1399: * WARNING:This method assumes that the number of words actually in use is jtulach@1399: * less than or equal to the current value of wordsInUse! jtulach@1399: */ jtulach@1399: private void recalculateWordsInUse() { jtulach@1399: // Traverse the bitset until a used word is found jtulach@1399: int i; jtulach@1399: for (i = wordsInUse-1; i >= 0; i--) jtulach@1399: if (words[i] != 0) jtulach@1399: break; jtulach@1399: jtulach@1399: wordsInUse = i+1; // The new logical size jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Creates a new bit set. All bits are initially {@code false}. jtulach@1399: */ jtulach@1399: public BitSet() { jtulach@1399: initWords(BITS_PER_WORD); jtulach@1399: sizeIsSticky = false; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Creates a bit set whose initial size is large enough to explicitly jtulach@1399: * represent bits with indices in the range {@code 0} through jtulach@1399: * {@code nbits-1}. All bits are initially {@code false}. jtulach@1399: * jtulach@1399: * @param nbits the initial size of the bit set jtulach@1399: * @throws NegativeArraySizeException if the specified initial size jtulach@1399: * is negative jtulach@1399: */ jtulach@1399: public BitSet(int nbits) { jtulach@1399: // nbits can't be negative; size 0 is OK jtulach@1399: if (nbits < 0) jtulach@1399: throw new NegativeArraySizeException("nbits < 0: " + nbits); jtulach@1399: jtulach@1399: initWords(nbits); jtulach@1399: sizeIsSticky = true; jtulach@1399: } jtulach@1399: jtulach@1399: private void initWords(int nbits) { jtulach@1399: words = new long[wordIndex(nbits-1) + 1]; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Creates a bit set using words as the internal representation. jtulach@1399: * The last word (if there is one) must be non-zero. jtulach@1399: */ jtulach@1399: private BitSet(long[] words) { jtulach@1399: this.words = words; jtulach@1399: this.wordsInUse = words.length; jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a new bit set containing all the bits in the given long array. jtulach@1399: * jtulach@1399: *

More precisely, jtulach@1399: *
{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)} jtulach@1399: *
for all {@code n < 64 * longs.length}. jtulach@1399: * jtulach@1399: *

This method is equivalent to jtulach@1399: * {@code BitSet.valueOf(LongBuffer.wrap(longs))}. jtulach@1399: * jtulach@1399: * @param longs a long array containing a little-endian representation jtulach@1399: * of a sequence of bits to be used as the initial bits of the jtulach@1399: * new bit set jtulach@1399: * @since 1.7 jtulach@1399: */ jtulach@1399: public static BitSet valueOf(long[] longs) { jtulach@1399: int n; jtulach@1399: for (n = longs.length; n > 0 && longs[n - 1] == 0; n--) jtulach@1399: ; jtulach@1399: return new BitSet(Arrays.copyOf(longs, n)); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a new bit set containing all the bits in the given long jtulach@1399: * buffer between its position and limit. jtulach@1399: * jtulach@1399: *

More precisely, jtulach@1399: *
{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)} jtulach@1399: *
for all {@code n < 64 * lb.remaining()}. jtulach@1399: * jtulach@1399: *

The long buffer is not modified by this method, and no jtulach@1399: * reference to the buffer is retained by the bit set. jtulach@1399: * jtulach@1399: * @param lb a long buffer containing a little-endian representation jtulach@1399: * of a sequence of bits between its position and limit, to be jtulach@1399: * used as the initial bits of the new bit set jtulach@1399: * @since 1.7 jtulach@1399: */ jaroslav@1401: // public static BitSet valueOf(LongBuffer lb) { jaroslav@1401: // lb = lb.slice(); jaroslav@1401: // int n; jaroslav@1401: // for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--) jaroslav@1401: // ; jaroslav@1401: // long[] words = new long[n]; jaroslav@1401: // lb.get(words); jaroslav@1401: // return new BitSet(words); jaroslav@1401: // } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a new bit set containing all the bits in the given byte array. jtulach@1399: * jtulach@1399: *

More precisely, jtulach@1399: *
{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)} jtulach@1399: *
for all {@code n < 8 * bytes.length}. jtulach@1399: * jtulach@1399: *

This method is equivalent to jtulach@1399: * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}. jtulach@1399: * jtulach@1399: * @param bytes a byte array containing a little-endian jtulach@1399: * representation of a sequence of bits to be used as the jtulach@1399: * initial bits of the new bit set jtulach@1399: * @since 1.7 jtulach@1399: */ jaroslav@1401: // public static BitSet valueOf(byte[] bytes) { jaroslav@1401: // return BitSet.valueOf(ByteBuffer.wrap(bytes)); jaroslav@1401: // } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a new bit set containing all the bits in the given byte jtulach@1399: * buffer between its position and limit. jtulach@1399: * jtulach@1399: *

More precisely, jtulach@1399: *
{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)} jtulach@1399: *
for all {@code n < 8 * bb.remaining()}. jtulach@1399: * jtulach@1399: *

The byte buffer is not modified by this method, and no jtulach@1399: * reference to the buffer is retained by the bit set. jtulach@1399: * jtulach@1399: * @param bb a byte buffer containing a little-endian representation jtulach@1399: * of a sequence of bits between its position and limit, to be jtulach@1399: * used as the initial bits of the new bit set jtulach@1399: * @since 1.7 jtulach@1399: */ jaroslav@1401: // public static BitSet valueOf(ByteBuffer bb) { jaroslav@1401: // bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN); jaroslav@1401: // int n; jaroslav@1401: // for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--) jaroslav@1401: // ; jaroslav@1401: // long[] words = new long[(n + 7) / 8]; jaroslav@1401: // bb.limit(n); jaroslav@1401: // int i = 0; jaroslav@1401: // while (bb.remaining() >= 8) jaroslav@1401: // words[i++] = bb.getLong(); jaroslav@1401: // for (int remaining = bb.remaining(), j = 0; j < remaining; j++) jaroslav@1401: // words[i] |= (bb.get() & 0xffL) << (8 * j); jaroslav@1401: // return new BitSet(words); jaroslav@1401: // } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a new byte array containing all the bits in this bit set. jtulach@1399: * jtulach@1399: *

More precisely, if jtulach@1399: *
{@code byte[] bytes = s.toByteArray();} jtulach@1399: *
then {@code bytes.length == (s.length()+7)/8} and jtulach@1399: *
{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)} jtulach@1399: *
for all {@code n < 8 * bytes.length}. jtulach@1399: * jtulach@1399: * @return a byte array containing a little-endian representation jtulach@1399: * of all the bits in this bit set jtulach@1399: * @since 1.7 jtulach@1399: */ jaroslav@1401: // public byte[] toByteArray() { jaroslav@1401: // int n = wordsInUse; jaroslav@1401: // if (n == 0) jaroslav@1401: // return new byte[0]; jaroslav@1401: // int len = 8 * (n-1); jaroslav@1401: // for (long x = words[n - 1]; x != 0; x >>>= 8) jaroslav@1401: // len++; jaroslav@1401: // byte[] bytes = new byte[len]; jaroslav@1401: // ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); jaroslav@1401: // for (int i = 0; i < n - 1; i++) jaroslav@1401: // bb.putLong(words[i]); jaroslav@1401: // for (long x = words[n - 1]; x != 0; x >>>= 8) jaroslav@1401: // bb.put((byte) (x & 0xff)); jaroslav@1401: // return bytes; jaroslav@1401: // } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a new long array containing all the bits in this bit set. jtulach@1399: * jtulach@1399: *

More precisely, if jtulach@1399: *
{@code long[] longs = s.toLongArray();} jtulach@1399: *
then {@code longs.length == (s.length()+63)/64} and jtulach@1399: *
{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)} jtulach@1399: *
for all {@code n < 64 * longs.length}. jtulach@1399: * jtulach@1399: * @return a long array containing a little-endian representation jtulach@1399: * of all the bits in this bit set jtulach@1399: * @since 1.7 jtulach@1399: */ jtulach@1399: public long[] toLongArray() { jtulach@1399: return Arrays.copyOf(words, wordsInUse); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Ensures that the BitSet can hold enough words. jtulach@1399: * @param wordsRequired the minimum acceptable number of words. jtulach@1399: */ jtulach@1399: private void ensureCapacity(int wordsRequired) { jtulach@1399: if (words.length < wordsRequired) { jtulach@1399: // Allocate larger of doubled size or required size jtulach@1399: int request = Math.max(2 * words.length, wordsRequired); jtulach@1399: words = Arrays.copyOf(words, request); jtulach@1399: sizeIsSticky = false; jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Ensures that the BitSet can accommodate a given wordIndex, jtulach@1399: * temporarily violating the invariants. The caller must jtulach@1399: * restore the invariants before returning to the user, jtulach@1399: * possibly using recalculateWordsInUse(). jtulach@1399: * @param wordIndex the index to be accommodated. jtulach@1399: */ jtulach@1399: private void expandTo(int wordIndex) { jtulach@1399: int wordsRequired = wordIndex+1; jtulach@1399: if (wordsInUse < wordsRequired) { jtulach@1399: ensureCapacity(wordsRequired); jtulach@1399: wordsInUse = wordsRequired; jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Checks that fromIndex ... toIndex is a valid range of bit indices. jtulach@1399: */ jtulach@1399: private static void checkRange(int fromIndex, int toIndex) { jtulach@1399: if (fromIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); jtulach@1399: if (toIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex); jtulach@1399: if (fromIndex > toIndex) jtulach@1399: throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + jtulach@1399: " > toIndex: " + toIndex); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the bit at the specified index to the complement of its jtulach@1399: * current value. jtulach@1399: * jtulach@1399: * @param bitIndex the index of the bit to flip jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is negative jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public void flip(int bitIndex) { jtulach@1399: if (bitIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); jtulach@1399: jtulach@1399: int wordIndex = wordIndex(bitIndex); jtulach@1399: expandTo(wordIndex); jtulach@1399: jtulach@1399: words[wordIndex] ^= (1L << bitIndex); jtulach@1399: jtulach@1399: recalculateWordsInUse(); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets each bit from the specified {@code fromIndex} (inclusive) to the jtulach@1399: * specified {@code toIndex} (exclusive) to the complement of its current jtulach@1399: * value. jtulach@1399: * jtulach@1399: * @param fromIndex index of the first bit to flip jtulach@1399: * @param toIndex index after the last bit to flip jtulach@1399: * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, jtulach@1399: * or {@code toIndex} is negative, or {@code fromIndex} is jtulach@1399: * larger than {@code toIndex} jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public void flip(int fromIndex, int toIndex) { jtulach@1399: checkRange(fromIndex, toIndex); jtulach@1399: jtulach@1399: if (fromIndex == toIndex) jtulach@1399: return; jtulach@1399: jtulach@1399: int startWordIndex = wordIndex(fromIndex); jtulach@1399: int endWordIndex = wordIndex(toIndex - 1); jtulach@1399: expandTo(endWordIndex); jtulach@1399: jtulach@1399: long firstWordMask = WORD_MASK << fromIndex; jtulach@1399: long lastWordMask = WORD_MASK >>> -toIndex; jtulach@1399: if (startWordIndex == endWordIndex) { jtulach@1399: // Case 1: One word jtulach@1399: words[startWordIndex] ^= (firstWordMask & lastWordMask); jtulach@1399: } else { jtulach@1399: // Case 2: Multiple words jtulach@1399: // Handle first word jtulach@1399: words[startWordIndex] ^= firstWordMask; jtulach@1399: jtulach@1399: // Handle intermediate words, if any jtulach@1399: for (int i = startWordIndex+1; i < endWordIndex; i++) jtulach@1399: words[i] ^= WORD_MASK; jtulach@1399: jtulach@1399: // Handle last word jtulach@1399: words[endWordIndex] ^= lastWordMask; jtulach@1399: } jtulach@1399: jtulach@1399: recalculateWordsInUse(); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the bit at the specified index to {@code true}. jtulach@1399: * jtulach@1399: * @param bitIndex a bit index jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is negative jtulach@1399: * @since JDK1.0 jtulach@1399: */ jtulach@1399: public void set(int bitIndex) { jtulach@1399: if (bitIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); jtulach@1399: jtulach@1399: int wordIndex = wordIndex(bitIndex); jtulach@1399: expandTo(wordIndex); jtulach@1399: jtulach@1399: words[wordIndex] |= (1L << bitIndex); // Restores invariants jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the bit at the specified index to the specified value. jtulach@1399: * jtulach@1399: * @param bitIndex a bit index jtulach@1399: * @param value a boolean value to set jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is negative jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public void set(int bitIndex, boolean value) { jtulach@1399: if (value) jtulach@1399: set(bitIndex); jtulach@1399: else jtulach@1399: clear(bitIndex); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the bits from the specified {@code fromIndex} (inclusive) to the jtulach@1399: * specified {@code toIndex} (exclusive) to {@code true}. jtulach@1399: * jtulach@1399: * @param fromIndex index of the first bit to be set jtulach@1399: * @param toIndex index after the last bit to be set jtulach@1399: * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, jtulach@1399: * or {@code toIndex} is negative, or {@code fromIndex} is jtulach@1399: * larger than {@code toIndex} jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public void set(int fromIndex, int toIndex) { jtulach@1399: checkRange(fromIndex, toIndex); jtulach@1399: jtulach@1399: if (fromIndex == toIndex) jtulach@1399: return; jtulach@1399: jtulach@1399: // Increase capacity if necessary jtulach@1399: int startWordIndex = wordIndex(fromIndex); jtulach@1399: int endWordIndex = wordIndex(toIndex - 1); jtulach@1399: expandTo(endWordIndex); jtulach@1399: jtulach@1399: long firstWordMask = WORD_MASK << fromIndex; jtulach@1399: long lastWordMask = WORD_MASK >>> -toIndex; jtulach@1399: if (startWordIndex == endWordIndex) { jtulach@1399: // Case 1: One word jtulach@1399: words[startWordIndex] |= (firstWordMask & lastWordMask); jtulach@1399: } else { jtulach@1399: // Case 2: Multiple words jtulach@1399: // Handle first word jtulach@1399: words[startWordIndex] |= firstWordMask; jtulach@1399: jtulach@1399: // Handle intermediate words, if any jtulach@1399: for (int i = startWordIndex+1; i < endWordIndex; i++) jtulach@1399: words[i] = WORD_MASK; jtulach@1399: jtulach@1399: // Handle last word (restores invariants) jtulach@1399: words[endWordIndex] |= lastWordMask; jtulach@1399: } jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the bits from the specified {@code fromIndex} (inclusive) to the jtulach@1399: * specified {@code toIndex} (exclusive) to the specified value. jtulach@1399: * jtulach@1399: * @param fromIndex index of the first bit to be set jtulach@1399: * @param toIndex index after the last bit to be set jtulach@1399: * @param value value to set the selected bits to jtulach@1399: * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, jtulach@1399: * or {@code toIndex} is negative, or {@code fromIndex} is jtulach@1399: * larger than {@code toIndex} jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public void set(int fromIndex, int toIndex, boolean value) { jtulach@1399: if (value) jtulach@1399: set(fromIndex, toIndex); jtulach@1399: else jtulach@1399: clear(fromIndex, toIndex); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the bit specified by the index to {@code false}. jtulach@1399: * jtulach@1399: * @param bitIndex the index of the bit to be cleared jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is negative jtulach@1399: * @since JDK1.0 jtulach@1399: */ jtulach@1399: public void clear(int bitIndex) { jtulach@1399: if (bitIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); jtulach@1399: jtulach@1399: int wordIndex = wordIndex(bitIndex); jtulach@1399: if (wordIndex >= wordsInUse) jtulach@1399: return; jtulach@1399: jtulach@1399: words[wordIndex] &= ~(1L << bitIndex); jtulach@1399: jtulach@1399: recalculateWordsInUse(); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets the bits from the specified {@code fromIndex} (inclusive) to the jtulach@1399: * specified {@code toIndex} (exclusive) to {@code false}. jtulach@1399: * jtulach@1399: * @param fromIndex index of the first bit to be cleared jtulach@1399: * @param toIndex index after the last bit to be cleared jtulach@1399: * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, jtulach@1399: * or {@code toIndex} is negative, or {@code fromIndex} is jtulach@1399: * larger than {@code toIndex} jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public void clear(int fromIndex, int toIndex) { jtulach@1399: checkRange(fromIndex, toIndex); jtulach@1399: jtulach@1399: if (fromIndex == toIndex) jtulach@1399: return; jtulach@1399: jtulach@1399: int startWordIndex = wordIndex(fromIndex); jtulach@1399: if (startWordIndex >= wordsInUse) jtulach@1399: return; jtulach@1399: jtulach@1399: int endWordIndex = wordIndex(toIndex - 1); jtulach@1399: if (endWordIndex >= wordsInUse) { jtulach@1399: toIndex = length(); jtulach@1399: endWordIndex = wordsInUse - 1; jtulach@1399: } jtulach@1399: jtulach@1399: long firstWordMask = WORD_MASK << fromIndex; jtulach@1399: long lastWordMask = WORD_MASK >>> -toIndex; jtulach@1399: if (startWordIndex == endWordIndex) { jtulach@1399: // Case 1: One word jtulach@1399: words[startWordIndex] &= ~(firstWordMask & lastWordMask); jtulach@1399: } else { jtulach@1399: // Case 2: Multiple words jtulach@1399: // Handle first word jtulach@1399: words[startWordIndex] &= ~firstWordMask; jtulach@1399: jtulach@1399: // Handle intermediate words, if any jtulach@1399: for (int i = startWordIndex+1; i < endWordIndex; i++) jtulach@1399: words[i] = 0; jtulach@1399: jtulach@1399: // Handle last word jtulach@1399: words[endWordIndex] &= ~lastWordMask; jtulach@1399: } jtulach@1399: jtulach@1399: recalculateWordsInUse(); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Sets all of the bits in this BitSet to {@code false}. jtulach@1399: * jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public void clear() { jtulach@1399: while (wordsInUse > 0) jtulach@1399: words[--wordsInUse] = 0; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the value of the bit with the specified index. The value jtulach@1399: * is {@code true} if the bit with the index {@code bitIndex} jtulach@1399: * is currently set in this {@code BitSet}; otherwise, the result jtulach@1399: * is {@code false}. jtulach@1399: * jtulach@1399: * @param bitIndex the bit index jtulach@1399: * @return the value of the bit with the specified index jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is negative jtulach@1399: */ jtulach@1399: public boolean get(int bitIndex) { jtulach@1399: if (bitIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: int wordIndex = wordIndex(bitIndex); jtulach@1399: return (wordIndex < wordsInUse) jtulach@1399: && ((words[wordIndex] & (1L << bitIndex)) != 0); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a new {@code BitSet} composed of bits from this {@code BitSet} jtulach@1399: * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive). jtulach@1399: * jtulach@1399: * @param fromIndex index of the first bit to include jtulach@1399: * @param toIndex index after the last bit to include jtulach@1399: * @return a new {@code BitSet} from a range of this {@code BitSet} jtulach@1399: * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, jtulach@1399: * or {@code toIndex} is negative, or {@code fromIndex} is jtulach@1399: * larger than {@code toIndex} jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public BitSet get(int fromIndex, int toIndex) { jtulach@1399: checkRange(fromIndex, toIndex); jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: int len = length(); jtulach@1399: jtulach@1399: // If no set bits in range return empty bitset jtulach@1399: if (len <= fromIndex || fromIndex == toIndex) jtulach@1399: return new BitSet(0); jtulach@1399: jtulach@1399: // An optimization jtulach@1399: if (toIndex > len) jtulach@1399: toIndex = len; jtulach@1399: jtulach@1399: BitSet result = new BitSet(toIndex - fromIndex); jtulach@1399: int targetWords = wordIndex(toIndex - fromIndex - 1) + 1; jtulach@1399: int sourceIndex = wordIndex(fromIndex); jtulach@1399: boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0); jtulach@1399: jtulach@1399: // Process all words but the last word jtulach@1399: for (int i = 0; i < targetWords - 1; i++, sourceIndex++) jtulach@1399: result.words[i] = wordAligned ? words[sourceIndex] : jtulach@1399: (words[sourceIndex] >>> fromIndex) | jtulach@1399: (words[sourceIndex+1] << -fromIndex); jtulach@1399: jtulach@1399: // Process the last word jtulach@1399: long lastWordMask = WORD_MASK >>> -toIndex; jtulach@1399: result.words[targetWords - 1] = jtulach@1399: ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK) jtulach@1399: ? /* straddles source words */ jtulach@1399: ((words[sourceIndex] >>> fromIndex) | jtulach@1399: (words[sourceIndex+1] & lastWordMask) << -fromIndex) jtulach@1399: : jtulach@1399: ((words[sourceIndex] & lastWordMask) >>> fromIndex); jtulach@1399: jtulach@1399: // Set wordsInUse correctly jtulach@1399: result.wordsInUse = targetWords; jtulach@1399: result.recalculateWordsInUse(); jtulach@1399: result.checkInvariants(); jtulach@1399: jtulach@1399: return result; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the index of the first bit that is set to {@code true} jtulach@1399: * that occurs on or after the specified starting index. If no such jtulach@1399: * bit exists then {@code -1} is returned. jtulach@1399: * jtulach@1399: *

To iterate over the {@code true} bits in a {@code BitSet}, jtulach@1399: * use the following loop: jtulach@1399: * jtulach@1399: *

 {@code
jtulach@1399:      * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
jtulach@1399:      *     // operate on index i here
jtulach@1399:      * }}
jtulach@1399: * jtulach@1399: * @param fromIndex the index to start checking from (inclusive) jtulach@1399: * @return the index of the next set bit, or {@code -1} if there jtulach@1399: * is no such bit jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is negative jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public int nextSetBit(int fromIndex) { jtulach@1399: if (fromIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: int u = wordIndex(fromIndex); jtulach@1399: if (u >= wordsInUse) jtulach@1399: return -1; jtulach@1399: jtulach@1399: long word = words[u] & (WORD_MASK << fromIndex); jtulach@1399: jtulach@1399: while (true) { jtulach@1399: if (word != 0) jtulach@1399: return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); jtulach@1399: if (++u == wordsInUse) jtulach@1399: return -1; jtulach@1399: word = words[u]; jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the index of the first bit that is set to {@code false} jtulach@1399: * that occurs on or after the specified starting index. jtulach@1399: * jtulach@1399: * @param fromIndex the index to start checking from (inclusive) jtulach@1399: * @return the index of the next clear bit jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is negative jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public int nextClearBit(int fromIndex) { jtulach@1399: // Neither spec nor implementation handle bitsets of maximal length. jtulach@1399: // See 4816253. jtulach@1399: if (fromIndex < 0) jtulach@1399: throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: int u = wordIndex(fromIndex); jtulach@1399: if (u >= wordsInUse) jtulach@1399: return fromIndex; jtulach@1399: jtulach@1399: long word = ~words[u] & (WORD_MASK << fromIndex); jtulach@1399: jtulach@1399: while (true) { jtulach@1399: if (word != 0) jtulach@1399: return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); jtulach@1399: if (++u == wordsInUse) jtulach@1399: return wordsInUse * BITS_PER_WORD; jtulach@1399: word = ~words[u]; jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the index of the nearest bit that is set to {@code true} jtulach@1399: * that occurs on or before the specified starting index. jtulach@1399: * If no such bit exists, or if {@code -1} is given as the jtulach@1399: * starting index, then {@code -1} is returned. jtulach@1399: * jtulach@1399: *

To iterate over the {@code true} bits in a {@code BitSet}, jtulach@1399: * use the following loop: jtulach@1399: * jtulach@1399: *

 {@code
jtulach@1399:      * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
jtulach@1399:      *     // operate on index i here
jtulach@1399:      * }}
jtulach@1399: * jtulach@1399: * @param fromIndex the index to start checking from (inclusive) jtulach@1399: * @return the index of the previous set bit, or {@code -1} if there jtulach@1399: * is no such bit jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is less jtulach@1399: * than {@code -1} jtulach@1399: * @since 1.7 jtulach@1399: */ jtulach@1399: public int previousSetBit(int fromIndex) { jtulach@1399: if (fromIndex < 0) { jtulach@1399: if (fromIndex == -1) jtulach@1399: return -1; jtulach@1399: throw new IndexOutOfBoundsException( jtulach@1399: "fromIndex < -1: " + fromIndex); jtulach@1399: } jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: int u = wordIndex(fromIndex); jtulach@1399: if (u >= wordsInUse) jtulach@1399: return length() - 1; jtulach@1399: jtulach@1399: long word = words[u] & (WORD_MASK >>> -(fromIndex+1)); jtulach@1399: jtulach@1399: while (true) { jtulach@1399: if (word != 0) jtulach@1399: return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word); jtulach@1399: if (u-- == 0) jtulach@1399: return -1; jtulach@1399: word = words[u]; jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the index of the nearest bit that is set to {@code false} jtulach@1399: * that occurs on or before the specified starting index. jtulach@1399: * If no such bit exists, or if {@code -1} is given as the jtulach@1399: * starting index, then {@code -1} is returned. jtulach@1399: * jtulach@1399: * @param fromIndex the index to start checking from (inclusive) jtulach@1399: * @return the index of the previous clear bit, or {@code -1} if there jtulach@1399: * is no such bit jtulach@1399: * @throws IndexOutOfBoundsException if the specified index is less jtulach@1399: * than {@code -1} jtulach@1399: * @since 1.7 jtulach@1399: */ jtulach@1399: public int previousClearBit(int fromIndex) { jtulach@1399: if (fromIndex < 0) { jtulach@1399: if (fromIndex == -1) jtulach@1399: return -1; jtulach@1399: throw new IndexOutOfBoundsException( jtulach@1399: "fromIndex < -1: " + fromIndex); jtulach@1399: } jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: int u = wordIndex(fromIndex); jtulach@1399: if (u >= wordsInUse) jtulach@1399: return fromIndex; jtulach@1399: jtulach@1399: long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1)); jtulach@1399: jtulach@1399: while (true) { jtulach@1399: if (word != 0) jtulach@1399: return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word); jtulach@1399: if (u-- == 0) jtulach@1399: return -1; jtulach@1399: word = ~words[u]; jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the "logical size" of this {@code BitSet}: the index of jtulach@1399: * the highest set bit in the {@code BitSet} plus one. Returns zero jtulach@1399: * if the {@code BitSet} contains no set bits. jtulach@1399: * jtulach@1399: * @return the logical size of this {@code BitSet} jtulach@1399: * @since 1.2 jtulach@1399: */ jtulach@1399: public int length() { jtulach@1399: if (wordsInUse == 0) jtulach@1399: return 0; jtulach@1399: jtulach@1399: return BITS_PER_WORD * (wordsInUse - 1) + jtulach@1399: (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1])); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns true if this {@code BitSet} contains no bits that are set jtulach@1399: * to {@code true}. jtulach@1399: * jtulach@1399: * @return boolean indicating whether this {@code BitSet} is empty jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public boolean isEmpty() { jtulach@1399: return wordsInUse == 0; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns true if the specified {@code BitSet} has any bits set to jtulach@1399: * {@code true} that are also set to {@code true} in this {@code BitSet}. jtulach@1399: * jtulach@1399: * @param set {@code BitSet} to intersect with jtulach@1399: * @return boolean indicating whether this {@code BitSet} intersects jtulach@1399: * the specified {@code BitSet} jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public boolean intersects(BitSet set) { jtulach@1399: for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) jtulach@1399: if ((words[i] & set.words[i]) != 0) jtulach@1399: return true; jtulach@1399: return false; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the number of bits set to {@code true} in this {@code BitSet}. jtulach@1399: * jtulach@1399: * @return the number of bits set to {@code true} in this {@code BitSet} jtulach@1399: * @since 1.4 jtulach@1399: */ jtulach@1399: public int cardinality() { jtulach@1399: int sum = 0; jtulach@1399: for (int i = 0; i < wordsInUse; i++) jtulach@1399: sum += Long.bitCount(words[i]); jtulach@1399: return sum; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Performs a logical AND of this target bit set with the jtulach@1399: * argument bit set. This bit set is modified so that each bit in it jtulach@1399: * has the value {@code true} if and only if it both initially jtulach@1399: * had the value {@code true} and the corresponding bit in the jtulach@1399: * bit set argument also had the value {@code true}. jtulach@1399: * jtulach@1399: * @param set a bit set jtulach@1399: */ jtulach@1399: public void and(BitSet set) { jtulach@1399: if (this == set) jtulach@1399: return; jtulach@1399: jtulach@1399: while (wordsInUse > set.wordsInUse) jtulach@1399: words[--wordsInUse] = 0; jtulach@1399: jtulach@1399: // Perform logical AND on words in common jtulach@1399: for (int i = 0; i < wordsInUse; i++) jtulach@1399: words[i] &= set.words[i]; jtulach@1399: jtulach@1399: recalculateWordsInUse(); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Performs a logical OR of this bit set with the bit set jtulach@1399: * argument. This bit set is modified so that a bit in it has the jtulach@1399: * value {@code true} if and only if it either already had the jtulach@1399: * value {@code true} or the corresponding bit in the bit set jtulach@1399: * argument has the value {@code true}. jtulach@1399: * jtulach@1399: * @param set a bit set jtulach@1399: */ jtulach@1399: public void or(BitSet set) { jtulach@1399: if (this == set) jtulach@1399: return; jtulach@1399: jtulach@1399: int wordsInCommon = Math.min(wordsInUse, set.wordsInUse); jtulach@1399: jtulach@1399: if (wordsInUse < set.wordsInUse) { jtulach@1399: ensureCapacity(set.wordsInUse); jtulach@1399: wordsInUse = set.wordsInUse; jtulach@1399: } jtulach@1399: jtulach@1399: // Perform logical OR on words in common jtulach@1399: for (int i = 0; i < wordsInCommon; i++) jtulach@1399: words[i] |= set.words[i]; jtulach@1399: jtulach@1399: // Copy any remaining words jtulach@1399: if (wordsInCommon < set.wordsInUse) jtulach@1399: System.arraycopy(set.words, wordsInCommon, jtulach@1399: words, wordsInCommon, jtulach@1399: wordsInUse - wordsInCommon); jtulach@1399: jtulach@1399: // recalculateWordsInUse() is unnecessary jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Performs a logical XOR of this bit set with the bit set jtulach@1399: * argument. This bit set is modified so that a bit in it has the jtulach@1399: * value {@code true} if and only if one of the following jtulach@1399: * statements holds: jtulach@1399: * jtulach@1399: * jtulach@1399: * @param set a bit set jtulach@1399: */ jtulach@1399: public void xor(BitSet set) { jtulach@1399: int wordsInCommon = Math.min(wordsInUse, set.wordsInUse); jtulach@1399: jtulach@1399: if (wordsInUse < set.wordsInUse) { jtulach@1399: ensureCapacity(set.wordsInUse); jtulach@1399: wordsInUse = set.wordsInUse; jtulach@1399: } jtulach@1399: jtulach@1399: // Perform logical XOR on words in common jtulach@1399: for (int i = 0; i < wordsInCommon; i++) jtulach@1399: words[i] ^= set.words[i]; jtulach@1399: jtulach@1399: // Copy any remaining words jtulach@1399: if (wordsInCommon < set.wordsInUse) jtulach@1399: System.arraycopy(set.words, wordsInCommon, jtulach@1399: words, wordsInCommon, jtulach@1399: set.wordsInUse - wordsInCommon); jtulach@1399: jtulach@1399: recalculateWordsInUse(); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Clears all of the bits in this {@code BitSet} whose corresponding jtulach@1399: * bit is set in the specified {@code BitSet}. jtulach@1399: * jtulach@1399: * @param set the {@code BitSet} with which to mask this jtulach@1399: * {@code BitSet} jtulach@1399: * @since 1.2 jtulach@1399: */ jtulach@1399: public void andNot(BitSet set) { jtulach@1399: // Perform logical (a & !b) on words in common jtulach@1399: for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) jtulach@1399: words[i] &= ~set.words[i]; jtulach@1399: jtulach@1399: recalculateWordsInUse(); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the hash code value for this bit set. The hash code depends jtulach@1399: * only on which bits are set within this {@code BitSet}. jtulach@1399: * jtulach@1399: *

The hash code is defined to be the result of the following jtulach@1399: * calculation: jtulach@1399: *

 {@code
jtulach@1399:      * public int hashCode() {
jtulach@1399:      *     long h = 1234;
jtulach@1399:      *     long[] words = toLongArray();
jtulach@1399:      *     for (int i = words.length; --i >= 0; )
jtulach@1399:      *         h ^= words[i] * (i + 1);
jtulach@1399:      *     return (int)((h >> 32) ^ h);
jtulach@1399:      * }}
jtulach@1399: * Note that the hash code changes if the set of bits is altered. jtulach@1399: * jtulach@1399: * @return the hash code value for this bit set jtulach@1399: */ jtulach@1399: public int hashCode() { jtulach@1399: long h = 1234; jtulach@1399: for (int i = wordsInUse; --i >= 0; ) jtulach@1399: h ^= words[i] * (i + 1); jtulach@1399: jtulach@1399: return (int)((h >> 32) ^ h); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns the number of bits of space actually in use by this jtulach@1399: * {@code BitSet} to represent bit values. jtulach@1399: * The maximum element in the set is the size - 1st element. jtulach@1399: * jtulach@1399: * @return the number of bits currently in this bit set jtulach@1399: */ jtulach@1399: public int size() { jtulach@1399: return words.length * BITS_PER_WORD; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Compares this object against the specified object. jtulach@1399: * The result is {@code true} if and only if the argument is jtulach@1399: * not {@code null} and is a {@code Bitset} object that has jtulach@1399: * exactly the same set of bits set to {@code true} as this bit jtulach@1399: * set. That is, for every nonnegative {@code int} index {@code k}, jtulach@1399: *
((BitSet)obj).get(k) == this.get(k)
jtulach@1399: * must be true. The current sizes of the two bit sets are not compared. jtulach@1399: * jtulach@1399: * @param obj the object to compare with jtulach@1399: * @return {@code true} if the objects are the same; jtulach@1399: * {@code false} otherwise jtulach@1399: * @see #size() jtulach@1399: */ jtulach@1399: public boolean equals(Object obj) { jtulach@1399: if (!(obj instanceof BitSet)) jtulach@1399: return false; jtulach@1399: if (this == obj) jtulach@1399: return true; jtulach@1399: jtulach@1399: BitSet set = (BitSet) obj; jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: set.checkInvariants(); jtulach@1399: jtulach@1399: if (wordsInUse != set.wordsInUse) jtulach@1399: return false; jtulach@1399: jtulach@1399: // Check words in use by both BitSets jtulach@1399: for (int i = 0; i < wordsInUse; i++) jtulach@1399: if (words[i] != set.words[i]) jtulach@1399: return false; jtulach@1399: jtulach@1399: return true; jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Cloning this {@code BitSet} produces a new {@code BitSet} jtulach@1399: * that is equal to it. jtulach@1399: * The clone of the bit set is another bit set that has exactly the jtulach@1399: * same bits set to {@code true} as this bit set. jtulach@1399: * jtulach@1399: * @return a clone of this bit set jtulach@1399: * @see #size() jtulach@1399: */ jtulach@1399: public Object clone() { jtulach@1399: if (! sizeIsSticky) jtulach@1399: trimToSize(); jtulach@1399: jtulach@1399: try { jtulach@1399: BitSet result = (BitSet) super.clone(); jtulach@1399: result.words = words.clone(); jtulach@1399: result.checkInvariants(); jtulach@1399: return result; jtulach@1399: } catch (CloneNotSupportedException e) { jtulach@1399: throw new InternalError(); jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Attempts to reduce internal storage used for the bits in this bit set. jtulach@1399: * Calling this method may, but is not required to, affect the value jtulach@1399: * returned by a subsequent call to the {@link #size()} method. jtulach@1399: */ jtulach@1399: private void trimToSize() { jtulach@1399: if (wordsInUse != words.length) { jtulach@1399: words = Arrays.copyOf(words, wordsInUse); jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Save the state of the {@code BitSet} instance to a stream (i.e., jtulach@1399: * serialize it). jtulach@1399: */ jtulach@1399: private void writeObject(ObjectOutputStream s) jtulach@1399: throws IOException { jtulach@1399: jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: if (! sizeIsSticky) jtulach@1399: trimToSize(); jtulach@1399: jtulach@1399: ObjectOutputStream.PutField fields = s.putFields(); jtulach@1399: fields.put("bits", words); jtulach@1399: s.writeFields(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Reconstitute the {@code BitSet} instance from a stream (i.e., jtulach@1399: * deserialize it). jtulach@1399: */ jtulach@1399: private void readObject(ObjectInputStream s) jtulach@1399: throws IOException, ClassNotFoundException { jtulach@1399: jtulach@1399: ObjectInputStream.GetField fields = s.readFields(); jtulach@1399: words = (long[]) fields.get("bits", null); jtulach@1399: jtulach@1399: // Assume maximum length then find real length jtulach@1399: // because recalculateWordsInUse assumes maintenance jtulach@1399: // or reduction in logical size jtulach@1399: wordsInUse = words.length; jtulach@1399: recalculateWordsInUse(); jtulach@1399: sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic jtulach@1399: checkInvariants(); jtulach@1399: } jtulach@1399: jtulach@1399: /** jtulach@1399: * Returns a string representation of this bit set. For every index jtulach@1399: * for which this {@code BitSet} contains a bit in the set jtulach@1399: * state, the decimal representation of that index is included in jtulach@1399: * the result. Such indices are listed in order from lowest to jtulach@1399: * highest, separated by ", " (a comma and a space) and jtulach@1399: * surrounded by braces, resulting in the usual mathematical jtulach@1399: * notation for a set of integers. jtulach@1399: * jtulach@1399: *

Example: jtulach@1399: *

jtulach@1399:      * BitSet drPepper = new BitSet();
jtulach@1399: * Now {@code drPepper.toString()} returns "{@code {}}".

jtulach@1399: *

jtulach@1399:      * drPepper.set(2);
jtulach@1399: * Now {@code drPepper.toString()} returns "{@code {2}}".

jtulach@1399: *

jtulach@1399:      * drPepper.set(4);
jtulach@1399:      * drPepper.set(10);
jtulach@1399: * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}". jtulach@1399: * jtulach@1399: * @return a string representation of this bit set jtulach@1399: */ jtulach@1399: public String toString() { jtulach@1399: checkInvariants(); jtulach@1399: jtulach@1399: int numBits = (wordsInUse > 128) ? jtulach@1399: cardinality() : wordsInUse * BITS_PER_WORD; jtulach@1399: StringBuilder b = new StringBuilder(6*numBits + 2); jtulach@1399: b.append('{'); jtulach@1399: jtulach@1399: int i = nextSetBit(0); jtulach@1399: if (i != -1) { jtulach@1399: b.append(i); jtulach@1399: for (i = nextSetBit(i+1); i >= 0; i = nextSetBit(i+1)) { jtulach@1399: int endOfRun = nextClearBit(i); jtulach@1399: do { b.append(", ").append(i); } jtulach@1399: while (++i < endOfRun); jtulach@1399: } jtulach@1399: } jtulach@1399: jtulach@1399: b.append('}'); jtulach@1399: return b.toString(); jtulach@1399: } jtulach@1399: }