Skip to content

Commit f98814a

Browse files
committed
fix(key): Use String#intern in KeyImpl
Used to save on memory usage with the same key objects created, a better option than using a key pool, and should be faster to compute #equals by reference checks for long-lived keys. Also pull out internal property API into properties package to use a shared lib.
1 parent 2f48b6b commit f98814a

File tree

8 files changed

+51
-2
lines changed

8 files changed

+51
-2
lines changed

api/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ dependencies {
1414
api(libs.examination.api)
1515
api(libs.examination.string)
1616
compileOnlyApi(libs.jetbrainsAnnotations)
17+
implementation(projects.adventureProperties)
1718
testImplementation(libs.guava)
1819
annotationProcessor(projects.adventureAnnotationProcessors)
1920
testCompileOnly(libs.autoService.annotations)

key/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dependencies {
1212
api(libs.examination.api)
1313
api(libs.examination.string)
1414
compileOnlyApi(libs.jetbrainsAnnotations)
15+
implementation(projects.adventureProperties)
1516
testImplementation(libs.guava)
1617
}
1718

key/src/main/java/net/kyori/adventure/key/KeyImpl.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Objects;
3030
import java.util.OptionalInt;
3131
import java.util.stream.Stream;
32+
import net.kyori.adventure.internal.properties.AdventureProperties;
3233
import net.kyori.examination.ExaminableProperty;
3334
import org.intellij.lang.annotations.RegExp;
3435
import org.jetbrains.annotations.NotNull;
@@ -41,14 +42,16 @@ final class KeyImpl implements Key {
4142
static final @RegExp String NAMESPACE_PATTERN = "[a-z0-9_\\-.]+";
4243
static final @RegExp String VALUE_PATTERN = "[a-z0-9_\\-./]+";
4344

45+
static final AdventureProperties.KeyInternStrategy INTERN_STRATEGY = AdventureProperties.KEY_INTERN_STRATEGY.value();
46+
4447
private final String namespace;
4548
private final String value;
4649

4750
KeyImpl(final @NotNull String namespace, final @NotNull String value) {
4851
checkError("namespace", namespace, namespace, value, Key.checkNamespace(namespace), NAMESPACE_PATTERN);
4952
checkError("value", value, namespace, value, Key.checkValue(value), VALUE_PATTERN);
50-
this.namespace = requireNonNull(namespace, "namespace");
51-
this.value = requireNonNull(value, "value");
53+
this.namespace = finalizeNamespace(requireNonNull(namespace, "namespace"));
54+
this.value = finalizeValue(requireNonNull(value, "value"));
5255
}
5356

5457
private static void checkError(final String name, final String checkPart, final String namespace, final String value, final OptionalInt index, final String pattern) {
@@ -66,6 +69,20 @@ private static void checkError(final String name, final String checkPart, final
6669
}
6770
}
6871

72+
private static String finalizeNamespace(final @NotNull String namespace) {
73+
if (AdventureProperties.KeyInternStrategy.ALL.equals(INTERN_STRATEGY) || AdventureProperties.KeyInternStrategy.NAMESPACE.equals(INTERN_STRATEGY)) {
74+
return namespace.intern();
75+
}
76+
return namespace;
77+
}
78+
79+
private static String finalizeValue(final @NotNull String value) {
80+
if (AdventureProperties.KeyInternStrategy.ALL.equals(INTERN_STRATEGY)) {
81+
return value.intern();
82+
}
83+
return value;
84+
}
85+
6986
static boolean allowedInNamespace(final char character) {
7087
return character == '_' || character == '-' || (character >= 'a' && character <= 'z') || (character >= '0' && character <= '9') || character == '.';
7188
}

properties/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
plugins {
2+
id("adventure.common-conventions")
3+
}
4+
5+
dependencies {
6+
api(libs.examination.api)
7+
api(libs.examination.string)
8+
}
9+
10+
applyJarMetadata("net.kyori.adventure.internal.properties")

api/src/main/java/net/kyori/adventure/internal/properties/AdventureProperties.java renamed to properties/src/main/java/net/kyori/adventure/internal/properties/AdventureProperties.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ public final class AdventureProperties {
6060
*/
6161
public static final Property<Boolean> TEXT_WARN_WHEN_LEGACY_FORMATTING_DETECTED = property("text.warnWhenLegacyFormattingDetected", Boolean::parseBoolean, Boolean.FALSE);
6262

63+
/**
64+
* Property for specifying what strategy to use for interning strings in keys.
65+
*
66+
* @since 4.22.0
67+
*/
68+
public static final Property<KeyInternStrategy> KEY_INTERN_STRATEGY = property("key.internStrategy", KeyInternStrategy::valueOf, KeyInternStrategy.NAMESPACE);
69+
6370
private AdventureProperties() {
6471
}
6572

@@ -94,4 +101,16 @@ public interface Property<T> {
94101
*/
95102
@Nullable T value();
96103
}
104+
105+
/**
106+
* The strategy to use for interning strings in keys.
107+
*
108+
* @since 4.22.0
109+
*/
110+
@ApiStatus.Internal
111+
public enum KeyInternStrategy {
112+
NONE,
113+
NAMESPACE,
114+
ALL
115+
}
97116
}

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ sequenceOf(
3737
"extra-kotlin",
3838
"key",
3939
"nbt",
40+
"properties",
4041
"serializer-configurate4",
4142
"text-logger-slf4j",
4243
"text-minimessage",

0 commit comments

Comments
 (0)