You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.8 KiB
109 lines
3.8 KiB
5 years ago
|
package com.fr.third.bitmap.roaringbitmap;
|
||
|
|
||
|
|
||
|
import java.util.Arrays;
|
||
|
import java.util.BitSet;
|
||
|
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* This class provides convenience functions to manipulate BitSet and RoaringBitmap objects.
|
||
|
*
|
||
|
*/
|
||
|
public class BitSetUtil {
|
||
|
// todo: add a method to convert a RoaringBitmap to a BitSet using BitSet.valueOf
|
||
|
|
||
|
// a block consists has a maximum of 1024 words, each representing 64 bits,
|
||
|
// thus representing at maximum 65536 bits
|
||
|
static final private int BLOCK_LENGTH = BitmapContainer.MAX_CAPACITY / Long.SIZE; //
|
||
|
// 64-bit
|
||
|
// word
|
||
|
|
||
|
private static ArrayContainer arrayContainerOf(final int from, final int to,
|
||
|
final int cardinality, final long[] words) {
|
||
|
// precondition: cardinality is max 4096
|
||
|
final short[] content = new short[cardinality];
|
||
|
int index = 0;
|
||
|
|
||
|
for (int i = from, socket = 0; i < to; ++i, socket += Long.SIZE) {
|
||
|
long word = words[i];
|
||
|
while (word != 0) {
|
||
|
long t = word & -word;
|
||
|
content[index++] = (short) (socket + Long.bitCount(t - 1));
|
||
|
word ^= t;
|
||
|
}
|
||
|
}
|
||
|
return new ArrayContainer(content);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Generate a RoaringBitmap out of a long[], each long using little-endian representation of its
|
||
|
* bits
|
||
|
*
|
||
|
* @param words array of longs (will not be modified)
|
||
|
* @return roaring bitmap
|
||
|
* @see BitSet#toLongArray() for an equivalent
|
||
|
*/
|
||
|
public static RoaringBitmap bitmapOf(final long[] words) {
|
||
|
// split long[] into blocks.
|
||
|
// each block becomes a single container, if any bit is set
|
||
|
final RoaringBitmap ans = new RoaringBitmap();
|
||
|
int containerIndex = 0;
|
||
|
for (int from = 0; from < words.length; from += BLOCK_LENGTH) {
|
||
|
final int to = Math.min(from + BLOCK_LENGTH, words.length);
|
||
|
final int blockCardinality = cardinality(from, to, words);
|
||
|
if (blockCardinality > 0) {
|
||
|
ans.highLowContainer.insertNewKeyValueAt(containerIndex++, Util.highbits(from * Long.SIZE),
|
||
|
BitSetUtil.containerOf(from, to, blockCardinality, words));
|
||
|
}
|
||
|
}
|
||
|
return ans;
|
||
|
}
|
||
|
|
||
|
private static int cardinality(final int from, final int to, final long[] words) {
|
||
|
int sum = 0;
|
||
|
for (int i = from; i < to; i++) {
|
||
|
sum += Long.bitCount(words[i]);
|
||
|
}
|
||
|
return sum;
|
||
|
}
|
||
|
|
||
|
|
||
|
private static Container containerOf(final int from, final int to, final int blockCardinality,
|
||
|
final long[] words) {
|
||
|
// find the best container available
|
||
|
if (blockCardinality <= ArrayContainer.DEFAULT_MAX_SIZE) {
|
||
|
// containers with DEFAULT_MAX_SIZE or less integers should be
|
||
|
// ArrayContainers
|
||
|
return arrayContainerOf(from, to, blockCardinality, words);
|
||
|
} else {
|
||
|
// otherwise use bitmap container
|
||
|
return new BitmapContainer(Arrays.copyOfRange(words, from, from + BLOCK_LENGTH),
|
||
|
blockCardinality);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Compares a RoaringBitmap and a BitSet. They are equal if and only if they contain the same set
|
||
|
* of integers.
|
||
|
*
|
||
|
* @param bitset first object to be compared
|
||
|
* @param bitmap second object to be compared
|
||
|
* @return whether they are equals
|
||
|
*/
|
||
|
public static boolean equals(final BitSet bitset, final RoaringBitmap bitmap) {
|
||
|
if (bitset.cardinality() != bitmap.getCardinality()) {
|
||
|
return false;
|
||
|
}
|
||
|
final IntIterator it = bitmap.getIntIterator();
|
||
|
while (it.hasNext()) {
|
||
|
int val = it.next();
|
||
|
if (!bitset.get(val)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|