soot.jimple.infoflow.android.axml.flags.BitwiseFlagSystem Maven / Gradle / Ivy
package soot.jimple.infoflow.android.axml.flags;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* In some cases, bitmasks might be used in a way where there is a precendence
* of certain masks to save space. For "normal" bitmasks, the traditional way of
* checking is much faster.
*
* Simple Example: Option A (can be used alone or in combination with others):
* 01 Option B (cannot be used with option A): 10 Option C (only valid when used
* with Option A): 11
*
* In this case, we could do checking of B via ((v & 10) == 1) && ((v & 1) != 1)
* but sometimes there are a lot of options (e.g. inputType)
*
* @param the keys used to distinguish flags
*/
public class BitwiseFlagSystem {
private List keys = new ArrayList();
private List values = new ArrayList();
/**
* Associate the given key with the bits set in set bits. The first registration
* wins.
*
* @param key the key
* @param setBits the bits set
*/
public void register(T key, int setBits) {
keys.add(key);
values.add(setBits);
}
/**
* Returns all matching flags
*
* @param value input value
*/
public final Collection getFlags(int value) {
List matchedResults = new ArrayList<>(4);
List matchedValues = new ArrayList<>(4);
for (int i = 0; i < keys.size(); i++) {
int v = values.get(i);
if ((v & value) == v) {
if (!hadAnyMatch(v, matchedValues)) {
matchedResults.add(keys.get(i));
matchedValues.add(v);
}
}
}
return matchedResults;
}
private static boolean hadAnyMatch(int value, List matchedValues) {
for (int c : matchedValues) {
if ((c & value) == value) {
return true;
}
}
return false;
}
/**
* Checks whether all the given flags are set
*
* @param inputValue input value
* @param flag the flags to check
*/
@SafeVarargs
public final boolean isSet(int inputValue, T... flag) {
List flagsLeft = new ArrayList(flag.length);
for (T i : flag)
flagsLeft.add(i);
for (T t : getFlags(inputValue)) {
Iterator it = flagsLeft.iterator();
while (it.hasNext()) {
if (it.next().equals(t)) {
it.remove();
if (flagsLeft.isEmpty())
return true;
}
}
}
return false;
}
}