/* * Copyright 2015, 2016 Tagir Valeev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package one.util.streamex; import java.util.Spliterator; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.DoubleBinaryOperator; import java.util.function.DoubleConsumer; import java.util.function.DoubleUnaryOperator; import java.util.function.Function; import java.util.function.IntBinaryOperator; import java.util.function.IntConsumer; import java.util.function.IntUnaryOperator; import java.util.function.LongBinaryOperator; import java.util.function.LongConsumer; import java.util.function.LongUnaryOperator; import static one.util.streamex.StreamExInternals.*; /** * @author Tagir Valeev */ /* package */abstract class PairSpliterator<T, S extends Spliterator<T>, R, SS extends PairSpliterator<T, S, R, SS>> extends CloneableSpliterator<R, SS> { static final int MODE_PAIRS = 0; static final int MODE_MAP_FIRST = 1; static final int MODE_MAP_LAST = 2; static final int MODE_MAP_FIRST_OR_ELSE = 3; static final int MODE_MAP_LAST_OR_ELSE = 4; static Sink<?> EMPTY = new Sink<>(null); // Common lock for all the derived spliterators final Object lock = new Object(); final int mode; S source; @SuppressWarnings("unchecked") Sink<T> left = (Sink<T>) EMPTY; @SuppressWarnings("unchecked") Sink<T> right = (Sink<T>) EMPTY; static final class Sink<T> { Sink<T> other; private T payload = none(); private final Object lock; Sink(Object lock) { this.lock = lock; } boolean push(T payload, BiConsumer<T, T> fn, boolean isLeft) { if (lock == null) return false; T otherPayload; synchronized (lock) { Sink<T> that = other; if (that == null) return false; otherPayload = that.payload; if (otherPayload == NONE) { this.payload = payload; return false; } other = null; that.clear(); } if (isLeft) fn.accept(payload, otherPayload); else fn.accept(otherPayload, payload); return true; } boolean connect(Sink<T> right, BiConsumer<T, T> fn) { if (lock == null) return false; T a, b; synchronized (lock) { Sink<T> leftLeft = this.other; Sink<T> rightRight = right.other; if (leftLeft == null || rightRight == null) { if (rightRight != null) rightRight.clear(); if (leftLeft != null) leftLeft.clear(); return false; } rightRight.other = leftLeft; leftLeft.other = rightRight; if (leftLeft.payload == NONE || rightRight.payload == NONE) return false; a = leftLeft.payload; b = rightRight.payload; leftLeft.clear(); rightRight.clear(); } fn.accept(a, b); return true; } void clear() { other = null; payload = none(); } } PairSpliterator(S source, int mode, T headTail) { this.source = source; this.mode = mode; if(mode != MODE_PAIRS) { Sink<T> sink = new Sink<>(this.lock); Sink<T> other = new Sink<>(this.lock); sink.other = other; other.other = sink; other.push(headTail, null, true); if(mode == MODE_MAP_FIRST || mode == MODE_MAP_FIRST_OR_ELSE) this.left = sink; else this.right = sink; } } @Override public long estimateSize() { long size = source.estimateSize(); if (size == Long.MAX_VALUE || size == 0) return size; return size - 1; } @Override public int characteristics() { return source.characteristics() & ((left == EMPTY && right == EMPTY ? SIZED : 0) | CONCURRENT | IMMUTABLE | ORDERED); } @SuppressWarnings("unchecked") @Override public SS trySplit() { S prefixSource = (S) source.trySplit(); if (prefixSource == null) return null; SS clone = doClone(); Sink<T> left = new Sink<>(lock); Sink<T> right = new Sink<>(lock); clone.source = prefixSource; clone.right = right.other = left; this.left = left.other = right; return clone; } void finish(BiConsumer<T, T> fn, T cur) { Sink<T> r = right, l = left; right = left = null; if (l != null) { l.connect(r, fn); } else if (r != null) { r.push(cur, fn, true); } } static class PSOfRef<T, R> extends PairSpliterator<T, Spliterator<T>, R, PSOfRef<T, R>> implements Consumer<T>, TailSpliterator<R> { private static final Object HEAD_TAIL = new Object(); private final BiFunction<? super T, ? super T, ? extends R> mapper; private T cur; PSOfRef(BiFunction<? super T, ? super T, ? extends R> mapper, Spliterator<T> source) { super(source, MODE_PAIRS, null); this.mapper = mapper; } // Must be called only if T == R @SuppressWarnings("unchecked") PSOfRef(Function<? super T, ? extends R> mapper, Spliterator<T> source, boolean first) { super(source, first ? MODE_MAP_FIRST : MODE_MAP_LAST, (T)HEAD_TAIL); BiFunction<? super T, ? super T, ?> m = first ? ((a, b) -> a == HEAD_TAIL ? mapper.apply(b) : (T)b) : ((a, b) -> b == HEAD_TAIL ? mapper.apply(a) : (T)a); this.mapper = (BiFunction<? super T, ? super T, ? extends R>) m; } @SuppressWarnings("unchecked") PSOfRef(Function<? super T, ? extends R> boundMapper, Function<? super T, ? extends R> elseMapper, Spliterator<T> source, boolean first) { super(source, first ? MODE_MAP_FIRST_OR_ELSE : MODE_MAP_LAST_OR_ELSE, (T)HEAD_TAIL); this.mapper = first ? ((a, b) -> a == HEAD_TAIL ? boundMapper.apply(b) : elseMapper.apply(b)) : ((a, b) -> b == HEAD_TAIL ? boundMapper.apply(a) : elseMapper.apply(a)); } @Override public void accept(T t) { cur = t; } private BiConsumer<T, T> fn(Consumer<? super R> action) { return (a, b) -> action.accept(mapper.apply(a, b)); } @Override public boolean tryAdvance(Consumer<? super R> action) { Sink<T> l = left, r = right; if (l != null) { left = null; if (!source.tryAdvance(this)) { right = null; return l.connect(r, fn(action)); } if (l.push(cur, fn(action), false)) return true; } T prev = cur; if (!source.tryAdvance(this)) { right = null; return r != null && r.push(prev, fn(action), true); } action.accept(mapper.apply(prev, cur)); return true; } @Override public void forEachRemaining(Consumer<? super R> action) { BiConsumer<T, T> fn = fn(action); source.forEachRemaining(next -> { if (left != null) { left.push(cur = next, fn, false); left = null; } else { action.accept(mapper.apply(cur, cur = next)); } }); finish(fn, cur); } @Override public Spliterator<R> tryAdvanceOrTail(Consumer<? super R> action) { if (mode != MODE_MAP_FIRST || right != EMPTY) { return tryAdvance(action) ? this : null; } if (left != null) { Sink<T> l = left; left = null; source = TailSpliterator.tryAdvanceWithTail(source, this); if (source == null) { right = null; return null; } if (l.push(cur, fn(action), false)) return this; } @SuppressWarnings("unchecked") Spliterator<R> s = (Spliterator<R>)source; source = null; return s; } @Override public Spliterator<R> forEachOrTail(Consumer<? super R> action) { if(mode != MODE_MAP_FIRST || right != EMPTY) { forEachRemaining(action); return null; } while (true) { Spliterator<R> tail = tryAdvanceOrTail(action); if (tail != this) return tail; } } } static final class PSOfInt extends PairSpliterator<Integer, Spliterator.OfInt, Integer, PSOfInt> implements Spliterator.OfInt, IntConsumer { private final IntBinaryOperator mapper; private final IntUnaryOperator unaryMapper; private int cur; PSOfInt(IntBinaryOperator mapper, IntUnaryOperator unaryMapper, Spliterator.OfInt source, int mode) { super(source, mode, null); this.mapper = mapper; this.unaryMapper = unaryMapper; } @Override public void accept(int t) { cur = t; } private BiConsumer<Integer, Integer> fn(IntConsumer action) { switch(mode) { case MODE_MAP_FIRST: return (a, b) -> action.accept(a == null ? unaryMapper.applyAsInt(b) : b); case MODE_MAP_LAST: return (a, b) -> action.accept(b == null ? unaryMapper.applyAsInt(a) : a); default: return (a, b) -> action.accept(mapper.applyAsInt(a, b)); } } @Override public boolean tryAdvance(IntConsumer action) { Sink<Integer> l = left, r = right; if (l != null) { left = null; if (!source.tryAdvance(this)) { right = null; return l.connect(r, fn(action)); } if (l.push(cur, fn(action), false)) return true; } int prev = cur; if (!source.tryAdvance(this)) { right = null; return r != null && r.push(prev, fn(action), true); } action.accept(mapper.applyAsInt(prev, cur)); return true; } @Override public void forEachRemaining(IntConsumer action) { BiConsumer<Integer, Integer> fn = fn(action); source.forEachRemaining((int next) -> { if (left != null) { left.push(cur = next, fn, false); left = null; } else { action.accept(mapper.applyAsInt(cur, cur = next)); } }); finish(fn, cur); } } static final class PSOfLong extends PairSpliterator<Long, Spliterator.OfLong, Long, PSOfLong> implements Spliterator.OfLong, LongConsumer { private final LongBinaryOperator mapper; private final LongUnaryOperator unaryMapper; private long cur; PSOfLong(LongBinaryOperator mapper, LongUnaryOperator unaryMapper, Spliterator.OfLong source, int mode) { super(source, mode, null); this.mapper = mapper; this.unaryMapper = unaryMapper; } @Override public void accept(long t) { cur = t; } private BiConsumer<Long, Long> fn(LongConsumer action) { switch(mode) { case MODE_MAP_FIRST: return (a, b) -> action.accept(a == null ? unaryMapper.applyAsLong(b) : b); case MODE_MAP_LAST: return (a, b) -> action.accept(b == null ? unaryMapper.applyAsLong(a) : a); default: return (a, b) -> action.accept(mapper.applyAsLong(a, b)); } } @Override public boolean tryAdvance(LongConsumer action) { Sink<Long> l = left, r = right; if (l != null) { left = null; if (!source.tryAdvance(this)) { right = null; return l.connect(r, fn(action)); } if (l.push(cur, fn(action), false)) return true; } long prev = cur; if (!source.tryAdvance(this)) { right = null; return r != null && r.push(prev, fn(action), true); } action.accept(mapper.applyAsLong(prev, cur)); return true; } @Override public void forEachRemaining(LongConsumer action) { BiConsumer<Long, Long> fn = fn(action); source.forEachRemaining((long next) -> { if (left != null) { left.push(cur = next, fn, false); left = null; } else { action.accept(mapper.applyAsLong(cur, cur = next)); } }); finish(fn, cur); } } static final class PSOfDouble extends PairSpliterator<Double, Spliterator.OfDouble, Double, PSOfDouble> implements Spliterator.OfDouble, DoubleConsumer { private final DoubleBinaryOperator mapper; private final DoubleUnaryOperator unaryMapper; private double cur; PSOfDouble(DoubleBinaryOperator mapper, DoubleUnaryOperator unaryMapper, Spliterator.OfDouble source, int mode) { super(source, mode, null); this.mapper = mapper; this.unaryMapper = unaryMapper; } @Override public void accept(double t) { cur = t; } private BiConsumer<Double, Double> fn(DoubleConsumer action) { switch(mode) { case MODE_MAP_FIRST: return (a, b) -> action.accept(a == null ? unaryMapper.applyAsDouble(b) : b); case MODE_MAP_LAST: return (a, b) -> action.accept(b == null ? unaryMapper.applyAsDouble(a) : a); default: return (a, b) -> action.accept(mapper.applyAsDouble(a, b)); } } @Override public boolean tryAdvance(DoubleConsumer action) { Sink<Double> l = left, r = right; if (l != null) { left = null; if (!source.tryAdvance(this)) { right = null; return l.connect(r, fn(action)); } if (l.push(cur, fn(action), false)) return true; } double prev = cur; if (!source.tryAdvance(this)) { right = null; return r != null && r.push(prev, fn(action), true); } action.accept(mapper.applyAsDouble(prev, cur)); return true; } @Override public void forEachRemaining(DoubleConsumer action) { BiConsumer<Double, Double> fn = fn(action); source.forEachRemaining((double next) -> { if (left != null) { left.push(cur = next, fn, false); left = null; } else { action.accept(mapper.applyAsDouble(cur, cur = next)); } }); finish(fn, cur); } } }