From fe15e4ed7a868ec8a2cf93fa2e676e5b836afb7b Mon Sep 17 00:00:00 2001 From: ichocomilk Date: Wed, 4 Feb 2026 19:49:54 -0300 Subject: [PATCH] Update Gradle dependencies and add benchmarks --- build.gradle.kts | 14 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../java/me/clip/placeholderapi/Values.java | 94 ++++++++++++ .../replacer/OldCharsReplacer.java | 136 ++++++++++++++++++ .../replacer/ReplacerBenchmarks.java | 66 +++++++++ .../replacer/ReplacerBenchmarks.java | 38 ----- 6 files changed, 305 insertions(+), 45 deletions(-) create mode 100644 src/jmh/java/me/clip/placeholderapi/Values.java create mode 100644 src/jmh/java/me/clip/placeholderapi/replacer/OldCharsReplacer.java create mode 100644 src/jmh/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java delete mode 100644 src/test/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java diff --git a/build.gradle.kts b/build.gradle.kts index c5cf45b..311eb54 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,8 @@ plugins { `java-library` `maven-publish` // id("com.github.hierynomus.license") version "0.16.1" - id("io.github.goooler.shadow") version "8.1.7" + id("com.gradleup.shadow") version "9.3.1" + id("me.champeau.jmh") version "0.7.2" } group = "me.clip" @@ -41,12 +42,13 @@ dependencies { compileOnly("dev.folia:folia-api:1.21.11-R0.1-SNAPSHOT") compileOnlyApi("org.jetbrains:annotations:23.0.0") - testImplementation("org.openjdk.jmh:jmh-core:1.32") - testImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.32") - testImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.2") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1") -} + jmh("org.openjdk.jmh:jmh-core:1.37") + jmh("org.openjdk.jmh:jmh-generator-annprocess:1.37") + jmhAnnotationProcessor("org.openjdk.jmh:jmh-generator-annprocess:1.37") + testImplementation("org.junit.jupiter:junit-jupiter:6.0.2") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} java { sourceCompatibility = JavaVersion.VERSION_1_8 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2617362..aa28adb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/jmh/java/me/clip/placeholderapi/Values.java b/src/jmh/java/me/clip/placeholderapi/Values.java new file mode 100644 index 0000000..ff06e7d --- /dev/null +++ b/src/jmh/java/me/clip/placeholderapi/Values.java @@ -0,0 +1,94 @@ +/* + * This file is part of PlaceholderAPI + * + * PlaceholderAPI + * Copyright (c) 2015 - 2026 PlaceholderAPI Team + * + * PlaceholderAPI free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlaceholderAPI 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.clip.placeholderapi; + +import com.google.common.collect.ImmutableMap; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import me.clip.placeholderapi.replacer.CharsReplacer; +import me.clip.placeholderapi.replacer.OldCharsReplacer; +import me.clip.placeholderapi.replacer.Replacer; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface Values { + + String SMALL_TEXT = "My name is %player_name%"; + String LARGE_TEXT = "My name is %player_name% and my location is (%player_x%, %player_y%, %player_z%), this placeholder is invalid %server_name%"; + + ImmutableMap PLACEHOLDERS = ImmutableMap.builder() + .put("player", new MockPlayerPlaceholderExpansion()) + .build(); + + + Replacer CHARS_REPLACER = new CharsReplacer(Replacer.Closure.PERCENT); + Replacer OLD_CHARS_REPLACER = new OldCharsReplacer(Replacer.Closure.PERCENT); + + final class MockPlayerPlaceholderExpansion extends PlaceholderExpansion { + + public static final String PLAYER_X = "10"; + public static final String PLAYER_Y = "20"; + public static final String PLAYER_Z = "30"; + public static final String PLAYER_NAME = "Sxtanna"; + + + @NotNull + @Override + public String getIdentifier() { + return "player"; + } + + @NotNull + @Override + public String getAuthor() { + return "Sxtanna"; + } + + @NotNull + @Override + public String getVersion() { + return "1.0"; + } + + @Override + public String onRequest(@Nullable final OfflinePlayer player, @NotNull final String params) { + final String[] parts = params.split("_"); + if (parts.length == 0) { + return null; + } + + switch (parts[0]) { + case "name": + return PLAYER_NAME; + case "x": + return PLAYER_X; + case "y": + return PLAYER_Y; + case "z": + return PLAYER_Z; + } + + return null; + } + + } + +} diff --git a/src/jmh/java/me/clip/placeholderapi/replacer/OldCharsReplacer.java b/src/jmh/java/me/clip/placeholderapi/replacer/OldCharsReplacer.java new file mode 100644 index 0000000..2941f21 --- /dev/null +++ b/src/jmh/java/me/clip/placeholderapi/replacer/OldCharsReplacer.java @@ -0,0 +1,136 @@ +package me.clip.placeholderapi.replacer; + +/* + * This file is part of PlaceholderAPI + * + * PlaceholderAPI + * Copyright (c) 2015 - 2026 PlaceholderAPI Team + * + * PlaceholderAPI free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlaceholderAPI 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import java.util.Locale; +import java.util.function.Function; + +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class OldCharsReplacer implements Replacer { + + @NotNull + private final Closure closure; + + public OldCharsReplacer(@NotNull final Closure closure) { + this.closure = closure; + } + + @NotNull + @Override + public String apply(@NotNull final String text, @Nullable final OfflinePlayer player, + @NotNull final Function lookup) { + final char[] chars = text.toCharArray(); + final StringBuilder builder = new StringBuilder(text.length()); + + final StringBuilder identifier = new StringBuilder(); + final StringBuilder parameters = new StringBuilder(); + + for (int i = 0; i < chars.length; i++) { + final char l = chars[i]; + + if (l != closure.head || i + 1 >= chars.length) { + builder.append(l); + continue; + } + + boolean identified = false; + boolean invalid = true; + boolean hadSpace = false; + + while (++i < chars.length) { + final char p = chars[i]; + + if (p == ' ' && !identified) { + hadSpace = true; + break; + } + if (p == closure.tail) { + invalid = false; + break; + } + + if (p == '_' && !identified) { + identified = true; + continue; + } + + if (identified) { + parameters.append(p); + } else { + identifier.append(p); + } + } + + final String identifierString = identifier.toString(); + final String lowercaseIdentifierString = identifierString.toLowerCase(Locale.ROOT); + final String parametersString = parameters.toString(); + + identifier.setLength(0); + parameters.setLength(0); + + if (invalid) { + builder.append(closure.head).append(identifierString); + + if (identified) { + builder.append('_').append(parametersString); + } + + if (hadSpace) { + builder.append(' '); + } + continue; + } + + final PlaceholderExpansion placeholder = lookup.apply(lowercaseIdentifierString); + if (placeholder == null) { + builder.append(closure.head).append(identifierString); + + if (identified) { + builder.append('_'); + } + + builder.append(parametersString).append(closure.tail); + continue; + } + + final String replacement = placeholder.onRequest(player, parametersString); + if (replacement == null) { + builder.append(closure.head).append(identifierString); + + if (identified) { + builder.append('_'); + } + + builder.append(parametersString).append(closure.tail); + continue; + } + + builder.append(replacement); + } + + return builder.toString(); + } + +} \ No newline at end of file diff --git a/src/jmh/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java b/src/jmh/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java new file mode 100644 index 0000000..7469f64 --- /dev/null +++ b/src/jmh/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java @@ -0,0 +1,66 @@ +/* + * This file is part of PlaceholderAPI + * + * PlaceholderAPI + * Copyright (c) 2015 - 2026 PlaceholderAPI Team + * + * PlaceholderAPI free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PlaceholderAPI 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package me.clip.placeholderapi.replacer; + +import me.clip.placeholderapi.Values; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.jetbrains.annotations.Nullable; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@BenchmarkMode({Mode.AverageTime, Mode.Throughput}) +@Fork(value = 3, warmups = 1) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 10, time = 1) +public class ReplacerBenchmarks { + + private Function expansionFunction; + + @Setup + public void setup() { + this.expansionFunction = Values.PLACEHOLDERS::get; + } + + @Benchmark + public void measureCharsReplacerSmallText(final Blackhole blackhole) { + blackhole.consume(Values.CHARS_REPLACER.apply(Values.SMALL_TEXT, null, expansionFunction)); + } + + @Benchmark + public void measureCharsReplacerLargeText(final Blackhole blackhole) { + blackhole.consume(Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, expansionFunction)); + } + + @Benchmark + public void measureCharsReplacerSmallTextOld(final Blackhole blackhole) { + blackhole.consume(Values.OLD_CHARS_REPLACER.apply(Values.SMALL_TEXT, null, expansionFunction)); + } + + @Benchmark + public void measureCharsReplacerLargeTextOld(final Blackhole blackhole) { + blackhole.consume(Values.OLD_CHARS_REPLACER.apply(Values.LARGE_TEXT, null, expansionFunction)); + } +} \ No newline at end of file diff --git a/src/test/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java b/src/test/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java deleted file mode 100644 index 1283299..0000000 --- a/src/test/java/me/clip/placeholderapi/replacer/ReplacerBenchmarks.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of PlaceholderAPI - * - * PlaceholderAPI - * Copyright (c) 2015 - 2026 PlaceholderAPI Team - * - * PlaceholderAPI free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PlaceholderAPI 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package me.clip.placeholderapi.replacer; - -import me.clip.placeholderapi.Values; -import org.openjdk.jmh.annotations.Benchmark; - -public class ReplacerBenchmarks { - - @Benchmark - public void measureCharsReplacerSmallText() { - Values.CHARS_REPLACER.apply(Values.SMALL_TEXT, null, Values.PLACEHOLDERS::get); - } - - @Benchmark - public void measureCharsReplacerLargeText() { - Values.CHARS_REPLACER.apply(Values.LARGE_TEXT, null, Values.PLACEHOLDERS::get); - } - -} \ No newline at end of file