new bit vectors that do not require 0 to be the first index; also a new intset implementation that uses them combined with a sparse set and makes some attempt to minimize space use

git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@512 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
dolby-oss 2006-12-21 18:04:07 +00:00
parent ae9272eb7e
commit 8c87eb9b13
6 changed files with 1316 additions and 211 deletions

View File

@ -18,23 +18,9 @@ import com.ibm.wala.util.debug.Assertions;
* @author sfink
*
*/
public class BitVector implements Cloneable, Serializable {
public final class BitVector extends BitVectorBase<BitVector> {
private static final long serialVersionUID = 9087259335807761617L;
private final static int LOG_BITS_PER_UNIT = 5;
private final static int BITS_PER_UNIT = 32;
private final static int MASK = 0xffffffff;
private final static int LOW_MASK = 0x1f;
int bits[];
private final static boolean DEBUG = false;
/**
* Convert bitIndex to a subscript into the bits[] array.
*/
public static int subscript(int bitIndex) {
return bitIndex >> LOG_BITS_PER_UNIT;
}
public BitVector() {
this(1);
@ -72,15 +58,6 @@ public class BitVector implements Cloneable, Serializable {
copyBits(s);
}
/**
* Sets all bits.
*/
public final void setAll() {
for (int i = 0; i < bits.length; i++) {
bits[i] = MASK;
}
}
/**
* Sets a bit.
*
@ -102,15 +79,6 @@ public class BitVector implements Cloneable, Serializable {
}
}
/**
* Clears all bits.
*/
public final void clearAll() {
for (int i = 0; i < bits.length; i++) {
bits[i] = 0;
}
}
/**
* Clears a bit.
*
@ -144,15 +112,6 @@ public class BitVector implements Cloneable, Serializable {
return ((bits[ss] & (1 << shiftBits)) != 0);
}
/**
* Logically NOT this bit string
*/
public final void not() {
for (int i = 0; i < bits.length; i++) {
bits[i] ^= MASK;
}
}
/**
* Return the NOT of a bit string
*/
@ -287,45 +246,6 @@ public class BitVector implements Cloneable, Serializable {
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
*/
public final void copyBits(BitVector set) {
int setLength = set.bits.length;
bits = new int[setLength];
for (int i = setLength - 1; i >= 0;) {
bits[i] = set.bits[i];
i--;
}
}
/**
* Gets the hashcode.
*/
public int hashCode() {
int h = 1234;
for (int i = bits.length - 1; i >= 0;) {
h ^= bits[i] * (i + 1);
i--;
}
return h;
}
/**
* How many bits are set?
*/
public final int populationCount() {
int count = 0;
for (int i = 0; i < bits.length; i++) {
count += Bits.populationCount(bits[i]);
}
return count;
}
/**
* Calculates and returns the set's size in bits. The maximum element in the
* set is the size - 1st element.
@ -366,135 +286,6 @@ public class BitVector implements Cloneable, Serializable {
return true;
}
/**
* Compares this object against the specified object.
*
* @param obj
* the object to compare with
* @return true if the objects are the same; false otherwise.
*/
public boolean equals(Object obj) {
if ((obj != null) && (obj instanceof BitVector)) {
if (this == obj) { // should help alias analysis
return true;
}
BitVector set = (BitVector) obj;
return sameBits(set);
}
return false;
}
public boolean isZero() {
int setLength = bits.length;
for (int i = setLength - 1; i >= 0;) {
if (bits[i] != 0)
return false;
i--;
}
return true;
}
/**
* Clones the FixedSizeBitVector.
*/
public Object clone() {
BitVector result = null;
try {
result = (BitVector) super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
result.bits = new int[bits.length];
System.arraycopy(bits, 0, result.bits, 0, result.bits.length);
return result;
}
/**
* Converts the FixedSizeBitVector to a String.
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
boolean needSeparator = false;
buffer.append('{');
int limit = length();
for (int i = 0; i < limit; i++) {
if (get(i)) {
if (needSeparator) {
buffer.append(", ");
} else {
needSeparator = true;
}
buffer.append(i);
}
}
buffer.append('}');
return buffer.toString();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.util.intset.IntSet#contains(int)
*/
public boolean contains(int i) {
return get(i);
}
private static final int[][] masks = new int[][] {
{ 0xFFFF0000 },
{ 0xFF000000, 0x0000FF00 },
{ 0xF0000000, 0x00F00000, 0x0000F000, 0x000000F0 },
{ 0xC0000000, 0x0C000000, 0x00C00000, 0x000C0000, 0x0000C000, 0x00000C00, 0x000000C0, 0x0000000C},
{ 0x80000000, 0x20000000, 0x08000000, 0x02000000, 0x00800000, 0x00200000, 0x00080000, 0x00020000, 0x00008000, 0x00002000, 0x00000800, 0x00000200, 0x00000080, 0x00000020, 0x00000008, 0x00000002 }
};
public int max() {
int lastWord = bits.length - 1;
int count = lastWord * BITS_PER_UNIT;
int top = bits[lastWord];
// Assertions._assert(top != 0);
int j = 0;
for (int i = 0; i < masks.length; i++) {
if ((top & masks[i][j]) != 0) {
j <<= 1;
} else {
j <<= 1;
j++;
}
}
return count + (31-j);
}
/**
* @param start
* @return min j >= start s.t get(j)
*/
public int nextSetBit(int start) {
int word = subscript(start);
int bit = (1 << (start & LOW_MASK));
while (word < bits.length) {
if (bits[word] != 0) {
do {
if ((bits[word] & bit) != 0)
return start;
bit <<= 1;
start++;
} while (bit != 0);
} else {
start += (BITS_PER_UNIT - (start&LOW_MASK));
}
word++;
bit = 1;
}
return -1;
}
/**
* @param other
* @return true iff this is a subset of other
@ -527,6 +318,42 @@ public class BitVector implements Cloneable, Serializable {
bits[ai] = bits[ai] & (~vector.bits[bi]);
}
}
/**
* Compares this object against the specified object.
*
* @param obj
* the object to compare with
* @return true if the objects are the same; false otherwise.
*/
public boolean equals(Object obj) {
if ((obj != null) && (obj instanceof BitVector)) {
if (this == obj) { // should help alias analysis
return true;
}
BitVector set = (BitVector) obj;
return sameBits(set);
}
return false;
}
/**
* Sets all bits.
*/
public final void setAll() {
for (int i = 0; i < bits.length; i++) {
bits[i] = MASK;
}
}
/**
* Logically NOT this bit string
*/
public final void not() {
for (int i = 0; i < bits.length; i++) {
bits[i] ^= MASK;
}
}
/**
* Return a new bit string as the AND of two others.

View File

@ -0,0 +1,226 @@
/*******************************************************************************
* 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;
import java.io.Serializable;
import com.ibm.wala.util.debug.Assertions;
/**
* @author sfink
* @author Julian Dolby (dolby@us.ibm.com)
*/
abstract public class BitVectorBase<T extends BitVectorBase>
implements Cloneable, Serializable
{
protected final static boolean DEBUG = false;
protected final static int LOG_BITS_PER_UNIT = 5;
protected final static int BITS_PER_UNIT = 32;
protected final static int MASK = 0xffffffff;
protected final static int LOW_MASK = 0x1f;
protected int bits[];
public abstract void set(int bit);
public abstract void clear(int bit);
public abstract boolean get(int bit);
public abstract int length();
public abstract void and(T other);
public abstract void andNot(T other);
public abstract void or(T other);
public abstract void xor(T other);
public abstract boolean sameBits(T other);
public abstract boolean isSubset(T other);
public abstract boolean intersectionEmpty(T other);
/**
* Convert bitIndex to a subscript into the bits[] array.
*/
public static int subscript(int bitIndex) {
return bitIndex >> LOG_BITS_PER_UNIT;
}
/**
* Clears all bits.
*/
public final void clearAll() {
for (int i = 0; i < bits.length; i++) {
bits[i] = 0;
}
}
/**
* Gets the hashcode.
*/
public int hashCode() {
int h = 1234;
for (int i = bits.length - 1; i >= 0;) {
h ^= bits[i] * (i + 1);
i--;
}
return h;
}
/**
* How many bits are set?
*/
public final int populationCount() {
int count = 0;
for (int i = 0; i < bits.length; i++) {
count += Bits.populationCount(bits[i]);
}
return count;
}
public boolean isZero() {
int setLength = bits.length;
for (int i = setLength - 1; i >= 0;) {
if (bits[i] != 0)
return false;
i--;
}
return true;
}
/**
* Clones the FixedSizeBitVector.
*/
public Object clone() {
BitVector result = null;
try {
result = (BitVector) super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
result.bits = new int[bits.length];
System.arraycopy(bits, 0, result.bits, 0, result.bits.length);
return result;
}
/**
* Converts the FixedSizeBitVector to a String.
*/
public String toString() {
StringBuffer buffer = new StringBuffer();
boolean needSeparator = false;
buffer.append('{');
int limit = length();
for (int i = 0; i < limit; i++) {
if (get(i)) {
if (needSeparator) {
buffer.append(", ");
} else {
needSeparator = true;
}
buffer.append(i);
}
}
buffer.append('}');
return buffer.toString();
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.util.intset.IntSet#contains(int)
*/
public boolean contains(int i) {
return get(i);
}
private static final int[][] masks = new int[][] {
{ 0xFFFF0000 },
{ 0xFF000000, 0x0000FF00 },
{ 0xF0000000, 0x00F00000, 0x0000F000, 0x000000F0 },
{ 0xC0000000, 0x0C000000, 0x00C00000, 0x000C0000, 0x0000C000, 0x00000C00, 0x000000C0, 0x0000000C},
{ 0x80000000, 0x20000000, 0x08000000, 0x02000000, 0x00800000, 0x00200000, 0x00080000, 0x00020000, 0x00008000, 0x00002000, 0x00000800, 0x00000200, 0x00000080, 0x00000020, 0x00000008, 0x00000002 }
};
public int max() {
int lastWord = bits.length - 1;
while (lastWord >= 0 && bits[lastWord] == 0) lastWord--;
if (lastWord < 0) return -1;
int count = lastWord * BITS_PER_UNIT;
int top = bits[lastWord];
int j = 0;
for (int i = 0; i < masks.length; i++) {
if ((top & masks[i][j]) != 0) {
j <<= 1;
} else {
j <<= 1;
j++;
}
}
return count + (31-j);
}
/**
* @param start
* @return min j >= start s.t get(j)
*/
public int nextSetBit(int start) {
int word = subscript(start);
int bit = (1 << (start & LOW_MASK));
while (word < bits.length) {
if (bits[word] != 0) {
do {
if ((bits[word] & bit) != 0)
return start;
bit <<= 1;
start++;
} while (bit != 0);
} else {
start += (BITS_PER_UNIT - (start&LOW_MASK));
}
word++;
bit = 1;
}
return -1;
}
/**
* Copies the values of the bits in the specified set into this set.
*
* @param set
* the bit set to copy the bits from
*/
public void copyBits(BitVectorBase set) {
int setLength = set.bits.length;
bits = new int[setLength];
for (int i = setLength - 1; i >= 0;) {
bits[i] = set.bits[i];
i--;
}
}
}

View File

@ -56,7 +56,7 @@ public class DebuggingMutableIntSetFactory implements MutableIntSetFactory {
Assertions._assert( pr.sameValue( db.primaryImpl ) );
Assertions._assert( sr.sameValue( db.secondaryImpl ) );
Assertions._assert( sr.sameValue( pr ) );
Assertions._assert( pr.sameValue( sr ) );
return new DebuggingMutableIntSet(pr, sr);
} else {

View File

@ -0,0 +1,467 @@
/*******************************************************************************
* 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;
import java.io.Serializable;
import com.ibm.wala.util.debug.Assertions;
/**
* @author Julian Dolby (dolby@us.ibm.com)
*
*/
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;
}
/**
* @param set
*/
private void ensureCapacity(int newOffset, int newCapacity) {
if (newOffset < offset || newCapacity>(bits.length<< LOG_BITS_PER_UNIT)) {
expand(newOffset, newCapacity);
}
}
private void ensureCapacity(OffsetBitVector set) {
int newOffset = Math.min(offset, set.offset);
int newCapacity =
Math.max(length(),set.length())-newOffset;
ensureCapacity(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) {
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
*/
public OffsetBitVector(OffsetBitVector s) {
offset = s.offset;
bits = new int[s.bits.length];
copyBits(s);
}
public String toString() {
return super.toString() + "(offset:" + offset + ")";
}
public int getOffset() {
return offset;
}
/**
* Sets a bit.
*
* @param bit
* the bit to be set
*/
public final void set(int bit) {
int shiftBits;
int subscript;
if (bit < offset) {
int newOffset = bit&~LOW_MASK;
expand(newOffset, length()-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
*/
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
*/
public final boolean get(int bit) {
if (DEBUG) {
Assertions._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)
*/
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());
}
for (int i = 0; i < bits.length; i++) {
bits[i] ^= MASK;
}
}
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.
*/
public final int length() {
return (bits.length << LOG_BITS_PER_UNIT) + offset;
}
/**
* Sets all bits.
*/
public final void setAll() {
expand(0, length());
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.
*/
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 other
* the set to check intersection with
*/
public final boolean intersectionEmpty(OffsetBitVector set) {
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 B
* the object to compare with
* @return true if the objects are the same; false otherwise.
*/
public final boolean sameBits(OffsetBitVector B) {
if (this == B) { // should help alias analysis
return true;
}
int n = Math.min(bits.length, B.bits.length);
if (bits.length > B.bits.length) {
for (int i = n; i < bits.length; i++) {
if (bits[i] != 0)
return false;
}
} else if (B.bits.length > bits.length) {
for (int i = n; i < B.bits.length; i++) {
if (B.bits[i] != 0)
return false;
}
}
for (int i = n - 1; i >= 0;) {
if (bits[i] != B.bits[i]) {
return false;
}
i--;
}
return true;
}
/**
* @param other
* @return true iff this is a subset of other
*/
public boolean isSubset(OffsetBitVector other) {
if (this == other) { // should help alias analysis
return true;
}
int wordDiff = wordDiff(offset, other.offset);
int i = 0;
for ( ; i < -wordDiff; i++) {
if (other.bits[i] != 0) {
return false;
}
}
int min = Math.min(bits.length, other.bits.length+wordDiff);
for ( ; i < min; 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
*/
public final void copyBits(OffsetBitVector set) {
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
*/
public final void and(OffsetBitVector set) {
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
*/
public final void or(OffsetBitVector set) {
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
*/
public final void xor(OffsetBitVector set) {
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];
}
}
/**
* @param vector
*/
public void andNot(OffsetBitVector set) {
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(offset, set.offset);
int n = Math.min(bits.length, set.bits.length+wordDiff);
for (int i = n - 1; i >= 0;) {
bits[i] &= ~(set.bits[i-wordDiff]);
i--;
}
}
/**
* 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.
*/
public static OffsetBitVector and(OffsetBitVector b1, OffsetBitVector b2) {
OffsetBitVector b = new OffsetBitVector(b1);
b.and(b2);
return b;
}
/**
* Return a new FixedSizeBitVector as the OR of two others
*/
public static OffsetBitVector or(OffsetBitVector b1, OffsetBitVector b2) {
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;
}
}

View File

@ -0,0 +1,512 @@
/*******************************************************************************
* 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;
import com.ibm.wala.util.collections.*;
public class SemiSparseMutableIntSet implements MutableIntSet {
private static final int SPARSE_INSERT_THRESHOLD = 10;
private MutableSparseIntSet sparsePart = new MutableSparseIntSet();
private OffsetBitVector densePart = null;
private int sparseInsertCount = 0;
private void fixAfterSparseInsert() {
if (sparseInsertCount++ > SPARSE_INSERT_THRESHOLD) {
sparseInsertCount = 0;
IntIterator sparseBits = sparsePart.intIterator();
int thisBit = sparseBits.next();
if (densePart == null) {
int maxOffset = -1;
int maxCount = -1;
int maxMax = -1;
int maxBit = -1;
int offset = thisBit;
int bits = 32;
int count = 1;
while (sparseBits.hasNext()) {
int nextBit = sparseBits.next();
int newBits = bits + (nextBit - thisBit);
int newCount = count + 1;
if (newBits > (32*newCount)) {
count = newCount;
bits = newBits;
} else if (bits > 32*count) {
if (count > maxCount) {
maxOffset = offset;
maxMax = thisBit;
maxCount = count;
}
offset = nextBit;
count = 1;
bits = 32;
}
thisBit = nextBit;
}
if (maxOffset != -1) {
densePart = new OffsetBitVector(maxOffset, maxMax);
sparseBits = sparsePart.intIterator();
int bit;
while ((bit = sparseBits.next()) != maxOffset);
for(int i = 0; i < maxCount; i++) {
densePart.set(sparseBits.next());
}
for(int bit1 = densePart.nextSetBit(0);
bit1 != -1;
bit1 = densePart.nextSetBit(bit1+1))
{
sparsePart.remove(bit1);
}
}
} else {
int moveCount = 0;
int newOffset = -1;
int newLength = -1;
// push stuff just below dense part into it, if it saves space
if (thisBit < densePart.getOffset()) {
newOffset = thisBit;
int bits = 32;
int count = 1;
while (sparseBits.hasNext()) {
int nextBit = sparseBits.next();
if (nextBit >= densePart.getOffset()) {
if (bits > (32*count)) {
moveCount += count;
break;
} else {
newOffset = -1;
}
} else {
bits += (nextBit - thisBit);
count++;
if (bits > (32*count)) {
newOffset = nextBit;
count = 1;
bits = 32;
}
}
}
}
// push stuff just above dense part into it, if it saves space
if (thisBit >= densePart.length()) {
int count = 1;
int bits = (thisBit + 1 - densePart.length());
if (32*count > bits) {
newLength = thisBit;
}
while (sparseBits.hasNext()) {
thisBit = sparseBits.next();
count++;
bits = (thisBit + 1 - densePart.length());
newLength = (32*count > bits)? thisBit: newLength;
}
if (newLength > -1) {
moveCount += count;
}
}
// actually move bits from sparse to dense
if (newOffset != -1 || newLength != -1) {
int index = 0;
int[] bits = new int[ moveCount ];
for(sparseBits = sparsePart.intIterator(); sparseBits.hasNext(); ) {
int bit = sparseBits.next();
if (newOffset!=-1 && bit>=newOffset && bit<=densePart.getOffset()) {
bits[index++] = bit;
}
if (newLength!=-1 && bit>=densePart.length() && bit<=newLength) {
bits[index++] = bit;
}
}
for(int i = 0; i < moveCount; i++) {
sparsePart.remove(bits[i]);
densePart.set(bits[i]);
}
}
}
}
}
/**
* @param i
* @return true iff this set contains integer i
*/
public boolean contains(int i) {
return
sparsePart.contains(i) || (densePart != null && densePart.contains(i));
}
/**
* @return true iff this set contains integer i
*/
public boolean containsAny(IntSet set) {
if (!sparsePart.isEmpty() && sparsePart.containsAny(set)) {
return true;
} else if (densePart != null) {
int lower = densePart.getOffset();
for(IntIterator is = set.intIterator(); is.hasNext(); ) {
int i = is.next();
if (i < lower) continue;
if (densePart.get(i)) {
return true;
}
}
}
return false;
}
/**
* This implementation must not despoil the original value of "this"
*
* @return a new IntSet which is the intersection of this and that
*/
public IntSet intersection(IntSet that) {
SemiSparseMutableIntSet newThis = new SemiSparseMutableIntSet();
for(IntIterator bits = intIterator(); bits.hasNext(); ) {
int bit = bits.next();
if (that.contains(bit)) {
newThis.add(bit);
}
}
return newThis;
}
/**
* @return true iff this set is empty
*/
public boolean isEmpty() {
return sparsePart.isEmpty() && (densePart == null || densePart.isZero());
}
/**
* @return the number of elements in this set
*/
public int size() {
return sparsePart.size() + (densePart==null? 0: densePart.populationCount());
}
/**
* @return a perhaps more efficient iterator
*/
public IntIterator intIterator() {
class DensePartIterator implements IntIterator {
private int i = -1;
public boolean hasNext() {
return densePart.nextSetBit(i+1) != -1;
}
public int next() {
int next = densePart.nextSetBit(i+1);
i = next+1;
return next;
}
};
if (sparsePart.isEmpty()) {
if (densePart == null || densePart.isZero()) {
return EmptyIntIterator.instance();
} else {
return new DensePartIterator();
}
} else {
if (densePart == null || densePart.isZero()) {
return sparsePart.intIterator();
} else {
return
new CompoundIntIterator(
sparsePart.intIterator(),
new DensePartIterator());
}
}
}
/**
* Invoke an action on each element of the Set
*
* @param action
*/
public void foreach(IntSetAction action) {
sparsePart.foreach(action);
if (densePart != null) {
for(int b = densePart.nextSetBit(0);
b != -1;
b = densePart.nextSetBit(b+1))
{
action.act(b);
}
}
}
/**
* Invoke an action on each element of the Set, excluding elements of Set X
*
* @param action
*/
public void foreachExcluding(IntSet X, IntSetAction action) {
sparsePart.foreachExcluding(X, action);
if (densePart != null) {
for(int b = densePart.nextSetBit(0);
b != -1;
b = densePart.nextSetBit(b+1))
{
if (! X.contains(b)) {
action.act(b);
}
}
}
}
/**
* @return maximum integer in this set.
*/
public int max() {
if (densePart == null) {
return sparsePart.max();
} else {
return Math.max(sparsePart.max(), densePart.max());
}
}
/**
* @return true iff <code>this</code> has the same value as
* <code>that</code>.
*/
public boolean sameValue(IntSet that) {
if (size() != that.size()) {
return false;
}
if (densePart != null) {
for(int bit = densePart.nextSetBit(0);
bit != -1;
bit = densePart.nextSetBit(bit+1))
{
if (! that.contains(bit)) {
return false;
}
}
}
for(IntIterator bits = sparsePart.intIterator(); bits.hasNext(); ) {
if (! that.contains(bits.next())) {
return false;
}
}
return true;
}
/**
* @return true iff <code>this</code> is a subset of <code>that</code>.
*/
public boolean isSubset(IntSet that) {
if (size() > that.size()) {
return false;
}
for(IntIterator bits = sparsePart.intIterator(); bits.hasNext(); ) {
if (! that.contains(bits.next())) {
return false;
}
}
if (densePart != null) {
for(int b = densePart.nextSetBit(0);
b != -1;
b = densePart.nextSetBit(b+1))
{
if (! that.contains(b)) {
return false;
}
}
}
return true;
}
/**
* Set the value of this to be the same as the value of set
*
* @param set
*/
public void copySet(IntSet set) {
if (set instanceof SemiSparseMutableIntSet) {
SemiSparseMutableIntSet that = (SemiSparseMutableIntSet) set;
sparsePart = new MutableSparseIntSet(that.sparsePart);
if (that.densePart == null) {
densePart = null;
} else {
densePart = new OffsetBitVector(that.densePart);
}
} else {
densePart = null;
sparsePart = new MutableSparseIntSet();
for(IntIterator bits = set.intIterator(); bits.hasNext(); ) {
add( bits.next() );
}
}
}
/**
* Add all members of set to this.
*
* @param set
* @return true iff the value of this changes.
*/
public boolean addAll(IntSet set) {
boolean change = false;
if (set instanceof SemiSparseMutableIntSet) {
SemiSparseMutableIntSet that = (SemiSparseMutableIntSet) set;
if (densePart == null) {
// that dense part only
if (that.densePart != null) {
densePart = new OffsetBitVector(that.densePart);
for(int b = densePart.nextSetBit(0);
b != -1;
b = densePart.nextSetBit(b+1))
{
if (sparsePart.contains(b)) {
sparsePart.remove(b);
} else {
change = true;
}
}
for(IntIterator bits = that.sparsePart.intIterator();
bits.hasNext(); )
{
change |= sparsePart.add( bits.next() );
}
// no dense part
} else {
for(IntIterator bs = that.sparsePart.intIterator(); bs.hasNext(); ) {
change |= add( bs.next() );
}
}
} else {
int oldSize = size();
// both dense parts
if (that.densePart != null) {
densePart.or(that.densePart);
for(IntIterator bs = that.sparsePart.intIterator(); bs.hasNext(); ) {
add( bs.next() );
}
for(IntIterator bs = sparsePart.intIterator(); bs.hasNext(); ) {
int b = bs.next();
if (densePart.get(b)) {
sparsePart.remove(b);
}
}
change = (size() != oldSize);
// this dense part only
} else {
for(IntIterator bs = that.sparsePart.intIterator(); bs.hasNext(); ) {
change |= add(bs.next());
}
}
}
} else {
for(IntIterator bs = set.intIterator(); bs.hasNext(); ) {
change |= add(bs.next());
}
}
return change;
}
/**
* Add an integer value to this set.
*
* @param i integer to add
* @return true iff the value of this changes.
*/
public boolean add(int i) {
if (! contains(i)) {
if (densePart!=null && densePart.getOffset()<=i && densePart.length()>i){
densePart.set(i);
} else {
sparsePart.add(i);
fixAfterSparseInsert();
}
return true;
} else {
return false;
}
}
/**
* Remove an integer from this set.
*
* @param i integer to remove
* @return true iff the value of this changes.
*/
public boolean remove(int i) {
if (densePart != null && densePart.get(i)) {
densePart.clear(i);
return true;
} else if (sparsePart.contains(i)) {
sparsePart.remove(i);
return true;
} else {
return false;
}
}
/**
* Interset this with another set.
*
* @param set
*/
public void intersectWith(IntSet set) {
sparsePart.intersectWith(set);
if (densePart != null) {
for(int b = densePart.nextSetBit(0);
b != -1;
b = densePart.nextSetBit(b+1))
{
if (! set.contains(b)) {
densePart.clear(b);
}
}
}
}
/**
* @param other
* @param filter
*/
public boolean addAllInIntersection(IntSet other, IntSet filter) {
boolean change = false;
for(IntIterator bits = other.intIterator(); bits.hasNext(); ) {
int bit = bits.next();
if (filter.contains(bit)) {
change |= add( bit );
}
}
return change;
}
}

View File

@ -0,0 +1,73 @@
/*******************************************************************************
* 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;
import java.util.Iterator;
import java.util.TreeSet;
/**
* @author Julian Dolby (dolby@us.ibm.com)
*/
public class SemiSparseMutableIntSetFactory implements MutableIntSetFactory {
/**
* @param set
*/
public MutableIntSet make(int[] set) {
if (set.length == 0) {
return new BitVectorIntSet();
} else {
// XXX not very efficient.
TreeSet<Integer> T = new TreeSet<Integer>();
for (int i = 0; i < set.length; i++) {
T.add(new Integer(set[i]));
}
MutableIntSet result = new SemiSparseMutableIntSet();
for (Iterator<Integer> it = T.iterator(); it.hasNext();) {
Integer I = it.next();
result.add(I.intValue());
}
return result;
}
}
/**
* @param string
*/
public MutableIntSet parse(String string) {
int[] data = SparseIntSet.parseIntArray(string);
MutableIntSet result = new SemiSparseMutableIntSet();
for (int i = 0; i < data.length; i++)
result.add(data[i]);
return result;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.util.intset.MutableIntSetFactory#make(com.ibm.wala.util.intset.IntSet)
*/
public MutableIntSet makeCopy(IntSet x) {
MutableIntSet y = new SemiSparseMutableIntSet();
y.copySet(x);
return y;
}
/*
* (non-Javadoc)
*
* @see com.ibm.wala.util.intset.MutableIntSetFactory#make()
*/
public MutableIntSet make() {
return new SemiSparseMutableIntSet();
}
}