private <R> StreamEx<R> collapseInternal(BiPredicate<? super T, ? super T> collapsible, Function<T, R> mapper, BiFunction<R, T, R> accumulator, BinaryOperator<R> combiner) { CollapseSpliterator<T, R> spliterator = new CollapseSpliterator<>(collapsible, mapper, accumulator, combiner, spliterator()); return new StreamEx<>(spliterator, context); }
@Override public void forEachRemaining(Consumer<? super R> action) { while (left != null) { accept(handleLeft(), action); } if (a != NONE) { acc = mapper.apply(a); } source.forEachRemaining(next -> { if (a == NONE) { acc = mapper.apply(next); } else if (!this.mergeable.test(a, next)) { action.accept(acc); acc = mapper.apply(next); } else { acc = accumulator.apply(acc, next); } a = next; }); if (a == NONE) { accept(pushRight(none(), none()), action); } else if (accept(pushRight(acc, a), action)) { if (right != null) { action.accept(right.acc); right = null; } } }
private R connectOne(T first, R acc, T last) { synchronized (root) { Connector<T, R> l = left; if (l == null) { return pushRight(acc, last); } if (l.acc == NONE) { l.acc = acc; l.left = first; l.right = last; return connectEmpty(); } T laright = l.right; if (mergeable.test(laright, first)) { l.acc = combiner.apply(l.acc, acc); l.right = last; return connectEmpty(); } left = null; l.rhs = null; l.right = none(); if (l.left != NONE) { return pushRight(acc, last); } acc = pushRight(acc, last); if (acc != NONE) left = new Connector<>(null, acc, this); return l.drain(); } }
private R handleLeft() { synchronized (root) { Connector<T, R> l = left; if (l == null) { return none(); } if (l.left == NONE && l.right == NONE && l.acc != NONE) { return l.drain(); } } if (source.tryAdvance(this)) { T first = this.a; T last = first; R acc = this.mapper.apply(first); while (source.tryAdvance(this)) { if (!this.mergeable.test(last, a)) return pushLeft(first, acc); last = a; acc = this.accumulator.apply(acc, last); } a = none(); return connectOne(first, acc, last); } return connectEmpty(); }
Connector<T, R> l = left, r = right; if (l == null) { return pushRight(none(), none());
@Override public boolean tryAdvance(Consumer<? super R> action) { if (left != null) { if (accept(handleLeft(), action)) { return true; } } if (a == NONE) {// start if (!source.tryAdvance(this)) { return accept(pushRight(none(), none()), action); } } T first = a; R acc = mapper.apply(a); T last = first; while (source.tryAdvance(this)) { if (!this.mergeable.test(last, a)) { action.accept(acc); return true; } last = a; acc = this.accumulator.apply(acc, last); } return accept(pushRight(acc, last), action); }
/** * Merge series of adjacent stream entries with equal keys combining the * corresponding values using the provided function. * * <p> * This is a <a href="package-summary.html#StreamOps">quasi-intermediate</a> * partial reduction operation. * * <p> * The key of the resulting entry is the key of the first merged entry. * * @param merger a non-interfering, stateless, associative function to merge * values of two adjacent entries which keys are equal. Note that it * can be applied to the results if previous merges. * @return a new {@code EntryStream} which keys are the keys of the original * stream and the values are values of the adjacent entries with the * same keys, combined using the provided merger function. * @see StreamEx#collapse(BiPredicate, BinaryOperator) * @since 0.5.5 */ public EntryStream<K, V> collapseKeys(BinaryOperator<V> merger) { BinaryOperator<Entry<K, V>> entryMerger = (e1, e2) -> new SimpleImmutableEntry<>(e1.getKey(), merger.apply(e1 .getValue(), e2.getValue())); return new EntryStream<>(new CollapseSpliterator<>(equalKeys(), Function.identity(), entryMerger, entryMerger, spliterator()), context); }
@Override public Spliterator<R> trySplit() { Spliterator<T> prefix = source.trySplit(); if (prefix == null) return null; Connector<T, R> newBox = new Connector<>(null, none(), this); synchronized (root) { CollapseSpliterator<T, R> result = new CollapseSpliterator<>(root, prefix, left, newBox); this.left = newBox; return result; } }