Browse Source

Optimise EntryRegistryImpl.registerEntries by first checking in a set to see if the given entry already exists before adding it, instead of looping through the whole list to see if any of them match.

AlexIIL 5 năm trước cách đây
mục cha
commit
b1d9c13aec

+ 11 - 0
src/main/java/me/shedaniel/rei/api/EntryRegistry.java

@@ -10,6 +10,7 @@ import me.shedaniel.rei.utils.CollectionUtils;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 
+import java.util.Collection;
 import java.util.List;
 
 public interface EntryRegistry {
@@ -72,6 +73,16 @@ public interface EntryRegistry {
         }
     }
 
+    /**
+     * Registers multiple stacks to the item list
+     *
+     * @param afterStack the stack to put after
+     * @param stacks     the stacks to register
+     */
+    default void registerEntriesAfter(EntryStack afterStack, Collection<? extends EntryStack> stacks) {
+        registerEntriesAfter(afterStack, stacks.toArray(new EntryStack[0]));
+    }
+
     /**
      * Registers multiple stacks to the item list
      *

+ 5 - 0
src/main/java/me/shedaniel/rei/api/EntryStack.java

@@ -127,6 +127,11 @@ public interface EntryStack {
 
     boolean equalsAll(EntryStack stack);
 
+    /** {@link #hashCode()} for {@link #equalsAll(EntryStack)}. */
+    default int hashOfAll() {
+        return hashCode();
+    }
+
     int getZ();
 
     void setZ(int z);

+ 65 - 13
src/main/java/me/shedaniel/rei/impl/EntryRegistryImpl.java

@@ -13,16 +13,39 @@ import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.util.DefaultedList;
 
