pascal.taie.util.collection.HybridBitSet Maven / Gradle / Ivy
Show all versions of tai-e Show documentation
/*
* Tai-e: A Static Analysis Framework for Java
*
* Copyright (C) 2022 Tian Tan
* Copyright (C) 2022 Yue Li
*
* This file is part of Tai-e.
*
* Tai-e is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
* Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Tai-e. If not, see .
*/
package pascal.taie.util.collection;
import pascal.taie.util.Indexer;
import javax.annotation.Nonnull;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
/**
* Hybrid set that uses bit set for large set.
*
* It is important to note that batch operations such as {@link #addAll(Collection)},
* {@link #removeAll(Collection)}, {@link #retainAll(Collection)}, and {@link #containsAll(Collection)}
* can experience performance degradation when used with {@link IndexerBitSet}.
*
* For example, when removing elements of a {@link HybridBitSet} from an {@link IndexerBitSet}
* (i.e., {@code indexerBitSet.removeAll(hybridBitSet)}) or vice versa,
* the operation does not take advantage of bit-level operations.
* Instead, it falls back on an iterative removal process that is less efficient.
*
* Users are advised to be aware of these potential performance implications when performing
* batch operations between {@link IndexerBitSet} and {@link HybridBitSet} instances
* to avoid unexpected inefficiencies.
*
* @see IndexerBitSet
*/
public final class HybridBitSet extends AbstractHybridSet
implements Serializable {
private final Indexer indexer;
private final boolean isSparse;
public HybridBitSet(Indexer indexer, boolean isSparse) {
this.indexer = indexer;
this.isSparse = isSparse;
}
@Override
protected Set newLargeSet(int unused) {
return new IndexerBitSet<>(indexer, isSparse);
}
@Override
public boolean addAll(@Nonnull Collection extends E> c) {
// optimize when c is HybridBitSet
if (this.set instanceof GenericBitSet thisBitSet
&& c instanceof HybridBitSet extends E> other
&& other.set instanceof GenericBitSet extends E> otherBitSet) {
return thisBitSet.addAll(otherBitSet);
}
return super.addAll(c);
}
@Override
public boolean containsAll(Collection> c) {
// optimize when c is HybridBitSet
if (this.set instanceof GenericBitSet thisBitSet
&& c instanceof HybridBitSet> other
&& other.set instanceof GenericBitSet> otherBitSet) {
return thisBitSet.containsAll(otherBitSet);
}
return super.containsAll(c);
}
@Override
public boolean removeAll(Collection> c) {
// optimize when c is HybridBitSet
if (this.set instanceof GenericBitSet thisBitSet
&& c instanceof HybridBitSet> other
&& other.set instanceof GenericBitSet> otherBitSet) {
return thisBitSet.removeAll(otherBitSet);
}
return super.removeAll(c);
}
@Override
public boolean retainAll(@Nonnull Collection> c) {
// optimize when c is HybridBitSet
if (this.set instanceof GenericBitSet thisBitSet
&& c instanceof HybridBitSet> other
&& other.set instanceof GenericBitSet> otherBitSet) {
return thisBitSet.retainAll(otherBitSet);
}
return super.retainAll(c);
}
@Override
public HybridBitSet addAllDiff(Collection extends E> c) {
HybridBitSet diff = new HybridBitSet<>(indexer, isSparse);
if (c instanceof HybridBitSet other && other.isLargeSet) {
//noinspection unchecked
SetEx otherSet = (SetEx) other.set;
Set diffSet;
if (set == null) {
set = otherSet.copy();
diffSet = otherSet.copy();
if (singleton != null) {
set.add(singleton);
diffSet.remove(singleton);
singleton = null;
}
} else if (!isLargeSet) {
// current set is small set
Set oldSet = set;
set = otherSet.copy();
diffSet = otherSet.copy();
set.addAll(oldSet);
diffSet.removeAll(oldSet);
} else {
// current set is already a large set
diffSet = ((SetEx) set).addAllDiff(otherSet);
}
diff.set = diffSet;
diff.isLargeSet = isLargeSet = true;
} else {
for (E e : c) {
if (add(e)) {
diff.add(e);
}
}
}
return diff;
}
@Override
public HybridBitSet copy() {
HybridBitSet copy = new HybridBitSet<>(indexer, isSparse);
copy.singleton = singleton;
copy.isLargeSet = isLargeSet;
if (set != null) {
copy.set = ((SetEx) set).copy();
}
return copy;
}
}