WALA/com.ibm.wala.util/src/com/ibm/wala/util/intset/BimodalMutableIntSet.java

390 lines
11 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.debug.Assertions;
import com.ibm.wala.util.debug.UnimplementedError;
/**
* An implementation of {@link MutableIntSet} that delegates to either a {@link MutableSparseIntSet} or a {@link BitVectorIntSet}
*/
public class BimodalMutableIntSet implements MutableIntSet {
private static final long serialVersionUID = 7332332295529936562L;
MutableIntSet impl;
/*
* @see com.ibm.wala.util.intset.MutableIntSet#copySet(com.ibm.wala.util.intset.IntSet)
*/
@Override
public void copySet(IntSet set) {
if (set == null) {
throw new IllegalArgumentException("null set");
}
if (set instanceof BimodalMutableIntSet) {
impl = IntSetUtil.makeMutableCopy(((BimodalMutableIntSet) set).impl);
} else if (sameRepresentation(impl, set)) {
// V and other.V use the same representation. update in place.
impl.copySet(set);
} else if (set instanceof BitVectorIntSet || set instanceof SparseIntSet) {
// other.V has a different representation. make a new copy
impl = IntSetUtil.makeMutableCopy(set);
} else if (set instanceof MutableSharedBitVectorIntSet) {
impl = IntSetUtil.makeMutableCopy(((MutableSharedBitVectorIntSet) set).makeSparseCopy());
} else {
Assertions.UNREACHABLE("Unexpected type " + set.getClass());
}
assert impl instanceof BitVectorIntSet || impl instanceof MutableSparseIntSet;
}
/**
* @return true iff we would like to use the same representation for V as we do for W
*/
private static boolean sameRepresentation(IntSet V, IntSet W) {
// for now we assume that we always want to use the same representation for
// V as
// for W.
return (V.getClass().equals(W.getClass()));
}
/*
* @see com.ibm.wala.util.intset.MutableIntSet#addAll(com.ibm.wala.util.intset.IntSet)
*/
@Override
public boolean addAll(IntSet set) {
if (set instanceof BitVectorIntSet && !(impl instanceof BitVectorIntSet)) {
// change the representation before performing the operation
impl = new BitVectorIntSet(impl);
}
boolean result = impl.addAll(set);
if (result) {
maybeChangeRepresentation();
}
return result;
}
/*
* @see com.ibm.wala.util.intset.MutableIntSet#addAll(com.ibm.wala.util.intset.IntSet)
*/
@Override
public boolean addAllInIntersection(IntSet other, IntSet filter) {
if (other instanceof BitVectorIntSet && !(impl instanceof BitVectorIntSet)) {
// change the representation before performing the operation
impl = new BitVectorIntSet(impl);
}
boolean result = impl.addAllInIntersection(other, filter);
if (result) {
maybeChangeRepresentation();
}
return result;
}
/**
* If appropriate, change the representation of V.
*
* For now, this method will change a MutableSparseIntSet to a BitVector if it saves space.
*
* TODO: add more variants.
*/
private void maybeChangeRepresentation() {
assert impl instanceof BitVectorIntSet || impl instanceof MutableSparseIntSet;
if (impl == null) {
return;
}
int sparseSize = impl.size();
if (sparseSize <= 2) {
// don't bother
return;
}
int bvSize = BitVectorBase.subscript(impl.max()) + 1;
if (sparseSize > bvSize) {
if (!(impl instanceof BitVectorIntSet)) {
impl = new BitVectorIntSet(impl);
}
} else {
if (!(impl instanceof MutableSparseIntSet)) {
impl = MutableSparseIntSet.make(impl);
}
}
assert impl instanceof BitVectorIntSet || impl instanceof MutableSparseIntSet;
}
/*
* @see com.ibm.wala.util.intset.MutableIntSet#add(int)
*/
@Override
public boolean add(int i) {
boolean result = impl.add(i);
if (result) {
maybeChangeRepresentation();
}
return result;
}
/*
* @see com.ibm.wala.util.intset.MutableIntSet#remove(int)
*/
@Override
public boolean remove(int i) {
boolean result = impl.remove(i);
maybeChangeRepresentation();
return result;
}
/*
* @see com.ibm.wala.util.intset.MutableIntSet#intersectWith(com.ibm.wala.util.intset.IntSet)
*/
@Override
public void intersectWith(IntSet set) throws UnimplementedError {
if (set == null) {
throw new IllegalArgumentException("null set");
}
if (set instanceof BimodalMutableIntSet) {
BimodalMutableIntSet that = (BimodalMutableIntSet) set;
impl.intersectWith(that.impl);
} else {
Assertions.UNREACHABLE();
}
}
/*
* @see com.ibm.wala.util.intset.IntSet#contains(int)
*/
@Override
public boolean contains(int i) {
return impl.contains(i);
}
/*
* @see com.ibm.wala.util.intset.IntSet#intersection(com.ibm.wala.util.intset.IntSet)
*/
@Override
public IntSet intersection(IntSet that) throws UnimplementedError {
if (that instanceof BimodalMutableIntSet) {
BimodalMutableIntSet b = (BimodalMutableIntSet) that;
return impl.intersection(b.impl);
} else if (that instanceof BitVectorIntSet) {
return impl.intersection(that);
} else {
Assertions.UNREACHABLE("Unexpected: " + that);
return null;
}
}
/*
* @see com.ibm.wala.util.intset.IntSet#union(com.ibm.wala.util.intset.IntSet)
*/
@Override
public IntSet union(IntSet that) {
BimodalMutableIntSet temp = new BimodalMutableIntSet();
temp.addAll(this);
temp.addAll(that);
return temp;
}
/*
* @see com.ibm.wala.util.intset.IntSet#isEmpty()
*/
@Override
public boolean isEmpty() {
return impl.isEmpty();
}
/*
* @see com.ibm.wala.util.intset.IntSet#size()
*/
@Override
public int size() {
return impl.size();
}
/*
* @see com.ibm.wala.util.intset.IntSet#iterator()
*/
@Override
public IntIterator intIterator() {
return impl.intIterator();
}
/*
* @see com.ibm.wala.util.intset.IntSet#foreach(com.ibm.wala.util.intset.IntSetAction)
*/
@Override
public void foreach(IntSetAction action) {
impl.foreach(action);
}
/*
* @see com.ibm.wala.util.intset.IntSet#foreachExcluding(com.ibm.wala.util.intset.IntSet, com.ibm.wala.util.intset.IntSetAction)
*/
@Override
public void foreachExcluding(IntSet X, IntSetAction action) {
impl.foreachExcluding(X, action);
}
/*
* @see com.ibm.wala.util.intset.IntSet#max()
*/
@Override
public int max() throws IllegalStateException {
return impl.max();
}
public static BimodalMutableIntSet makeCopy(IntSet B) throws UnimplementedError, IllegalArgumentException {
if (B == null) {
throw new IllegalArgumentException("B == null");
}
if (B instanceof BimodalMutableIntSet) {
BimodalMutableIntSet that = (BimodalMutableIntSet) B;
BimodalMutableIntSet result = new BimodalMutableIntSet();
result.impl = IntSetUtil.makeMutableCopy(that.impl);
return result;
} else if (B instanceof MutableSharedBitVectorIntSet) {
BimodalMutableIntSet result = new BimodalMutableIntSet();
MutableSharedBitVectorIntSet s = (MutableSharedBitVectorIntSet) B;
result.impl = IntSetUtil.makeMutableCopy(s.makeSparseCopy());
assert result.impl instanceof BitVectorIntSet || result.impl instanceof MutableSparseIntSet;
return result;
} else {
BimodalMutableIntSet result = new BimodalMutableIntSet();
result.impl = IntSetUtil.makeMutableCopy(B);
assert result.impl instanceof BitVectorIntSet || result.impl instanceof MutableSparseIntSet;
return result;
}
}
public BimodalMutableIntSet() {
impl = MutableSparseIntSet.makeEmpty();
}
public BimodalMutableIntSet(int initialSize, float expansionFactor) {
impl = new TunedMutableSparseIntSet(initialSize, expansionFactor);
}
/*
* @see com.ibm.wala.util.intset.MutableIntSet#clear()
*/
@Override
public void clear() {
impl = MutableSparseIntSet.makeEmpty();
}
/**
* @param x
* @throws IllegalArgumentException if x is null
*/
public BimodalMutableIntSet(BimodalMutableIntSet x) {
if (x == null) {
throw new IllegalArgumentException("x is null");
}
impl = IntSetUtil.makeMutableCopy(x.impl);
assert impl instanceof BitVectorIntSet || impl instanceof MutableSparseIntSet;
}
/*
* @see com.ibm.wala.util.intset.IntSet#sameValue(com.ibm.wala.util.intset.IntSet)
*/
@Override
public boolean sameValue(IntSet that) {
return impl.sameValue(that);
}
/*
* @see com.ibm.wala.util.intset.IntSet#isSubset(com.ibm.wala.util.intset.SparseIntSet)
*/
@Override
public boolean isSubset(IntSet that) throws IllegalArgumentException {
if (that == null) {
throw new IllegalArgumentException("that == null");
}
if (that instanceof BimodalMutableIntSet) {
BimodalMutableIntSet b = (BimodalMutableIntSet) that;
return impl.isSubset(b.impl);
} else {
// slow!
BitVectorIntSet a = new BitVectorIntSet(this);
BitVectorIntSet b = new BitVectorIntSet(that);
return a.isSubset(b);
}
}
/**
* use with care
*
*/
public IntSet getBackingStore() {
return impl;
}
@Override
public String toString() {
return impl.toString();
}
/*
* @see com.ibm.wala.util.intset.IntSet#containsAny(com.ibm.wala.util.intset.IntSet)
*/
@Override
public boolean containsAny(IntSet that) throws IllegalArgumentException, UnimplementedError {
if (that == null) {
throw new IllegalArgumentException("that == null");
}
if (that instanceof BimodalMutableIntSet) {
BimodalMutableIntSet b = (BimodalMutableIntSet) that;
return impl.containsAny(b.impl);
} else if (that instanceof SparseIntSet) {
return impl.containsAny(that);
} else if (that instanceof BitVectorIntSet) {
return impl.containsAny(that);
} else {
Assertions.UNREACHABLE("unsupported " + that.getClass());
return false;
}
}
/**
* TODO: optimize ME!
*
* @throws IllegalArgumentException if that is null
*/
public boolean removeAll(IntSet that) {
if (that == null) {
throw new IllegalArgumentException("that is null");
}
boolean result = false;
for (IntIterator it = that.intIterator(); it.hasNext();) {
result |= remove(it.next());
}
return result;
}
/**
* TODO: optimize ME!
*
* @throws IllegalArgumentException if that is null
*/
public boolean containsAll(BimodalMutableIntSet that) {
if (that == null) {
throw new IllegalArgumentException("that is null");
}
for (IntIterator it = that.intIterator(); it.hasNext();) {
if (!contains(it.next())) {
return false;
}
}
return true;
}
}