| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.util; |
| |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.Serializable; |
| |
| import org.apache.harmony.luni.util.Msg; |
| |
| /** |
| * The {@code BitSet} class implements a bit field. Each element in a |
| * {@code BitSet} can be on(1) or off(0). A {@code BitSet} is created with a |
| * given size and grows if this size is exceeded. Growth is always rounded to a |
| * 64 bit boundary. |
| */ |
| public class BitSet implements Serializable, Cloneable { |
| private static final long serialVersionUID = 7997698588986878753L; |
| |
| private static final int OFFSET = 6; |
| |
| private static final int ELM_SIZE = 1 << OFFSET; |
| |
| private static final int RIGHT_BITS = ELM_SIZE - 1; |
| |
| private static final long[] TWO_N_ARRAY = new long[] { 0x1L, 0x2L, 0x4L, |
| 0x8L, 0x10L, 0x20L, 0x40L, 0x80L, 0x100L, 0x200L, 0x400L, 0x800L, |
| 0x1000L, 0x2000L, 0x4000L, 0x8000L, 0x10000L, 0x20000L, 0x40000L, |
| 0x80000L, 0x100000L, 0x200000L, 0x400000L, 0x800000L, 0x1000000L, |
| 0x2000000L, 0x4000000L, 0x8000000L, 0x10000000L, 0x20000000L, |
| 0x40000000L, 0x80000000L, 0x100000000L, 0x200000000L, 0x400000000L, |
| 0x800000000L, 0x1000000000L, 0x2000000000L, 0x4000000000L, |
| 0x8000000000L, 0x10000000000L, 0x20000000000L, 0x40000000000L, |
| 0x80000000000L, 0x100000000000L, 0x200000000000L, 0x400000000000L, |
| 0x800000000000L, 0x1000000000000L, 0x2000000000000L, |
| 0x4000000000000L, 0x8000000000000L, 0x10000000000000L, |
| 0x20000000000000L, 0x40000000000000L, 0x80000000000000L, |
| 0x100000000000000L, 0x200000000000000L, 0x400000000000000L, |
| 0x800000000000000L, 0x1000000000000000L, 0x2000000000000000L, |
| 0x4000000000000000L, 0x8000000000000000L }; |
| |
| private long[] bits; |
| |
| private transient boolean needClear; |
| |
| private transient int actualArrayLength; |
| |
| private transient boolean isLengthActual; |
| |
| /** |
| * Create a new {@code BitSet} with size equal to 64 bits. |
| * |
| * @see #clear(int) |
| * @see #set(int) |
| * @see #clear() |
| * @see #clear(int, int) |
| * @see #set(int, boolean) |
| * @see #set(int, int) |
| * @see #set(int, int, boolean) |
| */ |
| public BitSet() { |
| bits = new long[1]; |
| actualArrayLength = 0; |
| isLengthActual = true; |
| } |
| |
| /** |
| * Create a new {@code BitSet} with size equal to nbits. If nbits is not a |
| * multiple of 64, then create a {@code BitSet} with size nbits rounded to |
| * the next closest multiple of 64. |
| * |
| * @param nbits |
| * the size of the bit set. |
| * @throws NegativeArraySizeException |
| * if {@code nbits} is negative. |
| * @see #clear(int) |
| * @see #set(int) |
| * @see #clear() |
| * @see #clear(int, int) |
| * @see #set(int, boolean) |
| * @see #set(int, int) |
| * @see #set(int, int, boolean) |
| */ |
| public BitSet(int nbits) { |
| if (nbits < 0) { |
| throw new NegativeArraySizeException(); |
| } |
| bits = new long[(nbits >> OFFSET) + ((nbits & RIGHT_BITS) > 0 ? 1 : 0)]; |
| actualArrayLength = 0; |
| isLengthActual = true; |
| } |
| |
| /** |
| * Private constructor called from get(int, int) method |
| * |
| * @param bits |
| * the size of the bit set |
| */ |
| private BitSet(long[] bits, boolean needClear, int actualArrayLength, |
| boolean isLengthActual) { |
| this.bits = bits; |
| this.needClear = needClear; |
| this.actualArrayLength = actualArrayLength; |
| this.isLengthActual = isLengthActual; |
| } |
| |
| /** |
| * Creates a copy of this {@code BitSet}. |
| * |
| * @return a copy of this {@code BitSet}. |
| */ |
| @Override |
| public Object clone() { |
| try { |
| BitSet clone = (BitSet) super.clone(); |
| clone.bits = bits.clone(); |
| return clone; |
| } catch (CloneNotSupportedException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Compares the argument to this {@code BitSet} and returns whether they are |
| * equal. The object must be an instance of {@code BitSet} with the same |
| * bits set. |
| * |
| * @param obj |
| * the {@code BitSet} object to compare. |
| * @return a {@code boolean} indicating whether or not this {@code BitSet} and |
| * {@code obj} are equal. |
| * @see #hashCode |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj instanceof BitSet) { |
| long[] bsBits = ((BitSet) obj).bits; |
| int length1 = this.actualArrayLength, length2 = ((BitSet) obj).actualArrayLength; |
| if (this.isLengthActual && ((BitSet) obj).isLengthActual |
| && length1 != length2) { |
| return false; |
| } |
| // If one of the BitSets is larger than the other, check to see if |
| // any of its extra bits are set. If so return false. |
| if (length1 <= length2) { |
| for (int i = 0; i < length1; i++) { |
| if (bits[i] != bsBits[i]) { |
| return false; |
| } |
| } |
| for (int i = length1; i < length2; i++) { |
| if (bsBits[i] != 0) { |
| return false; |
| } |
| } |
| } else { |
| for (int i = 0; i < length2; i++) { |
| if (bits[i] != bsBits[i]) { |
| return false; |
| } |
| } |
| for (int i = length2; i < length1; i++) { |
| if (bits[i] != 0) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Increase the size of the internal array to accommodate {@code pos} bits. |
| * The new array max index will be a multiple of 64. |
| * |
| * @param len |
| * the index the new array needs to be able to access. |
| */ |
| private final void growLength(int len) { |
| long[] tempBits = new long[Math.max(len, bits.length * 2)]; |
| System.arraycopy(bits, 0, tempBits, 0, this.actualArrayLength); |
| bits = tempBits; |
| } |
| |
| /** |
| * Computes the hash code for this {@code BitSet}. If two {@code BitSet}s are equal |
| * the have to return the same result for {@code hashCode()}. |
| * |
| * @return the {@code int} representing the hash code for this bit |
| * set. |
| * @see #equals |
| * @see java.util.Hashtable |
| */ |
| @Override |
| public int hashCode() { |
| long x = 1234; |
| for (int i = 0, length = actualArrayLength; i < length; i++) { |
| x ^= bits[i] * (i + 1); |
| } |
| return (int) ((x >> 32) ^ x); |
| } |
| |
| /** |
| * Retrieves the bit at index {@code pos}. Grows the {@code BitSet} if |
| * {@code pos > size}. |
| * |
| * @param pos |
| * the index of the bit to be retrieved. |
| * @return {@code true} if the bit at {@code pos} is set, |
| * {@code false} otherwise. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos} is negative. |
| * @see #clear(int) |
| * @see #set(int) |
| * @see #clear() |
| * @see #clear(int, int) |
| * @see #set(int, boolean) |
| * @see #set(int, int) |
| * @see #set(int, int, boolean) |
| */ |
| public boolean get(int pos) { |
| if (pos < 0) { |
| // Negative index specified |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| int arrayPos = pos >> OFFSET; |
| if (arrayPos < actualArrayLength) { |
| return (bits[arrayPos] & TWO_N_ARRAY[pos & RIGHT_BITS]) != 0; |
| } |
| return false; |
| } |
| |
| /** |
| * Retrieves the bits starting from {@code pos1} to {@code pos2} and returns |
| * back a new bitset made of these bits. Grows the {@code BitSet} if |
| * {@code pos2 > size}. |
| * |
| * @param pos1 |
| * inclusive beginning position. |
| * @param pos2 |
| * exclusive ending position. |
| * @return new bitset of the range specified. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos1} or {@code pos2} is negative, or if |
| * {@code pos2} is smaller than {@code pos1}. |
| * @see #get(int) |
| */ |
| public BitSet get(int pos1, int pos2) { |
| if (pos1 < 0 || pos2 < 0 || pos2 < pos1) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| int last = actualArrayLength << OFFSET; |
| if (pos1 >= last || pos1 == pos2) { |
| return new BitSet(0); |
| } |
| if (pos2 > last) { |
| pos2 = last; |
| } |
| |
| int idx1 = pos1 >> OFFSET; |
| int idx2 = (pos2 - 1) >> OFFSET; |
| long factor1 = (~0L) << (pos1 & RIGHT_BITS); |
| long factor2 = (~0L) >>> (ELM_SIZE - (pos2 & RIGHT_BITS)); |
| |
| if (idx1 == idx2) { |
| long result = (bits[idx1] & (factor1 & factor2)) >>> (pos1 % ELM_SIZE); |
| if (result == 0) { |
| return new BitSet(0); |
| } |
| return new BitSet(new long[] { result }, needClear, 1, true); |
| } |
| long[] newbits = new long[idx2 - idx1 + 1]; |
| // first fill in the first and last indexes in the new bitset |
| newbits[0] = bits[idx1] & factor1; |
| newbits[newbits.length - 1] = bits[idx2] & factor2; |
| |
| // fill in the in between elements of the new bitset |
| for (int i = 1; i < idx2 - idx1; i++) { |
| newbits[i] = bits[idx1 + i]; |
| } |
| |
| // shift all the elements in the new bitset to the right by pos1 |
| // % ELM_SIZE |
| int numBitsToShift = pos1 & RIGHT_BITS; |
| int actualLen = newbits.length; |
| if (numBitsToShift != 0) { |
| for (int i = 0; i < newbits.length; i++) { |
| // shift the current element to the right regardless of |
| // sign |
| newbits[i] = newbits[i] >>> (numBitsToShift); |
| |
| // apply the last x bits of newbits[i+1] to the current |
| // element |
| if (i != newbits.length - 1) { |
| newbits[i] |= newbits[i + 1] << (ELM_SIZE - (numBitsToShift)); |
| } |
| if (newbits[i] != 0) { |
| actualLen = i + 1; |
| } |
| } |
| } |
| return new BitSet(newbits, needClear, actualLen, |
| newbits[actualLen - 1] != 0); |
| } |
| |
| /** |
| * Sets the bit at index {@code pos} to 1. Grows the {@code BitSet} if |
| * {@code pos > size}. |
| * |
| * @param pos |
| * the index of the bit to set. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos} is negative. |
| * @see #clear(int) |
| * @see #clear() |
| * @see #clear(int, int) |
| */ |
| public void set(int pos) { |
| if (pos < 0) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| int len = (pos >> OFFSET) + 1; |
| if (len > bits.length) { |
| growLength(len); |
| } |
| bits[len - 1] |= TWO_N_ARRAY[pos & RIGHT_BITS]; |
| if (len > actualArrayLength) { |
| actualArrayLength = len; |
| isLengthActual = true; |
| } |
| needClear(); |
| } |
| |
| /** |
| * Sets the bit at index {@code pos} to {@code val}. Grows the |
| * {@code BitSet} if {@code pos > size}. |
| * |
| * @param pos |
| * the index of the bit to set. |
| * @param val |
| * value to set the bit. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos} is negative. |
| * @see #set(int) |
| */ |
| public void set(int pos, boolean val) { |
| if (val) { |
| set(pos); |
| } else { |
| clear(pos); |
| } |
| } |
| |
| /** |
| * Sets the bits starting from {@code pos1} to {@code pos2}. Grows the |
| * {@code BitSet} if {@code pos2 > size}. |
| * |
| * @param pos1 |
| * inclusive beginning position. |
| * @param pos2 |
| * exclusive ending position. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos1} or {@code pos2} is negative, or if |
| * {@code pos2} is smaller than {@code pos1}. |
| * @see #set(int) |
| */ |
| public void set(int pos1, int pos2) { |
| if (pos1 < 0 || pos2 < 0 || pos2 < pos1) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| if (pos1 == pos2) { |
| return; |
| } |
| int len2 = ((pos2 - 1) >> OFFSET) + 1; |
| if (len2 > bits.length) { |
| growLength(len2); |
| } |
| |
| int idx1 = pos1 >> OFFSET; |
| int idx2 = (pos2 - 1) >> OFFSET; |
| long factor1 = (~0L) << (pos1 & RIGHT_BITS); |
| long factor2 = (~0L) >>> (ELM_SIZE - (pos2 & RIGHT_BITS)); |
| |
| if (idx1 == idx2) { |
| bits[idx1] |= (factor1 & factor2); |
| } else { |
| bits[idx1] |= factor1; |
| bits[idx2] |= factor2; |
| for (int i = idx1 + 1; i < idx2; i++) { |
| bits[i] |= (~0L); |
| } |
| } |
| if (idx2 + 1 > actualArrayLength) { |
| actualArrayLength = idx2 + 1; |
| isLengthActual = true; |
| } |
| needClear(); |
| } |
| |
| private void needClear() { |
| this.needClear = true; |
| } |
| |
| /** |
| * Sets the bits starting from {@code pos1} to {@code pos2} to the given |
| * {@code val}. Grows the {@code BitSet} if {@code pos2 > size}. |
| * |
| * @param pos1 |
| * inclusive beginning position. |
| * @param pos2 |
| * exclusive ending position. |
| * @param val |
| * value to set these bits. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos1} or {@code pos2} is negative, or if |
| * {@code pos2} is smaller than {@code pos1}. |
| * @see #set(int,int) |
| */ |
| public void set(int pos1, int pos2, boolean val) { |
| if (val) { |
| set(pos1, pos2); |
| } else { |
| clear(pos1, pos2); |
| } |
| } |
| |
| /** |
| * Clears all the bits in this {@code BitSet}. |
| * |
| * @see #clear(int) |
| * @see #clear(int, int) |
| */ |
| public void clear() { |
| if (needClear) { |
| for (int i = 0; i < bits.length; i++) { |
| bits[i] = 0L; |
| } |
| actualArrayLength = 0; |
| isLengthActual = true; |
| needClear = false; |
| } |
| } |
| |
| /** |
| * Clears the bit at index {@code pos}. Grows the {@code BitSet} if |
| * {@code pos > size}. |
| * |
| * @param pos |
| * the index of the bit to clear. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos} is negative. |
| * @see #clear(int, int) |
| */ |
| public void clear(int pos) { |
| if (pos < 0) { |
| // Negative index specified |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| if (!needClear) { |
| return; |
| } |
| int arrayPos = pos >> OFFSET; |
| if (arrayPos < actualArrayLength) { |
| bits[arrayPos] &= ~(TWO_N_ARRAY[pos & RIGHT_BITS]); |
| if (bits[actualArrayLength - 1] == 0) { |
| isLengthActual = false; |
| } |
| } |
| } |
| |
| /** |
| * Clears the bits starting from {@code pos1} to {@code pos2}. Grows the |
| * {@code BitSet} if {@code pos2 > size}. |
| * |
| * @param pos1 |
| * inclusive beginning position. |
| * @param pos2 |
| * exclusive ending position. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos1} or {@code pos2} is negative, or if |
| * {@code pos2} is smaller than {@code pos1}. |
| * @see #clear(int) |
| */ |
| public void clear(int pos1, int pos2) { |
| if (pos1 < 0 || pos2 < 0 || pos2 < pos1) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| if (!needClear) { |
| return; |
| } |
| int last = (actualArrayLength << OFFSET); |
| if (pos1 >= last || pos1 == pos2) { |
| return; |
| } |
| if (pos2 > last) { |
| pos2 = last; |
| } |
| |
| int idx1 = pos1 >> OFFSET; |
| int idx2 = (pos2 - 1) >> OFFSET; |
| long factor1 = (~0L) << (pos1 & RIGHT_BITS); |
| long factor2 = (~0L) >>> (ELM_SIZE - (pos2 & RIGHT_BITS)); |
| |
| if (idx1 == idx2) { |
| bits[idx1] &= ~(factor1 & factor2); |
| } else { |
| bits[idx1] &= ~factor1; |
| bits[idx2] &= ~factor2; |
| for (int i = idx1 + 1; i < idx2; i++) { |
| bits[i] = 0L; |
| } |
| } |
| if ((actualArrayLength > 0) && (bits[actualArrayLength - 1] == 0)) { |
| isLengthActual = false; |
| } |
| } |
| |
| /** |
| * Flips the bit at index {@code pos}. Grows the {@code BitSet} if |
| * {@code pos > size}. |
| * |
| * @param pos |
| * the index of the bit to flip. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos} is negative. |
| * @see #flip(int, int) |
| */ |
| public void flip(int pos) { |
| if (pos < 0) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| int len = (pos >> OFFSET) + 1; |
| if (len > bits.length) { |
| growLength(len); |
| } |
| bits[len - 1] ^= TWO_N_ARRAY[pos & RIGHT_BITS]; |
| if (len > actualArrayLength) { |
| actualArrayLength = len; |
| } |
| isLengthActual = !((actualArrayLength > 0) && (bits[actualArrayLength - 1] == 0)); |
| needClear(); |
| } |
| |
| /** |
| * Flips the bits starting from {@code pos1} to {@code pos2}. Grows the |
| * {@code BitSet} if {@code pos2 > size}. |
| * |
| * @param pos1 |
| * inclusive beginning position. |
| * @param pos2 |
| * exclusive ending position. |
| * @throws IndexOutOfBoundsException |
| * if {@code pos1} or {@code pos2} is negative, or if |
| * {@code pos2} is smaller than {@code pos1}. |
| * @see #flip(int) |
| */ |
| public void flip(int pos1, int pos2) { |
| if (pos1 < 0 || pos2 < 0 || pos2 < pos1) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| if (pos1 == pos2) { |
| return; |
| } |
| int len2 = ((pos2 - 1) >> OFFSET) + 1; |
| if (len2 > bits.length) { |
| growLength(len2); |
| } |
| |
| int idx1 = pos1 >> OFFSET; |
| int idx2 = (pos2 - 1) >> OFFSET; |
| long factor1 = (~0L) << (pos1 & RIGHT_BITS); |
| long factor2 = (~0L) >>> (ELM_SIZE - (pos2 & RIGHT_BITS)); |
| |
| if (idx1 == idx2) { |
| bits[idx1] ^= (factor1 & factor2); |
| } else { |
| bits[idx1] ^= factor1; |
| bits[idx2] ^= factor2; |
| for (int i = idx1 + 1; i < idx2; i++) { |
| bits[i] ^= (~0L); |
| } |
| } |
| if (len2 > actualArrayLength) { |
| actualArrayLength = len2; |
| } |
| isLengthActual = !((actualArrayLength > 0) && (bits[actualArrayLength - 1] == 0)); |
| needClear(); |
| } |
| |
| /** |
| * Checks if these two {@code BitSet}s have at least one bit set to true in the same |
| * position. |
| * |
| * @param bs |
| * {@code BitSet} used to calculate the intersection. |
| * @return {@code true} if bs intersects with this {@code BitSet}, |
| * {@code false} otherwise. |
| */ |
| public boolean intersects(BitSet bs) { |
| long[] bsBits = bs.bits; |
| int length1 = actualArrayLength, length2 = bs.actualArrayLength; |
| |
| if (length1 <= length2) { |
| for (int i = 0; i < length1; i++) { |
| if ((bits[i] & bsBits[i]) != 0L) { |
| return true; |
| } |
| } |
| } else { |
| for (int i = 0; i < length2; i++) { |
| if ((bits[i] & bsBits[i]) != 0L) { |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * Performs the logical AND of this {@code BitSet} with another |
| * {@code BitSet}. The values of this {@code BitSet} are changed accordingly. |
| * |
| * @param bs |
| * {@code BitSet} to AND with. |
| * @see #or |
| * @see #xor |
| */ |
| public void and(BitSet bs) { |
| long[] bsBits = bs.bits; |
| if (!needClear) { |
| return; |
| } |
| int length1 = actualArrayLength, length2 = bs.actualArrayLength; |
| if (length1 <= length2) { |
| for (int i = 0; i < length1; i++) { |
| bits[i] &= bsBits[i]; |
| } |
| } else { |
| for (int i = 0; i < length2; i++) { |
| bits[i] &= bsBits[i]; |
| } |
| for (int i = length2; i < length1; i++) { |
| bits[i] = 0; |
| } |
| actualArrayLength = length2; |
| } |
| isLengthActual = !((actualArrayLength > 0) && (bits[actualArrayLength - 1] == 0)); |
| } |
| |
| /** |
| * Clears all bits in the receiver which are also set in the parameter |
| * {@code BitSet}. The values of this {@code BitSet} are changed accordingly. |
| * |
| * @param bs |
| * {@code BitSet} to ANDNOT with. |
| */ |
| public void andNot(BitSet bs) { |
| long[] bsBits = bs.bits; |
| if (!needClear) { |
| return; |
| } |
| int range = actualArrayLength < bs.actualArrayLength ? actualArrayLength |
| : bs.actualArrayLength; |
| for (int i = 0; i < range; i++) { |
| bits[i] &= ~bsBits[i]; |
| } |
| |
| if (actualArrayLength < range) { |
| actualArrayLength = range; |
| } |
| isLengthActual = !((actualArrayLength > 0) && (bits[actualArrayLength - 1] == 0)); |
| } |
| |
| /** |
| * Performs the logical OR of this {@code BitSet} with another {@code BitSet}. |
| * The values of this {@code BitSet} are changed accordingly. |
| * |
| * @param bs |
| * {@code BitSet} to OR with. |
| * @see #xor |
| * @see #and |
| */ |
| public void or(BitSet bs) { |
| int bsActualLen = bs.getActualArrayLength(); |
| if (bsActualLen > bits.length) { |
| long[] tempBits = new long[bsActualLen]; |
| System.arraycopy(bs.bits, 0, tempBits, 0, bs.actualArrayLength); |
| for (int i = 0; i < actualArrayLength; i++) { |
| tempBits[i] |= bits[i]; |
| } |
| bits = tempBits; |
| actualArrayLength = bsActualLen; |
| isLengthActual = true; |
| } else { |
| long[] bsBits = bs.bits; |
| for (int i = 0; i < bsActualLen; i++) { |
| bits[i] |= bsBits[i]; |
| } |
| if (bsActualLen > actualArrayLength) { |
| actualArrayLength = bsActualLen; |
| isLengthActual = true; |
| } |
| } |
| needClear(); |
| } |
| |
| /** |
| * Performs the logical XOR of this {@code BitSet} with another {@code BitSet}. |
| * The values of this {@code BitSet} are changed accordingly. |
| * |
| * @param bs |
| * {@code BitSet} to XOR with. |
| * @see #or |
| * @see #and |
| */ |
| public void xor(BitSet bs) { |
| int bsActualLen = bs.getActualArrayLength(); |
| if (bsActualLen > bits.length) { |
| long[] tempBits = new long[bsActualLen]; |
| System.arraycopy(bs.bits, 0, tempBits, 0, bs.actualArrayLength); |
| for (int i = 0; i < actualArrayLength; i++) { |
| tempBits[i] ^= bits[i]; |
| } |
| bits = tempBits; |
| actualArrayLength = bsActualLen; |
| isLengthActual = !((actualArrayLength > 0) && (bits[actualArrayLength - 1] == 0)); |
| } else { |
| long[] bsBits = bs.bits; |
| for (int i = 0; i < bsActualLen; i++) { |
| bits[i] ^= bsBits[i]; |
| } |
| if (bsActualLen > actualArrayLength) { |
| actualArrayLength = bsActualLen; |
| isLengthActual = true; |
| } |
| } |
| needClear(); |
| } |
| |
| /** |
| * Returns the number of bits this {@code BitSet} has. |
| * |
| * @return the number of bits contained in this {@code BitSet}. |
| * @see #length |
| */ |
| public int size() { |
| return bits.length << OFFSET; |
| } |
| |
| /** |
| * Returns the number of bits up to and including the highest bit set. |
| * |
| * @return the length of the {@code BitSet}. |
| */ |
| public int length() { |
| int idx = actualArrayLength - 1; |
| while (idx >= 0 && bits[idx] == 0) { |
| --idx; |
| } |
| actualArrayLength = idx + 1; |
| if (idx == -1) { |
| return 0; |
| } |
| int i = ELM_SIZE - 1; |
| long val = bits[idx]; |
| while ((val & (TWO_N_ARRAY[i])) == 0 && i > 0) { |
| i--; |
| } |
| return (idx << OFFSET) + i + 1; |
| } |
| |
| private final int getActualArrayLength() { |
| if (isLengthActual) { |
| return actualArrayLength; |
| } |
| int idx = actualArrayLength - 1; |
| while (idx >= 0 && bits[idx] == 0) { |
| --idx; |
| } |
| actualArrayLength = idx + 1; |
| isLengthActual = true; |
| return actualArrayLength; |
| } |
| |
| /** |
| * Returns a string containing a concise, human-readable description of the |
| * receiver. |
| * |
| * @return a comma delimited list of the indices of all bits that are set. |
| */ |
| @Override |
| public String toString() { |
| StringBuffer sb = new StringBuffer(bits.length / 2); |
| int bitCount = 0; |
| sb.append('{'); |
| boolean comma = false; |
| for (int i = 0; i < bits.length; i++) { |
| if (bits[i] == 0) { |
| bitCount += ELM_SIZE; |
| continue; |
| } |
| for (int j = 0; j < ELM_SIZE; j++) { |
| if (((bits[i] & (TWO_N_ARRAY[j])) != 0)) { |
| if (comma) { |
| sb.append(", "); //$NON-NLS-1$ |
| } |
| sb.append(bitCount); |
| comma = true; |
| } |
| bitCount++; |
| } |
| } |
| sb.append('}'); |
| return sb.toString(); |
| } |
| |
| /** |
| * Returns the position of the first bit that is {@code true} on or after {@code pos}. |
| * |
| * @param pos |
| * the starting position (inclusive). |
| * @return -1 if there is no bits that are set to {@code true} on or after {@code pos}. |
| */ |
| public int nextSetBit(int pos) { |
| if (pos < 0) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| if (pos >= actualArrayLength << OFFSET) { |
| return -1; |
| } |
| |
| int idx = pos >> OFFSET; |
| // first check in the same bit set element |
| if (bits[idx] != 0L) { |
| for (int j = pos & RIGHT_BITS; j < ELM_SIZE; j++) { |
| if (((bits[idx] & (TWO_N_ARRAY[j])) != 0)) { |
| return (idx << OFFSET) + j; |
| } |
| } |
| |
| } |
| idx++; |
| while (idx < actualArrayLength && bits[idx] == 0L) { |
| idx++; |
| } |
| if (idx == actualArrayLength) { |
| return -1; |
| } |
| |
| // we know for sure there is a bit set to true in this element |
| // since the bitset value is not 0L |
| for (int j = 0; j < ELM_SIZE; j++) { |
| if (((bits[idx] & (TWO_N_ARRAY[j])) != 0)) { |
| return (idx << OFFSET) + j; |
| } |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * Returns the position of the first bit that is {@code false} on or after {@code pos}. |
| * |
| * @param pos |
| * the starting position (inclusive). |
| * @return the position of the next bit set to {@code false}, even if it is further |
| * than this {@code BitSet}'s size. |
| */ |
| public int nextClearBit(int pos) { |
| if (pos < 0) { |
| throw new IndexOutOfBoundsException(Msg.getString("K0006")); //$NON-NLS-1$ |
| } |
| |
| int length = actualArrayLength; |
| int bssize = length << OFFSET; |
| if (pos >= bssize) { |
| return pos; |
| } |
| |
| int idx = pos >> OFFSET; |
| // first check in the same bit set element |
| if (bits[idx] != (~0L)) { |
| for (int j = pos % ELM_SIZE; j < ELM_SIZE; j++) { |
| if (((bits[idx] & (TWO_N_ARRAY[j])) == 0)) { |
| return idx * ELM_SIZE + j; |
| } |
| } |
| } |
| idx++; |
| while (idx < length && bits[idx] == (~0L)) { |
| idx++; |
| } |
| if (idx == length) { |
| return bssize; |
| } |
| |
| // we know for sure there is a bit set to true in this element |
| // since the bitset value is not 0L |
| for (int j = 0; j < ELM_SIZE; j++) { |
| if (((bits[idx] & (TWO_N_ARRAY[j])) == 0)) { |
| return (idx << OFFSET) + j; |
| } |
| } |
| |
| return bssize; |
| } |
| |
| /** |
| * Returns true if all the bits in this {@code BitSet} are set to false. |
| * |
| * @return {@code true} if the {@code BitSet} is empty, |
| * {@code false} otherwise. |
| */ |
| public boolean isEmpty() { |
| if (!needClear) { |
| return true; |
| } |
| int length = bits.length; |
| for (int idx = 0; idx < length; idx++) { |
| if (bits[idx] != 0L) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Returns the number of bits that are {@code true} in this {@code BitSet}. |
| * |
| * @return the number of {@code true} bits in the set. |
| */ |
| public int cardinality() { |
| if (!needClear) { |
| return 0; |
| } |
| int count = 0; |
| int length = bits.length; |
| // FIXME: need to test performance, if still not satisfied, change it to |
| // 256-bits table based |
| for (int idx = 0; idx < length; idx++) { |
| count += pop(bits[idx] & 0xffffffffL); |
| count += pop(bits[idx] >>> 32); |
| } |
| return count; |
| } |
| |
| private final int pop(long x) { |
| // BEGIN android-note |
| // delegate to Integer.bitCount(i); consider using native code |
| // END android-note |
| x = x - ((x >>> 1) & 0x55555555); |
| x = (x & 0x33333333) + ((x >>> 2) & 0x33333333); |
| x = (x + (x >>> 4)) & 0x0f0f0f0f; |
| x = x + (x >>> 8); |
| x = x + (x >>> 16); |
| return (int) x & 0x0000003f; |
| } |
| |
| private void readObject(ObjectInputStream ois) throws IOException, |
| ClassNotFoundException { |
| ois.defaultReadObject(); |
| this.isLengthActual = false; |
| this.actualArrayLength = bits.length; |
| this.needClear = this.getActualArrayLength() != 0; |
| } |
| } |