From cb01b08b04f84455c0b0b9de7bd35ab4aeebf9b5 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 7 May 2022 16:26:39 +0200 Subject: [PATCH] Add experimental tag update methods Signed-off-by: TheMode --- .../minestom/server/tag/TagUpdateTest.java | 38 +++++++++++++ .../net/minestom/server/tag/TagHandler.java | 15 +++++ .../minestom/server/tag/TagHandlerImpl.java | 19 +++++++ .../minestom/server/tag/TagAtomicTest.java | 57 +++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 jcstress-tests/src/jcstress/java/net/minestom/server/tag/TagUpdateTest.java create mode 100644 src/test/java/net/minestom/server/tag/TagAtomicTest.java diff --git a/jcstress-tests/src/jcstress/java/net/minestom/server/tag/TagUpdateTest.java b/jcstress-tests/src/jcstress/java/net/minestom/server/tag/TagUpdateTest.java new file mode 100644 index 000000000..d2b77c56e --- /dev/null +++ b/jcstress-tests/src/jcstress/java/net/minestom/server/tag/TagUpdateTest.java @@ -0,0 +1,38 @@ +package net.minestom.server.tag; + +import org.openjdk.jcstress.annotations.Actor; +import org.openjdk.jcstress.annotations.JCStressTest; +import org.openjdk.jcstress.annotations.Outcome; +import org.openjdk.jcstress.annotations.State; +import org.openjdk.jcstress.infra.results.L_Result; + +import static org.openjdk.jcstress.annotations.Expect.ACCEPTABLE; + +@JCStressTest +@Outcome(id = "null", expect = ACCEPTABLE) +@Outcome(id = "3", expect = ACCEPTABLE) +@Outcome(id = "4", expect = ACCEPTABLE) +@Outcome(id = "10", expect = ACCEPTABLE) +@Outcome(id = "11", expect = ACCEPTABLE) +@State +public class TagUpdateTest { + private static final Tag TAG = Tag.Integer("key"); + + private final TagHandler handler = TagHandler.newHandler(); + + @Actor + public void actor1() { + handler.updateAndGetTag(TAG, integer -> integer == null ? 3 : integer + 1); + } + + @Actor + public void actor2() { + handler.updateAndGetTag(TAG, integer -> integer == null ? 10 : integer + 1); + } + + @Actor + public void arbiter(L_Result r) { + r.r1 = handler.getTag(TAG); + } +} + diff --git a/src/main/java/net/minestom/server/tag/TagHandler.java b/src/main/java/net/minestom/server/tag/TagHandler.java index 436026da8..ded8d4487 100644 --- a/src/main/java/net/minestom/server/tag/TagHandler.java +++ b/src/main/java/net/minestom/server/tag/TagHandler.java @@ -2,9 +2,12 @@ package net.minestom.server.tag; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.UnknownNullability; import org.jglrxavpok.hephaistos.nbt.NBTCompound; import org.jglrxavpok.hephaistos.nbt.NBTCompoundLike; +import java.util.function.UnaryOperator; + /** * Represents an element which can read and write {@link Tag tags}. */ @@ -46,6 +49,18 @@ public interface TagHandler extends TagReadable, TagWritable { */ @NotNull NBTCompound asCompound(); + @ApiStatus.Experimental + void updateTag(@NotNull Tag tag, + @NotNull UnaryOperator<@UnknownNullability T> value); + + @ApiStatus.Experimental + @UnknownNullability T updateAndGetTag(@NotNull Tag tag, + @NotNull UnaryOperator<@UnknownNullability T> value); + + @ApiStatus.Experimental + @UnknownNullability T getAndUpdateTag(@NotNull Tag tag, + @NotNull UnaryOperator<@UnknownNullability T> value); + @ApiStatus.Experimental static @NotNull TagHandler newHandler() { return new TagHandlerImpl(); diff --git a/src/main/java/net/minestom/server/tag/TagHandlerImpl.java b/src/main/java/net/minestom/server/tag/TagHandlerImpl.java index 273887df2..b4639c323 100644 --- a/src/main/java/net/minestom/server/tag/TagHandlerImpl.java +++ b/src/main/java/net/minestom/server/tag/TagHandlerImpl.java @@ -104,6 +104,25 @@ final class TagHandlerImpl implements TagHandler { } } + @Override + public synchronized void updateTag(@NotNull Tag tag, @NotNull UnaryOperator<@UnknownNullability T> value) { + setTag(tag, value.apply(getTag(tag))); + } + + @Override + public synchronized @UnknownNullability T updateAndGetTag(@NotNull Tag tag, @NotNull UnaryOperator<@UnknownNullability T> value) { + final T next = value.apply(getTag(tag)); + setTag(tag, next); + return next; + } + + @Override + public synchronized @UnknownNullability T getAndUpdateTag(@NotNull Tag tag, @NotNull UnaryOperator<@UnknownNullability T> value) { + final T prev = getTag(tag); + setTag(tag, value.apply(prev)); + return prev; + } + @Override public @NotNull TagReadable readableCopy() { return updatedCache(); diff --git a/src/test/java/net/minestom/server/tag/TagAtomicTest.java b/src/test/java/net/minestom/server/tag/TagAtomicTest.java new file mode 100644 index 000000000..dea05b232 --- /dev/null +++ b/src/test/java/net/minestom/server/tag/TagAtomicTest.java @@ -0,0 +1,57 @@ +package net.minestom.server.tag; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class TagAtomicTest { + + @Test + public void update() { + var tag = Tag.Integer("coin"); + var handler = TagHandler.newHandler(); + handler.updateTag(tag, integer -> { + assertNull(integer); + return 5; + }); + assertEquals(5, handler.getTag(tag)); + handler.updateTag(tag, integer -> { + assertEquals(5, integer); + return 10; + }); + assertEquals(10, handler.getTag(tag)); + } + + @Test + public void updateAndGet() { + var tag = Tag.Integer("coin"); + var handler = TagHandler.newHandler(); + var result = handler.updateAndGetTag(tag, integer -> { + assertNull(integer); + return 5; + }); + assertEquals(5, result); + result = handler.updateAndGetTag(tag, integer -> { + assertEquals(5, integer); + return 10; + }); + assertEquals(10, result); + } + + @Test + public void getAndUpdate() { + var tag = Tag.Integer("coin"); + var handler = TagHandler.newHandler(); + var result = handler.getAndUpdateTag(tag, integer -> { + assertNull(integer); + return 5; + }); + assertNull(result); + result = handler.getAndUpdateTag(tag, integer -> { + assertEquals(5, integer); + return 10; + }); + assertEquals(5, result); + } +}