A little optimization, dottedchain uses ArrayLists

This commit is contained in:
Jindra Petřík
2023-01-16 20:46:21 +01:00
parent 60e6e90310
commit 40ea1e4aa3
5 changed files with 166 additions and 163 deletions

View File

@@ -23,6 +23,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
*
@@ -31,7 +32,7 @@ import java.util.List;
public class DottedChain implements Serializable, Comparable<DottedChain> {
public static final DottedChain EMPTY = new DottedChain(true);
public static final DottedChain UNBOUNDED = new DottedChain(new String[]{"*"});
public static final DottedChain TOPLEVEL = new DottedChain(new String[]{});
@@ -64,30 +65,21 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
public static final DottedChain ALL = new DottedChain(new String[]{"*"});
private final String[] parts;
private final boolean[] attributes;
private final int length;
private final int hash;
private List<PathPart> parts;
private boolean isNull = false;
private String[] namespaceSuffixes;
public String getNamespaceSuffix(int index) {
return namespaceSuffixes[index];
return parts.get(index).namespaceSuffix;
}
public String getLastNamespaceSuffix() {
if (length == 0) {
if (parts.isEmpty()) {
return "";
}
return namespaceSuffixes[length - 1];
return parts.get(parts.size() - 1).namespaceSuffix;
}
public static final DottedChain parseNoSuffix(String name) {
if (name == null) {
return DottedChain.EMPTY;
@@ -95,18 +87,15 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
return DottedChain.TOPLEVEL;
} else {
String parts[] = name.split("\\.");
String nsSuffixes[] = new String[parts.length];
int i = 0;
List<PathPart> newParts = new ArrayList<>();
for (String part : parts) {
String nameNoSuffix = part;
parts[i] = nameNoSuffix;
nsSuffixes[i] = "";
i++;
newParts.add(new PathPart(part, false, ""));
}
return new DottedChain(parts, nsSuffixes);
return new DottedChain(newParts, false);
}
}
public static final DottedChain parseWithSuffix(String name) {
if (name == null) {
return DottedChain.EMPTY;
@@ -114,86 +103,63 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
return DottedChain.TOPLEVEL;
} else {
String parts[] = name.split("\\.");
String nsSuffixes[] = new String[parts.length];
int i = 0;
List<PathPart> newParts = new ArrayList<>();
for (String part : parts) {
String nameNoSuffix = part;
String namespaceSuffix = "";
if (part.matches(".*#[0-9]+$")) {
nameNoSuffix = part.substring(0, part.lastIndexOf("#"));
namespaceSuffix = part.substring(part.lastIndexOf("#"));
}
parts[i] = nameNoSuffix;
nsSuffixes[i] = namespaceSuffix;
i++;
}
newParts.add(new PathPart(nameNoSuffix, false, namespaceSuffix));
}
return new DottedChain(parts, nsSuffixes);
return new DottedChain(newParts, false);
}
}
private DottedChain(boolean isNull) {
this.isNull = isNull;
this.parts = new String[0];
this.length = 0;
this.hash = 0;
this.attributes = new boolean[0];
this.namespaceSuffixes = new String[0];
this.parts = new ArrayList<>();
}
public DottedChain(DottedChain src) {
this(src.parts, src.namespaceSuffixes);
this.parts = new ArrayList<>(src.parts);
this.isNull = src.isNull;
}
public DottedChain(String[] parts) {
this(Arrays.asList(parts));
}
public DottedChain(List<String> parts) {
length = parts.size();
this.parts = parts.toArray(new String[length]);
attributes = new boolean[length];
hash = calcHash();
this.namespaceSuffixes = new String[length];
for(int i = 0; i < length; i++) {
namespaceSuffixes[i] = "";
}
private DottedChain(List<PathPart> parts, boolean isNull) {
this.parts = parts;
this.isNull = isNull;
}
public DottedChain(List<String> parts) {
List<PathPart> newParts = new ArrayList<>();
for (String part : parts) {
newParts.add(new PathPart(part, false, ""));
}
this.parts = newParts;
}
/*public DottedChain(String onePart, String namespaceSuffix) {
this(new String[]{onePart}, namespaceSuffix);
}*/
public DottedChain(String[] parts, String[] namespaceSuffixes) {
this(new boolean[parts.length], parts, namespaceSuffixes);
}
public DottedChain(boolean attributes[], String[] parts, String[] namespaceSuffixes) {
if (parts.length == 1 && parts[0].isEmpty()) {
length = 0;
this.parts = new String[0];
} else {
length = parts.length;
this.parts = parts;
}
this.attributes = attributes;
hash = calcHash();
this.namespaceSuffixes = namespaceSuffixes;
}
private DottedChain(String[] parts, int length) {
this.length = length;
this.parts = parts;
attributes = new boolean[length];
this.namespaceSuffixes = new String[length];
for(int i = 0; i < length; i++) {
namespaceSuffixes[i] = "";
public DottedChain(boolean attributes[], String[] parts, String[] namespaceSuffixes) {
List<PathPart> newParts = new ArrayList<>();
for (int i = 0; i < attributes.length; i++) {
newParts.add(new PathPart(parts[i], attributes[i], namespaceSuffixes[i]));
}
hash = calcHash();
this.parts = newParts;
}
public boolean isTopLevel() {
return !isNull && length == 0;
return !isNull && parts.isEmpty();
}
public boolean isEmpty() {
@@ -201,51 +167,51 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
}
public int size() {
return length;
return parts.size();
}
public String get(int index) {
if (index >= length) {
if (index >= parts.size()) {
throw new ArrayIndexOutOfBoundsException();
}
return parts[index];
return parts.get(index).name;
}
public boolean isAttribute(int index) {
if (index >= length) {
if (index >= parts.size()) {
throw new ArrayIndexOutOfBoundsException();
}
return attributes[index];
return parts.get(index).attribute;
}
public DottedChain subChain(int count) {
if (count > length) {
if (count > parts.size()) {
throw new ArrayIndexOutOfBoundsException();
}
return new DottedChain(parts, count);
return new DottedChain(new ArrayList<>(parts.subList(0, count)), isNull);
}
public String getLast() {
if (isNull) {
return null;
}
if (length == 0) {
if (parts.isEmpty()) {
return "";
} else {
return parts[length - 1];
return parts.get(parts.size() - 1).name;
}
}
public boolean isLastAttribute() {
if (isNull) {
return false;
}
if (length == 0) {
if (parts.isEmpty()) {
return false;
} else {
return attributes[length - 1];
return parts.get(parts.size() - 1).attribute;
}
}
@@ -253,11 +219,11 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
if (isNull) {
return null;
}
if (length < 2) {
if (parts.size() < 2) {
return EMPTY;
}
return new DottedChain(parts, length - 1);
return subChain(parts.size() - 1);
}
public DottedChain addWithSuffix(String name) {
@@ -273,49 +239,40 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
public DottedChain add(String name, String namespaceSuffix) {
return add(false, name, namespaceSuffix);
}
public DottedChain add(boolean attribute, String name, String namespaceSuffix) {
if (name == null) {
return new DottedChain(this);
}
String[] nparts = new String[length + 1];
boolean[] nattributes = new boolean[length + 1];
String[] nnamespaceSuffixes = new String[length + 1];
if (length > 0) {
System.arraycopy(parts, 0, nparts, 0, length);
System.arraycopy(attributes, 0, nattributes, 0, length);
System.arraycopy(namespaceSuffixes, 0, nnamespaceSuffixes, 0, length);
}
nattributes[nattributes.length - 1] = attribute;
nparts[nparts.length - 1] = name;
nnamespaceSuffixes[nparts.length - 1] = namespaceSuffix;
return new DottedChain(nattributes, nparts, nnamespaceSuffixes);
List<PathPart> newParts = new ArrayList<>(parts);
newParts.add(new PathPart(name, attribute, namespaceSuffix));
return new DottedChain(newParts, false);
}
protected String toString(boolean as3, boolean raw, boolean withSuffix) {
if (isNull) {
return "";
}
if (length == 0) {
if (parts.isEmpty()) {
return "";
}
StringBuilder ret = new StringBuilder();
for (int i = 0; i < length; i++) {
for (int i = 0; i < parts.size(); i++) {
if (i > 0) {
ret.append(".");
}
if (attributes[i]) {
if (parts.get(i).attribute) {
ret.append("@");
}
String part = parts[i];
boolean lastStar = i == length - 1 && "*".equals(part);
String part = parts.get(i).name;
boolean lastStar = i == parts.size() - 1 && "*".equals(part);
ret.append((raw || lastStar) ? part : IdentifiersDeobfuscation.printIdentifier(as3, part));
if (withSuffix) {
ret.append(namespaceSuffixes[i]);
ret.append(parts.get(i).namespaceSuffix);
}
}
return ret.toString();
}
@@ -323,23 +280,27 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
if (isNull) {
return "";
}
if (length == 0) {
if (parts.isEmpty()) {
return "";
}
StringBuilder ret = new StringBuilder();
for (int i = 0; i < length; i++) {
for (int i = 0; i < parts.size(); i++) {
if (i > 0) {
ret.append(File.separator);
}
ret.append(Helper.makeFileName(IdentifiersDeobfuscation.printIdentifier(true, parts[i])));
ret.append(Helper.makeFileName(IdentifiersDeobfuscation.printIdentifier(true, parts.get(i).name)));
}
return ret.toString();
}
public List<String> toList() {
return new ArrayList<>(Arrays.asList(parts));
List<String> ret = new ArrayList<>();
for (PathPart p : parts) {
ret.add(p.name);
}
return ret;
}
public String toPrintableString(boolean as3) {
@@ -357,23 +318,17 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
@Override
public int hashCode() {
int hash = 7;
hash = 41 * hash + Objects.hashCode(this.parts);
hash = 41 * hash + (this.isNull ? 1 : 0);
return hash;
}
private int calcHash() {
if (isNull) {
return 0;
}
int result = 1;
for (int i = 0; i < length; i++) {
result = 31 * result + parts[i].hashCode();
}
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
@@ -381,32 +336,57 @@ public class DottedChain implements Serializable, Comparable<DottedChain> {
return false;
}
final DottedChain other = (DottedChain) obj;
if (isNull && other.isNull) {
return true;
}
if (length != other.length) {
if (this.isNull != other.isNull) {
return false;
}
for (int i = 0; i < length; i++) {
String s1 = parts[i];
String s2 = other.parts[i];
if (!s1.equals(s2)) {
return false;
}
if (attributes[i] != other.attributes[i]) {
return false;
}
if (!namespaceSuffixes[i].equals(other.namespaceSuffixes[i])) {
return false;
}
}
return true;
return Objects.equals(this.parts, other.parts);
}
@Override
public int compareTo(DottedChain o) {
return toRawString().compareTo(o.toRawString());
}
private static class PathPart {
public String name;
public boolean attribute;
public String namespaceSuffix;
public PathPart(String name, boolean attribute, String namespaceSuffix) {
this.name = name;
this.attribute = attribute;
this.namespaceSuffix = namespaceSuffix;
}
@Override
public int hashCode() {
int hash = 5;
hash = 79 * hash + Objects.hashCode(this.name);
hash = 79 * hash + (this.attribute ? 1 : 0);
hash = 79 * hash + Objects.hashCode(this.namespaceSuffix);
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final PathPart other = (PathPart) obj;
if (this.attribute != other.attribute) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return Objects.equals(this.namespaceSuffix, other.namespaceSuffix);
}
}
}