diff --git a/jmh-benchmarks/src/jmh/java/net/minestom/jmh/tag/TagReadPathBenchmark.java b/jmh-benchmarks/src/jmh/java/net/minestom/jmh/tag/TagReadPathBenchmark.java new file mode 100644 index 000000000..dbbe220c9 --- /dev/null +++ b/jmh-benchmarks/src/jmh/java/net/minestom/jmh/tag/TagReadPathBenchmark.java @@ -0,0 +1,40 @@ +package net.minestom.jmh.tag; + +import net.minestom.server.tag.Tag; +import net.minestom.server.tag.TagHandler; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS) +@Fork(3) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +public class TagReadPathBenchmark { + @Param({"0", "1", "2", "3"}) + public int scope; + + TagHandler tagHandler; + Tag tag; + + @Setup + public void setup() { + this.tagHandler = TagHandler.newHandler(); + + List path = new ArrayList<>(scope); + for (int i = 0; i < scope; i++) path.add("key" + i); + this.tag = Tag.String("key").path(path.toArray(String[]::new)); + + tagHandler.setTag(tag, "value"); + } + + @Benchmark + public void read(Blackhole blackhole) { + blackhole.consume(tagHandler.getTag(tag)); + } +} diff --git a/src/main/java/net/minestom/server/tag/Tag.java b/src/main/java/net/minestom/server/tag/Tag.java index 340e15b49..b7bbd4103 100644 --- a/src/main/java/net/minestom/server/tag/Tag.java +++ b/src/main/java/net/minestom/server/tag/Tag.java @@ -9,7 +9,6 @@ import org.jetbrains.annotations.Nullable; import org.jglrxavpok.hephaistos.nbt.*; import org.jglrxavpok.hephaistos.nbt.mutable.MutableNBTCompound; -import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.function.Supplier; @@ -37,14 +36,14 @@ public class Tag { final Function originalRead; // Optional properties - final List path; + final PathEntry[] path; final UnaryOperator copy; final int listScope; Tag(int index, String key, Function originalRead, Function readFunction, Function writeFunction, - Supplier defaultValue, List path, UnaryOperator copy, int listScope) { + Supplier defaultValue, PathEntry[] path, UnaryOperator copy, int listScope) { assert index == INDEX_MAP.get(key); this.index = index; this.key = key; @@ -150,7 +149,15 @@ public class Tag { @ApiStatus.Experimental @Contract(value = "_ -> new", pure = true) public Tag path(@NotNull String @Nullable ... path) { - final List entries = path != null ? Arrays.stream(path).map(s -> new PathEntry(s, INDEX_MAP.get(s))).toList() : null; + if (path == null || path.length == 0) { + return new Tag<>(index, key, originalRead, + readFunction, writeFunction, defaultValue, null, copy, listScope); + } + PathEntry[] entries = new PathEntry[path.length]; + for (int i = 0; i < path.length; i++) { + var name = path[i]; + entries[i] = new PathEntry(name, INDEX_MAP.get(name)); + } return new Tag<>(index, key, originalRead, readFunction, writeFunction, defaultValue, entries, copy, listScope); } diff --git a/src/main/java/net/minestom/server/tag/TagHandlerImpl.java b/src/main/java/net/minestom/server/tag/TagHandlerImpl.java index c8f0c0d66..4d8dd51c4 100644 --- a/src/main/java/net/minestom/server/tag/TagHandlerImpl.java +++ b/src/main/java/net/minestom/server/tag/TagHandlerImpl.java @@ -38,7 +38,7 @@ final class TagHandlerImpl implements TagHandler { final var paths = tag.path; TagHandlerImpl[] pathHandlers = null; if (paths != null) { - pathHandlers = new TagHandlerImpl[paths.size()]; + pathHandlers = new TagHandlerImpl[paths.length]; int in = 0; for (var path : paths) { final int pathIndex = path.index(); @@ -70,14 +70,14 @@ final class TagHandlerImpl implements TagHandler { empty = tagIndex >= entr.length || ArrayUtils.isEmpty(entr); if (empty && i > 0) { TagHandlerImpl parent = pathHandlers[i - 1]; - parent.entries[paths.get(i).index()] = null; + parent.entries[paths[i].index()] = null; } } if (empty) { // Remove the root handler local = this; entries = localEntries; - tagIndex = paths.get(0).index(); + tagIndex = paths[0].index(); } } } @@ -182,9 +182,9 @@ final class TagHandlerImpl implements TagHandler { private static T read(Entry[] entries, Tag tag) { final int index = tag.index; Entry entry; - if (tag.path != null) { + final var paths = tag.path; + if (paths != null) { // Must be a path-able entry - var paths = tag.path; for (var path : paths) { final int pathIndex = path.index(); if (pathIndex >= entries.length || (entry = entries[pathIndex]) == null) {