Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions java/common/src/main/java/org/apache/tsfile/utils/BitMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,35 @@ public boolean isMarked(int position) {
return implementation.isMarked(position);
}

/**
* Returns whether at least one bit in the specified range is marked. An empty range returns
* {@code false}.
*
* @throws IndexOutOfBoundsException if the range is outside this bitmap
*/
public boolean isRangeAnyMarked(int start, int length) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These public APIs distinguish any, all, and none semantics without forcing callers to scan individual bits. The Javadocs explicitly define empty-range results and preserve the existing bitmap range-error convention for invalid input.

return implementation.isRangeAnyMarked(start, length);
}

/**
* Returns whether every bit in the specified range is marked. An empty range returns {@code
* true}.
*
* @throws IndexOutOfBoundsException if the range is outside this bitmap
*/
public boolean isRangeAllMarked(int start, int length) {
return implementation.isRangeAllMarked(start, length);
}

/**
* Returns whether no bit in the specified range is marked. An empty range returns {@code true}.
*
* @throws IndexOutOfBoundsException if the range is outside this bitmap
*/
public boolean isRangeNoneMarked(int start, int length) {
return implementation.isRangeNoneMarked(start, length);
}

/** mark as 1 at all positions. */
public void markAll() {
implementation.markAll();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

package org.apache.tsfile.utils;

import org.apache.tsfile.i18n.Messages;

import java.util.Arrays;

class BitMapArrayImpl extends BitMapImpl {
Expand Down Expand Up @@ -76,6 +74,47 @@ boolean isMarked(int position) {
return (bits[position / Byte.SIZE] & BIT_UTIL[position % Byte.SIZE]) != 0;
}

@Override
boolean isRangeAnyMarked(int start, int length) {
checkRange(start, length);
return isRangeAnyMarkedUnchecked(start, length);
}

@Override
boolean isRangeAllMarked(int start, int length) {
checkRange(start, length);
if (length == 0) {
return true;
}

int end = start + length;
int firstByte = start >>> 3;
int lastByte = (end - 1) >>> 3;
if (firstByte == lastByte) {
int mask = ((1 << length) - 1) << (start & 7);
return (bits[firstByte] & mask) == mask;
}

int firstMask = (0xFF << (start & 7)) & 0xFF;
if ((bits[firstByte] & firstMask) != firstMask) {
return false;
}
for (int index = firstByte + 1; index < lastByte; index++) {
if (bits[index] != (byte) 0xFF) {
return false;
}
}
int lastBitCount = end & 7;
int lastMask = lastBitCount == 0 ? 0xFF : (1 << lastBitCount) - 1;
return (bits[lastByte] & lastMask) == lastMask;
}

@Override
boolean isRangeNoneMarked(int start, int length) {
checkRange(start, length);
return !isRangeAnyMarkedUnchecked(start, length);
}

@Override
void markAll() {
Arrays.fill(bits, (byte) 0XFF);
Expand Down Expand Up @@ -288,11 +327,30 @@ long getRetainedSizeInBytes() {
return INSTANCE_SIZE + RamUsageEstimator.sizeOfByteArray(bits.length);
}

private void checkRange(int startPosition, int length) {
if (startPosition < 0 || startPosition + length > size) {
throw new IndexOutOfBoundsException(
Messages.format(
"error.common.bitmap_start_length_out_of_range", startPosition, length, size));
private boolean isRangeAnyMarkedUnchecked(int start, int length) {
if (length == 0) {
return false;
}

int end = start + length;
int firstByte = start >>> 3;
int lastByte = (end - 1) >>> 3;
if (firstByte == lastByte) {
int mask = ((1 << length) - 1) << (start & 7);
return (bits[firstByte] & mask) != 0;
}

int firstMask = (0xFF << (start & 7)) & 0xFF;
if ((bits[firstByte] & firstMask) != 0) {
return true;
}
for (int index = firstByte + 1; index < lastByte; index++) {
if (bits[index] != 0) {
return true;
}
}
int lastBitCount = end & 7;
int lastMask = lastBitCount == 0 ? 0xFF : (1 << lastBitCount) - 1;
return (bits[lastByte] & lastMask) != 0;
}
}
15 changes: 15 additions & 0 deletions java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.apache.tsfile.utils;

import org.apache.tsfile.i18n.Messages;

abstract class BitMapImpl {

protected int size;
Expand All @@ -39,6 +41,12 @@ int getSize() {

abstract boolean isMarked(int position);

abstract boolean isRangeAnyMarked(int start, int length);

abstract boolean isRangeAllMarked(int start, int length);

abstract boolean isRangeNoneMarked(int start, int length);

abstract void markAll();

abstract void mark(int position);
Expand Down Expand Up @@ -102,4 +110,11 @@ int contentHashCode() {
abstract BitMapImpl extend(int newSize);

abstract long getRetainedSizeInBytes();

final void checkRange(int start, int length) {
if (start < 0 || length < 0 || start > size - length) {
throw new IndexOutOfBoundsException(
Messages.format("error.common.bitmap_start_length_out_of_range", start, length, size));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

package org.apache.tsfile.utils;

import org.apache.tsfile.i18n.Messages;

class BitMapLongImpl extends BitMapImpl {

private static final long ALL_BITS_MARKED = -1L;
Expand Down Expand Up @@ -79,6 +77,25 @@ boolean isMarked(int position) {
return (bits & (1L << position)) != 0;
}

@Override
boolean isRangeAnyMarked(int start, int length) {
checkRange(start, length);
return (bits & rangeMask(start, length)) != 0L;
}

@Override
boolean isRangeAllMarked(int start, int length) {
checkRange(start, length);
long mask = rangeMask(start, length);
return (bits & mask) == mask;
}

@Override
boolean isRangeNoneMarked(int start, int length) {
checkRange(start, length);
return (bits & rangeMask(start, length)) == 0L;
}

@Override
void markAll() {
bits = ALL_BITS_MARKED;
Expand Down Expand Up @@ -219,6 +236,10 @@ static long lowerBitsMask(int length) {
return length == Long.SIZE ? -1L : (1L << length) - 1;
}

private static long rangeMask(int start, int length) {
return lowerBitsMask(length) << start;
}

private byte[] getExtendedByteArray(int newSize) {
byte[] bytes = new byte[BitMap.getSizeOfBytes(newSize)];
for (int i = 0; i < Long.BYTES; i++) {
Expand All @@ -227,12 +248,4 @@ private byte[] getExtendedByteArray(int newSize) {
bytes[Long.BYTES] = paddingByte;
return bytes;
}

private void checkRange(int startPosition, int length) {
if (startPosition < 0 || startPosition + length > size) {
throw new IndexOutOfBoundsException(
Messages.format(
"error.common.bitmap_start_length_out_of_range", startPosition, length, size));
}
}
}
Loading
Loading