From 409b71250e4ec6b89dd041ab32d7e492d7bf30e7 Mon Sep 17 00:00:00 2001 From: Riley Park Date: Tue, 15 Dec 2020 13:30:23 -0800 Subject: [PATCH] nbt: ListBinaryTag from(Iterable) and add(Iterable) --- .../kyori/adventure/nbt/ListBinaryTag.java | 21 +++++-- .../adventure/nbt/ListBinaryTagImpl.java | 61 +++++++++++++------ .../kyori/adventure/nbt/ListTagBuilder.java | 20 ++++-- .../kyori/adventure/nbt/ListTagSetter.java | 9 +++ 4 files changed, 83 insertions(+), 28 deletions(-) diff --git a/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTag.java b/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTag.java index 5352db9d6..491f3a7c6 100644 --- a/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTag.java +++ b/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTag.java @@ -46,6 +46,19 @@ public interface ListBinaryTag extends ListTagSetter, return ListBinaryTagImpl.EMPTY; } + /** + * Creates a list tag from {@code tags}. + * + *

The {@link #elementType() element type} of the returned list tag is determined from {@code tags}.

+ * + * @return a list tag + * @throws IllegalArgumentException if {@code tags} has different tag types within + * @since 4.4.0 + */ + static @NonNull ListBinaryTag from(final @NonNull Iterable tags) { + return builder().add(tags).build(); + } + /** * Creates a builder. * @@ -130,21 +143,21 @@ public interface ListBinaryTag extends ListTagSetter, * * @param index the index * @param tag the tag - * @param removedConsumer a consumer which receives the tag being removed at index {@code index} + * @param removed a consumer which receives the tag being removed at index {@code index} * @return a list tag * @since 4.0.0 */ - @NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag tag, final @Nullable Consumer removedConsumer); + @NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag tag, final @Nullable Consumer removed); /** * Removes the tag at index {@code index}, optionally providing {@code removedConsumer} with the tag previously at index {@code index}. * * @param index the index - * @param removedConsumer a consumer which receives the tag being removed at index {@code index} + * @param removed a consumer which receives the tag being removed at index {@code index} * @return a list tag * @since 4.0.0 */ - @NonNull ListBinaryTag remove(final int index, final @Nullable Consumer removedConsumer); + @NonNull ListBinaryTag remove(final int index, final @Nullable Consumer removed); /** * Gets a byte. diff --git a/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTagImpl.java b/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTagImpl.java index dd5a5349d..4fe3b9ce6 100644 --- a/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTagImpl.java +++ b/nbt/src/main/java/net/kyori/adventure/nbt/ListBinaryTagImpl.java @@ -24,6 +24,7 @@ package net.kyori.adventure.nbt; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -43,7 +44,7 @@ final class ListBinaryTagImpl extends AbstractBinaryTag implements ListBinaryTag private final int hashCode; ListBinaryTagImpl(final BinaryTagType elementType, final List tags) { - this.tags = tags; + this.tags = Collections.unmodifiableList(tags); this.elementType = elementType; this.hashCode = tags.hashCode(); } @@ -64,34 +65,45 @@ public int size() { } @Override - public @NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag newTag, final @Nullable Consumer removedConsumer) { + public @NonNull ListBinaryTag set(final int index, final @NonNull BinaryTag newTag, final @Nullable Consumer removed) { return this.edit(tags -> { final BinaryTag oldTag = tags.set(index, newTag); - if(removedConsumer != null) { - removedConsumer.accept(oldTag); + if(removed != null) { + removed.accept(oldTag); } }, newTag.type()); } @Override - public @NonNull ListBinaryTag remove(final int index, final @Nullable Consumer removedConsumer) { + public @NonNull ListBinaryTag remove(final int index, final @Nullable Consumer removed) { return this.edit(tags -> { - final BinaryTag tag = tags.remove(index); - if(removedConsumer != null) { - removedConsumer.accept(tag); + final BinaryTag oldTag = tags.remove(index); + if(removed != null) { + removed.accept(oldTag); } }, null); } @Override public @NonNull ListBinaryTag add(final BinaryTag tag) { + noAddEnd(tag); + if(this.elementType != BinaryTagTypes.END) { + mustBeSameType(tag, this.elementType); + } + return this.edit(tags -> tags.add(tag), tag.type()); + } + + @Override + public @NonNull ListBinaryTag add(final Iterable tagsToAdd) { + if(tagsToAdd instanceof Collection && ((Collection) tagsToAdd).isEmpty()) { + return this; + } + final BinaryTagType type = ListBinaryTagImpl.mustBeSameType(tagsToAdd); return this.edit(tags -> { - noAddEnd(tag); - if(this.elementType != BinaryTagTypes.END) { - mustBeSameType(tag, this.elementType); + for(final BinaryTag tag : tagsToAdd) { + tags.add(tag); } - tags.add(tag); - }, tag.type()); + }, type); } // An end tag cannot be an element in a list tag @@ -101,6 +113,19 @@ static void noAddEnd(final BinaryTag tag) { } } + // Cannot have different element types in a list tag + static BinaryTagType mustBeSameType(final Iterable tags) { + BinaryTagType type = null; + for(final BinaryTag tag : tags) { + if(type == null) { + type = tag.type(); + } else { + mustBeSameType(tag, type); + } + } + return type; + } + // Cannot have different element types in a list tag static void mustBeSameType(final BinaryTag tag, final BinaryTagType type) { if(tag.type() != type) { @@ -108,15 +133,15 @@ static void mustBeSameType(final BinaryTag tag, final BinaryTagType> consumer, final @Nullable BinaryTagType maybeType) { + private ListBinaryTag edit(final Consumer> consumer, final @Nullable BinaryTagType maybeElementType) { final List tags = new ArrayList<>(this.tags); consumer.accept(tags); - BinaryTagType type = this.elementType; + BinaryTagType elementType = this.elementType; // set the type if it has not yet been set - if(maybeType != null && type == BinaryTagTypes.END) { - type = maybeType; + if(maybeElementType != null && elementType == BinaryTagTypes.END) { + elementType = maybeElementType; } - return new ListBinaryTagImpl(type, tags); + return new ListBinaryTagImpl(elementType, tags); } @Override diff --git a/nbt/src/main/java/net/kyori/adventure/nbt/ListTagBuilder.java b/nbt/src/main/java/net/kyori/adventure/nbt/ListTagBuilder.java index 3644f4b35..ec3ce71c3 100644 --- a/nbt/src/main/java/net/kyori/adventure/nbt/ListTagBuilder.java +++ b/nbt/src/main/java/net/kyori/adventure/nbt/ListTagBuilder.java @@ -30,25 +30,25 @@ final class ListTagBuilder implements ListBinaryTag.Builder { private @MonotonicNonNull List tags; - private BinaryTagType type; + private BinaryTagType elementType; ListTagBuilder() { this(BinaryTagTypes.END); } ListTagBuilder(final BinaryTagType type) { - this.type = type; + this.elementType = type; } @Override public ListBinaryTag.@NonNull Builder add(final BinaryTag tag) { ListBinaryTagImpl.noAddEnd(tag); // set the type if it has not yet been set - if(this.type == BinaryTagTypes.END) { - this.type = tag.type(); + if(this.elementType == BinaryTagTypes.END) { + this.elementType = tag.type(); } // check after changing from an empty tag - ListBinaryTagImpl.mustBeSameType(tag, this.type); + ListBinaryTagImpl.mustBeSameType(tag, this.elementType); if(this.tags == null) { this.tags = new ArrayList<>(); } @@ -56,9 +56,17 @@ final class ListTagBuilder implements ListBinaryTag.Builder return this; } + @Override + public ListBinaryTag.@NonNull Builder add(final Iterable tagsToAdd) { + for(final T tag : tagsToAdd) { + this.add(tag); + } + return this; + } + @Override public @NonNull ListBinaryTag build() { if(this.tags == null) return ListBinaryTag.empty(); - return new ListBinaryTagImpl(this.type, new ArrayList<>(this.tags)); + return new ListBinaryTagImpl(this.elementType, new ArrayList<>(this.tags)); } } diff --git a/nbt/src/main/java/net/kyori/adventure/nbt/ListTagSetter.java b/nbt/src/main/java/net/kyori/adventure/nbt/ListTagSetter.java index 79847f652..758c22a99 100644 --- a/nbt/src/main/java/net/kyori/adventure/nbt/ListTagSetter.java +++ b/nbt/src/main/java/net/kyori/adventure/nbt/ListTagSetter.java @@ -41,4 +41,13 @@ public interface ListTagSetter { * @since 4.0.0 */ @NonNull R add(final T tag); + + /** + * Adds multiple tags. + * + * @param tags the tags + * @return a list tag + * @since 4.4.0 + */ + @NonNull R add(final Iterable tags); }