/************************************************************************** * Copyright (c) 2001 by Punch Telematix. All rights reserved. * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * * notice, this list of conditions and the following disclaimer in the * * documentation and/or other materials provided with the distribution. * * 3. Neither the name of Punch Telematix nor the names of * * other contributors may be used to endorse or promote products * * derived from this software without specific prior written permission.* * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * * IN NO EVENT SHALL PUNCH TELEMATIX OR OTHER CONTRIBUTORS BE LIABLE * * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **************************************************************************/ /* ** $Id: BitSet.java,v 1.2 2006/04/18 11:35:28 cvs Exp $ */ package java.util; import java.io.*; /* * the current implementation of BitSet doesn't allow the BitSet to shrink * the size will only grow !!! * a clear will at a position larger then the size will grow the BitSet * */ public class BitSet implements Cloneable, java.io.Serializable { private static final long serialVersionUID = 7997698588986878753L; private long[] bits; private transient int bitsInUse; /* * the size of the bitset is always rounded up to the next 64 increment */ private int roundup (int n) { return ((n+63)/64); } public BitSet() { bits = new long[1]; } public BitSet(int nbits) { if (nbits < 0 ) throw new NegativeArraySizeException(); bits = new long[roundup(nbits)]; } public String toString() { if(bitsInUse == 0){ return "{}"; } long[] bits = this.bits; int length = bits.length; StringBuffer buf = new StringBuffer(3*bits.length+2); buf.append('{'); for (int i=0; i < length; ++i) { long l = bits[i]; int j = 0; while(l != 0){ if((l & 0x1) > 0){ buf.append((i*64 + j)); buf.append(", "); } l = l>>>1; j++; } } buf.setLength(buf.length()-2); buf.append('}'); return buf.toString(); } public synchronized boolean equals(Object obj) { if (!(obj instanceof BitSet)) { return false; } BitSet that = (BitSet)obj; int l = bits.length; int k = that.bits.length; if(k > l){ for(int i=0 ; i < l ; i++){ if(bits[i] != that.bits[i]){ return false; } } for(int j=l ; j < k ; j++){ if(that.bits[j] != 0){ return false; } } } else { for(int i=0 ; i < k ; i++){ if(bits[i] != that.bits[i]){ return false; } } for(int j=k ; j < l ; j++){ if(bits[j] != 0){ return false; } } } return true; } public synchronized int hashCode() { long h = 1234; for (int i = bits.length-1 ; i >= 0; i--) { h ^= bits[i] * (i+1); } return (int)((h>>32)^h); } public synchronized Object clone() { try { BitSet clone = (BitSet)super.clone(); clone.bits = (long[])bits.clone(); return clone; } catch(CloneNotSupportedException cne){ return null; } } public boolean get(int bitIndex) { if(bitIndex < 0){ throw new IndexOutOfBoundsException("index "+bitIndex); } if(bitsInUse <= bitIndex){ return false; } return (((bits[bitIndex/64])>>(bitIndex%64)) & 0x01) > 0; } private void grow() { if(bitsInUse > bits.length * 64){ long[] nbits = new long[roundup(bitsInUse)]; System.arraycopy(bits, 0, nbits, 0, bits.length); bits = nbits; } } public synchronized void set(int bitIndex) { if(bitIndex < 0){ throw new IndexOutOfBoundsException(); } if (bitIndex>=bitsInUse) { bitsInUse = bitIndex+1; grow(); } int i = bitIndex / 64; bits[i] = bits[i] | (1L<<(bitIndex%64)); } /** * * @since 1.4 */ public void clear() { for(int i=0; i < bits.length ; i++) { bits[i] = 0L; } bitsInUse = 0; } public synchronized void clear(int bitIndex) { if(bitIndex < 0){ throw new IndexOutOfBoundsException(); } if (bitsInUse > bitIndex) { int i = bitIndex / 64; bits[i] = bits[i] & ((1L<<(bitIndex%64)) ^ -1L); } checkBitsInUse(); } /** * * @since 1.4 */ public void clear(int begin, int end) { if(begin < 0 || end < begin) { throw new IndexOutOfBoundsException(); } if (begin <= bitsInUse) { int bidx = begin / 64; int eidx = end / 64; if (bidx == eidx) { bits[bidx] &= ((-1L<<(begin%64)) & (-1L>>>(64-(end%64)))) ^ -1L; } else { int stop = eidx > bits.length ? bits.length : eidx; int rshift = begin % 64; bits[bidx] &= rshift > 0 ? ((-1L<<(begin%64)) ^ -1L) : 0; for (int i=bidx+1 ; i<stop; i++) { bits[i] = 0; } int shift = 64 - (end%64); if(shift < 64 && eidx < bits.length) { bits[eidx] &= (-1L>>>(shift)) ^ -1L; } } if(end >= bitsInUse) { checkBitsInUse(); } } } /** * * @since 1.4 */ public void flip(int bitIndex) { if(bitIndex < 0) { throw new IndexOutOfBoundsException(String.valueOf(bitIndex)); } int idx = bitIndex / 64; if(idx >= bits.length) { long[] newArray = new long[idx+1]; System.arraycopy(bits,0,newArray,0,bits.length); bits = newArray; } bits[idx] ^= 0x1L<<(bitIndex % 64); } /** * * @since 1.4 */ public void flip(int begin, int end) { if(begin < 0 || end < begin) { throw new IndexOutOfBoundsException(); } int eidx = end / 64; if(eidx >= bits.length) { long[] newArray = new long[eidx+1]; System.arraycopy(bits,0,newArray,0,bits.length); bits = newArray; } int bidx = begin / 64; if (bidx == eidx) { bits[bidx] ^= ((-1L<<(begin%64)) & (-1L>>>(64-(end%64)))); } else { int stop = eidx > bits.length ? bits.length : eidx; int rshift = begin % 64; bits[bidx] ^= rshift > 0 ? -1L<<(rshift) : -1; for (int i=bidx+1 ; i<stop; i++) { bits[i] ^= -1L; } int shift = 64 - (end%64); if(shift < 64 && eidx < bits.length) { bits[eidx] ^= (-1L>>>(shift)); } } if(end >= bitsInUse) { checkBitsInUse(); } } /***************************************************************************** * @since 1.4 */ public BitSet get(int begin, int end) { if (begin < 0 || end < begin) { throw new IndexOutOfBoundsException(); } int size = end - begin; BitSet set = new BitSet(size); if (size == 0) { return set; } if (begin <= bitsInUse) { int bidx = begin / 64; int eidx = (end / 64); long word = bits[bidx]; int rshift = begin % 64; if (bidx == eidx) { set.bits[0] = (word >>> rshift) & (-1L >>> (64 + rshift - (end % 64))); } else { int lshift = 64 - rshift; int need = (size % 64) - lshift; int stop = bits.length < eidx ? bits.length : eidx; int j = 0; if (++bidx == eidx && need > 0) { set.bits[j++] = (-1L >>> 64 + need) & (word >>> rshift | (bits[bidx]) << lshift); } else { if (rshift == 0) { for (int i = bidx-1; i < stop; i++) { set.bits[j++] = bits[i]; } word = set.bits[j-1]; } else { for (int i = bidx; i <= stop; i++) { long nword = bits[i]; set.bits[j++] = (word >>> rshift) | (nword << lshift); word = nword; } } if (need >= 0) { // already wrote to many bits. set.bits[j - 1] &= -1L >>> (64 - (size % 64)); } else if (need < 0 && j < set.bits.length) { // we need some more bits need = lshift + need; set.bits[j] = (-1L >>> (65 - need)) | (word >>> rshift); } } } set.checkBitsInUse(); } return set; } /** * * @since 1.4 */ public boolean isEmpty() { return bitsInUse == 0; } /** * * @since 1.4 */ public boolean intersects(BitSet set) { int length = bits.length <= set.bits.length ? bits.length : set.bits.length; for(int i=0; i < length ; i++) { if((bits[i] & set.bits[i]) > 0) { return true; } } return false; } /** * * @since 1.4 */ public int nextSetBit(int fromIndex) { int idx = fromIndex / 64; if(idx < bits.length) { int shift = fromIndex % 64; long word = bits[idx]>> shift; int leftover = 64 - shift; if(word == 0L) { fromIndex += leftover; leftover = 64; while(++idx < bits.length && 0L == (word = bits[idx])) { fromIndex += 64; } } if(word != 0L) { for (int i=0; i < leftover ; i++) { if((word & 0x01) == 1) { return fromIndex + i; } word >>= 1; } } } return -1; } /** * * @since 1.4 */ public int nextClearBit(int fromIndex) { if(fromIndex < bitsInUse) { int idx = fromIndex / 64; if(idx < bits.length) { int shift = fromIndex % 64; long word = bits[idx]>> shift; int leftover = 64 - shift; if(word == -1L) { fromIndex += leftover; leftover = 64; while(++idx < bits.length && -1L == (word = bits[idx])) { fromIndex += 64; } } if(word != -1L) { for (int i=0; i < leftover ; i++) { if((word & 0x01) == 0) { return fromIndex + i; } word >>= 1; } } } } return fromIndex; } /** * * @since 1.4 */ public void set(int bitIndex, boolean value){ int idx = bitIndex / 64; long mask = 0x1L<<(bitIndex % 64); if(idx >= bits.length) { if (!value) { return; } long[] newBits = new long[idx+1]; System.arraycopy(bits,0, newBits, 0, bits.length); bits = newBits; newBits[idx] = mask; } else { long word = bits[idx]; bits[idx] = value ? (word | mask) : (word & (mask ^ -1L)); } checkBitsInUse(); } /** * * @since 1.4 */ public void set(int fromIndex, int toIndex){ set(fromIndex, toIndex, true); } /** * * @since 1.4 */ public void set(int begin, int end, boolean value) { if(begin < 0 || end < begin) { throw new IndexOutOfBoundsException(); } int eidx = end / 64; //grow the array if needed. if(eidx >= bits.length && value) { long[] newArray = new long[eidx+1]; System.arraycopy(bits,0,newArray,0,bits.length); bits = newArray; } int bidx = begin / 64; if (bidx == eidx) { //special case bidx and eidx are the same. long mask = ((-1L<<(begin%64)) & (-1L>>>(64-(end%64)))); bits[bidx] = value ? bits[bidx] | mask : bits[bidx] & (mask ^ -1L); } else { //first set bits[bidx]. int stop = eidx > bits.length ? bits.length : eidx; long mask = -1L<<(begin%64); bits[bidx] = value ? bits[bidx] | mask : bits[bidx] & (mask ^ -1L); long word = value ? -1L : 0L; for (int i=bidx+1 ; i<stop; i++) { bits[i] = word; } int shift = end%64; if(shift > 0 && eidx < bits.length) { mask = -1L>>>(64-(shift)); bits[eidx] = value ? bits[eidx] | mask : bits[eidx] & (mask ^ -1L); } } if(end >= bitsInUse) { checkBitsInUse(); } } public void and(BitSet bitset) { int k = bitset.bits.length; long[] bits = this.bits; int l = bits.length; if(k < l){ for(int j=k ; j < l ; j++){ bits[j] = 0L; } l = k; } long[] others = bitset.bits; for(int i=0 ; i < l ; i++){ bits[i] = bits[i] & others[i]; } checkBitsInUse(); } public void or(BitSet bitset) { int k = bitset.bits.length; int l = bits.length; if(k > l){ long[] newbits = new long[k]; System.arraycopy(bits,0, newbits, 0, l); bits = newbits; } long[] bits = this.bits; long[] others = bitset.bits; for(int i=0 ; i < k ; i++){ bits[i] = bits[i] | others[i]; } checkBitsInUse(); } public synchronized void xor(BitSet bitset) { int k = bitset.bits.length; int l = bits.length; if(k > l){ long[] newbits = new long[k]; System.arraycopy(bits,0, newbits, 0, l); bits = newbits; } long[] bits = this.bits; long[] others = bitset.bits; for(int i=0 ; i < k ; i++){ bits[i] = bits[i] ^ others[i]; } checkBitsInUse(); } public int size() { return bits.length * 64; } /* * this method is added in JDK 1.2 */ public int length() { return bitsInUse; } /** * * @since 1.4 */ public int cardinality() { int cardinality = 0; for(int i=0; i < bits.length ; i++) { long lbits = bits[i]; while(lbits != 0) { if((lbits & 0x1) == 1) { cardinality++; } lbits >>>= 1; } } return cardinality; } public void andNot(BitSet bs) { long[] others = bs.bits; int k = others.length; long[] bits = this.bits; int l = bits.length; if(k < l){ l = k; } for(int i=0 ; i < l ; i++){ bits[i] = bits[i] & (others[i] ^ -1); } checkBitsInUse(); } private void checkBitsInUse(){ long[] bits = this.bits; int l = bits.length - 1; if(l >= 0){ while(bits[l] == 0L){ if(--l < 0){ bitsInUse = 0; return; } } long value = bits[l]>>>1; int i = 1; while(value != 0){ value = (value)>>>1; i++; } bitsInUse = l * 64 + i; } } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); checkBitsInUse(); } }