Jelajahi Sumber

More tests and fixes for binary fast maps

malte0811 4 tahun lalu
induk
melakukan
c76718b13c

+ 6 - 3
common/src/main/java/malte0811/ferritecore/fastmap/BinaryFastMapKey.java

@@ -16,8 +16,7 @@ public class BinaryFastMapKey<T extends Comparable<T>> extends FastMapKey<T> {
         Preconditions.checkState(addedFactor < 2 * numValues());
         final int setBitInBaseFactor = MathHelper.log2(mapFactor);
         final int setBitInAddedFactor = MathHelper.log2(addedFactor);
-        //TODO off-by-one errors?
-        Preconditions.checkState(setBitInBaseFactor + setBitInAddedFactor < 32);
+        Preconditions.checkState(setBitInBaseFactor + setBitInAddedFactor <= 32);
         firstBitInValue = (byte) setBitInBaseFactor;
         firstBitAfterValue = (byte) (setBitInBaseFactor + setBitInAddedFactor);
     }
@@ -45,6 +44,10 @@ public class BinaryFastMapKey<T extends Comparable<T>> extends FastMapKey<T> {
     }
 
     private int lowestNBits(byte n) {
-        return (1 << n) - 1;
+        if (n >= Integer.SIZE) {
+            return -1;
+        } else {
+            return (1 << n) - 1;
+        }
     }
 }

+ 45 - 2
common/src/test/java/malte0811/ferritecore/fastmap/FastMapTest.java

@@ -12,12 +12,14 @@ import net.minecraft.state.*;
 import net.minecraft.util.Direction;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestFactory;
 
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -29,12 +31,53 @@ public class FastMapTest {
 
     @TestFactory
     public Stream<DynamicTest> basicMapping() {
-        return BOOLS.stream().map(b -> DynamicTest.dynamicTest("Compact: " + b, new TestData(b)::testBasic));
+        return forEachType(TestData::testBasic);
     }
 
     @TestFactory
     public Stream<DynamicTest> testWith() {
-        return BOOLS.stream().map(b -> DynamicTest.dynamicTest("Compact: " + b, new TestData(b)::testWith));
+        return forEachType(TestData::testWith);
+    }
+
+    private Stream<DynamicTest> forEachType(Consumer<TestData> test) {
+        return BOOLS.stream().map(
+                b -> DynamicTest.dynamicTest("Compact: " + b, () -> test.accept(new TestData(b)))
+        );
+    }
+
+    private void assertBinaryKeySize(int numElements, int expectedFactor) {
+        Property<?> temp = IntegerProperty.create("", 1, numElements);
+        BinaryFastMapKey<?> key = new BinaryFastMapKey<>(temp, 1);
+        Assertions.assertEquals(expectedFactor, key.getFactorToNext());
+    }
+
+    @Test
+    public void testBinaryKeySizes() {
+        assertBinaryKeySize(2, 2);
+        assertBinaryKeySize(16, 16);
+        assertBinaryKeySize(15, 16);
+        assertBinaryKeySize(17, 32);
+    }
+
+    @Test
+    public void testOversizedBinaryKey() {
+        new BinaryFastMapKey<>(IntegerProperty.create("", 1, 4), 1 << 30);
+        Assertions.assertThrows(
+                IllegalStateException.class,
+                () -> new BinaryFastMapKey<>(IntegerProperty.create("", 1, 4), 1 << 31)
+        );
+    }
+
+    @Test
+    public void testBinaryKey32Bits() {
+        int factor = 1;
+        for (int i = 0; i < 32; ++i) {
+            BinaryFastMapKey<Boolean> k = new BinaryFastMapKey<>(BOOL, factor);
+            Assertions.assertEquals(true, k.getValue(factor >>> 2));
+            Assertions.assertEquals(false, k.getValue(factor));
+            Assertions.assertEquals(true, k.getValue(factor << 2));
+            factor *= k.getFactorToNext();
+        }
     }
 
     private static class TestData {