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 */
013package org.jikesrvm.util;
014
015import java.io.Serializable;
016
017/**
018 * Implements a bit vector.
019 */
020public 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   * @param bitIndex the bit index
034   * @return subscript into the array
035   */
036  private static int subscript(int bitIndex) {
037    return bitIndex >> LOG_BITS_PER_UNIT;
038  }
039
040  /**
041   * Creates an empty string with the specified size.
042   * @param nbits the size of the string
043   */
044  public BitVector(int nbits) {
045    // subscript(nbits) is the length of the array needed to
046    // hold nbits
047    bits = new int[subscript(nbits) + 1];
048    this.nbits = nbits;
049  }
050
051  /**
052   * Creates a copy of a Bit String
053   * @param s the string to copy
054   */
055  public BitVector(BitVector s) {
056    bits = new int[s.bits.length];
057    this.nbits = s.nbits;
058    System.arraycopy(s.bits, 0, this.bits, 0, s.bits.length);
059  }
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   * @return the value of the bit, {@code 0} for {@code false}
098   */
099  public boolean get(int bit) {
100    int shiftBits = bit & LOW_MASK;
101    int n = subscript(bit);
102    return ((bits[n] & (1 << shiftBits)) != 0);
103  }
104
105  /**
106   * Logically NOT this bit string
107   */
108  public void not() {
109    for (int i = 0; i < bits.length; i++) {
110      bits[i] ^= MASK;
111    }
112  }
113
114  public static BitVector not(BitVector s) {
115    BitVector b = new BitVector(s);
116    b.not();
117    return b;
118  }
119
120  /**
121   * Logically ANDs this bit set with the specified set of bits.
122   * @param set the bit set to be ANDed with
123   */
124  public void and(BitVector set) {
125    if (this == set) {
126      return;
127    }
128    int n = bits.length;
129    for (int i = n; i-- > 0;) {
130      bits[i] &= set.bits[i];
131    }
132  }
133
134  public static BitVector and(BitVector b1, BitVector b2) {
135    BitVector b = new BitVector(b1);
136    b.and(b2);
137    return b;
138  }
139
140  /**
141   * Logically ORs this bit set with the specified set of bits.
142   * @param set the bit set to be ORed with
143   */
144  public void or(BitVector set) {
145    if (this == set) { // should help alias analysis
146      return;
147    }
148    int setLength = set.bits.length;
149    for (int i = setLength; i-- > 0;) {
150      bits[i] |= set.bits[i];
151    }
152  }
153
154  public static BitVector or(BitVector b1, BitVector b2) {
155    BitVector b = new BitVector(b1);
156    b.or(b2);
157    return b;
158  }
159
160  /**
161   * Logically XORs this bit set with the specified set of bits.
162   * @param set the bit set to be XORed with
163   */
164  public void xor(BitVector set) {
165    int setLength = set.bits.length;
166    for (int i = setLength; i-- > 0;) {
167      bits[i] ^= set.bits[i];
168    }
169  }
170
171  /**
172   * @param other the set to check intersection with
173   * @return whether the intersection of the two sets is empty
174   */
175  public boolean intersectionEmpty(BitVector other) {
176    int n = bits.length;
177    for (int i = n; i-- > 0;) {
178      if ((bits[i] & other.bits[i]) != 0) return false;
179    }
180    return true;
181  }
182
183  /**
184   * Copies the values of the bits in the specified set into this set.
185   * @param set the bit set to copy the bits from
186   */
187  public void copyBits(BitVector set) {
188    System.arraycopy(set.bits, 0, this.bits, 0, set.bits.length);
189  }
190
191  @Override
192  public int hashCode() {
193    int h = 1234;
194    for (int i = bits.length; --i >= 0;) {
195      h ^= bits[i] * (i + 1);
196    }
197    return h;
198  }
199
200  /**
201   * @return number of bits that are set
202   */
203  public int populationCount() {
204    int count = 0;
205    for (int bit : bits) {
206      count += Integer.bitCount(bit);
207    }
208    return count;
209  }
210
211  /**
212   * Calculates and returns the set's size in bits.
213   * The maximum element in the set is the size - 1st element.
214   *
215   * @return the length of this set in bits
216   */
217  public int length() {
218    return bits.length << LOG_BITS_PER_UNIT;
219  }
220
221  /**
222   * Compares this object against the specified object.
223   * @param obj the object to compare with
224   * @return true if the objects are the same; false otherwise.
225   */
226  @Override
227  public boolean equals(Object obj) {
228    if (obj instanceof BitVector) {
229      if (this == obj) { // should help alias analysis
230        return true;
231      }
232      BitVector set = (BitVector) obj;
233      int n = bits.length;
234      if (n != set.bits.length) return false;
235      for (int i = n; i-- > 0;) {
236        if (bits[i] != set.bits[i]) {
237          return false;
238        }
239      }
240      return true;
241    }
242    return false;
243  }
244
245  public boolean isZero() {
246    int setLength = bits.length;
247    for (int i = setLength; i-- > 0;) {
248      if (bits[i] != 0) return false;
249    }
250    return true;
251  }
252
253  public BitVector dup() {
254    return new BitVector(this);
255  }
256
257  @Override
258  public String toString() {
259    StringBuilder buffer = new StringBuilder();
260    boolean needSeparator = false;
261    buffer.append('{');
262//    int limit = length();
263    int limit = this.nbits;
264    for (int i = 0; i < limit; i++) {
265      if (get(i)) {
266        if (needSeparator) {
267          buffer.append(", ");
268        } else {
269          needSeparator = true;
270        }
271        buffer.append(i);
272      }
273    }
274    buffer.append('}');
275    return buffer.toString();
276  }
277}