[PATCH] Re: Custom spliterator for Collections.nCopies(n, obj).stream()
Tagir F. Valeev
amaembo at gmail.com
Sat Aug 22 14:27:01 UTC 2015
Seems that the patch attachment was filtered out. Just for the case
here it is:
diff --git a/src/java.base/share/classes/java/util/Collections.java b/src/java.base/share/classes/java/util/Collections.java
--- a/src/java.base/share/classes/java/util/Collections.java
+++ b/src/java.base/share/classes/java/util/Collections.java
@@ -4702,43 +4702,7 @@
* @return A singleton {@code Spliterator}
*/
static <T> Spliterator<T> singletonSpliterator(final T element) {
- return new Spliterator<T>() {
- long est = 1;
-
- @Override
- public Spliterator<T> trySplit() {
- return null;
- }
-
- @Override
- public boolean tryAdvance(Consumer<? super T> consumer) {
- Objects.requireNonNull(consumer);
- if (est > 0) {
- est--;
- consumer.accept(element);
- return true;
- }
- return false;
- }
-
- @Override
- public void forEachRemaining(Consumer<? super T> consumer) {
- tryAdvance(consumer);
- }
-
- @Override
- public long estimateSize() {
- return est;
- }
-
- @Override
- public int characteristics() {
- int value = (element != null) ? Spliterator.NONNULL : 0;
-
- return value | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE |
- Spliterator.DISTINCT | Spliterator.ORDERED;
- }
- };
+ return new ConstantSpliterator<>(1, element);
}
/**
@@ -5061,20 +5025,64 @@
return new CopiesList<>(toIndex - fromIndex, element);
}
- // Override default methods in Collection
- @Override
- public Stream<E> stream() {
- return IntStream.range(0, n).mapToObj(i -> element);
- }
-
- @Override
- public Stream<E> parallelStream() {
- return IntStream.range(0, n).parallel().mapToObj(i -> element);
- }
-
@Override
public Spliterator<E> spliterator() {
- return stream().spliterator();
+ return new ConstantSpliterator<>(n, element);
+ }
+ }
+
+ private static final class ConstantSpliterator<T> implements Spliterator<T> {
+ long est;
+ T element;
+
+ public ConstantSpliterator(long est, T element) {
+ this.est = est;
+ this.element = element;
+ }
+
+ @Override
+ public Spliterator<T> trySplit() {
+ long est = this.est;
+ if (est >= 2) {
+ est >>= 1;
+ Spliterator<T> prefix = new ConstantSpliterator<>(est, element);
+ this.est -= est;
+ return prefix;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean tryAdvance(Consumer<? super T> action) {
+ Objects.requireNonNull(action);
+ if (est <= 0)
+ return false;
+ action.accept(element);
+ est--;
+ return true;
+ }
+
+ @Override
+ public void forEachRemaining(Consumer<? super T> action) {
+ Objects.requireNonNull(action);
+ T element = this.element;
+ for (long r = est; r > 0; r--) {
+ action.accept(element);
+ }
+ est = 0;
+ }
+
+ @Override
+ public long estimateSize() {
+ return est;
+ }
+
+ @Override
+ public int characteristics() {
+ int nonNull = (element != null) ? NONNULL : 0;
+ int distinct = (est <= 1) ? DISTINCT : 0;
+
+ return SIZED | SUBSIZED | IMMUTABLE | ORDERED | nonNull | distinct;
}
}
With best regards,
Tagir Valeev.
TFV> Hello!
PS>> With reuse it becomes more compelling :-) In both cases of
PS>> singleton/nCopies the spliterator characteristics can be the same
PS>> and that of the already existing singleton spliterator implementation.
TFV> The only difference is the DISTINCT characteristic. I think it's good
TFV> to report it based on the list size, so
TFV> Collections.nCopies(1, obj).spliterator() can report DISTINCT as well.
PS>> I would be happy to accept a patch (with tests, if existing tests
PS>> do not cover this already, i suspect they might but we still need
PS>> to check). Have you signed the OCA [1]. If so i can accept a patch
PS>> from you and publish as a webrev for review.
TFV> Here's my patch to the Collections class. Implementation of the
TFV> ConstantSpliterator is added, singletonSpliterator method now uses it
TFV> as well as CopiesList::spliterator. CopiesList::stream and
TFV> CopiesList::parallelStream methods are removed as unnecessary.
TFV> The resulting bytecode is roughly 750 bytes less after applying my
TFV> patch.
TFV> As for tests, it seems that
TFV> test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java
TFV> covers both singletonSpliterator and nCopies().spliterator() pretty
TFV> well. I checked that these tests succeed with my changes while failed
TFV> when some mistake in ConstantSpliterator is introduced. If you think
TFV> that more tests are necessary, please suggest what exactly should be
TFV> tested and where to put them.
TFV> With best regards,
TFV> Tagir Valeev.
More information about the core-libs-dev
mailing list