001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.util;
014    
015    import java.io.Serializable;
016    
017    /**
018     * Implements a bit vector.
019     */
020    public final class BitVector implements Serializable {
021      /** Support for serialization */
022      static final long serialVersionUID = 6961578653974090041L;
023    
024      private static final int LOG_BITS_PER_UNIT = 5;
025      private static final int MASK = 0xffffffff;
026      private static final int LOW_MASK = 0x1f;
027      private final int[] bits;
028      private final int nbits;
029    
030      /**
031       * Convert bitIndex to a subscript into the bits[] array.
032       */
033      private static int subscript(int bitIndex) {
034        return bitIndex >> LOG_BITS_PER_UNIT;
035      }
036    
037      /**
038       * Creates an empty string with the specified size.
039       * @param nbits the size of the string
040       */
041      public BitVector(int nbits) {
042        // subscript(nbits) is the length of the array needed to
043        // hold nbits
044        bits = new int[subscript(nbits) + 1];
045        this.nbits = nbits;
046      }
047    
048      /**
049       * Creates a copy of a Bit String
050       * @param s the string to copy
051       */
052      public BitVector(BitVector s) {
053        bits = new int[s.bits.length];
054        this.nbits = s.nbits;
055        System.arraycopy(s.bits, 0, this.bits, 0, s.bits.length);
056      }
057    
058      /**
059       * Sets all bits.
060       */
061      public void setAll() {
062        for (int i = 0; i < bits.length; i++) {
063          bits[i] = MASK;
064        }
065      }
066    
067      /**
068       * Sets a bit.
069       * @param bit the bit to be set
070       */
071      public void set(int bit) {
072        int shiftBits = bit & LOW_MASK;
073        bits[subscript(bit)] |= (1 << shiftBits);
074      }
075    
076      /**
077       * Clears all bits.
078       */
079      public void clearAll() {
080        for (int i = 0; i < bits.length; i++) {
081          bits[i] = 0;
082        }
083      }
084    
085      /**
086       * Clears a bit.
087       * @param bit the bit to be cleared
088       */
089      public void clear(int bit) {
090        int shiftBits = bit & LOW_MASK;
091        bits[subscript(bit)] &= ~(1 << shiftBits);
092      }
093    
094      /**
095       * Gets a bit.
096       * @param bit the bit to be gotten
097       */
098      public boolean get(int bit) {
099        int shiftBits = bit & LOW_MASK;
100        int n = subscript(bit);
101        return ((bits[n] & (1 << shiftBits)) != 0);
102      }
103    
104      /**
105       * Logically NOT this bit string
106       */
107      public void not() {
108        for (int i = 0; i < bits.length; i++) {
109          bits[i] ^= MASK;
110        }
111      }
112    
113      /**
114       * Return the NOT of a bit string
115       */
116      public static BitVector not(BitVector s) {
117        BitVector b = new BitVector(s);
118        b.not();
119        return b;
120      }
121    
122      /**
123       * Logically ANDs this bit set with the specified set of bits.
124       * @param set the bit set to be ANDed with
125       */
126      public void and(BitVector set) {
127        if (this == set) {
128          return;
129        }
130        int n = bits.length;
131        for (int i = n; i-- > 0;) {
132          bits[i] &= set.bits[i];
133        }
134      }
135    
136      /**
137       * Return a new bit string as the AND of two others.
138       */
139      public static BitVector and(BitVector b1, BitVector b2) {
140        BitVector b = new BitVector(b1);
141        b.and(b2);
142        return b;
143      }
144    
145      /**
146       * Logically ORs this bit set with the specified set of bits.
147       * @param set the bit set to be ORed with
148       */
149      public void or(BitVector set) {
150        if (this == set) { // should help alias analysis
151          return;
152        }
153        int setLength = set.bits.length;
154        for (int i = setLength; i-- > 0;) {
155          bits[i] |= set.bits[i];
156        }
157      }
158    
159      /**
160       * Return a new BitVector as the OR of two others
161       */
162      public static BitVector or(BitVector b1, BitVector b2) {
163        BitVector b = new BitVector(b1);
164        b.or(b2);
165        return b;
166      }
167    
168      /**
169       * Logically XORs this bit set with the specified set of bits.
170       * @param set the bit set to be XORed with
171       */
172      public void xor(BitVector set) {
173        int setLength = set.bits.length;
174        for (int i = setLength; i-- > 0;) {
175          bits[i] ^= set.bits[i];
176        }
177      }
178    
179      /**
180       * Check if the intersection of the two sets is empty
181       * @param other the set to check intersection with
182       */
183      public boolean intersectionEmpty(BitVector other) {
184        int n = bits.length;
185        for (int i = n; i-- > 0;) {
186          if ((bits[i] & other.bits[i]) != 0) return false;
187        }
188        return true;
189      }
190    
191      /**
192       * Copies the values of the bits in the specified set into this set.
193       * @param set the bit set to copy the bits from
194       */
195      public void copyBits(BitVector set) {
196        System.arraycopy(set.bits, 0, this.bits, 0, set.bits.length);
197      }
198    
199      /**
200       * Gets the hashcode.
201       */
202      @Override
203      public int hashCode() {
204        int h = 1234;
205        for (int i = bits.length; --i >= 0;) {
206          h ^= bits[i] * (i + 1);
207        }
208        return h;
209      }
210    
211      /**
212       * How many bits are set?
213       */
214      public int populationCount() {
215        int count = 0;
216        for (int bit : bits) {
217          count += Integer.bitCount(bit);
218        }
219        return count;
220      }
221    
222      /**
223       * Calculates and returns the set's size in bits.
224       * The maximum element in the set is the size - 1st element.
225       */
226      public int length() {
227        return bits.length << LOG_BITS_PER_UNIT;
228      }
229    
230      /**
231       * Compares this object against the specified object.
232       * @param obj the object to compare with
233       * @return true if the objects are the same; false otherwise.
234       */
235      @Override
236      public boolean equals(Object obj) {
237        if ((obj != null) && (obj instanceof BitVector)) {
238          if (this == obj) { // should help alias analysis
239            return true;
240          }
241          BitVector set = (BitVector) obj;
242          int n = bits.length;
243          if (n != set.bits.length) return false;
244          for (int i = n; i-- > 0;) {
245            if (bits[i] != set.bits[i]) {
246              return false;
247            }
248          }
249          return true;
250        }
251        return false;
252      }
253    
254      public boolean isZero() {
255        int setLength = bits.length;
256        for (int i = setLength; i-- > 0;) {
257          if (bits[i] != 0) return false;
258        }
259        return true;
260      }
261    
262      public BitVector dup() {
263        return new BitVector(this);
264      }
265    
266      /**
267       * Converts the BitVector to a String.
268       */
269      @Override
270      public String toString() {
271        StringBuilder buffer = new StringBuilder();
272        boolean needSeparator = false;
273        buffer.append('{');
274    //    int limit = length();
275        int limit = this.nbits;
276        for (int i = 0; i < limit; i++) {
277          if (get(i)) {
278            if (needSeparator) {
279              buffer.append(", ");
280            } else {
281              needSeparator = true;
282            }
283            buffer.append(i);
284          }
285        }
286        buffer.append('}');
287        return buffer.toString();
288      }
289    }