524 lines
12 KiB
Java
524 lines
12 KiB
Java
/*******************************************************************************
|
|
* Copyright (c) 2002 - 2006 IBM Corporation.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* which accompanies this distribution, and is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
*
|
|
* Contributors:
|
|
* IBM Corporation - initial API and implementation
|
|
*******************************************************************************/
|
|
package com.ibm.wala.util.intset;
|
|
|
|
/**
|
|
*/
|
|
public final class OffsetBitVector extends BitVectorBase<OffsetBitVector> {
|
|
|
|
int offset;
|
|
|
|
private int wordDiff(int offset1, int offset2) {
|
|
return (offset1 > offset2) ? (offset1 - offset2) >> LOG_BITS_PER_UNIT : -((offset2 - offset1) >> LOG_BITS_PER_UNIT);
|
|
}
|
|
|
|
/**
|
|
* Expand this bit vector to size newCapacity.
|
|
*/
|
|
private void expand(int newOffset, int newCapacity) {
|
|
int wordDiff = wordDiff(newOffset, offset);
|
|
|
|
int[] oldbits = bits;
|
|
bits = new int[subscript(newCapacity) + 1];
|
|
for (int i = 0; i < oldbits.length; i++) {
|
|
bits[i - wordDiff] = oldbits[i];
|
|
}
|
|
offset = newOffset;
|
|
}
|
|
|
|
private void ensureCapacity(int newOffset, int newCapacity) {
|
|
if (newOffset < offset || newCapacity > (bits.length << LOG_BITS_PER_UNIT)) {
|
|
expand(newOffset, newCapacity);
|
|
}
|
|
}
|
|
|
|
public OffsetBitVector() {
|
|
this(0, 1);
|
|
}
|
|
|
|
/**
|
|
* Creates an empty string with the specified size.
|
|
*
|
|
* @param nbits the size of the string
|
|
*/
|
|
public OffsetBitVector(int offset, int nbits) {
|
|
if (nbits < 0) {
|
|
throw new IllegalArgumentException("invalid nbits: " + nbits);
|
|
}
|
|
if (offset < 0) {
|
|
throw new IllegalArgumentException("invalid offset: " + offset);
|
|
}
|
|
offset = (offset & ~LOW_MASK);
|
|
this.offset = offset;
|
|
this.bits = new int[subscript(nbits) + 1];
|
|
}
|
|
|
|
/**
|
|
* Creates a copy of a Bit String
|
|
*
|
|
* @param s the string to copy
|
|
* @throws IllegalArgumentException if s is null
|
|
*/
|
|
public OffsetBitVector(OffsetBitVector s) {
|
|
if (s == null) {
|
|
throw new IllegalArgumentException("s is null");
|
|
}
|
|
offset = s.offset;
|
|
bits = new int[s.bits.length];
|
|
System.arraycopy(s.bits, 0, bits, 0, s.bits.length);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return super.toString() + "(offset:" + offset + ")";
|
|
}
|
|
|
|
void growCapacity(float fraction) {
|
|
expand(offset, (int) (fraction * (bits.length << LOG_BITS_PER_UNIT)));
|
|
}
|
|
|
|
public int getOffset() {
|
|
return offset;
|
|
}
|
|
|
|
int getSize() {
|
|
return bits.length;
|
|
}
|
|
|
|
/**
|
|
* Sets a bit.
|
|
*
|
|
* @param bit the bit to be set
|
|
*/
|
|
@Override
|
|
public final void set(int bit) {
|
|
if (bit < 0) {
|
|
throw new IllegalArgumentException("illegal bit: " + bit);
|
|
}
|
|
int shiftBits;
|
|
int subscript;
|
|
if (bit < offset) {
|
|
int newOffset = bit & ~LOW_MASK;
|
|
expand(newOffset, length() - 1 - newOffset);
|
|
shiftBits = bit & LOW_MASK;
|
|
subscript = 0;
|
|
} else {
|
|
bit -= offset;
|
|
shiftBits = bit & LOW_MASK;
|
|
subscript = subscript(bit);
|
|
if (subscript >= bits.length) {
|
|
expand(offset, bit);
|
|
}
|
|
}
|
|
|
|
try {
|
|
bits[subscript] |= (1 << shiftBits);
|
|
} catch (RuntimeException e) {
|
|
e.printStackTrace();
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clears a bit.
|
|
*
|
|
* @param bit the bit to be cleared
|
|
*/
|
|
@Override
|
|
public final void clear(int bit) {
|
|
if (bit < offset) {
|
|
return;
|
|
}
|
|
bit -= offset;
|
|
|
|
int ss = subscript(bit);
|
|
if (ss >= bits.length) {
|
|
return;
|
|
}
|
|
int shiftBits = bit & LOW_MASK;
|
|
bits[ss] &= ~(1 << shiftBits);
|
|
}
|
|
|
|
/**
|
|
* Gets a bit.
|
|
*
|
|
* @param bit the bit to be gotten
|
|
*/
|
|
@Override
|
|
public final boolean get(int bit) {
|
|
if (DEBUG) {
|
|
assert bit >= 0;
|
|
}
|
|
if (bit < offset) {
|
|
return false;
|
|
}
|
|
bit -= offset;
|
|
|
|
int ss = subscript(bit);
|
|
if (ss >= bits.length) {
|
|
return false;
|
|
}
|
|
int shiftBits = bit & LOW_MASK;
|
|
return ((bits[ss] & (1 << shiftBits)) != 0);
|
|
}
|
|
|
|
/**
|
|
* @param start
|
|
* @return min j >= start s.t get(j)
|
|
*/
|
|
@Override
|
|
public int nextSetBit(int start) {
|
|
int nb = super.nextSetBit(Math.max(0, start - offset));
|
|
return nb == -1 ? -1 : offset + nb;
|
|
}
|
|
|
|
/**
|
|
* Logically NOT this bit string
|
|
*/
|
|
public final void not() {
|
|
if (offset != 0) {
|
|
expand(0, offset + length() - 1);
|
|
}
|
|
for (int i = 0; i < bits.length; i++) {
|
|
bits[i] ^= MASK;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int max() {
|
|
return super.max() + offset;
|
|
}
|
|
|
|
/**
|
|
* Calculates and returns the set's size in bits. The maximum element in the set is the size - 1st element.
|
|
*/
|
|
@Override
|
|
public final int length() {
|
|
return (bits.length << LOG_BITS_PER_UNIT) + offset;
|
|
}
|
|
|
|
/**
|
|
* Sets all bits.
|
|
*/
|
|
public final void setAll() {
|
|
expand(0, length() - 1);
|
|
for (int i = 0; i < bits.length; i++) {
|
|
bits[i] = MASK;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compares this object against the specified object.
|
|
*
|
|
* @param obj the object to compare with
|
|
* @return true if the objects are the same; false otherwise.
|
|
*/
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if ((obj != null) && (obj instanceof OffsetBitVector)) {
|
|
if (this == obj) { // should help alias analysis
|
|
return true;
|
|
}
|
|
OffsetBitVector set = (OffsetBitVector) obj;
|
|
return sameBits(set);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if the intersection of the two sets is empty
|
|
*
|
|
* @param set the set to check intersection with
|
|
* @throws IllegalArgumentException if set == null
|
|
*/
|
|
@Override
|
|
public final boolean intersectionEmpty(OffsetBitVector set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
if (this == set) {
|
|
return isZero();
|
|
}
|
|
|
|
int wordDiff = wordDiff(offset, set.offset);
|
|
int maxWord = Math.min(bits.length, set.bits.length - wordDiff);
|
|
|
|
int i = Math.max(0, -wordDiff);
|
|
|
|
for (; i < maxWord; i++) {
|
|
if ((bits[i] & set.bits[i + wordDiff]) != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Compares this object against the specified object.
|
|
*
|
|
* @param set the object to compare with
|
|
* @return true if the objects are the same; false otherwise.
|
|
* @throws IllegalArgumentException if set == null
|
|
*/
|
|
@Override
|
|
public final boolean sameBits(OffsetBitVector set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
if (this == set) { // should help alias analysis
|
|
return true;
|
|
}
|
|
|
|
int wordDiff = wordDiff(offset, set.offset);
|
|
int maxWord = Math.min(bits.length, set.bits.length - wordDiff);
|
|
|
|
int i = 0;
|
|
|
|
if (wordDiff < 0) {
|
|
for (; i < -wordDiff; i++) {
|
|
if (bits[i] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
for (int j = 0; j < wordDiff; j++) {
|
|
if (set.bits[j] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (; i < maxWord; i++) {
|
|
if (bits[i] != set.bits[i + wordDiff]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (int j = maxWord + wordDiff; j < set.bits.length; j++) {
|
|
if (set.bits[j] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (; i < bits.length; i++) {
|
|
if (bits[i] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* @param other @return true iff this is a subset of other
|
|
*/
|
|
@Override
|
|
public boolean isSubset(OffsetBitVector other) throws IllegalArgumentException {
|
|
if (other == null) {
|
|
throw new IllegalArgumentException("other == null");
|
|
}
|
|
if (this == other) { // should help alias analysis
|
|
return true;
|
|
}
|
|
int wordDiff = wordDiff(offset, other.offset);
|
|
int maxWord = Math.min(bits.length, other.bits.length - wordDiff);
|
|
|
|
int i = 0;
|
|
|
|
for (; i < -wordDiff; i++) {
|
|
if (bits[i] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (; i < maxWord; i++) {
|
|
if ((bits[i] & ~other.bits[i + wordDiff]) != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (; i < bits.length; i++) {
|
|
if (bits[i] != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Copies the values of the bits in the specified set into this set.
|
|
*
|
|
* @param set the bit set to copy the bits from
|
|
* @throws IllegalArgumentException if set is null
|
|
*/
|
|
public final void copyBits(OffsetBitVector set) {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set is null");
|
|
}
|
|
super.copyBits(set);
|
|
offset = set.offset;
|
|
}
|
|
|
|
/**
|
|
* Logically ANDs this bit set with the specified set of bits.
|
|
*
|
|
* @param set the bit set to be ANDed with
|
|
* @throws IllegalArgumentException if set == null
|
|
*/
|
|
@Override
|
|
public final void and(OffsetBitVector set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
if (this == set) {
|
|
return;
|
|
}
|
|
|
|
int wordDiff = wordDiff(offset, set.offset);
|
|
int maxWord = Math.min(bits.length, set.bits.length - wordDiff);
|
|
|
|
int i = 0;
|
|
|
|
for (; i < -wordDiff; i++) {
|
|
bits[i] = 0;
|
|
}
|
|
|
|
for (; i < maxWord; i++) {
|
|
bits[i] &= set.bits[i + wordDiff];
|
|
}
|
|
|
|
for (; i < bits.length; i++) {
|
|
bits[i] = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Logically ORs this bit set with the specified set of bits.
|
|
*
|
|
* @param set the bit set to be ORed with
|
|
* @throws IllegalArgumentException if set == null
|
|
*/
|
|
@Override
|
|
public final void or(OffsetBitVector set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
if (this == set) { // should help alias analysis
|
|
return;
|
|
}
|
|
|
|
int newOffset = Math.min(offset, set.offset);
|
|
int newCapacity = Math.max(length(), set.length()) - newOffset;
|
|
ensureCapacity(newOffset, newCapacity);
|
|
|
|
int wordDiff = wordDiff(newOffset, set.offset);
|
|
|
|
for (int i = 0; i < set.bits.length; i++) {
|
|
bits[i - wordDiff] |= set.bits[i];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Logically XORs this bit set with the specified set of bits.
|
|
*
|
|
* @param set the bit set to be XORed with
|
|
* @throws IllegalArgumentException if set == null
|
|
*/
|
|
@Override
|
|
public final void xor(OffsetBitVector set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
if (this == set) {
|
|
clearAll();
|
|
return;
|
|
}
|
|
|
|
int newOffset = Math.min(offset, set.offset);
|
|
int newCapacity = Math.max(length(), set.length()) - newOffset;
|
|
ensureCapacity(newOffset, newCapacity);
|
|
|
|
int wordDiff = wordDiff(newOffset, set.offset);
|
|
|
|
for (int i = 0; i < set.bits.length; i++) {
|
|
bits[i - wordDiff] ^= set.bits[i];
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void andNot(OffsetBitVector set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
if (this == set) {
|
|
clearAll();
|
|
return;
|
|
}
|
|
|
|
int wordDiff = wordDiff(offset, set.offset);
|
|
int maxWord = Math.min(bits.length, set.bits.length - wordDiff);
|
|
|
|
int i = Math.max(0, -wordDiff);
|
|
|
|
for (; i < maxWord; i++) {
|
|
bits[i] &= ~set.bits[i + wordDiff];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the NOT of a bit string
|
|
*/
|
|
public static OffsetBitVector not(OffsetBitVector s) {
|
|
OffsetBitVector b = new OffsetBitVector(s);
|
|
b.not();
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Return a new bit string as the AND of two others.
|
|
*
|
|
* @throws IllegalArgumentException if b2 == null
|
|
*/
|
|
public static OffsetBitVector and(OffsetBitVector b1, OffsetBitVector b2) throws IllegalArgumentException {
|
|
if (b2 == null) {
|
|
throw new IllegalArgumentException("b2 == null");
|
|
}
|
|
OffsetBitVector b = new OffsetBitVector(b1);
|
|
b.and(b2);
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Return a new FixedSizeBitVector as the OR of two others
|
|
*
|
|
* @throws IllegalArgumentException if b2 == null
|
|
*/
|
|
public static OffsetBitVector or(OffsetBitVector b1, OffsetBitVector b2) throws IllegalArgumentException {
|
|
if (b2 == null) {
|
|
throw new IllegalArgumentException("b2 == null");
|
|
}
|
|
OffsetBitVector b = new OffsetBitVector(b1);
|
|
b.or(b2);
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Return a new bit string as the AND of two others.
|
|
*/
|
|
public static OffsetBitVector andNot(OffsetBitVector b1, OffsetBitVector b2) {
|
|
OffsetBitVector b = new OffsetBitVector(b1);
|
|
b.andNot(b2);
|
|
return b;
|
|
}
|
|
}
|