/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.util; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import xxl.core.io.Convertable; import xxl.core.io.converters.SizeConverter; /** * This class is a replacement for <tt>java.util.BitSet</tt> which neither * implements the interfaces <tt>Convertable</tt> nor <tt>Comparable</tt>. <br> * * This class implements a vector of bits. Each component of the bit set * has a <code>boolean</code> value. * The bits of a <code>BitSet</code> are indexed by nonnegative integers. * Individual indexed bits can be examined, set, or cleared. One * <code>BitSet</code> may be used to modify the contents of another * <code>BitSet</code> through logical AND, logical inclusive OR, and * logical exclusive OR operations. * Furthermore this class offers the opportunity to a convert a SDK's BitSet * to an instance of this class using a default precision of 64 bit. * * <p> * By default, all bits in the set initially have the value * <code>false</code>. * <p> * The array <code>bits</code> represents the bits of a BitSet. * BitSets are packed into arrays of "units." Currently a unit is a long, * which consists of 64 bits, requiring 6 address bits. * The ith bit is stored in bits[i/64] at * bit position i % 64 (where bit position 0 refers to the most * significant bit and 63 refers to the least significant bit). * Every bit set has a precision, which determines the user-relevant * number of bits stored by this bit set. <br> * Note, that the precision is related to the implementation * of a bit set, so it may change with * implementation. * The dependence of the array <code>bits</code> and the user * specified <code>precision</code> in a constructor is as follows: * <br><br> * <code><pre> * bits = new long[ precision%64 == 0 ? (precision >>>6) : (precision>>>6)+1 ] * </code></pre> * The size of a bit set relates to logical length * of a bit set and is defined independently of implementation. * <p> * This class provides methods to read instances * of this class from the data input and also write them to the data * output. * Further different methods to compare two BitSets are supported, e.g. * only a specified sequence of bits can be compared or only one dimension * can be compared, which is especially useful if space filling curves * are represented by bit sets (e.g. z-code in {@link xxl.core.spatial spatial}). * <p> * <b>Example usage (1):</b> * <br><br> * <code><pre> * BitSet bitSet = new BitSet(62); * System.out.println("bitSet :" +bitSet); * System.out.println("bitSet's size:" +bitSet.size()); * System.out.println("bitSet's precision:" +bitSet.precision()); * System.out.println("Setting bits: 1, 19, 23, 54"); * bitSet.set(1); * bitSet.set(19); * bitSet.set(23); * bitSet.set(54); * System.out.println("bitSet :" +bitSet); * System.out.println("Clearing bit with index 19."); * bitSet.clear(19); * System.out.println("bitSet :" +bitSet); * </code></pre> * This first example creates a new instance of a BitSet with a precision of 62 bits. * Initially all bits are <tt>false</tt>, and the size is 64 bits, because the internal * used array <code>bits</code> has length 1. <br> * The bits at position 1, 19, 23 and 54 are set. After that the bit with index * 19 is cleared. * So the final output of the bits that are set is: <tt>{1, 23, 54}</tt>. * <p> * <b>Example usage (2):</b> * <br><br> * <code><pre> * BitSet bitSet1 = new BitSet( new long[] {first, 7, 13, 42}); * System.out.println("bitSet1: " +bitSet1); * System.out.println("bitSet1's size:" +bitSet1.size()); * System.out.println("bitSet1's precision:" +bitSet1.precision()); * System.out.println("bitSet2 gets a clone of bitSet1."); * BitSet bitSet2 = (BitSet)bitSet1.clone(); * System.out.println("Clearing bit with index 125 of bitSet2. "); * bitSet2.clear(125); * System.out.println("bitSet2: " +bitSet2); * System.out.println("Determining first different bit between bitSet1 and bitSet2:"); * System.out.println("first different bit: " +bitSet1.diff(bitSet2)); * </code></pre> * In this example a BitSet is created initializing the attribute <code>bits</code> * with long values: 1l<<63(first), 7, 13, 42. So bits[0] = first, bits[1] = 7 and so on. * In this case the precision is 256 (bits.length * 64) and also the size. * Then bitSet1 is cloned and bit with index 125 is cleared. Therefore the following * comparison returns this index as the first different bit. * <p> * <b>Example usage (3):</b> * <br><br> * <code><pre> * bitSet1 = new BitSet( new long[] {first, 7, 13, 42}, 64); * System.out.println("bitSet1: " +bitSet1); * System.out.println("bitSet1's size:" +bitSet1.size()); * System.out.println("bitSet1's precision:" +bitSet1.precision()); * System.out.println("result of comparison between bitSet1 and bitSet2 (precision = 64): " +bitSet1.compare(bitSet2)); * System.out.println("result of comparison between bitSet1 and bitSet2: " +bitSet1.compareTo(bitSet2)); * System.out.println("comparing only the first 20 bits: " +bitSet1.compare(bitSet2, 20)); * System.out.println("comparing the first two longs directly: " +bitSet1.compare2(bitSet2, 2)); * </code></pre> * The last example creates nearly the same BitSet as example (2), but the precision * is only 64 bits. If the two BitSets, bitSet1 and bitSet2, are compared now, the * call <code>bitSet1.compare(bitSet2)</code> returns 0, that means that the * two BitSets are equal. But there is still a difference in the bit at position 125, * this difference does not matter, because the precision is set to only 64 bit. * If the same comparison is fulfilled with the method <code>compareTo</code> the * result is -1, because in this case all indices are compared. * Comparing only the first 20 bits delivers the same results as <code>compare()</code>, * but comparing the first two longs using the method <code>compare2()</code> returns * -1, because now the comparison is fulfilled with 128 bits. * * @see java.io.DataInput * @see java.io.DataOutput * @see java.lang.Cloneable * @see java.lang.Comparable * @see xxl.core.io.Convertable */ public class BitSet implements Cloneable, Comparable<BitSet>, Convertable { /** * Converter for BitSets. */ public static SizeConverter<BitSet> DEFAULT_CONVERTER = new SizeConverter<BitSet>() { /** * Reads the state (the attributes) for an BitSet object from * the specified data input and restores the calling object. * In this case an Integer object is read at first, which contains the * information about the BitSet's precision, i.e. the number of * bits stored by this BitSet. After that the array <tt>bits</tt> is * created and filled up with <code>bits.length</code> Long objects read * from the specified data input. * @param dataInput the stream to read data from in order to restore * the object. * @throws IOException if I/O errors occur. */ @Override public BitSet read(DataInput dataInput, BitSet b) throws IOException { int precision = dataInput.readInt(); if (b == null) b = new BitSet(precision); else { if (b.precision != precision) throw new RuntimeException("Precision of the object was not correct!"); } for(int i = 0; i < b.bits.length; i++) b.bits[i] = dataInput.readLong(); return b; } /** * Writes the state (the attributes) of the calling object to the * specified data output. * At first an Integer object is written representing the BitSet's * precision, i.e. the number of bits stored by this BitSet. After * that the long array <code>bits</code> is written to the data output * by calling the data output's method <code>writeLong</code> * for each component of the array. * * @param dataOutput the stream to write the state (the attributes) of * the object to. * @throws IOException includes any I/O exceptions that may occur. */ @Override public void write(DataOutput dataOutput, BitSet b) throws IOException { dataOutput.writeInt(b.precision); for(int i = 0; i < b.bits.length; i++) dataOutput.writeLong(b.bits[i]); } /** * Returns the number of bytes used for serialization/deserialization. * of a BitSet. * @param b The BitSet of which the size is returned. * @return the number of bytes. */ @Override public int getSerializedSize(BitSet b) { return 4 + b.bits.length * 8; } }; /** * Returns the serialization size of a BitSet of a certain * precision. * @param precision Precision of the BitSet. * @return Size in bytes. */ public static int getSize(int precision) { return 4 + ((precision+63)/64)*8; } /** * The bits in this BitSet. The ith bit is stored in bits[i/64] at * bit position i % 64 (where bit position 0 refers to the most * significant bit and 63 refers to the least significant bit). */ protected long[] bits; /** * The user-relevant number of bits stored by this BitSet. * This number can be chosen smaller than the size of a bit set, * showing that the user does not need the whole precision. * This possible loss of precision results in a better performance * when comparing bit sets. */ protected int precision = 0; /** * The BitSet's (first) highest bit is set to <tt>true</tt> * using a 64 bit representation. * All other bits are set to <tt>false</tt>. */ protected static final long first = 1l<<63; /** * The given SDK's BitSet is converted to a {@link xxl.core.util.BitSet} * using a default precision of 64 bits. * So the resulting bit set is absolutely identical to the given bit set * in each bit. * @param bitSet input SDK's BitSet * @return copy of input BitSet as {@link xxl.core.util.BitSet} */ public static BitSet convert (java.util.BitSet bitSet) { return new BitSet(bitSet); } /** * Creates a new BitSet by setting <code>bits</code> to <tt>null</tt> * and <code>precision</code> to 0. */ public BitSet(){ this(null, 0); } /** * Creates a new BitSet using a precision of 64 bits and * an array containg only the specified long component. * * @param l component representing the vector of bits. */ public BitSet(long l){ this(new long[]{l}, 64); } /** * Creates a new BitSet using the given precision. * The array <code>bits</code> is created as follows: * <br><br> * <code><pre> * new long[ precision%64 == 0 ? (precision >>>6) : (precision>>>6)+1 ] * </code></pre> * That is the case, because the array's component type is <tt>long</tt>, * i.e. 64 bits. So the number of bits to be stored (precision) has * to be partioned in sections of 64 bits. * * @param precision the user-relevant number of bits stored by this BitSet. */ public BitSet(int precision){ this(new long[ precision%64 == 0 ? (precision >>>6) : (precision>>>6)+1 ], precision); } /** * Creates a new BitSet. (Copy-constructor) * The new instance is created by cloning the array <code>bits</code> * of the given BitSet b and calling the constructor * {@link #BitSet(long[] bits, int precision)} with this cloned * array and the precision of BitSet b. * * @param b the BitSet to be copied. */ public BitSet(BitSet b){ this(b.bits.clone(), b.precision); } /** * Creates a new BitSet using the specified array and * precision that results in <tt>bits.length*64</tt>. * * @param bits the array representing a vector of bits. */ public BitSet(long[] bits){ this(bits,bits.length<<6); } /** * Creates a new BitSet using the given array and precision. * * @param bits the array representing a vector of bits. * @param precision the user-relevant number of bits to be stored by this BitSet. */ public BitSet(long[] bits, int precision){ this.bits = bits; this.precision = precision; } /** * Creates a new BitSet using the given {@link java.util.BitSet}. * A default precision of 64 bits is used. * So the created bit set is absolutely identical to the given bit set * in each bit. * * @param bitSet an instance of {@link java.util.BitSet}. */ public BitSet(java.util.BitSet bitSet) { this(bitSet.length()); for (int i=0; i<bitSet.length(); i++) if(bitSet.get(i)) this.set(i); } /** * Returns the BitSet's precision, i.e. the number of bits * stored by this BitSet. * * @return the precision of this BitSet. */ public int precision(){ return precision; } /** * Cloning this <code>BitSet</code> produces a new <code>BitSet</code> * 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</code> as this bit set and the same * precision. * <p>Overrides the <code>clone</code> method of <code>Object</code>. * The copy-constructor {@link #BitSet(BitSet)} is called. * * @return a clone of this bit set. */ @Override public Object clone(){ return new BitSet(this); } /** * Sets the bit specified by the index to <code>true</code>. * * @param bitIndex a bit index. * @throws IndexOutOfBoundsException if the specified index is negative. */ public void set(int bitIndex){ bits[bitIndex>>>6] |= first >>> (bitIndex%64); // bits[bitIndex>>>6] |= 1l<<(bitIndex%64); } /** * Returns the value of the bit with the specified index. The value * is <code>true</code> if the bit with the index <code>bitIndex</code> * is currently set in this <code>BitSet</code>; otherwise, the result * is <code>false</code>. * * @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){ return ((bits[bitIndex>>>6] << (bitIndex%64)) & first) == first; // return ((bits[bitIndex>>>6] >>> (bitIndex%64)) & 1l) == 1l; } /** * Sets the bit specified by the index to <code>false</code>. * * @param bitIndex the index of the bit to be cleared. * @throws IndexOutOfBoundsException if the specified index is negative. */ public void clear(int bitIndex){ bits[bitIndex>>>6] &= ~(first >>>(bitIndex%64)); // bits[bitIndex>>>6] &= ~(1l<<(bitIndex%64)); } /** * Returns the number of bits of space actually in use by this * <code>BitSet</code> to represent bit values. * The size is determined by <code>bits.length<<6</code>, i.e. * bits.length*64, because the array's component type is <tt>long</tt>. * * @return the size of this bit set. */ public int size(){ return bits.length<<6; } /** * Returns a string representation of this bit set. * For every index for which this <code>BitSet</code> * contains a bit in the set state, the decimal representation * of that index is included in the result. * Such indeces are listed in order from lowest to * highest, separated by ",$nbsp;" (a comma and a space) and * surrounded by braces, resulting in the usual mathematical * notation for a set of integers.<p> * Overrides the <code>toString</code> method of <code>Object</code>. * * @return a string representation of this bit set. */ @Override public String toString(){ StringBuffer sb = new StringBuffer(); sb.append("bits in set state: {"); String separator = ""; for (int i=0; i<size(); i++) { if (get(i)) { sb.append(separator); separator = ", "; sb.append(i); } } sb.append("}"); return new String(sb); } /** Alternate visualization of this String. * @return resulting string */ public String toString2(){ StringBuffer sb = new StringBuffer(size()+"\nsfc: "); if(size()<200){ for(int i=0; i<size();i++) sb.append(get(i)?"1":"0"); sb.append("\t\tprecision:\t"+precision+"\n "); for(int i=0; i<size();i++) sb.append(i%10); sb.append("\n "); for(int i=0; i<size();i+=10) sb.append((i/10)+" "); } else sb.append("Error: String is too long!"); return sb.toString(); } /** * Reads the state (the attributes) for an object of this class from * the specified data input and restores the calling object. The state * of the object before calling <tt>read</tt> will be lost.<br> * In this case an Integer object is read at first, which contains the * information about the BitSet's precision, i.e. the number of * bits stored by this BitSet. After that the array <tt>bits</tt> is * created and filled up with <code>bits.length</code> Long objects read * from the specified data input. * * @param in the stream to read data from in order to restore * the object. * @throws IOException if I/O errors occur. */ public void read(DataInput in) throws IOException{ precision = in.readInt(); bits = new long[ precision%64 == 0 ? (precision>>>6) : (precision>>>6)+1];//ensure that there is enough space in the array for(int i=0; i<bits.length; i++) bits[i] = in.readLong();/**/ } /** * Writes the state (the attributes) of the calling object to the * specified data output. * At first an Integer object is written representing the BitSet's * precision, i.e. the number of bits stored by this BitSet. After * that the long array <code>bits</code> is written to the data output * by calling the data output's method <code>writeLong</code> * for each component of the array. * * @param out the stream to write the state (the attributes) of * the object to. * @throws IOException includes any I/O exceptions that may occur. */ public void write(DataOutput out) throws IOException{ out.writeInt(precision); //DEBUG for(int i=0; i<bits.length; i++) out.writeLong(bits[i]);/**/ } /** * Compares two BitSets and returns the index of the first bit * that differs starting at bit index 0. * A maximum of Integer.MAX_VALUE bits will be compared. * * @param b the BitSet to be compared with the BitSet * calling this method. * @return the index of the first bit that differs. * @see #diff(BitSet, int) */ public int diff(BitSet b){ return diff(b,Integer.MAX_VALUE); } /** * Compares two BitSets concerning the specified number of bits * <tt>nobits</tt> and returns the index of the first bit * that differs starting at bit index 0. * A maximum of <tt>min{<code>precision, b.precision, nobits</code>}</tt> * bits will be compared. * * @param b the BitSet to be compared with the BitSet * calling this method. * @param nobits the maximum number of bits to be compared. * @return the index of the first bit that differs. */ public int diff(BitSet b, int nobits){ int bitIndex = 0; for(nobits = Math.min(Math.min(precision,b.precision),nobits); bitIndex < nobits; bitIndex++) if(get(bitIndex) != b.get(bitIndex) ) return bitIndex; return bitIndex; } /** * Compares the calling Bitset with the given BitSet <tt>b</tt>. * The comparsion starts at bit index 0. * A maximum of <tt>min{<code>precision, b.precision</code>}</tt> * bits will be compared. * This method returns a negative if this (the calling) BitSet is smaller than * the given BitSet b, a positive value if BitSet b is smaller, * otherwise 0 is returned. * * @param b the BitSet to be compared with the BitSet * calling this method. * @return a negative value if this (the calling) BitSet is smaller than * the given BitSet b, a positive value if BitSet b is smaller, * else 0 is returned. * @see #compare(BitSet, int, int, int) */ public int compare(BitSet b){ return compare(b,precision,0,1); } /** * Compares the calling Bitset with the given BitSet <tt>b</tt> in * the specified number of bits <tt>nobits</tt>. * The comparsion starts at bit index 0. * A maximum of <tt>min{<code>precision, b.precision, nobits</code>}</tt> * bits will be compared. * This method returns a negative if this (the calling) BitSet is smaller than * the given BitSet b, a positive value if BitSet b is smaller, * otherwise 0 is returned. * * @param b the BitSet to be compared with the BitSet * calling this method. * @param nobits the maximum number of bits to be compared. * @return a negative value if this (the calling) BitSet is smaller than * the given BitSet b, a positive value if BitSet b is smaller, * else 0 is returned. * @see #compare(BitSet, int, int, int) */ public int compare(BitSet b, int nobits){ return compare(b,nobits,0,1); } /** * Compares two BitSets with regard to only one dimension <tt>dim</tt>. <br> * This method is implemented as follows: * <br><br> * <code><pre> * int bitIndex = dim; * for(nobits = Math.min( Math.min(precision,b.precision),nobits ); bitIndex < nobits; bitIndex += maxDim) * if( get(bitIndex) != b.get(bitIndex) ) * return (get(bitIndex)?1:0) - (b.get(bitIndex)?1:0); * return 0; * </code></pre> * A maximum of <tt>min{<code>precision, b.precision, nobits</code>}</tt> * bits will be compared. * The bits at bit index <tt>bitIndex</tt> will be compared starting with * <code>bitIndex = dim</code>. * Each time the comparison of two bits delivers <tt>true</tt> the * bitIndex is incremented by <tt>maxDim</tt>. <br> * * This method returns a negative if this (the calling) BitSet is smaller than * the given BitSet b, a positive value if BitSet b is smaller, * otherwise 0 is returned. * * @param b the BitSet to be compared with the BitSet * calling this method. * @param nobits the maximum number of bits to be compared. * @param dim the bit index the comparison starts. * @param maxDim a value which is added after each comparsion of two * bits to the current bit index. * @return a negative value if this (the calling) BitSet is smaller than * the given BitSet b, a positive value if BitSet b is smaller, * else 0 is returned. * @see xxl.core.spatial */ public int compare(BitSet b, int nobits, int dim, int maxDim){ int bitIndex = dim; for(nobits = Math.min( Math.min(precision,b.precision),nobits ); bitIndex < nobits; bitIndex += maxDim) if( get(bitIndex) != b.get(bitIndex) ) return (get(bitIndex)?1:0) - (b.get(bitIndex)?1:0); return 0; } /** * Compares the calling Bitset with the given BitSet <tt>b</tt> * in terms of their components, i.e. the longs will be compared * directly. The given parameter <tt>noLongs</tt>, number of longs, * specifies the maximum number of long components of the array * <tt>bits</tt> to be compared. * * So this method is faster than {@link #compare(BitSet,int)}. * * @param b the BitSet to be compared with the BitSet * calling this method. * @param noLongs the number of longs to be compared, i.e. * bits[0], ..., bits[noLongs] will be compared at the most. * @return a negative value if this (the calling) BitSet is smaller than * the given BitSet b, a positive value if BitSet b is smaller, * else 0 is returned. * @throws IndexOutOfBoundsException if <tt>noLongs</tt> is negative * or it is larger than <tt>min{bits.length-1, b.bits.length-1}</tt>. */ public int compare2(BitSet b, int noLongs){ for(int i=0 ; i < noLongs; i++){ //kann man das folgende if eventuell sogar weglassen? if ((bits[i] & first) != (b.bits[i] & first)) return bits[i] < b.bits[i] ? +1 : -1; //ACHTUNG: kehrt sich hier um! if (bits[i] < b.bits[i]) return -1; if (bits[i] > b.bits[i]) return +1; } return 0; } /** * Compares the calling Bitset with the given Object <tt>o</tt> casted * to a BitSet. * The comparison returns a negative if this (the calling) BitSet is smaller than * the given BitSet o, a positive value if BitSet o is smaller, * otherwise 0 is returned. * * @param bs the BitSet to be compared with the BitSet * calling this method. * @return a negative value if this (the calling) BitSet is smaller than * the given BitSet o, a positive value if BitSet o is smaller, * else 0 is returned. */ public int compareTo(BitSet bs) { //compare longs directly int comp = compare2(bs, Math.min( bits.length, bs.bits.length)); //compare BitSets return comp != 0 ? //equals 0 (i.e. BitSets are equal from bit 0 to bit <min> comp //return comp : precision < bs.precision ? -1 : (precision > bs.precision ? +1 : 0); //the shortest BitSet is smaller/**/ /* int comp = compare(bs, Math.min( precision, bs.precision),0,1); //compare BitSets return comp != 0 ? //equals 0 (i.e. BitSets are equal fomr bit 0 to bit <min> comp //return comp : precision < bs.precision ? -1 : (precision > bs.precision ? +1 : 0); //smaller is the shortest BitSet /**/ } /** * Tests if this is equal to the BitSet which is given as parameter. * @param o second BitSet object. * @return true iff both BitSets are equal. */ @Override public boolean equals(Object o) { return compareTo((BitSet)o)==0; } /** * Returns a hash code for the BitSet. * @return the hash code. */ @Override public int hashCode() { if (bits == null || bits.length == 0) return 4711; return (int) bits[0]; } /** * Performs a logical <b>OR</b> of this bit set with the specified * bit set. This bit set is modified so that a bit in it has the * value <code>true</code> if and only if it either already had the * value <code>true</code> or the corresponding bit in the bit set * argument has the value <code>true</code>. <br> * <b>Note</b>, this BitSet's capacity may change when executing * this method, because the two BitSet are set to the larger * length of the internal used array <tt>bits</tt>, so this * array will have the following length: <br> * <br><br> * <code><pre> * Math.max(bits.length, bitSet.bits.length) * </code></pre> * * @param bitSet a bit set the operation should be fulfilled with. */ public void or (BitSet bitSet) { if (compareTo(bitSet) != 0) { // ensure capacity long[] result = new long[Math.max(bits.length, bitSet.bits.length)]; int i; // position int min = Math.min(bits.length, bitSet.bits.length); // perform logical OR on bits in common for (i=0; i<min; i++) result[i] = bits[i] | bitSet.bits[i]; BitSet set = (result.length == bits.length) ? this : bitSet; // larger bit set // copy any remaining bits for ( ; i<result.length; i++) result[i] = set.bits[i]; this.bits = result; // assign the bit-array } } /** * Performs a logical <b>AND</b> 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</code> if and only if it both initially * had the value <code>true</code> and the corresponding bit in the * bit set argument also had the value <code>true</code>. <br> * <b>Note</b>, this BitSet's capacity may change when executing * this method, because the two BitSet are set to the larger * length of the internal used array <tt>bits</tt>, so this * array will have the following length: <br> * <br><br> * <code><pre> * Math.max(bits.length, bitSet.bits.length) * </code></pre> * * @param bitSet a bit set the operation should be fulfilled with. */ public void and (BitSet bitSet) { if (compareTo(bitSet) != 0) { // ensure capacity long[] result = new long[Math.max(bits.length, bitSet.bits.length)]; int i; //position int min = Math.min(bits.length, bitSet.bits.length); // perform logical AND on bits in common for (i=0; i<min; i++) result[i] = bits[i] & bitSet.bits[i]; // clear out remaining bits for ( ; i< result.length; i++) result[i] = 0; this.bits = result; //assign the bit-array } } /** * Performs a logical <b>XOR</b> 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</code> if and only if one of the following * statements holds: * <ul> * <li>The bit initially has the value <code>true</code>, and the * corresponding bit in the argument has the value <code>false</code>. * <li>The bit initially has the value <code>false</code>, and the * corresponding bit in the argument has the value <code>true</code>. * </ul> <br> * <b>Note</b>, this BitSet's capacity may change when executing * this method, because the two BitSet are set to the larger * length of the internal used array <tt>bits</tt>, so this * array will have the following length: <br> * <br><br> * <code><pre> * Math.max(bits.length, bitSet.bits.length) * </code></pre> * * @param bitSet a bit set the operation should be fulfilled with. */ public void xor (BitSet bitSet) { // ensure capacity long[] result = new long[Math.max(bits.length, bitSet.bits.length)]; if (compareTo(bitSet)!=0) { int i; //position int min = Math.min(bits.length, bitSet.bits.length); // perform logical XOR on bits in common for (i=0; i<min; i++) result[i] = bits[i] ^ bitSet.bits[i]; BitSet set = (result.length == bits.length) ? this : bitSet; // larger bit set // copy any remaining bits for ( ; i<result.length; i++) result[i] = set.bits[i]; } this.bits = result; //assign the bit-array } /** * Performs a logical <b>NOT</b> of this bit set. * This bit set is modified so that every bit is negated, i.e. * a set bit is cleared and a bit set to <tt>false</tt> is set * to <tt>true</tt>. */ public void not () { // perform logical NOT for (int i=0; i<bits.length; i++) bits[i] = ~bits[i]; } }