From c34f422737bf2a550a1c7ac87120dfc6e210926d Mon Sep 17 00:00:00 2001 From: Basique Date: Thu, 15 Jun 2023 17:29:12 +0300 Subject: [PATCH 1/2] optimize NestedPackages sorting --- .../cuchaz/enigma/gui/NestedPackages.java | 46 +++----- .../gui/node/ClassSelectorPackageNode.java | 10 +- .../gui/node/SortedMutableTreeNode.java | 108 ++++++++++++++++++ 3 files changed, 130 insertions(+), 34 deletions(-) create mode 100644 enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java index c4541fc67..a115a0985 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java @@ -2,23 +2,21 @@ import java.util.Collection; import java.util.Comparator; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import cuchaz.enigma.gui.node.ClassSelectorClassNode; import cuchaz.enigma.gui.node.ClassSelectorPackageNode; +import cuchaz.enigma.gui.node.SortedMutableTreeNode; import cuchaz.enigma.translation.mapping.EntryRemapper; import cuchaz.enigma.translation.representation.entry.ClassEntry; public class NestedPackages { - private final DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - private final Map packageToNode = new HashMap<>(); + private final SortedMutableTreeNode root; + private final Map packageToNode = new HashMap<>(); private final Map classToNode = new HashMap<>(); private final EntryRemapper remapper; private final Comparator comparator; @@ -42,6 +40,7 @@ public NestedPackages(Iterable entries, Comparator entry return 0; }; + this.root = new SortedMutableTreeNode(comparator); for (ClassEntry entry : entries) { addEntry(entry); @@ -52,31 +51,31 @@ public void addEntry(ClassEntry entry) { ClassEntry translated = remapper.deobfuscate(entry); var me = new ClassSelectorClassNode(entry, translated); classToNode.put(entry, me); - insert(getPackage(translated.getPackageName()), me); + getPackage(translated.getPackageName()).insert(me, 0); } - public DefaultMutableTreeNode getPackage(String packageName) { - DefaultMutableTreeNode node = packageToNode.get(packageName); + public SortedMutableTreeNode getPackage(String packageName) { + SortedMutableTreeNode node = packageToNode.get(packageName); if (packageName == null) { return root; } if (node == null) { - node = new ClassSelectorPackageNode(packageName); - insert(getPackage(ClassEntry.getParentPackage(packageName)), node); + node = new ClassSelectorPackageNode(this.comparator, packageName); + getPackage(ClassEntry.getParentPackage(packageName)).insert(node, 0); packageToNode.put(packageName, node); } return node; } - public DefaultMutableTreeNode getRoot() { + public SortedMutableTreeNode getRoot() { return root; } public TreePath getPackagePath(String packageName) { - DefaultMutableTreeNode node = packageToNode.getOrDefault(packageName, root); + SortedMutableTreeNode node = packageToNode.getOrDefault(packageName, root); return new TreePath(node.getPath()); } @@ -90,11 +89,11 @@ public void removeClassNode(ClassEntry entry) { if (node != null) { node.removeFromParent(); // remove dangling packages - DefaultMutableTreeNode packageNode = packageToNode.get(entry.getPackageName()); + SortedMutableTreeNode packageNode = packageToNode.get(entry.getPackageName()); while (packageNode != null && packageNode.getChildCount() == 0) { - DefaultMutableTreeNode theNode = packageNode; - packageNode = (DefaultMutableTreeNode) packageNode.getParent(); + SortedMutableTreeNode theNode = packageNode; + packageNode = (SortedMutableTreeNode) packageNode.getParent(); theNode.removeFromParent(); if (theNode instanceof ClassSelectorPackageNode pn) { @@ -104,22 +103,7 @@ public void removeClassNode(ClassEntry entry) { } } - public Collection getPackageNodes() { + public Collection getPackageNodes() { return packageToNode.values(); } - - private void insert(DefaultMutableTreeNode parent, MutableTreeNode child) { - int index = 0; - Enumeration children = parent.children(); - - while (children.hasMoreElements()) { - if (comparator.compare(children.nextElement(), child) < 0) { - index++; - } else { - break; - } - } - - parent.insert(child, index); - } } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java index dfcbd8c19..f7ea860d9 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java @@ -11,14 +11,18 @@ package cuchaz.enigma.gui.node; -import javax.swing.tree.DefaultMutableTreeNode; +import java.util.Comparator; + +import javax.swing.tree.TreeNode; import cuchaz.enigma.translation.representation.entry.ClassEntry; -public class ClassSelectorPackageNode extends DefaultMutableTreeNode { +public class ClassSelectorPackageNode extends SortedMutableTreeNode { private String packageName; - public ClassSelectorPackageNode(String packageName) { + public ClassSelectorPackageNode(Comparator comparator, String packageName) { + super(comparator); + this.packageName = packageName != null ? packageName : "(none)"; } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java new file mode 100644 index 000000000..efee30f39 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java @@ -0,0 +1,108 @@ +package cuchaz.enigma.gui.node; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; + +import com.google.common.collect.Iterables; + +/** + * A MutableTreeNode whose contents are always guaranteed to be sorted with the given comparator. + */ +public class SortedMutableTreeNode extends DefaultMutableTreeNode { + private final Comparator comparator; + private final List children; + private boolean isSorted = true; + + public SortedMutableTreeNode(Comparator comparator) { + this.comparator = comparator; + this.children = new ArrayList<>(); + } + + @Override + public void insert(MutableTreeNode child, int index) { + if (child == null) { + throw new IllegalArgumentException("child is null"); + } + + MutableTreeNode oldParent = (MutableTreeNode) child.getParent(); + + if (oldParent != null) { + oldParent.remove(child); + } + + child.setParent(this); + this.children.add(child); + this.isSorted = false; + } + + private void checkSorted() { + if (!this.isSorted) { + this.isSorted = true; + this.children.sort(this.comparator); + } + } + + @Override + public void remove(int index) { + checkSorted(); + + remove((MutableTreeNode) getChildAt(index)); + } + + @Override + public void remove(MutableTreeNode node) { + this.children.remove(node); + node.setParent(null); + } + + @Override + public TreeNode getChildAt(int childIndex) { + checkSorted(); + + return this.children.get(childIndex); + } + + @Override + public int getChildCount() { + return this.children.size(); + } + + @Override + public int getIndex(TreeNode node) { + return Iterables.indexOf(this.children, other -> this.comparator.compare(node, other) == 0); + } + + @Override + public boolean getAllowsChildren() { + return true; + } + + @Override + public boolean isLeaf() { + return this.children.isEmpty(); + } + + @Override + public Enumeration children() { + Iterator iter = this.children.iterator(); + + return new Enumeration<>() { + @Override + public boolean hasMoreElements() { + return iter.hasNext(); + } + + @Override + public TreeNode nextElement() { + return iter.next(); + } + }; + } +} From e0740498ee3029e6461febc04a5d5163cc590be3 Mon Sep 17 00:00:00 2001 From: Basique Date: Fri, 16 Jun 2023 16:37:20 +0300 Subject: [PATCH 2/2] address reviews --- .../enigma/gui/node/SortedMutableTreeNode.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java index efee30f39..9cef4fadc 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/node/SortedMutableTreeNode.java @@ -10,8 +10,6 @@ import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; -import com.google.common.collect.Iterables; - /** * A MutableTreeNode whose contents are always guaranteed to be sorted with the given comparator. */ @@ -76,7 +74,15 @@ public int getChildCount() { @Override public int getIndex(TreeNode node) { - return Iterables.indexOf(this.children, other -> this.comparator.compare(node, other) == 0); + checkSorted(); + + for (int i = 0; i < this.children.size(); i++) { + if (this.comparator.compare(node, children.get(i)) == 0) { + return i; + } + } + + return -1; } @Override @@ -91,6 +97,8 @@ public boolean isLeaf() { @Override public Enumeration children() { + checkSorted(); + Iterator iter = this.children.iterator(); return new Enumeration<>() {