761 lines
21 KiB
Java
761 lines
21 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;
|
|
|
|
import com.ibm.wala.util.collections.CompoundIntIterator;
|
|
import com.ibm.wala.util.collections.EmptyIntIterator;
|
|
|
|
public class SemiSparseMutableIntSet implements MutableIntSet {
|
|
private static final boolean DEBUG = true;
|
|
|
|
private static final double FIX_SPARSE_MOD = 12;
|
|
|
|
private static final double FIX_SPARSE_RATIO = .05;
|
|
|
|
private MutableSparseIntSet sparsePart;
|
|
|
|
private OffsetBitVector densePart = null;
|
|
|
|
public SemiSparseMutableIntSet() {
|
|
this(MutableSparseIntSet.makeEmpty());
|
|
}
|
|
|
|
private SemiSparseMutableIntSet(MutableSparseIntSet sparsePart) {
|
|
this.sparsePart = sparsePart;
|
|
}
|
|
|
|
private SemiSparseMutableIntSet(MutableSparseIntSet sparsePart, OffsetBitVector densePart) {
|
|
this.sparsePart = sparsePart;
|
|
this.densePart = densePart;
|
|
}
|
|
|
|
public SemiSparseMutableIntSet(SemiSparseMutableIntSet set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
copySet(set);
|
|
}
|
|
|
|
private final boolean assertDisjoint() {
|
|
if (DEBUG) {
|
|
if (densePart != null) {
|
|
for (IntIterator sparseBits = sparsePart.intIterator(); sparseBits.hasNext();) {
|
|
int bit = sparseBits.next();
|
|
if (densePart.contains(bit)) {
|
|
return false;
|
|
}
|
|
if (inDenseRange(bit)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void fixAfterSparseInsert() {
|
|
if (sparsePart.size() % FIX_SPARSE_MOD == FIX_SPARSE_MOD - 1
|
|
&& (densePart == null || (densePart != null && sparsePart.size() > FIX_SPARSE_RATIO * densePart.getSize()))) {
|
|
assert assertDisjoint() : this.toString();
|
|
|
|
if (densePart == null) {
|
|
IntIterator sparseBits = sparsePart.intIterator();
|
|
|
|
int maxOffset = -1;
|
|
int maxCount = -1;
|
|
int maxMax = -1;
|
|
|
|
int offset = 0;
|
|
int bits = 0;
|
|
int count = 0;
|
|
int oldBit = 0;
|
|
while (sparseBits.hasNext()) {
|
|
int nextBit = sparseBits.next();
|
|
|
|
int newBits = bits + (nextBit - oldBit);
|
|
int newCount = count + 1;
|
|
|
|
if (newBits < (32 * newCount)) {
|
|
count = newCount;
|
|
bits = newBits;
|
|
if (count > maxCount) {
|
|
maxOffset = offset;
|
|
maxMax = nextBit;
|
|
maxCount = count;
|
|
}
|
|
} else {
|
|
offset = nextBit;
|
|
count = 1;
|
|
bits = 32;
|
|
}
|
|
oldBit = nextBit;
|
|
}
|
|
|
|
if (maxOffset != -1) {
|
|
densePart = new OffsetBitVector(maxOffset, maxMax - maxOffset);
|
|
sparseBits = sparsePart.intIterator();
|
|
int bit;
|
|
while ((bit = sparseBits.next()) < maxOffset) {
|
|
// do nothing
|
|
}
|
|
|
|
densePart.set(bit);
|
|
for (int i = 1; i < maxCount; i++) {
|
|
densePart.set(sparseBits.next());
|
|
}
|
|
sparsePart.removeAll(densePart);
|
|
}
|
|
|
|
assert assertDisjoint() : this.toString() + ", maxOffset=" + maxOffset + ", maxMax=" + maxMax + ", maxCount=" + maxCount;
|
|
|
|
} else {
|
|
IntIterator sparseBits = sparsePart.intIterator();
|
|
int thisBit = sparseBits.next();
|
|
|
|
int moveCount = 0;
|
|
int newOffset = -1;
|
|
int newCount = -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() || !sparseBits.hasNext()) {
|
|
if (nextBit < densePart.getOffset() && !sparseBits.hasNext()) {
|
|
count++;
|
|
}
|
|
if (densePart.getOffset() - newOffset < (32 * count)) {
|
|
moveCount += count;
|
|
} else {
|
|
newOffset = -1;
|
|
}
|
|
thisBit = nextBit;
|
|
break;
|
|
} else {
|
|
bits += (nextBit - thisBit);
|
|
count++;
|
|
|
|
if (bits > (32 * count)) {
|
|
newOffset = nextBit;
|
|
count = 1;
|
|
bits = 32;
|
|
}
|
|
|
|
thisBit = nextBit;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (thisBit < densePart.length() && sparseBits.hasNext()) {
|
|
thisBit = sparseBits.next();
|
|
}
|
|
|
|
// 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;
|
|
newCount = 1;
|
|
}
|
|
while (sparseBits.hasNext()) {
|
|
thisBit = sparseBits.next();
|
|
count++;
|
|
bits = (thisBit + 1 - densePart.length());
|
|
if ((32 * count) > bits) {
|
|
newLength = thisBit;
|
|
newCount = count;
|
|
}
|
|
}
|
|
if (newLength > -1) {
|
|
moveCount += newCount;
|
|
}
|
|
}
|
|
|
|
// actually move bits from sparse to dense
|
|
if (moveCount > 0) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (index != moveCount) {
|
|
assert index == moveCount : "index is " + index + ", but moveCount is " + moveCount + " for " + this;
|
|
}
|
|
|
|
if (newLength != -1 && bits[index - 1] == sparsePart.max()) {
|
|
int base = densePart.getOffset();
|
|
int currentSize = densePart.length() - base;
|
|
float newSize = 1.1f * (bits[index - 1] - base);
|
|
float fraction = newSize / currentSize;
|
|
assert fraction > 1;
|
|
densePart.growCapacity(fraction);
|
|
}
|
|
|
|
for (int i = index - 1; i >= 0; i--) {
|
|
sparsePart.remove(bits[i]);
|
|
densePart.set(bits[i]);
|
|
}
|
|
}
|
|
|
|
assert assertDisjoint() : this.toString() + ", densePart.length()=" + densePart.length() + ", newOffset=" + newOffset
|
|
+ ", newLength=" + newLength + ", newCount=" + newCount + ", moveCount=" + moveCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @see com.ibm.wala.util.intset.MutableIntSet#clear()
|
|
*/
|
|
@Override
|
|
public void clear() {
|
|
sparsePart.clear();
|
|
densePart = null;
|
|
}
|
|
|
|
/**
|
|
* @param i
|
|
* @return true iff this set contains integer i
|
|
*/
|
|
@Override
|
|
public boolean contains(int i) {
|
|
if (densePart != null && inDenseRange(i)) {
|
|
return densePart.contains(i);
|
|
} else {
|
|
return sparsePart.contains(i);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return true iff this set contains integer i
|
|
*/
|
|
@Override
|
|
public boolean containsAny(IntSet set) {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("null 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
|
|
*/
|
|
@Override
|
|
public IntSet intersection(IntSet that) {
|
|
if (that == null) {
|
|
throw new IllegalArgumentException("null that");
|
|
}
|
|
SemiSparseMutableIntSet newThis = new SemiSparseMutableIntSet();
|
|
for (IntIterator bits = intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (that.contains(bit)) {
|
|
newThis.add(bit);
|
|
}
|
|
}
|
|
return newThis;
|
|
}
|
|
|
|
/*
|
|
* @see com.ibm.wala.util.intset.IntSet#union(com.ibm.wala.util.intset.IntSet)
|
|
*/
|
|
@Override
|
|
public IntSet union(IntSet that) {
|
|
SemiSparseMutableIntSet temp = new SemiSparseMutableIntSet();
|
|
temp.addAll(this);
|
|
temp.addAll(that);
|
|
|
|
return temp;
|
|
}
|
|
|
|
/**
|
|
* @return true iff this set is empty
|
|
*/
|
|
@Override
|
|
public boolean isEmpty() {
|
|
return sparsePart.isEmpty() && (densePart == null || densePart.isZero());
|
|
}
|
|
|
|
/**
|
|
* @return the number of elements in this set
|
|
*/
|
|
@Override
|
|
public int size() {
|
|
return sparsePart.size() + (densePart == null ? 0 : densePart.populationCount());
|
|
}
|
|
|
|
/**
|
|
* @return a perhaps more efficient iterator
|
|
*/
|
|
@Override
|
|
public IntIterator intIterator() {
|
|
class DensePartIterator implements IntIterator {
|
|
private int i = -1;
|
|
|
|
@Override
|
|
public boolean hasNext() {
|
|
return densePart.nextSetBit(i + 1) != -1;
|
|
}
|
|
|
|
@Override
|
|
public int next() {
|
|
int next = densePart.nextSetBit(i + 1);
|
|
i = next;
|
|
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
|
|
*/
|
|
@Override
|
|
public void foreach(IntSetAction action) {
|
|
if (action == null) {
|
|
throw new IllegalArgumentException("null 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
|
|
*/
|
|
@Override
|
|
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.
|
|
*/
|
|
@Override
|
|
public int max() throws IllegalStateException {
|
|
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>.
|
|
* @throws IllegalArgumentException if that is null
|
|
*/
|
|
@Override
|
|
public boolean sameValue(IntSet that) {
|
|
if (that == null) {
|
|
throw new IllegalArgumentException("that is null");
|
|
}
|
|
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>.
|
|
* @throws IllegalArgumentException if that is null
|
|
*/
|
|
@Override
|
|
public boolean isSubset(IntSet that) {
|
|
if (that == null) {
|
|
throw new IllegalArgumentException("that is null");
|
|
}
|
|
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
|
|
*
|
|
* @throws IllegalArgumentException if set == null
|
|
*/
|
|
@Override
|
|
public void copySet(IntSet set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
if (set instanceof SemiSparseMutableIntSet) {
|
|
SemiSparseMutableIntSet that = (SemiSparseMutableIntSet) set;
|
|
sparsePart = MutableSparseIntSet.make(that.sparsePart);
|
|
if (that.densePart == null) {
|
|
densePart = null;
|
|
} else {
|
|
densePart = new OffsetBitVector(that.densePart);
|
|
}
|
|
} else {
|
|
densePart = null;
|
|
sparsePart = MutableSparseIntSet.makeEmpty();
|
|
for (IntIterator bits = set.intIterator(); bits.hasNext();) {
|
|
add(bits.next());
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean inDenseRange(int i) {
|
|
return densePart.getOffset() <= i && densePart.length() > i;
|
|
}
|
|
|
|
/**
|
|
* Add all members of set to this.
|
|
*
|
|
* @return true iff the value of this changes.
|
|
* @throws IllegalArgumentException if set == null
|
|
*/
|
|
@Override
|
|
public boolean addAll(IntSet set) throws IllegalArgumentException {
|
|
if (set == null) {
|
|
throw new IllegalArgumentException("set == null");
|
|
}
|
|
boolean change = false;
|
|
if (set instanceof SemiSparseMutableIntSet) {
|
|
SemiSparseMutableIntSet that = (SemiSparseMutableIntSet) set;
|
|
|
|
if (densePart == null) {
|
|
|
|
// that dense part only
|
|
if (that.densePart != null) {
|
|
int oldSize = size();
|
|
densePart = new OffsetBitVector(that.densePart);
|
|
|
|
for (IntIterator bits = sparsePart.intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (inDenseRange(bit)) {
|
|
densePart.set(bit);
|
|
}
|
|
}
|
|
|
|
sparsePart.removeAll(densePart);
|
|
sparsePart.addAll(that.sparsePart);
|
|
|
|
change = size() != oldSize;
|
|
|
|
// no dense part
|
|
} else {
|
|
change = sparsePart.addAll(that.sparsePart);
|
|
fixAfterSparseInsert();
|
|
}
|
|
|
|
} else {
|
|
// both dense parts
|
|
if (that.densePart != null) {
|
|
int oldSize = size();
|
|
|
|
densePart.or(that.densePart);
|
|
|
|
sparsePart.addAll(that.sparsePart);
|
|
|
|
for (IntIterator bits = sparsePart.intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (inDenseRange(bit)) {
|
|
densePart.set(bit);
|
|
}
|
|
}
|
|
|
|
sparsePart.removeAll(densePart);
|
|
|
|
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());
|
|
}
|
|
}
|
|
|
|
assert assertDisjoint() : this.toString();
|
|
|
|
return change;
|
|
}
|
|
|
|
/**
|
|
* Add an integer value to this set.
|
|
*
|
|
* @param i integer to add
|
|
* @return true iff the value of this changes.
|
|
*/
|
|
@Override
|
|
public boolean add(int i) {
|
|
if (densePart != null && inDenseRange(i)) {
|
|
if (!densePart.get(i)) {
|
|
densePart.set(i);
|
|
assert assertDisjoint() : this.toString();
|
|
return true;
|
|
}
|
|
} else if (!sparsePart.contains(i)) {
|
|
sparsePart.add(i);
|
|
assert assertDisjoint() : this.toString();
|
|
fixAfterSparseInsert();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Remove an integer from this set.
|
|
*
|
|
* @param i integer to remove
|
|
* @return true iff the value of this changes.
|
|
*/
|
|
@Override
|
|
public boolean remove(int i) {
|
|
if (densePart != null && densePart.get(i)) {
|
|
densePart.clear(i);
|
|
if (densePart.nextSetBit(0) == -1) {
|
|
densePart = null;
|
|
}
|
|
return true;
|
|
} else if (sparsePart.contains(i)) {
|
|
sparsePart.remove(i);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Interset this with another set.
|
|
*
|
|
* @param set
|
|
*/
|
|
@Override
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @throws IllegalArgumentException if other is null
|
|
*/
|
|
@Override
|
|
public boolean addAllInIntersection(IntSet other, IntSet filter) {
|
|
if (other == null) {
|
|
throw new IllegalArgumentException("other is null");
|
|
}
|
|
if (filter == null) {
|
|
throw new IllegalArgumentException("null filter");
|
|
}
|
|
boolean change = false;
|
|
for (IntIterator bits = other.intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (filter.contains(bit)) {
|
|
change |= add(bit);
|
|
}
|
|
}
|
|
|
|
return change;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
StringBuffer sb = new StringBuffer("[");
|
|
if (densePart != null) {
|
|
sb.append("densePart: ").append(densePart.toString()).append(" ");
|
|
}
|
|
sb.append("sparsePart: ").append(sparsePart.toString()).append("]");
|
|
return sb.toString();
|
|
}
|
|
|
|
public SemiSparseMutableIntSet removeAll(SemiSparseMutableIntSet B) {
|
|
if (B == null) {
|
|
throw new IllegalArgumentException("B null");
|
|
}
|
|
if (densePart == null) {
|
|
if (B.densePart == null) {
|
|
sparsePart = MutableSparseIntSet.diff(sparsePart, B.sparsePart);
|
|
} else {
|
|
MutableSparseIntSet C = MutableSparseIntSet.diff(sparsePart, B.sparsePart);
|
|
for (IntIterator bits = sparsePart.intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (B.densePart.get(bit)) {
|
|
C.remove(bit);
|
|
}
|
|
}
|
|
sparsePart = C;
|
|
}
|
|
} else {
|
|
if (B.densePart == null) {
|
|
for (IntIterator bits = B.sparsePart.intIterator(); bits.hasNext();) {
|
|
densePart.clear(bits.next());
|
|
}
|
|
sparsePart = MutableSparseIntSet.diff(sparsePart, B.sparsePart);
|
|
} else {
|
|
densePart.andNot(B.densePart);
|
|
for (IntIterator bits = B.sparsePart.intIterator(); bits.hasNext();) {
|
|
densePart.clear(bits.next());
|
|
}
|
|
|
|
MutableSparseIntSet C = MutableSparseIntSet.diff(sparsePart, B.sparsePart);
|
|
for (IntIterator bits = sparsePart.intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (B.densePart.get(bit)) {
|
|
C.remove(bit);
|
|
}
|
|
}
|
|
|
|
sparsePart = C;
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public static SemiSparseMutableIntSet diff(SemiSparseMutableIntSet A, SemiSparseMutableIntSet B) {
|
|
if (A == null) {
|
|
throw new IllegalArgumentException("A is null");
|
|
}
|
|
if (B == null) {
|
|
throw new IllegalArgumentException("B is null");
|
|
}
|
|
if (A.densePart == null) {
|
|
if (B.densePart == null) {
|
|
return new SemiSparseMutableIntSet(MutableSparseIntSet.diff(A.sparsePart, B.sparsePart));
|
|
|
|
} else {
|
|
MutableSparseIntSet C = MutableSparseIntSet.diff(A.sparsePart, B.sparsePart);
|
|
for (IntIterator bits = A.sparsePart.intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (B.densePart.get(bit)) {
|
|
C.remove(bit);
|
|
}
|
|
}
|
|
|
|
return new SemiSparseMutableIntSet(C);
|
|
}
|
|
|
|
} else {
|
|
if (B.densePart == null) {
|
|
OffsetBitVector newDensePart = new OffsetBitVector(A.densePart);
|
|
for (IntIterator bits = B.sparsePart.intIterator(); bits.hasNext();) {
|
|
newDensePart.clear(bits.next());
|
|
}
|
|
|
|
return new SemiSparseMutableIntSet(MutableSparseIntSet.diff(A.sparsePart, B.sparsePart), newDensePart);
|
|
|
|
} else {
|
|
OffsetBitVector newDensePart = new OffsetBitVector(A.densePart);
|
|
newDensePart.andNot(B.densePart);
|
|
for (IntIterator bits = B.sparsePart.intIterator(); bits.hasNext();) {
|
|
newDensePart.clear(bits.next());
|
|
}
|
|
|
|
MutableSparseIntSet C = MutableSparseIntSet.diff(A.sparsePart, B.sparsePart);
|
|
for (IntIterator bits = A.sparsePart.intIterator(); bits.hasNext();) {
|
|
int bit = bits.next();
|
|
if (B.densePart.get(bit)) {
|
|
C.remove(bit);
|
|
}
|
|
}
|
|
|
|
return new SemiSparseMutableIntSet(C, newDensePart);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|