+import it.unimi.dsi.fastutil.Hash;
+import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
+import it.unimi.dsi.fastutil.objects.ObjectSets;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
-import java.util.TreeSet;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.stream.Collectors;
 
 @Deprecated
 @Internal
 public class EntryRegistryImpl implements EntryRegistry {
 
     private final CopyOnWriteArrayList<EntryStack> entries = Lists.newCopyOnWriteArrayList();
+    private final Set<EntryStack> entrySet = ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(new Hash.Strategy<EntryStack>() {
+        @Override
+        public int hashCode(EntryStack entry) {
+            return entry == null ? 0 : entry.hashOfAll();
+        }
+
+        @Override
+        public boolean equals(EntryStack a, EntryStack b) {
+            if (a == null || b == null) {
+                return a == b;
+            } else {
+                boolean result = a.equalsAll(b);
+                assert result == b.equalsAll(a) : "a.equalsAll(b) != b.equalsAll(a); (a = " + a + ", b = " + b + ")";
+                return result;
+            }
+        }
+    }));
 
     @Override
     public List<EntryStack> getStacksList() {
@@ -34,23 +57,52 @@ public class EntryRegistryImpl implements EntryRegistry {
         DefaultedList<ItemStack> list = DefaultedList.of();
         list.add(item.getStackForRender());
         item.appendStacks(item.getGroup(), list);
-        TreeSet<ItemStack> stackSet = list.stream().collect(Collectors.toCollection(() -> new TreeSet<ItemStack>((p1, p2) -> ItemStack.areEqualIgnoreDamage(p1, p2) ? 0 : 1)));
-        return Lists.newArrayList(stackSet).toArray(new ItemStack[0]);
+        ItemStack[] array = list.toArray(new ItemStack[0]);
+        Arrays.sort(array, (a, b) -> ItemStack.areEqualIgnoreDamage(a, b) ? 0 : 1);
+        return array;
     }
 
     @Override
     @Deprecated
     public void registerEntryAfter(EntryStack afterEntry, EntryStack stack, boolean checkAlreadyContains) {
-        if (!stack.isEmpty() && (!checkAlreadyContains || !alreadyContain(stack)))
-            if (afterEntry == null || afterEntry.isEmpty())
-                entries.add(stack);
-            else {
-                int last = entries.size();
-                for (int i = 0; i < entries.size(); i++)
-                    if (entries.get(i).equalsAll(afterEntry))
-                        last = i + 1;
-                entries.add(last, stack);
+        if (stack.isEmpty()) return;
+        boolean isNew = entrySet.add(stack);
+        if (checkAlreadyContains && !isNew) {
+            return;
+        }
+        if (afterEntry == null) {
+            entries.add(stack);
+        } else {
+            int last = entries.size();
+            for (int i = 0; i < entries.size(); i++)
+                if (entries.get(i).equalsAll(afterEntry))
+                    last = i + 1;
+            entries.add(last, stack);
+        }
+    }
+
+    @Override
+    public void registerEntriesAfter(EntryStack afterStack, Collection<? extends EntryStack> stacks) {
+        List<EntryStack> nonDuplicates = new ArrayList<>();
+        for (EntryStack stack : stacks) {
+            if (entrySet.add(stack)) {
+                nonDuplicates.add(stack);
+            }
+        }
+        int index = entries.size();
+        if (afterStack != null) {
+            for (int i = index - 1; i >= 0; i--) {
+                if (entries.get(i).equalsAll(afterStack)) {
+                    index = i + 1;
+                    break;
+                }
             }
+        }
+        entries.addAll(index, nonDuplicates);
     }
 
+    @Override
+    public void registerEntriesAfter(EntryStack afterStack, EntryStack... stacks) {
+        registerEntriesAfter(afterStack, Arrays.asList(stacks));
+    }
 }

+ 14 - 6
src/main/java/me/shedaniel/rei/impl/ItemEntryStack.java

@@ -34,6 +34,7 @@ import java.util.Optional;
 public class ItemEntryStack extends AbstractEntryStack {
 
     private ItemStack itemStack;
+    private int hash = -1;
 
     public ItemEntryStack(ItemStack itemStack) {
         this.itemStack = itemStack;
@@ -57,6 +58,7 @@ public class ItemEntryStack extends AbstractEntryStack {
     @Override
     public void setAmount(int amount) {
         itemStack.setCount(amount);
+        hash = -1;
     }
 
     @Override
@@ -114,12 +116,18 @@ public class ItemEntryStack extends AbstractEntryStack {
 
     @Override
     public int hashCode() {
-        int result = 1;
-        result = 31 * result + getType().ordinal();
-        result = 31 * result + itemStack.getItem().hashCode();
-        result = 31 * result + itemStack.getCount();
-        result = 31 * result + (itemStack.hasTag() ? itemStack.getTag().hashCode() : 0);
-        return result;
+        if (hash == -1) {
+            int result = 1;
+            result = 31 * result + getType().ordinal();
+            result = 31 * result + itemStack.getItem().hashCode();
+            result = 31 * result + itemStack.getCount();
+            result = 31 * result + (itemStack.hasTag() ? itemStack.getTag().hashCode() : 0);
+            hash = result;
+            if (hash == -1) {
+                hash = -2;
+            }
+        }
+        return hash;
     }
 
     @Nullable

+ 3 - 1
src/main/java/me/shedaniel/rei/plugin/DefaultPlugin.java

@@ -110,15 +110,17 @@ public class DefaultPlugin implements REIPluginV0 {
                 entryRegistry.registerEntry(EntryStack.create(item));
         }
         EntryStack stack = EntryStack.create(Items.ENCHANTED_BOOK);
+        List<EntryStack> enchantments = new ArrayList<>(); 
         for (Enchantment enchantment : Registry.ENCHANTMENT) {
             for (int i = enchantment.getMinimumLevel(); i <= enchantment.getMaximumLevel(); i++) {
                 Map<Enchantment, Integer> map = new HashMap<>();
                 map.put(enchantment, i);
                 ItemStack itemStack = new ItemStack(Items.ENCHANTED_BOOK);
                 EnchantmentHelper.set(map, itemStack);
-                entryRegistry.registerEntriesAfter(stack, EntryStack.create(itemStack));
+                enchantments.add(EntryStack.create(itemStack));
             }
         }
+        entryRegistry.registerEntriesAfter(stack, enchantments);
         for (Fluid fluid : Registry.FLUID) {
             if (!(fluid instanceof EmptyFluid))
                 entryRegistry.registerEntry(EntryStack.create(fluid));