From 045ebdf216e833229988eb7d4ddc960827d512c8 Mon Sep 17 00:00:00 2001 From: ihromant Date: Mon, 9 Sep 2024 14:43:33 +0300 Subject: [PATCH] Small BitSet fixes and improvements --- .../org/teavm/classlib/java/util/TBitSet.java | 43 +++++++++++++++---- .../teavm/classlib/java/util/BitSetTest.java | 28 ++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TBitSet.java b/classlib/src/main/java/org/teavm/classlib/java/util/TBitSet.java index d5816cf47..b029ceab0 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TBitSet.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TBitSet.java @@ -18,6 +18,9 @@ import java.util.function.IntPredicate; import org.teavm.classlib.java.io.TSerializable; 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.intimpl.TSimpleIntStreamImpl; import org.teavm.interop.Rename; @@ -52,6 +55,13 @@ public static TBitSet valueOf(long[] longs) { 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) { int[] ints = new int[(bytes.length + 3) / 4]; int fullInts = bytes.length / 4; @@ -76,12 +86,19 @@ public static TBitSet valueOf(byte[] bytes) { 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() { byte[] bytes = new byte[(length + 7) / 8]; - int fullInts = length / TInteger.SIZE; + int fullInts = bytes.length / 4; int j = 0; int i = 0; - for (; i < fullInts; i += 4) { + for (; i < fullInts; i++) { bytes[j++] = (byte) data[i]; bytes[j++] = (byte) (data[i] >>> 8); bytes[j++] = (byte) (data[i] >>> 16); @@ -348,8 +365,12 @@ public int nextClearBit(int fromIndex) { } public int previousSetBit(int fromIndex) { - if (fromIndex == -1) { - return -1; + if (fromIndex < 0) { + if (fromIndex == -1) { + return -1; + } else { + throw new IndexOutOfBoundsException(); + } } if (fromIndex >= length) { fromIndex = length; @@ -360,7 +381,7 @@ public int previousSetBit(int fromIndex) { if (val != 0) { 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) { return (i + 1) * 32 - TInteger.numberOfLeadingZeros(data[i]) - 1; } @@ -369,8 +390,12 @@ public int previousSetBit(int fromIndex) { } public int previousClearBit(int fromIndex) { - if (fromIndex == -1) { - return -1; + if (fromIndex < 0) { + if (fromIndex == -1) { + return -1; + } else { + throw new IndexOutOfBoundsException(); + } } if (fromIndex >= length) { return fromIndex; @@ -381,7 +406,7 @@ public int previousClearBit(int fromIndex) { if (val != 0) { 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) { return (i + 1) * 32 - TInteger.numberOfLeadingZeros(~data[i]) - 1; } @@ -425,7 +450,7 @@ public boolean intersects(TBitSet set) { public int cardinality() { int result = 0; - int sz = 1 + length / 32; + int sz = (length + 31) / 32; for (int i = 0; i < sz; ++i) { result += TInteger.bitCount(data[i]); } diff --git a/tests/src/test/java/org/teavm/classlib/java/util/BitSetTest.java b/tests/src/test/java/org/teavm/classlib/java/util/BitSetTest.java index 49ccffa78..3c3d52fd3 100644 --- a/tests/src/test/java/org/teavm/classlib/java/util/BitSetTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/util/BitSetTest.java @@ -97,6 +97,16 @@ public void constructFromBytes() { } } + @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 public void constructFromLongs() { BitSet bs = BitSet.valueOf(new long[] { 7, 2, 5, 1L << 36 }); @@ -1225,6 +1235,10 @@ public void cardinality() { bs.set(0, 500); assertEquals("cardinality() returned wrong value", 500, bs.cardinality()); + + bs = new BitSet(); + bs.set(31); + assertEquals(1, bs.cardinality()); } @Test @@ -1251,6 +1265,20 @@ public void previousSetBitFound() { assertEquals(2, bs.previousSetBit(2)); assertEquals(-1, bs.previousSetBit(1)); 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