From 71c39a25b94ff21138f763f0eaa778c08d06d0a4 Mon Sep 17 00:00:00 2001 From: BradBot_1 Date: Tue, 11 Jul 2023 22:36:53 +0100 Subject: [PATCH 1/6] Make StructureModifier Iterable --- .../protocol/reflect/StructureModifier.java | 12 +++- .../reflect/StructureModifierIterator.java | 56 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java index 7b2881d08..099c325c3 100644 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java @@ -26,6 +26,8 @@ import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; +import java.lang.Iterable; +import java.util.Iterator; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.reflect.Field; @@ -51,7 +53,7 @@ * @param Type of the fields to retrieve. * @author Kristian */ -public class StructureModifier { +public class StructureModifier implements Iterable { // Instance generator we will use private static final DefaultInstances DEFAULT_GENERATOR = getDefaultGenerator(); @@ -666,4 +668,12 @@ protected void setConverter(EquivalentConverter converter) { public String toString() { return "StructureModifier[fieldType=" + this.fieldType + ", data=" + this.accessors + "]"; } + + /** + * {@inheritDoc} + */ + @Override + public Iterator iterator() { + return new StructureModifierIterator(this); + } } diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java new file mode 100644 index 000000000..6d35c153d --- /dev/null +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java @@ -0,0 +1,56 @@ +/* + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2012 Kristian S. Stangeland + * + * This program is 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 2 of + * the License, or (at your option) any later version. + * + * This program 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.reflect; + +import java.util.Iterator; + +/** + * Provides iterator access to a {@link StructureModifier} + * + * @param Type of the fields in the {@link StructureModifier} + * @author BradBot_1 + */ +class StructureModifierIterator implements Iterator { + + private final StructureModifier structure; + private int index = 0; + + /** + * @param structure - {@link StructureModifier} to operate on. + */ + StructureModifierIterator(final StructureModifier structure) { + this.structure = structure; + } + + /** + * {@inheritDoc} + */ + @Override + public final boolean hasNext() { + return this.index < this.structure.size(); + } + + /** + * {@inheritDoc} + */ + @Override + public final T next() { + if (!this.hasNext()) return null; + return structure.read(index++); + } + +} From 13545ab5dba69d7f739562177c1a0dd2e233a2bf Mon Sep 17 00:00:00 2001 From: BradBot_1 Date: Tue, 11 Jul 2023 23:04:39 +0100 Subject: [PATCH 2/6] Add StructureModifierIntermediate for r/w access --- .../protocol/reflect/StructureModifier.java | 4 +- .../StructureModifierIntermediate.java | 57 +++++++++++++++++++ .../reflect/StructureModifierIterator.java | 8 +-- 3 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java index 099c325c3..4682da1a8 100644 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java @@ -53,7 +53,7 @@ * @param Type of the fields to retrieve. * @author Kristian */ -public class StructureModifier implements Iterable { +public class StructureModifier implements Iterable> { // Instance generator we will use private static final DefaultInstances DEFAULT_GENERATOR = getDefaultGenerator(); @@ -673,7 +673,7 @@ public String toString() { * {@inheritDoc} */ @Override - public Iterator iterator() { + public Iterator> iterator() { return new StructureModifierIterator(this); } } diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java new file mode 100644 index 000000000..99b31d675 --- /dev/null +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java @@ -0,0 +1,57 @@ +/* + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2012 Kristian S. Stangeland + * + * This program is 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 2 of + * the License, or (at your option) any later version. + * + * This program 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.reflect; + +/** + * Created by {@link StructureModifierIterator} iterator access to a {@link StructureModifier} + * + * @param Type of the fields in the {@link StructureModifier} + * @author BradBot_1 + */ +public class StructureModifierIntermediate { + + protected final StructureModifier structure; + protected final int index; + + /** + * @param structure - {@link StructureModifier} to operate on. + * @param index - index to access. + * + * @apiNote Must be public, else extending it would not work properly. + */ + public StructureModifierIntermediate(final StructureModifier structure, final int index) { + this.structure = structure; + this.index = index; + } + + /** + * @return Object at index. + */ + public T get() { + return this.structure.read(this.index); + } + + /** + * Overwrites the existing value at the index in the structure. + * + * @param toWrite - Object to overwrite the existing one. + */ + public void set(final T toWrite) { + this.structure.write(index, toWrite); + } + +} diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java index 6d35c153d..03921721c 100644 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java @@ -24,7 +24,7 @@ * @param Type of the fields in the {@link StructureModifier} * @author BradBot_1 */ -class StructureModifierIterator implements Iterator { +class StructureModifierIterator implements Iterator> { private final StructureModifier structure; private int index = 0; @@ -40,7 +40,7 @@ class StructureModifierIterator implements Iterator { * {@inheritDoc} */ @Override - public final boolean hasNext() { + public boolean hasNext() { return this.index < this.structure.size(); } @@ -48,9 +48,9 @@ public final boolean hasNext() { * {@inheritDoc} */ @Override - public final T next() { + public StructureModifierIntermediate next() { if (!this.hasNext()) return null; - return structure.read(index++); + return new StructureModifierIntermediate(this.structure, this.index++); } } From f768ea025f516aee0a44f63e949e837ee002b6b8 Mon Sep 17 00:00:00 2001 From: BradBot_1 Date: Thu, 13 Jul 2023 12:37:39 +0100 Subject: [PATCH 3/6] Throw NSE Exception over null --- .../comphenix/protocol/reflect/StructureModifierIterator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java index 03921721c..4a6f45a45 100644 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIterator.java @@ -17,6 +17,7 @@ package com.comphenix.protocol.reflect; import java.util.Iterator; +import java.util.NoSuchElementException; /** * Provides iterator access to a {@link StructureModifier} @@ -49,7 +50,7 @@ public boolean hasNext() { */ @Override public StructureModifierIntermediate next() { - if (!this.hasNext()) return null; + if (!this.hasNext()) throw new NoSuchElementException(); return new StructureModifierIntermediate(this.structure, this.index++); } From 9f4ede696a0b2c5793d416999477872567b951c2 Mon Sep 17 00:00:00 2001 From: BradBot_1 Date: Thu, 13 Jul 2023 13:33:53 +0100 Subject: [PATCH 4/6] Custom Spliterator for Structure Modifier --- .../protocol/reflect/StructureModifier.java | 10 ++ .../reflect/StructureModifierSpliterator.java | 126 ++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java index 4682da1a8..13f05399d 100644 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java @@ -42,8 +42,10 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Spliterator; import java.util.function.UnaryOperator; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Provides list-oriented access to the fields of a Minecraft packet. @@ -676,4 +678,12 @@ public String toString() { public Iterator> iterator() { return new StructureModifierIterator(this); } + + /** + * {@inheritDoc} + */ + @Override + public Spliterator> spliterator() { + return new StructureModifierSpliterator(this); + } } diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java new file mode 100644 index 000000000..16d80ba28 --- /dev/null +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java @@ -0,0 +1,126 @@ +/* + * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. + * Copyright (C) 2012 Kristian S. Stangeland + * + * This program is 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 2 of + * the License, or (at your option) any later version. + * + * This program 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + */ +package com.comphenix.protocol.reflect; + +import java.util.Spliterator; +import java.util.function.Consumer; + +/** + * Provides {@link Spliterator} access to a {@link StructureModifier} + * + * @param Type of the fields in the {@link StructureModifier} + * @author BradBot_1 + */ +class StructureModifierSpliterator implements Spliterator> { + + private final StructureModifier structure; + private int index; + private int bounds; + + /** + * @param structure - {@link StructureModifier} to operate on. + */ + StructureModifierSpliterator(final StructureModifier structure) { + this(structure, 0, structure.size()); + } + + /** + * @param structure - {@link StructureModifier} to operate on. + * @param offset - The offset to start at + * @param bounds - The max bound for reading. + */ + StructureModifierSpliterator(final StructureModifier structure, final int offset, final int bounds) { + this.structure = structure; + this.index = offset; + this.bounds = bounds; + } + + + /** + * {@inheritDoc} + */ + @Override + public StructureModifierSpliterator trySplit() { + final int remainingElements = this.bounds - this.index; + if (remainingElements <= 1) return null; // as spec + final int newSplitBounds = bounds; + this.bounds -= (remainingElements - (remainingElements % 2)) / 2; + return new StructureModifierSpliterator(this.structure, this.bounds, newSplitBounds); + } + + + /** + * {@inheritDoc} + */ + @Override + public boolean tryAdvance(final Consumer> action) throws NullPointerException { + // as demanded by the spec + if (action == null) throw new NullPointerException("The provided consumer is null!"); + if (this.index >= this.bounds) return false; // hit end of this spliterator + final StructureModifierIntermediate intermediate = new StructureModifierIntermediate(this.structure, this.index++); + // since it's defined as not null we have to perform this check + // yes this makes {@link #estimateSize} inaccurate in some situations, but that's better than a null + if (intermediate.get() == null) return tryAdvance(action); + action.accept(intermediate); + return true; + } + + + /** + * {@inheritDoc} + */ + @Override + public void forEachRemaining(Consumer> action) { + // as demanded by the spec + if (action == null) throw new NullPointerException("The provided consumer is null!"); + while (this.index < this.bounds) { + final StructureModifierIntermediate intermediate = new StructureModifierIntermediate(this.structure, this.index++); + // since it's defined as not null we have to perform this check + if (intermediate.get() == null) continue; + action.accept(intermediate); + } + } + + /** + * {@inheritDoc} + */ + @Override + public long estimateSize() { + return this.bounds - this.index; + } + + + /** + * {@inheritDoc} + * + * @apiNote Since this implementation is ordered we do not need to perform the check, instead we can just call the method + */ + @Override + public long getExactSizeIfKnown() { + return this.estimateSize(); + } + + + /** + * {@inheritDoc} + */ + @Override + public int characteristics() { + return Spliterator.DISTINCT/* | Spliterator.IMMUTABLE*/ | Spliterator.NONNULL | Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; + } + +} From 18c87ee2b7cf98e2059faf3f2b9634e8e0d9eee7 Mon Sep 17 00:00:00 2001 From: BradBot_1 Date: Thu, 13 Jul 2023 13:56:31 +0100 Subject: [PATCH 5/6] Allow access 2 internal structure via intermediate --- .../protocol/reflect/StructureModifierIntermediate.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java index 99b31d675..76b535e26 100644 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifierIntermediate.java @@ -54,4 +54,11 @@ public void set(final T toWrite) { this.structure.write(index, toWrite); } + /** + * @return The internal structure modifier + */ + public StructureModifier getInternalStructureModifier() { + return this.structure; + } + } From 0e5d5f5cd8d7895c4c0462312c21ced1fcd71574 Mon Sep 17 00:00:00 2001 From: BradBot_1 Date: Thu, 13 Jul 2023 14:07:22 +0100 Subject: [PATCH 6/6] Rollback Spliterator implemenation in favor of api --- .../protocol/reflect/StructureModifier.java | 3 +- .../reflect/StructureModifierSpliterator.java | 126 ------------------ 2 files changed, 2 insertions(+), 127 deletions(-) delete mode 100644 src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java index 13f05399d..a912b5c61 100644 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java +++ b/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java @@ -43,6 +43,7 @@ import java.util.Map; import java.util.Optional; import java.util.Spliterator; +import java.util.Spliterators; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -684,6 +685,6 @@ public Iterator> iterator() { */ @Override public Spliterator> spliterator() { - return new StructureModifierSpliterator(this); + return Spliterators.spliterator(this.iterator(), this.size(), Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.ORDERED | Spliterator.SIZED); } } diff --git a/src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java b/src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java deleted file mode 100644 index 16d80ba28..000000000 --- a/src/main/java/com/comphenix/protocol/reflect/StructureModifierSpliterator.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * ProtocolLib - Bukkit server library that allows access to the Minecraft protocol. - * Copyright (C) 2012 Kristian S. Stangeland - * - * This program is 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 2 of - * the License, or (at your option) any later version. - * - * This program 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -package com.comphenix.protocol.reflect; - -import java.util.Spliterator; -import java.util.function.Consumer; - -/** - * Provides {@link Spliterator} access to a {@link StructureModifier} - * - * @param Type of the fields in the {@link StructureModifier} - * @author BradBot_1 - */ -class StructureModifierSpliterator implements Spliterator> { - - private final StructureModifier structure; - private int index; - private int bounds; - - /** - * @param structure - {@link StructureModifier} to operate on. - */ - StructureModifierSpliterator(final StructureModifier structure) { - this(structure, 0, structure.size()); - } - - /** - * @param structure - {@link StructureModifier} to operate on. - * @param offset - The offset to start at - * @param bounds - The max bound for reading. - */ - StructureModifierSpliterator(final StructureModifier structure, final int offset, final int bounds) { - this.structure = structure; - this.index = offset; - this.bounds = bounds; - } - - - /** - * {@inheritDoc} - */ - @Override - public StructureModifierSpliterator trySplit() { - final int remainingElements = this.bounds - this.index; - if (remainingElements <= 1) return null; // as spec - final int newSplitBounds = bounds; - this.bounds -= (remainingElements - (remainingElements % 2)) / 2; - return new StructureModifierSpliterator(this.structure, this.bounds, newSplitBounds); - } - - - /** - * {@inheritDoc} - */ - @Override - public boolean tryAdvance(final Consumer> action) throws NullPointerException { - // as demanded by the spec - if (action == null) throw new NullPointerException("The provided consumer is null!"); - if (this.index >= this.bounds) return false; // hit end of this spliterator - final StructureModifierIntermediate intermediate = new StructureModifierIntermediate(this.structure, this.index++); - // since it's defined as not null we have to perform this check - // yes this makes {@link #estimateSize} inaccurate in some situations, but that's better than a null - if (intermediate.get() == null) return tryAdvance(action); - action.accept(intermediate); - return true; - } - - - /** - * {@inheritDoc} - */ - @Override - public void forEachRemaining(Consumer> action) { - // as demanded by the spec - if (action == null) throw new NullPointerException("The provided consumer is null!"); - while (this.index < this.bounds) { - final StructureModifierIntermediate intermediate = new StructureModifierIntermediate(this.structure, this.index++); - // since it's defined as not null we have to perform this check - if (intermediate.get() == null) continue; - action.accept(intermediate); - } - } - - /** - * {@inheritDoc} - */ - @Override - public long estimateSize() { - return this.bounds - this.index; - } - - - /** - * {@inheritDoc} - * - * @apiNote Since this implementation is ordered we do not need to perform the check, instead we can just call the method - */ - @Override - public long getExactSizeIfKnown() { - return this.estimateSize(); - } - - - /** - * {@inheritDoc} - */ - @Override - public int characteristics() { - return Spliterator.DISTINCT/* | Spliterator.IMMUTABLE*/ | Spliterator.NONNULL | Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; - } - -}