Преглед на файлове

Add basic tests for FastMap, fix some issues with binary keys

malte0811 преди 4 години
родител
ревизия
340b6af739

+ 2 - 2
build.gradle

@@ -1,8 +1,8 @@
 import java.util.stream.Collectors
 
 plugins {
-    id "architectury-plugin" version "2.0.66"
-    id "forgified-fabric-loom" version "0.6.59" apply false
+    id "architectury-plugin" version "2.0.68"
+    id "forgified-fabric-loom" version "0.6.64" apply false
 }
 
 architectury {

+ 7 - 1
common/build.gradle

@@ -1,4 +1,4 @@
-import java.util.stream.Collectors
+apply plugin: 'java'
 
 dependencies {
     minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
@@ -7,9 +7,15 @@ dependencies {
     // We depend on fabric loader here to use the fabric @Environment annotations
     // Do NOT use other classes from fabric loader
     modCompile "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
+    testImplementation(platform('org.junit:junit-bom:5.7.1'))
+    testImplementation('org.junit.jupiter:junit-jupiter')
 }
 
 architectury {
     injectInjectables = false
     common()
 }
+
+test {
+    useJUnitPlatform()
+}

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

@@ -24,7 +24,7 @@ public class BinaryFastMapKey<T extends Comparable<T>> extends FastMapKey<T> {
 
     @Override
     public T getValue(int mapIndex) {
-        final int clearAbove = mapIndex & ~lowestNBits(firstBitAfterValue);
+        final int clearAbove = mapIndex & lowestNBits(firstBitAfterValue);
         return byInternalIndex(clearAbove >>> firstBitInValue);
     }
 

+ 10 - 3
common/src/main/java/malte0811/ferritecore/fastmap/FastMap.java

@@ -15,13 +15,20 @@ public class FastMap<Value> {
     // would likely be more effort than it's worth
     private final Map<Property<?>, Integer> toKeyIndex;
 
-    public FastMap(Collection<Property<?>> properties, Map<Map<Property<?>, Comparable<?>>, Value> valuesMap) {
+    public FastMap(
+            Collection<Property<?>> properties, Map<Map<Property<?>, Comparable<?>>, Value> valuesMap, boolean compact
+    ) {
         List<FastMapKey<?>> keys = new ArrayList<>(properties.size());
         int factorUpTo = 1;
         ImmutableMap.Builder<Property<?>, Integer> toKeyIndex = ImmutableMap.builder();
         for (Property<?> prop : properties) {
             toKeyIndex.put(prop, keys.size());
-            FastMapKey<?> nextKey = new CompactFastMapKey<>(prop, factorUpTo);
+            FastMapKey<?> nextKey;
+            if (compact) {
+                nextKey = new CompactFastMapKey<>(prop, factorUpTo);
+            } else {
+                nextKey = new BinaryFastMapKey<>(prop, factorUpTo);
+            }
             keys.add(nextKey);
             factorUpTo *= nextKey.getFactorToNext();
         }
@@ -35,7 +42,7 @@ public class FastMap<Value> {
         for (Map.Entry<Map<Property<?>, Comparable<?>>, Value> state : valuesMap.entrySet()) {
             valuesList.set(getIndexOf(state.getKey()), state.getValue());
         }
-        this.valueMatrix = ImmutableList.copyOf(valuesList);
+        this.valueMatrix = Collections.unmodifiableList(valuesList);
     }
 
     @Nullable

+ 10 - 5
common/src/main/java/malte0811/ferritecore/fastmap/PropertyIndexer.java

@@ -12,10 +12,7 @@ import net.minecraft.state.properties.BlockStateProperties;
 import net.minecraft.util.Direction;
 import net.minecraft.util.IStringSerializable;
 
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 public abstract class PropertyIndexer<T extends Comparable<T>> {
     private static final Map<Property<?>, PropertyIndexer<?>> KNOWN_INDEXERS = new Object2ObjectOpenHashMap<>();
@@ -31,7 +28,7 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
                     result = new BoolIndexer((BooleanProperty) propInner);
                 } else if (propInner instanceof IntegerProperty) {
                     result = new IntIndexer((IntegerProperty) propInner);
-                } else if (propInner == BlockStateProperties.FACING) {
+                } else if (WeirdVanillaDirectionIndexer.isApplicable(propInner)) {
                     result = new WeirdVanillaDirectionIndexer();
                 } else if (propInner instanceof EnumProperty<?>) {
                     result = new EnumIndexer<>((EnumProperty<?>) propInner);
@@ -152,6 +149,14 @@ public abstract class PropertyIndexer<T extends Comparable<T>> {
             Preconditions.checkState(isValid());
         }
 
+        static boolean isApplicable(Property<?> prop) {
+            Collection<?> values = prop.getAllowedValues();
+            if (values.size() != ORDER.length) {
+                return false;
+            }
+            return Arrays.equals(ORDER, values.toArray());
+        }
+
         @Override
         public Direction byIndex(int index) {
             return ORDER[index];

+ 2 - 1
common/src/main/java/malte0811/ferritecore/impl/StateHolderImpl.java

@@ -21,7 +21,8 @@ public class StateHolderImpl {
             holder.setStateMap((FastMap<S>) LAST_FAST_STATE_MAP.get());
         } else {
             LAST_STATE_MAP.set(states);
-            FastMap<S> globalTable = new FastMap<>(holder.getVanillaPropertyMap().keySet(), states);
+            //TODO option
+            FastMap<S> globalTable = new FastMap<>(holder.getVanillaPropertyMap().keySet(), states, true);
             holder.setStateMap(globalTable);
             LAST_FAST_STATE_MAP.set(globalTable);
         }

+ 95 - 0
common/src/test/java/malte0811/ferritecore/fastmap/FastMapTest.java

@@ -0,0 +1,95 @@
+package malte0811.ferritecore.fastmap;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.mojang.datafixers.util.Pair;
+import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
+import it.unimi.dsi.fastutil.booleans.BooleanList;
+import malte0811.ferritecore.classloading.FastImmutableMapDefiner;
+import malte0811.ferritecore.ducks.FastMapStateHolder;
+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.TestFactory;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class FastMapTest {
+    private static final BooleanProperty BOOL = BooleanProperty.create("A");
+    private static final IntegerProperty INT = IntegerProperty.create("B", 0, 7);
+    private static final EnumProperty<Direction> DIR = DirectionProperty.create("C", Direction.class);
+    private static final BooleanList BOOLS = new BooleanArrayList(new boolean[]{false, true});
+
+    @TestFactory
+    public Stream<DynamicTest> basicMapping() {
+        return BOOLS.stream().map(b -> DynamicTest.dynamicTest("Compact: " + b, new TestData(b)::testBasic));
+    }
+
+    @TestFactory
+    public Stream<DynamicTest> testWith() {
+        return BOOLS.stream().map(b -> DynamicTest.dynamicTest("Compact: " + b, new TestData(b)::testWith));
+    }
+
+    private static class TestData {
+        private final FastMap<Map<Property<?>, Comparable<?>>> map;
+        private final ImmutableMap<Map<Property<?>, Comparable<?>>, Map<Property<?>, Comparable<?>>> values;
+
+        public TestData(boolean compact) {
+            List<Property<?>> properties = ImmutableList.of(BOOL, INT, DIR);
+            ImmutableMap.Builder<Map<Property<?>, Comparable<?>>, Map<Property<?>, Comparable<?>>> values = ImmutableMap.builder();
+            Stream<List<Pair<Property<?>, Comparable<?>>>> stream = Stream.of(Collections.emptyList());
+
+            for (Property<?> property : properties) {
+                stream = stream.flatMap(baseList -> property.getAllowedValues().stream().map(value -> {
+                    List<Pair<Property<?>, Comparable<?>>> withAdded = Lists.newArrayList(baseList);
+                    withAdded.add(Pair.of(property, value));
+                    return withAdded;
+                }));
+            }
+            stream.forEach(l -> {
+                Map<Property<?>, Comparable<?>> entry = l.stream().collect(Collectors.toMap(
+                        Pair::getFirst,
+                        Pair::getSecond
+                ));
+                values.put(entry, entry);
+            });
+            this.values = values.build();
+            map = new FastMap<>(properties, this.values, compact);
+        }
+
+        private void testBasic() {
+            for (Map<Property<?>, Comparable<?>> e : values.keySet()) {
+                int index = map.getIndexOf(e);
+                FastMapStateHolder<Map<Property<?>, Comparable<?>>> holder = new MockFMStateHolder<>(map, index);
+                Map<Property<?>, Comparable<?>> map = FastImmutableMapDefiner.makeMap(holder);
+                Assertions.assertEquals(new HashMap<>(e), new HashMap<>(map));
+            }
+        }
+
+        private void testWith() {
+            for (Map<Property<?>, Comparable<?>> baseMap : values.keySet()) {
+                final int baseIndex = map.getIndexOf(baseMap);
+                for (Property<?> toSwap : baseMap.keySet()) {
+                    testSwaps(baseIndex, toSwap, baseMap);
+                }
+            }
+        }
+
+        private <T extends Comparable<T>>
+        void testSwaps(int baseIndex, Property<T> toSwap, Map<Property<?>, Comparable<?>> baseMap) {
+            Map<Property<?>, Comparable<?>> expected = new HashMap<>(baseMap);
+            for (T newValue : toSwap.getAllowedValues()) {
+                Map<Property<?>, Comparable<?>> newMap = map.with(baseIndex, toSwap, newValue);
+                expected.put(toSwap, newValue);
+                Assertions.assertEquals(expected, newMap);
+            }
+        }
+    }
+}

+ 45 - 0
common/src/test/java/malte0811/ferritecore/fastmap/MockFMStateHolder.java

@@ -0,0 +1,45 @@
+package malte0811.ferritecore.fastmap;
+
+import com.google.common.collect.ImmutableMap;
+import malte0811.ferritecore.ducks.FastMapStateHolder;
+import net.minecraft.state.Property;
+
+public class MockFMStateHolder<T> implements FastMapStateHolder<T> {
+    private final FastMap<T> map;
+    private final int index;
+
+    public MockFMStateHolder(FastMap<T> map, int index) {
+        this.map = map;
+        this.index = index;
+    }
+
+    @Override
+    public FastMap<T> getStateMap() {
+        return map;
+    }
+
+    @Override
+    public void setStateMap(FastMap<T> newValue) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getStateIndex() {
+        return index;
+    }
+
+    @Override
+    public void setStateIndex(int newValue) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ImmutableMap<Property<?>, Comparable<?>> getVanillaPropertyMap() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void replacePropertyMap(ImmutableMap<Property<?>, Comparable<?>> newMap) {
+        throw new UnsupportedOperationException();
+    }
+}