org.roaringbitmap.art.Node256 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of RoaringBitmap Show documentation
Show all versions of RoaringBitmap Show documentation
Roaring bitmaps are compressed bitmaps (also called bitsets) which tend to outperform
conventional compressed bitmaps such as WAH or Concise.
package org.roaringbitmap.art;
import static java.lang.Long.numberOfTrailingZeros;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.LongBuffer;
public class Node256 extends Node {
Node[] children = new Node[256];
//a helper utility field
long[] bitmapMask = new long[4];
private static final long LONG_MASK = 0xffffffffffffffffL;
public Node256(int compressedPrefixSize) {
super(NodeType.NODE256, compressedPrefixSize);
}
@Override
public int getChildPos(byte k) {
int pos = Byte.toUnsignedInt(k);
if (children[pos] != null) {
return pos;
}
return ILLEGAL_IDX;
}
@Override
public SearchResult getNearestChildPos(byte k) {
int pos = Byte.toUnsignedInt(k);
if (children[pos] != null) {
return SearchResult.found(pos);
}
return SearchResult.notFound(getNextSmallerPos(pos), getNextLargerPos(pos));
}
@Override
public byte getChildKey(int pos) {
return (byte) pos;
}
@Override
public Node getChild(int pos) {
return children[pos];
}
@Override
public void replaceNode(int pos, Node freshOne) {
children[pos] = freshOne;
}
@Override
public int getMinPos() {
for (int i = 0; i < 4; i++) {
long longVal = bitmapMask[i];
if (longVal == 0) {
continue;
}
int v = Long.numberOfTrailingZeros(longVal);
return i * 64 + v;
}
return ILLEGAL_IDX;
}
@Override
public int getNextLargerPos(int pos) {
if (pos == ILLEGAL_IDX) {
pos = 0;
} else {
pos++;
}
int longPos = pos >> 6;
if (longPos >= 4) {
return ILLEGAL_IDX;
}
long longVal = bitmapMask[longPos] & (LONG_MASK << pos);
while (true) {
if (longVal != 0) {
return (longPos * 64) + Long.numberOfTrailingZeros(longVal);
}
if (++longPos == 4) {
return ILLEGAL_IDX;
}
longVal = bitmapMask[longPos];
}
}
@Override
public int getMaxPos() {
for (int i = 3; i >= 0; i--) {
long longVal = bitmapMask[i];
if (longVal == 0) {
continue;
}
int v = Long.numberOfLeadingZeros(longVal);
return i * 64 + (63 - v);
}
return ILLEGAL_IDX;
}
@Override
public int getNextSmallerPos(int pos) {
if (pos == ILLEGAL_IDX) {
pos = 256;
}
if (pos == 0) {
return ILLEGAL_IDX;
}
pos--;
int longPos = pos >>> 6;
long longVal = bitmapMask[longPos] & (LONG_MASK >>> -(pos + 1));
while (true) {
if (longVal != 0) {
return (longPos + 1) * 64 - 1 - Long.numberOfLeadingZeros(longVal);
}
if (longPos-- == 0) {
return ILLEGAL_IDX;
}
longVal = bitmapMask[longPos];
}
}
/**
* insert the child node into the node256 node with the key byte
*
* @param currentNode the node256
* @param child the child node
* @param key the key byte
* @return the node256 node
*/
public static Node256 insert(Node currentNode, Node child, byte key) {
Node256 node256 = (Node256) currentNode;
node256.count++;
int i = Byte.toUnsignedInt(key);
node256.children[i] = child;
setBit(key, node256.bitmapMask);
return node256;
}
static void setBit(byte key, long[] bitmapMask) {
int i = Byte.toUnsignedInt(key);
int longIdx = i >>> 6;
final long previous = bitmapMask[longIdx];
long newVal = previous | (1L << i);
bitmapMask[longIdx] = newVal;
}
@Override
public Node remove(int pos) {
this.children[pos] = null;
int longPos = pos >>> 6;
bitmapMask[longPos] &= ~(1L << pos);
this.count--;
if (this.count <= 36) {
Node48 node48 = new Node48(this.prefixLength);
int j = 0;
int currentPos = ILLEGAL_IDX;
while ((currentPos = getNextLargerPos(currentPos)) != ILLEGAL_IDX) {
Node child = getChild(currentPos);
node48.children[j] = child;
Node48.setOneByte(currentPos, (byte) j, node48.childIndex);
j++;
}
node48.count = (short) j;
copyPrefix(this, node48);
return node48;
}
return this;
}
@Override
public void replaceChildren(Node[] children) {
if (children.length == this.children.length) {
//short circuit path
this.children = children;
return;
}
int offset = 0;
int x = 0;
for (long longv : bitmapMask) {
int w = 0;
while (longv != 0) {
int pos = x * 64 + numberOfTrailingZeros(longv);
this.children[pos] = children[offset + w];
longv &= (longv - 1);
w++;
}
offset += w;
x++;
}
}
@Override
public void serializeNodeBody(DataOutput dataOutput) throws IOException {
for (long longv : bitmapMask) {
dataOutput.writeLong(Long.reverseBytes(longv));
}
}
@Override
public void serializeNodeBody(ByteBuffer byteBuffer) throws IOException {
LongBuffer longBuffer = byteBuffer.asLongBuffer();
longBuffer.put(bitmapMask);
byteBuffer.position(byteBuffer.position() + 4 * 8);
}
@Override
public void deserializeNodeBody(DataInput dataInput) throws IOException {
for (int i = 0; i < 4; i++) {
long longv = Long.reverseBytes(dataInput.readLong());
bitmapMask[i] = longv;
}
}
@Override
public void deserializeNodeBody(ByteBuffer byteBuffer) throws IOException {
LongBuffer longBuffer = byteBuffer.asLongBuffer();
longBuffer.get(bitmapMask);
byteBuffer.position(byteBuffer.position() + 4 * 8);
}
@Override
public int serializeNodeBodySizeInBytes() {
return 4 * 8;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy