Skip to content

Commit

Permalink
8317795: Add an ImmutableBitSetPredicate variant for bitsets <= 128 e…
Browse files Browse the repository at this point in the history
…lements

Reviewed-by: pminborg, rriggs
  • Loading branch information
cl4es committed Oct 10, 2023
1 parent fb4098f commit 33591a3
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,21 @@ private ImmutableBitSetPredicate(BitSet original) {
this.words = original.toLongArray();
}

/**
* @param bitIndex the bit index to test
* @return true if the bit is in the range of the BitSet and the bit is set, otherwise false
*/
@Override
public boolean test(int bitIndex) {
if (bitIndex < 0)
throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
if (bitIndex < 0) {
return false;
}

int wordIndex = wordIndex(bitIndex);
int wordIndex = bitIndex >> 6;
return (wordIndex < words.length)
&& ((words[wordIndex] & (1L << bitIndex)) != 0);
}

/**
* Given a bit index, return word index containing it.
*/
private static int wordIndex(int bitIndex) {
return bitIndex >> 6;
}

/**
* {@return a new {@link IntPredicate } representing the {@link BitSet#get(int)} method applied
* on an immutable snapshot of the current state of this BitSet}.
Expand All @@ -79,7 +77,38 @@ private static int wordIndex(int bitIndex) {
* @since 22
*/
public static IntPredicate of(BitSet original) {
if (original.size() <= 128) {
long[] array = original.toLongArray();
return new SmallImmutableBitSetPredicate(
array.length > 0 ? array[0] : 0L,
array.length > 1 ? array[1] : 0L);
}
return new ImmutableBitSetPredicate(original);
}

/**
* Specialization for small sets of 128 bits or less
* @param first - bits index 0 through 63, inclusive
* @param second - bits index 64 through 127, inclusive
*/
public record SmallImmutableBitSetPredicate(long first, long second) implements IntPredicate {

/**
* @param bitIndex the bit index to test
* @return true if the bit is in the range of the BitSet and the bit is set, otherwise false
*/
@Override
public boolean test(int bitIndex) {
if (bitIndex < 0) {
return false;
}

int wordIndex = bitIndex >> 6;
if (wordIndex > 1) {
return false;
}
long bits = wordIndex == 0 ? first : second;
return (bits & (1L << bitIndex)) != 0;
}
}
}
36 changes: 22 additions & 14 deletions test/jdk/java/util/BitSet/ImmutableBitSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.BitSet;
import java.util.Random;
import java.util.function.IntPredicate;
import java.util.stream.IntStream;

import static org.junit.jupiter.api.Assertions.*;

Expand All @@ -48,30 +49,37 @@ void empty() {

@Test
void negativeIndex() {
BitSet bs = new BitSet();
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
assertThrows(IndexOutOfBoundsException.class, () -> {
ibs.test(-1);
});
IntStream.of(0, 127, 128, 129, 143, 4711).forEach(k -> {
BitSet bs = new BitSet(k);
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
assertFalse(ibs.test(-1));
assertFalse(ibs.test(Integer.MIN_VALUE));
});
}

@Test
void basic() {
BitSet bs = createReference(147);
IntStream.of(0, 16, 127, 128, 129, 143, 4711).forEach(k -> basic(k));
}

void basic(int length) {
BitSet bs = createReference(length);
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
test(bs, ibs);
}

@Test
void clearedAtTheTail() {
for (int i = Long.BYTES - 1; i < Long.BYTES + 2; i++) {
BitSet bs = createReference(i);
for (int j = bs.length() - 1; j > Long.BYTES - 1; j++) {
bs.clear(j);
IntStream.of(0, 16, 127, 128, 129, 143, 4711).forEach(k -> {
for (int i = Long.BYTES - 1; i < Long.BYTES + 2; i++) {
BitSet bs = createReference(k + i);
for (int j = bs.length() - 1; j > Long.BYTES - 1; j--) {
bs.clear(j);
}
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
test(bs, ibs);
}
IntPredicate ibs = ImmutableBitSetPredicate.of(bs);
test(bs, ibs);
}
});
}

static void test(BitSet expected, IntPredicate actual) {
Expand All @@ -81,7 +89,7 @@ static void test(BitSet expected, IntPredicate actual) {
}

private static BitSet createReference(int length) {
BitSet result = new BitSet();
BitSet result = new BitSet(length);
Random random = new Random(length);
for (int i = 0; i < length; i++) {
result.set(i, random.nextBoolean());
Expand Down

1 comment on commit 33591a3

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.