qilin.core.sets.HybridPointsToSet Maven / Gradle / Ivy
/* Qilin - a Java Pointer Analysis Framework
* Copyright (C) 2021-2030 Qilin developers
*
* This program 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.0 of the
* License, or (at your option) any later version.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
*/
package qilin.core.sets;
import java.util.Arrays;
import java.util.Iterator;
import qilin.util.BitSetIterator;
import qilin.util.BitVector;
/**
* Hybrid implementation of points-to set, which uses an explicit array for small sets, and a bit
* vector for large sets.
*
* @author Ondrej Lhotak
*/
public final class HybridPointsToSet extends PointsToSetInternal {
private static HybridPointsToSet emptySet = null;
public static HybridPointsToSet getEmptySet() {
if (emptySet == null) {
emptySet = new HybridPointsToSet();
}
return emptySet;
}
private final int[] nodeIdxs = new int[16];
private BitVector bits = null;
private int size = 0;
private boolean empty = true;
/** Returns true if this set contains no run-time objects. */
@Override
public boolean isEmpty() {
return empty;
}
@Override
public void clear() {
Arrays.fill(nodeIdxs, 0);
bits = null;
empty = true;
size = 0;
}
private boolean nativeAddAll(HybridPointsToSet other, PointsToSetInternal exclude) {
boolean ret = false;
for (Iterator it = other.iterator(); it.hasNext(); ) {
int idx = it.next();
if (exclude == null || !exclude.contains(idx)) {
ret |= add(idx);
}
}
return ret;
}
/** Adds contents of other into this set, returns true if this set changed. */
public boolean addAll(final PointsToSetInternal other, final PointsToSetInternal exclude) {
if (other == null) {
return false;
}
if (other instanceof DoublePointsToSet) {
DoublePointsToSet dpts = (DoublePointsToSet) other;
return nativeAddAll(dpts.getNewSet(), exclude) | nativeAddAll(dpts.getOldSet(), exclude);
}
return nativeAddAll((HybridPointsToSet) other, exclude);
}
private class HybridPTSIterator implements Iterator {
private BitSetIterator it;
private int idx;
public HybridPTSIterator() {
if (bits == null) {
idx = 0;
} else {
it = bits.iterator();
}
}
@Override
public boolean hasNext() {
if (bits == null) {
return idx < nodeIdxs.length && nodeIdxs[idx] != 0;
} else {
return it.hasNext();
}
}
@Override
public Integer next() {
if (bits == null) {
return nodeIdxs[idx++];
} else {
return it.next();
}
}
}
@Override
public Iterator iterator() {
return new HybridPTSIterator();
}
@Override
public int size() {
return size;
}
/** Calls v's visit method on all nodes in this set. */
public boolean forall(P2SetVisitor v) {
if (bits == null) {
for (int nodeIdx : nodeIdxs) {
if (nodeIdx == 0) {
return v.getReturnValue();
}
v.visit(nodeIdx);
}
} else {
for (BitSetIterator it = bits.iterator(); it.hasNext(); ) {
v.visit(it.next());
}
}
return v.getReturnValue();
}
/** Returns true iff the set contains node idx. */
public boolean contains(int idx) {
if (bits == null) {
for (int nodeIdx : nodeIdxs) {
if (idx == nodeIdx) {
return true;
}
if (nodeIdx == 0) {
break;
}
}
return false;
} else {
return bits.get(idx);
}
}
/** Adds idx to this set, returns true if idx was not already in this set. */
public boolean add(int idx) {
if (bits == null) {
for (int i = 0; i < nodeIdxs.length; i++) {
if (nodeIdxs[i] == 0) {
empty = false;
nodeIdxs[i] = idx;
++size;
return true;
} else if (nodeIdxs[i] == idx) {
return false;
}
}
// convert to Bits
bits = new BitVector();
for (int nodeIdx : nodeIdxs) {
if (nodeIdx != 0) {
bits.set(nodeIdx);
}
}
}
boolean ret = bits.set(idx);
if (ret) {
++size;
empty = false;
}
return ret;
}
}