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.
108 lines
3.8 KiB
108 lines
3.8 KiB
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; |
|
} |
|
}
|
|
|