Skip to content

Commit

Permalink
MappingUtil.split benchmarks
Browse files Browse the repository at this point in the history
Remarks: The original version of MappingUtil.split wins. It is slightly slower, but it doesn't allocate extra memory
  • Loading branch information
XiaoPangxie732 committed Nov 19, 2024
1 parent 9fc76ba commit f7c93f1
Show file tree
Hide file tree
Showing 19 changed files with 341 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ public static RuntimeException wrapInRuntime(Throwable e) {

public static <I, O, E extends Throwable> O[] mapArray(I[] input, IntFunction<O[]> outputGenerator,
LambdaUtil.Function_WithThrowable<I, O, E> func) throws E {
Objects.requireNonNull(input);// TODO: Do we need these 2 checks?
Objects.requireNonNull(outputGenerator);
Objects.requireNonNull(func);
O[] output = outputGenerator.apply(input.length);
O[] output = Objects.requireNonNull(outputGenerator.apply(input.length));
for (int i = 0; i < input.length; i++) {
output[i] = Objects.requireNonNull(func.apply(Objects.requireNonNull(input[i])));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;

/**
* Base class of all mappings
Expand Down Expand Up @@ -62,6 +63,21 @@ public final <C extends Component> C getComponent(@NotNull Class<? extends C> co
return (C) components.get(component);
}

/**
* Gets the component of given type if it is present, otherwise create a new component<br>
*
* @param component Given component type. Cannot be null
* @return The component if exists, or the newly created component
*/
@SuppressWarnings("unchecked")
public final <C extends Component> @NotNull C getOrCreateComponent(@NotNull Class<? extends C> component, Supplier<? extends C> factory) {
var value = components.get(component);
if (value != null) return (C) value;
value = Objects.requireNonNull(factory.get());
components.put(component, value);
return (C) value;
}

/**
* Gets the component of given type.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public ClassifiedMapping<PairedMapping> process(ObjectList<String> content) {
ClassifiedMapping<PairedMapping> mappings = new ClassifiedMapping<>();
Object2ObjectOpenHashMap<String, ClassMapping<PairedMapping>> classes = new Object2ObjectOpenHashMap<>(); // k: unmapped name
content.parallelStream().forEach(s -> {
String[] strings = s.split(" ", 6);
String[] strings = MappingUtil.split(s, ' ');
switch (strings[0]) {
case "CL:" -> {
ClassMapping<PairedMapping> classMapping = new ClassMapping<>(new PairedMapping(strings[1], strings[2]));
Expand Down Expand Up @@ -111,7 +111,7 @@ public ClassifiedMapping<PairedMapping> process(ObjectList<String> content) {
ClassifiedMapping<PairedMapping> mappings = new ClassifiedMapping<>();
Object2ObjectOpenHashMap<String, ClassMapping<PairedMapping>> classes = new Object2ObjectOpenHashMap<>(); // k: unmapped name
content.parallelStream().forEach(s -> {
String[] sa = s.split(" ", 5);
String[] sa = MappingUtil.split(s, ' ');
switch (sa.length) {
case 2 -> { // Class / Package
if (sa[0].charAt(sa[0].length() - 1) == '/') synchronized (mappings.packages) {
Expand Down Expand Up @@ -158,7 +158,7 @@ public MappingFormat<PairedMapping, ClassifiedMapping<PairedMapping>> getFormat(
public ClassifiedMapping<PairedMapping> process(ObjectList<String> content) {
ClassifiedMapping<PairedMapping> mappings = new ClassifiedMapping<>();
for (int i = 0, len = content.size(); i < len;) {
String[] sa = content.get(i).split(" ");
String[] sa = MappingUtil.split(content.get(i), ' ');
if (sa[0].charAt(0) != '\t') {
if (sa[0].charAt(sa[0].length() - 1) == '/') {
mappings.packages.add(new PairedMapping(sa[0].substring(0, sa[0].length() - 1),
Expand All @@ -178,7 +178,7 @@ private static int processTree(int index, int size, ObjectList<String> content,
for (index = index + 1; index < size; index++) {
String s = content.get(index);
if (s.charAt(0) == '\t') {
String[] sa = s.substring(1).split(" ");
String[] sa = MappingUtil.split(s, ' ', 1);
switch (sa.length) {
case 2 -> classMapping.addField(MappingUtil.Paired.o(sa[0], sa[1]));
case 3 -> classMapping.addMethod(MappingUtil.Paired.duo(sa[0], sa[2], sa[1]));
Expand All @@ -203,10 +203,10 @@ public MappingFormat<NamespacedMapping, ClassifiedMapping<NamespacedMapping>> ge
@Override
public ClassifiedMapping<NamespacedMapping> process(ObjectList<String> content) {
if(!content.get(0).startsWith("tsrg2")) error();
String[] namespaces = content.get(0).substring(6).split(" ");
String[] namespaces = MappingUtil.split(content.get(0), ' ', 6);
ClassifiedMapping<NamespacedMapping> mappings = new ClassifiedMapping<>(new NamespacedTrait(namespaces));
for (int i = 1, len = content.size(); i < len; ) {
String[] sa = content.get(i).split(" ");
String[] sa = MappingUtil.split(content.get(i), ' ');
if (sa[0].charAt(0) != '\t') {
if (sa[0].charAt(sa[0].length() - 1) == '/') {
for (int j = 0; j < sa.length; j++) sa[j] = sa[j].substring(0, sa[j].length() - 1);
Expand All @@ -228,7 +228,7 @@ private static int processTree(int index, int size, String[] namespaces, ObjectL
for (index = index + 1; index < size; index++) {
String s = content.get(index);
if (s.charAt(0) == '\t') {
String[] sa = s.substring(1).split(" ");
String[] sa = MappingUtil.split(s, ' ', 1);
switch (sa.length - namespaces.length) {
case 0 -> classMapping.addField(MappingUtil.Namespaced.o(namespaces, sa));
case 1 -> {
Expand Down Expand Up @@ -257,7 +257,7 @@ private static int processTree1(int index, int size, String[] namespaces, Object
if (s.charAt(1) == '\t') {
if (s.equals("\t\tstatic")) methodMapping.getComponent(StaticIdentifiable.class).setStatic(true);
else {
String[] sa = s.substring(2).split(" ");
String[] sa = MappingUtil.split(s, ' ', 2);
methodMapping.getComponent(LocalVariableTable.Namespaced.class)
.setLocalVariable(Integer.parseInt(sa[0]), new NamespacedMapping(namespaces, sa, 1));
}
Expand Down Expand Up @@ -361,12 +361,12 @@ public MappingFormat<NamespacedMapping, ClassifiedMapping<NamespacedMapping>> ge
@Override
public ClassifiedMapping<NamespacedMapping> process(ObjectList<String> content) {// TODO: Support properties
if (!content.get(0).startsWith("v1")) error();
String[] namespaces = content.get(0).substring(3).split("\t");
String[] namespaces = MappingUtil.split(content.get(0), '\t', 3);
ClassifiedMapping<NamespacedMapping> mappings = new ClassifiedMapping<>(new NamespacedTrait(namespaces));
Object2ObjectOpenHashMap<String, ClassMapping<NamespacedMapping>> classes = new Object2ObjectOpenHashMap<>(); // k: the first namespace, usually unmapped name
String k = namespaces[0];
content.parallelStream().skip(1).forEach(s -> {
String[] sa = s.split("\t");
String[] sa = MappingUtil.split(s, '\t');
if (s.startsWith("CLASS")) {
ClassMapping<NamespacedMapping> classMapping = new ClassMapping<>(new NamespacedMapping(namespaces, sa, 1)
.setUnmappedNamespace(k));
Expand Down Expand Up @@ -405,7 +405,7 @@ public MappingFormat<NamespacedMapping, ClassifiedMapping<NamespacedMapping>> ge
@Override
public ClassifiedMapping<NamespacedMapping> process(ObjectList<String> content) {// TODO: Support properties
if (!content.get(0).startsWith("tiny\t2\t0")) error();
String[] namespaces = MappingUtil.split(content.get(0).substring(9), '\t');
String[] namespaces = MappingUtil.split(content.get(0), '\t', 9);
ClassifiedMapping<NamespacedMapping> mappings = new ClassifiedMapping<>(new NamespacedTrait(namespaces));
for (int i = 1, len = content.size(); i < len; ) {
String[] sa = MappingUtil.split(content.get(i), '\t');
Expand All @@ -423,7 +423,7 @@ private static int processTree(int index, int size, String[] namespaces, ObjectL
for (index = index + 1; index < size; index++) {
String s = content.get(index);
if (s.charAt(0) == '\t') {
String[] sa = MappingUtil.split(s.substring(3), '\t');
String[] sa = MappingUtil.split(s, '\t', 3);
switch (s.charAt(1)) {
case 'c' -> classMapping.mapping.getComponent(Documented.class).setContentString(TinyUtil.unescape(sa[0]));
case 'f' -> {
Expand All @@ -449,9 +449,9 @@ private static int processTree1(int index, int size, String[] namespaces, Object
String s = content.get(index);
if (s.charAt(1) == '\t' && s.charAt(0) == '\t') {
switch (s.charAt(2)) {
case 'c' -> mapping.getComponent(Documented.class).setContentString(TinyUtil.unescape(s.substring(4)));
case 'c' -> mapping.getComponent(Documented.class).setContentString(TinyUtil.unescape(s, 4));
case 'p' -> {
String[] sa = MappingUtil.split(s.substring(4), '\t');
String[] sa = MappingUtil.split(s, '\t', 4);
NamespacedMapping localVariable = MappingUtil.Namespaced.d(namespaces, sa, 1);
mapping.getComponent(LocalVariableTable.Namespaced.class)
.setLocalVariable(Integer.parseInt(sa[0]), localVariable);
Expand All @@ -468,7 +468,7 @@ private static int processTree2(int index, int size, ObjectList<String> content,
if (++index < size) {
String s = content.get(index);
if (s.charAt(2) == '\t' && s.charAt(1) == '\t' && s.charAt(0) == '\t') {
if (s.charAt(3) == 'c') localVariable.getComponent(Documented.class).setContentString(TinyUtil.unescape(s.substring(5)));
if (s.charAt(3) == 'c') localVariable.getComponent(Documented.class).setContentString(TinyUtil.unescape(s, 5));
else error();
return index;
}
Expand Down Expand Up @@ -524,11 +524,8 @@ public ClassifiedMapping<PairedMapping> process(ObjectList<String> content) {
PairedMapping local = new PairedMapping(parts[1], parts[2]);
local.addComponent(new Documented(parts[5]));
PairedMapping method = getMethod(parts[3], null, null, classes, methodMap);
LocalVariableTable.Paired lvt = method.getComponent(LocalVariableTable.Paired.class);
if (lvt == null) {// TODO
lvt = new LocalVariableTable.Paired();
method.addComponent(lvt);
}
LocalVariableTable.Paired lvt = method.getOrCreateComponent(LocalVariableTable.Paired.class,
LocalVariableTable.Paired::new);
lvt.setLocalVariable(Integer.parseInt(parts[4]), local);
}
case "Include", "Incluir" -> inheritanceMap.put(parts[1].replace('.', '/'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,19 @@ public static NamespacedMapping dlduo(String[] namespaces, String[] names, int s
}
}

public static String[] split(String s, char c) {// TODO: Do we need an withMapping version?
int n = 2;
int i = s.indexOf(c);
public static String[] split(String s, char c) {
return split(s, c, 0);
}

public static String[] split(String s, char c, int beginIndex) {// TODO: Do we need an withMapping version?
int i = s.indexOf(c, beginIndex);
if (i == -1) return new String[] {s};
int n = 2;
while ((i = s.indexOf(c, i + 1)) != -1) n++;

String[] ret = new String[n];
int start = 0;
for (int j = s.indexOf(c), p = 0; j != -1; j = s.indexOf(c, start)) {
int start = beginIndex;
for (int j = s.indexOf(c, beginIndex), p = 0; j != -1; j = s.indexOf(c, start)) {
ret[p++] = s.substring(start, j);
start = j + 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ public static String escape(String unescaped) {
}

public static String unescape(String escaped) {
return unescape(escaped, 0);
}

public static String unescape(String escaped, int beginIndex) {
StringBuilder sb = new StringBuilder(escaped.length());
int mark = 0;
for (int i = escaped.indexOf('\\'); i >= 0; i = escaped.indexOf('\\', mark)) {
int mark = beginIndex;
for (int i = escaped.indexOf('\\', beginIndex); i >= 0; i = escaped.indexOf('\\', mark)) {
char unescaped = switch (escaped.charAt(++i)) {
case '\\' -> '\\';
case 'n' -> '\n';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* MinecraftDecompiler. A tool/library to deobfuscate and decompile jars.
* Copyright (C) 2019-2024 MaxPixelStudios(XiaoPangxie732)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package cn.maxpixel.mcdecompiler.test.mappings;

import cn.maxpixel.mcdecompiler.mapping.Mapping;
import cn.maxpixel.mcdecompiler.mapping.collection.ClassifiedMapping;
import cn.maxpixel.mcdecompiler.mapping.format.MappingFormat;
import cn.maxpixel.mcdecompiler.mapping.format.MappingFormats;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.CleanupMode;
import org.junit.jupiter.api.io.TempDir;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.assertNotNull;

class MappingProcessorGeneratorTest {
@Test
void testSrg(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1.srg", MappingFormats.SRG);
}

@Test
void testCsrg(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1.csrg", MappingFormats.CSRG);
}

@Test
void testTsrg(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1.tsrg", MappingFormats.TSRG_V1);
}

@Test
void testTsrg2(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1-v2.tsrg", MappingFormats.TSRG_V2);
}

@Test
void testProguard(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1.txt", MappingFormats.PROGUARD);
}

@Test
void testTiny1(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1.tiny", MappingFormats.TINY_V1);
}

@Test
void testTiny2(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1-v2.tiny", MappingFormats.TINY_V2);
}

@Test
void testPDME(@TempDir(cleanup = CleanupMode.ON_SUCCESS) Path tmp) throws IOException {
test(tmp, "1.17.1.pdme", MappingFormats.PDME);
}

private static <M extends Mapping, C extends ClassifiedMapping<M>> void test(Path tmp, String fileName, MappingFormat<M, C> format) throws IOException {
var is = MappingProcessorGeneratorTest.class.getClassLoader().getResourceAsStream(fileName);
assertNotNull(is);
var c1 = format.read(is);
Path path = tmp.resolve(fileName);
try (var os = Files.newOutputStream(path)) {
format.write(c1, os);
}
try (var reader = Files.newBufferedReader(path)) {
var c2 = format.read(reader);
// c1.classes.stream().collect(Collectors.toMap(cm -> cm.mapping.getUnmappedName(), Function.identity()));
// assertEquals(c1, c2);// FIXME: How to assert equals mappings?
}
}
}

This file was deleted.

Loading

0 comments on commit f7c93f1

Please sign in to comment.