Improve tag value sharing

This commit is contained in:
themode 2022-03-25 17:48:18 +01:00
parent edabb19891
commit 8dcb3191f6
2 changed files with 67 additions and 14 deletions

View File

@ -35,29 +35,34 @@ public class Tag<T> {
final Function<T, NBT> writeFunction;
private final Supplier<T> defaultValue;
final Function<?, ?> originalRead;
// Optional properties
final List<PathEntry> path;
final UnaryOperator<T> copy;
final int listScope;
Tag(int index, String key,
Function<NBT, T> readFunction,
Function<T, NBT> writeFunction,
@Nullable Supplier<T> defaultValue, @Nullable List<PathEntry> path,
@Nullable UnaryOperator<T> copy) {
Function<?, ?> originalRead,
Function<NBT, T> readFunction, Function<T, NBT> writeFunction,
Supplier<T> defaultValue, List<PathEntry> path, UnaryOperator<T> copy, int listScope) {
assert index == INDEX_MAP.get(key);
this.index = index;
this.key = key;
this.originalRead = originalRead;
this.readFunction = readFunction;
this.writeFunction = writeFunction;
this.defaultValue = defaultValue;
this.path = path;
this.copy = copy;
this.listScope = listScope;
}
static <T, N extends NBT> Tag<T> tag(@NotNull String key,
@NotNull Function<N, T> readFunction,
@NotNull Function<T, N> writeFunction) {
return new Tag<>(INDEX_MAP.get(key), key, (Function<NBT, T>) readFunction, (Function<T, NBT>) writeFunction,
null, null, null);
return new Tag<>(INDEX_MAP.get(key), key, readFunction,
(Function<NBT, T>) readFunction, (Function<T, NBT>) writeFunction,
null, null, null, 0);
}
/**
@ -71,7 +76,7 @@ public class Tag<T> {
@Contract(value = "_ -> new", pure = true)
public Tag<T> defaultValue(@NotNull Supplier<T> defaultValue) {
return new Tag<>(index, key, readFunction, writeFunction, defaultValue, path, copy);
return new Tag<>(index, key, originalRead, readFunction, writeFunction, defaultValue, path, copy, listScope);
}
@Contract(value = "_ -> new", pure = true)
@ -83,6 +88,7 @@ public class Tag<T> {
public <R> Tag<R> map(@NotNull Function<T, R> readMap,
@NotNull Function<R, T> writeMap) {
return new Tag<>(index, key,
readMap,
// Read
readFunction.andThen(t -> {
if (t == null) return null;
@ -92,13 +98,13 @@ public class Tag<T> {
writeMap.andThen(writeFunction),
// Default value
() -> readMap.apply(createDefault()),
path, null);
path, null, listScope);
}
@ApiStatus.Experimental
@Contract(value = "-> new", pure = true)
public Tag<List<T>> list() {
return new Tag<>(index, key,
return new Tag<>(index, key, originalRead,
read -> {
var list = (NBTList<?>) read;
final int size = list.getSize();
@ -138,14 +144,15 @@ public class Tag<T> {
array[i] = copy;
}
return shallowCopy ? List.copyOf(ts) : List.of(array);
} : List::copyOf);
} : List::copyOf, listScope + 1);
}
@ApiStatus.Experimental
@Contract(value = "_ -> new", pure = true)
public Tag<T> path(@NotNull String @Nullable ... path) {
final List<PathEntry> entries = path != null ? Arrays.stream(path).map(s -> new PathEntry(s, INDEX_MAP.get(s))).toList() : null;
return new Tag<>(index, key, readFunction, writeFunction, defaultValue, entries, copy);
return new Tag<>(index, key, originalRead,
readFunction, writeFunction, defaultValue, entries, copy, listScope);
}
public @Nullable T read(@NotNull NBTCompoundLike nbt) {
@ -186,7 +193,7 @@ public class Tag<T> {
final boolean shareValue(@NotNull Tag<?> other) {
// Verify if these 2 tags can share the same cached value
// Key/Default value/Path are ignored
return this == other || this.readFunction == other.readFunction;
return this == other || (this.originalRead == other.originalRead && this.listScope == other.listScope);
}
public static @NotNull Tag<Byte> Byte(@NotNull String key) {

View File

@ -2,6 +2,8 @@ package net.minestom.server.tag;
import org.junit.jupiter.api.Test;
import java.util.function.Function;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -10,6 +12,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
*/
public class TagEqualityTest {
record Entry(int value) {
}
@Test
public void same() {
var tag = Tag.String("test");
@ -37,17 +42,58 @@ public class TagEqualityTest {
assertFalse(tag.shareValue(tag2));
}
@Test
public void mapSame() {
// Force identical functions
Function<Integer, Entry> t1 = Entry::new;
Function<Entry, Integer> t2 = Entry::value;
var tag = Tag.Integer("key");
var map1 = tag.map(t1, t2);
var map2 = tag.map(t1, t2);
assertTrue(map1.shareValue(map2));
}
@Test
public void mapChild() {
var intTag = Tag.Integer("key");
var tag = intTag.map(Entry::new, Entry::value);
assertFalse(intTag.shareValue(tag));
}
@Test
public void list() {
var tag = Tag.String("test").list();
assertTrue(tag.shareValue(tag));
}
//@Test
@Test
public void listScope() {
var tag = Tag.String("test");
assertFalse(tag.shareValue(tag.list()));
}
@Test
public void similarList() {
// TODO make work
var tag = Tag.String("test").list();
var tag2 = Tag.String("test").list();
assertTrue(tag.shareValue(tag2));
assertTrue(tag.list().shareValue(tag2.list()));
}
@Test
public void differentList() {
var tag = Tag.String("test").list();
var tag2 = Tag.String("test").list();
assertFalse(tag.shareValue(tag2.list()));
assertFalse(tag.list().shareValue(tag2.list().list()));
}
@Test
public void differentListType() {
var tag = Tag.String("test").list();
var tag2 = Tag.Integer("test").list();
assertFalse(tag.shareValue(tag2));
assertFalse(tag.list().shareValue(tag2.list()));
}
}