This is an automated email from the ASF dual-hosted git repository. jt2594838 pushed a commit to branch add_bitmap_interface in repository https://gitbox.apache.org/repos/asf/tsfile.git
commit 3dacbaa4552f8bf028e6bbe3227bb090f891788f Author: Tian Jiang <[email protected]> AuthorDate: Thu Jul 30 16:48:18 2026 +0800 add range test interface --- .../main/java/org/apache/tsfile/utils/BitMap.java | 29 ++++++++++++++++ .../java/org/apache/tsfile/utils/BitMapImpl.java | 35 +++++++++++++++++++ .../java/org/apache/tsfile/utils/BitMapTest.java | 40 ++++++++++++++++++++++ 3 files changed, 104 insertions(+) diff --git a/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java b/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java index 629cda9c0..337bec90f 100644 --- a/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java +++ b/java/common/src/main/java/org/apache/tsfile/utils/BitMap.java @@ -54,6 +54,35 @@ public class BitMap implements Accountable { 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) { + 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(); diff --git a/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java b/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java index d9f296fe2..801e67cc8 100644 --- a/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java +++ b/java/common/src/main/java/org/apache/tsfile/utils/BitMapImpl.java @@ -19,6 +19,8 @@ package org.apache.tsfile.utils; +import org.apache.tsfile.i18n.Messages; + abstract class BitMapImpl { protected int size; @@ -39,6 +41,32 @@ abstract class BitMapImpl { abstract boolean isMarked(int position); + boolean isRangeAnyMarked(int start, int length) { + checkRange(start, length); + for (int offset = 0; offset < length; offset += Long.SIZE) { + int batchSize = Math.min(length - offset, Long.SIZE); + if (extractBits(start + offset, batchSize) != 0L) { + return true; + } + } + return false; + } + + boolean isRangeAllMarked(int start, int length) { + checkRange(start, length); + for (int offset = 0; offset < length; offset += Long.SIZE) { + int batchSize = Math.min(length - offset, Long.SIZE); + if (extractBits(start + offset, batchSize) != BitMapLongImpl.lowerBitsMask(batchSize)) { + return false; + } + } + return true; + } + + boolean isRangeNoneMarked(int start, int length) { + return !isRangeAnyMarked(start, length); + } + abstract void markAll(); abstract void mark(int position); @@ -102,4 +130,11 @@ abstract class BitMapImpl { abstract BitMapImpl extend(int newSize); abstract long getRetainedSizeInBytes(); + + private 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)); + } + } } diff --git a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java index e4b59e452..ef73614ad 100644 --- a/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java +++ b/java/tsfile/src/test/java/org/apache/tsfile/utils/BitMapTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; public class BitMapTest { @@ -217,6 +218,45 @@ public class BitMapTest { assertFalse(bitMap.isAllUnmarked(10)); } + @Test + public void testRangeMarkedQueries() { + assertRangeMarkedQueries(new BitMap(0)); + assertRangeMarkedQueries(new BitMap(64)); + assertRangeMarkedQueries(BitMap.createBitMapDynamically(64)); + assertRangeMarkedQueries(new BitMap(100)); + } + + private void assertRangeMarkedQueries(BitMap bitMap) { + for (int i = 0; i < bitMap.getSize(); i++) { + if (i % 4 != 2) { + bitMap.mark(i); + } + } + + for (int start = 0; start <= bitMap.getSize(); start++) { + for (int length = 0; length <= bitMap.getSize() - start; length++) { + boolean anyMarked = false; + boolean allMarked = true; + for (int i = start; i < start + length; i++) { + anyMarked |= bitMap.isMarked(i); + allMarked &= bitMap.isMarked(i); + } + assertEquals(anyMarked, bitMap.isRangeAnyMarked(start, length)); + assertEquals(allMarked, bitMap.isRangeAllMarked(start, length)); + assertEquals(!anyMarked, bitMap.isRangeNoneMarked(start, length)); + } + } + + assertThrows(IndexOutOfBoundsException.class, () -> bitMap.isRangeAnyMarked(-1, 0)); + assertThrows(IndexOutOfBoundsException.class, () -> bitMap.isRangeAllMarked(0, -1)); + assertThrows( + IndexOutOfBoundsException.class, () -> bitMap.isRangeNoneMarked(bitMap.getSize() + 1, 0)); + assertThrows( + IndexOutOfBoundsException.class, () -> bitMap.isRangeAnyMarked(bitMap.getSize(), 1)); + assertThrows( + IndexOutOfBoundsException.class, () -> bitMap.isRangeAllMarked(1, Integer.MAX_VALUE)); + } + @Test public void testGetTruncatedByteArray() { BitMap bitMap = new BitMap(16);
