classlib: small BitSet fixes and improvements (#950)

This commit is contained in:
Ivan Hetman 2024-09-09 15:44:42 +03:00 committed by GitHub
parent 349ed8fc2d
commit e2699554b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 63 additions and 10 deletions

View File

@ -18,6 +18,9 @@ package org.teavm.classlib.java.util;
import java.util.function.IntPredicate; import java.util.function.IntPredicate;
import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.*; import org.teavm.classlib.java.lang.*;
import org.teavm.classlib.java.nio.TByteBuffer;
import org.teavm.classlib.java.nio.TByteOrder;
import org.teavm.classlib.java.nio.TLongBuffer;
import org.teavm.classlib.java.util.stream.TIntStream; import org.teavm.classlib.java.util.stream.TIntStream;
import org.teavm.classlib.java.util.stream.intimpl.TSimpleIntStreamImpl; import org.teavm.classlib.java.util.stream.intimpl.TSimpleIntStreamImpl;
import org.teavm.interop.Rename; import org.teavm.interop.Rename;
@ -52,9 +55,16 @@ public class TBitSet extends TObject implements TCloneable, TSerializable {
return new TBitSet(ints); return new TBitSet(ints);
} }
public static TBitSet valueOf(TLongBuffer buff) {
buff = buff.slice();
long[] words = new long[buff.remaining()];
buff.get(words);
return valueOf(words);
}
public static TBitSet valueOf(byte[] bytes) { public static TBitSet valueOf(byte[] bytes) {
int[] ints = new int[(bytes.length + 3) / 4]; int[] ints = new int[(bytes.length + 3) / 4];
int fullInts = bytes.length / 4; int fullInts = bytes.length / TInteger.BYTES;
for (int i = 0; i < fullInts; ++i) { for (int i = 0; i < fullInts; ++i) {
ints[i] = (bytes[i * 4] & 0xFF) | ((bytes[i * 4 + 1] & 0xFF) << 8) | ((bytes[i * 4 + 2] & 0xFF) << 16) ints[i] = (bytes[i * 4] & 0xFF) | ((bytes[i * 4 + 1] & 0xFF) << 8) | ((bytes[i * 4 + 2] & 0xFF) << 16)
| ((bytes[i * 4 + 3] & 0xFF) << 24); | ((bytes[i * 4 + 3] & 0xFF) << 24);
@ -76,12 +86,19 @@ public class TBitSet extends TObject implements TCloneable, TSerializable {
return new TBitSet(ints); return new TBitSet(ints);
} }
public static TBitSet valueOf(TByteBuffer buff) {
buff = buff.slice().order(TByteOrder.LITTLE_ENDIAN);
byte[] words = new byte[buff.remaining()];
buff.get(words);
return valueOf(words);
}
public byte[] toByteArray() { public byte[] toByteArray() {
byte[] bytes = new byte[(length + 7) / 8]; byte[] bytes = new byte[(length + 7) / 8];
int fullInts = length / TInteger.SIZE; int fullInts = bytes.length / TInteger.BYTES;
int j = 0; int j = 0;
int i = 0; int i = 0;
for (; i < fullInts; i += 4) { for (; i < fullInts; i++) {
bytes[j++] = (byte) data[i]; bytes[j++] = (byte) data[i];
bytes[j++] = (byte) (data[i] >>> 8); bytes[j++] = (byte) (data[i] >>> 8);
bytes[j++] = (byte) (data[i] >>> 16); bytes[j++] = (byte) (data[i] >>> 16);
@ -348,8 +365,12 @@ public class TBitSet extends TObject implements TCloneable, TSerializable {
} }
public int previousSetBit(int fromIndex) { public int previousSetBit(int fromIndex) {
if (fromIndex < 0) {
if (fromIndex == -1) { if (fromIndex == -1) {
return -1; return -1;
} else {
throw new IndexOutOfBoundsException();
}
} }
if (fromIndex >= length) { if (fromIndex >= length) {
fromIndex = length; fromIndex = length;
@ -360,7 +381,7 @@ public class TBitSet extends TObject implements TCloneable, TSerializable {
if (val != 0) { if (val != 0) {
return fromIndex - TInteger.numberOfLeadingZeros(val); return fromIndex - TInteger.numberOfLeadingZeros(val);
} }
for (int i = index - 1; i >= 0; ++i) { for (int i = index - 1; i >= 0; --i) {
if (data[i] != 0) { if (data[i] != 0) {
return (i + 1) * 32 - TInteger.numberOfLeadingZeros(data[i]) - 1; return (i + 1) * 32 - TInteger.numberOfLeadingZeros(data[i]) - 1;
} }
@ -369,8 +390,12 @@ public class TBitSet extends TObject implements TCloneable, TSerializable {
} }
public int previousClearBit(int fromIndex) { public int previousClearBit(int fromIndex) {
if (fromIndex < 0) {
if (fromIndex == -1) { if (fromIndex == -1) {
return -1; return -1;
} else {
throw new IndexOutOfBoundsException();
}
} }
if (fromIndex >= length) { if (fromIndex >= length) {
return fromIndex; return fromIndex;
@ -381,7 +406,7 @@ public class TBitSet extends TObject implements TCloneable, TSerializable {
if (val != 0) { if (val != 0) {
return fromIndex - TInteger.numberOfLeadingZeros(val); return fromIndex - TInteger.numberOfLeadingZeros(val);
} }
for (int i = index - 1; i >= 0; ++i) { for (int i = index - 1; i >= 0; --i) {
if (data[i] != 0xFFFFFFFF) { if (data[i] != 0xFFFFFFFF) {
return (i + 1) * 32 - TInteger.numberOfLeadingZeros(~data[i]) - 1; return (i + 1) * 32 - TInteger.numberOfLeadingZeros(~data[i]) - 1;
} }
@ -425,7 +450,7 @@ public class TBitSet extends TObject implements TCloneable, TSerializable {
public int cardinality() { public int cardinality() {
int result = 0; int result = 0;
int sz = 1 + length / 32; int sz = (length + 31) / 32;
for (int i = 0; i < sz; ++i) { for (int i = 0; i < sz; ++i) {
result += TInteger.bitCount(data[i]); result += TInteger.bitCount(data[i]);
} }

View File

@ -97,6 +97,16 @@ public class BitSetTest {
} }
} }
@Test
public void toByteArray() throws Exception {
assertEquals("[]", Arrays.toString(BitSet.valueOf(new long[0]).toByteArray()));
assertEquals("[1]", Arrays.toString(BitSet.valueOf(new long[] { 1 }).toByteArray()));
assertEquals("[-17, -51, -85, -112, 120, 86, 52, 18]",
Arrays.toString(BitSet.valueOf(new long[] { 0x1234567890abcdefL }).toByteArray()));
assertEquals("[1, 0, 0, 0, 0, 0, 0, 0, 2]",
Arrays.toString(BitSet.valueOf(new long[] { 1, 2 }).toByteArray()));
}
@Test @Test
public void constructFromLongs() { public void constructFromLongs() {
BitSet bs = BitSet.valueOf(new long[] { 7, 2, 5, 1L << 36 }); BitSet bs = BitSet.valueOf(new long[] { 7, 2, 5, 1L << 36 });
@ -1225,6 +1235,10 @@ public class BitSetTest {
bs.set(0, 500); bs.set(0, 500);
assertEquals("cardinality() returned wrong value", 500, bs.cardinality()); assertEquals("cardinality() returned wrong value", 500, bs.cardinality());
bs = new BitSet();
bs.set(31);
assertEquals(1, bs.cardinality());
} }
@Test @Test
@ -1251,6 +1265,20 @@ public class BitSetTest {
assertEquals(2, bs.previousSetBit(2)); assertEquals(2, bs.previousSetBit(2));
assertEquals(-1, bs.previousSetBit(1)); assertEquals(-1, bs.previousSetBit(1));
assertEquals(-1, bs.previousSetBit(0)); assertEquals(-1, bs.previousSetBit(0));
bs = new BitSet();
bs.set(0);
bs.set(1);
bs.set(32);
bs.set(192);
bs.set(666);
assertEquals(666, bs.previousSetBit(999));
assertEquals(666, bs.previousSetBit(667));
assertEquals(666, bs.previousSetBit(666));
assertEquals(192, bs.previousSetBit(665));
assertEquals(32, bs.previousSetBit(191));
assertEquals(1, bs.previousSetBit(31));
assertEquals(0, bs.previousSetBit(0));
assertEquals(-1, bs.previousSetBit(-1));
} }
@Test @Test