/*
* 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.Comparator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.Spliterators.AbstractDoubleSpliterator;
import java.util.Spliterators.AbstractIntSpliterator;
import java.util.Spliterators.AbstractLongSpliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.DoublePredicate;
import java.util.function.IntConsumer;
import java.util.function.IntPredicate;
import java.util.function.LongConsumer;
import java.util.function.LongPredicate;
import java.util.function.Predicate;
import one.util.streamex.StreamExInternals.CloneableSpliterator;
/**
* @author Tagir Valeev
*/
class TakeDrop {
static final class TDOfRef<T> extends AbstractSpliterator<T> implements Consumer<T> {
private final Predicate<? super T> predicate;
private final boolean drop;
private final boolean inclusive;
private boolean checked;
private final Spliterator<T> source;
private T cur;
TDOfRef(Spliterator<T> source, boolean drop, boolean inclusive, Predicate<? super T> predicate) {
super(source.estimateSize(), source.characteristics()
& (ORDERED | SORTED | CONCURRENT | IMMUTABLE | NONNULL | DISTINCT));
this.drop = drop;
this.predicate = predicate;
this.inclusive = inclusive;
this.source = source;
}
@Override
public Comparator<? super T> getComparator() {
return source.getComparator();
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (drop) {
if (checked)
return source.tryAdvance(action);
while (source.tryAdvance(this)) {
if (!predicate.test(cur)) {
checked = true;
action.accept(cur);
return true;
}
}
return false;
}
if (!checked && source.tryAdvance(this) && (predicate.test(cur) || (checked = inclusive))) {
action.accept(cur);
return true;
}
checked = true;
return false;
}
@Override
public void forEachRemaining(Consumer<? super T> action) {
if (drop) {
if (checked)
source.forEachRemaining(action);
else {
source.forEachRemaining(e -> {
if (checked)
action.accept(e);
else {
if (!predicate.test(e)) {
checked = true;
action.accept(e);
}
}
});
}
} else
super.forEachRemaining(action);
}
@Override
public void accept(T t) {
this.cur = t;
}
}
static final class UnorderedTDOfRef<T> extends CloneableSpliterator<T, UnorderedTDOfRef<T>> implements Consumer<T> {
private final Predicate<? super T> predicate;
private final boolean drop;
private final boolean inclusive;
private final AtomicBoolean checked = new AtomicBoolean();
private Spliterator<T> source;
private T cur;
UnorderedTDOfRef(Spliterator<T> source, boolean drop, boolean inclusive, Predicate<? super T> predicate) {
this.drop = drop;
this.predicate = predicate;
this.inclusive = inclusive;
this.source = source;
}
@Override
public void accept(T t) {
this.cur = t;
}
@Override
public boolean tryAdvance(Consumer<? super T> action) {
if (drop) {
if (checked.get())
return source.tryAdvance(action);
while (source.tryAdvance(this)) {
if (!predicate.test(cur)) {
checked.set(true);
action.accept(cur);
return true;
}
}
return false;
}
if (!checked.get() && source.tryAdvance(this) &&
(predicate.test(cur) || (checked.compareAndSet(false, true) && inclusive))) {
action.accept(cur);
return true;
}
return false;
}
@Override
public Spliterator<T> trySplit() {
Spliterator<T> prefix = source.trySplit();
if(prefix == null) {
return null;
}
if(checked.get()) {
return drop ? prefix : Spliterators.emptySpliterator();
}
UnorderedTDOfRef<T> clone = doClone();
clone.source = prefix;
return clone;
}
@Override
public long estimateSize() {
return source.estimateSize();
}
@Override
public int characteristics() {
return source.characteristics() & (DISTINCT | NONNULL);
}
}
static final class TDOfInt extends AbstractIntSpliterator implements IntConsumer {
private final IntPredicate predicate;
private final boolean drop;
private final boolean inclusive;
private boolean checked;
private final Spliterator.OfInt source;
private int cur;
TDOfInt(Spliterator.OfInt source, boolean drop, boolean inclusive, IntPredicate predicate) {
super(source.estimateSize(), source.characteristics() & (ORDERED | SORTED | CONCURRENT | IMMUTABLE | NONNULL
| DISTINCT));
this.drop = drop;
this.predicate = predicate;
this.inclusive = inclusive;
this.source = source;
}
@Override
public Comparator<? super Integer> getComparator() {
return source.getComparator();
}
@Override
public boolean tryAdvance(IntConsumer action) {
if (drop) {
if (checked)
return source.tryAdvance(action);
while (source.tryAdvance(this)) {
if (!predicate.test(cur)) {
checked = true;
action.accept(cur);
return true;
}
}
return false;
}
if (!checked && source.tryAdvance(this) && (predicate.test(cur) || (checked = inclusive))) {
action.accept(cur);
return true;
}
checked = true;
return false;
}
@Override
public void forEachRemaining(IntConsumer action) {
if (drop) {
if (checked)
source.forEachRemaining(action);
else {
source.forEachRemaining((int e) -> {
if (checked)
action.accept(e);
else {
if (!predicate.test(e)) {
checked = true;
action.accept(e);
}
}
});
}
} else
super.forEachRemaining(action);
}
@Override
public void accept(int t) {
this.cur = t;
}
}
static final class TDOfLong extends AbstractLongSpliterator implements LongConsumer {
private final LongPredicate predicate;
private final boolean drop;
private final boolean inclusive;
private boolean checked;
private final Spliterator.OfLong source;
private long cur;
TDOfLong(Spliterator.OfLong source, boolean drop, boolean inclusive, LongPredicate predicate) {
super(source.estimateSize(), source.characteristics() & (ORDERED | SORTED | CONCURRENT | IMMUTABLE | NONNULL
| DISTINCT));
this.drop = drop;
this.predicate = predicate;
this.inclusive = inclusive;
this.source = source;
}
@Override
public Comparator<? super Long> getComparator() {
return source.getComparator();
}
@Override
public boolean tryAdvance(LongConsumer action) {
if (drop) {
if (checked)
return source.tryAdvance(action);
while (source.tryAdvance(this)) {
if (!predicate.test(cur)) {
checked = true;
action.accept(cur);
return true;
}
}
return false;
}
if (!checked && source.tryAdvance(this) && (predicate.test(cur) || (checked = inclusive))) {
action.accept(cur);
return true;
}
checked = true;
return false;
}
@Override
public void forEachRemaining(LongConsumer action) {
if (drop) {
if (checked)
source.forEachRemaining(action);
else {
source.forEachRemaining((long e) -> {
if (checked)
action.accept(e);
else {
if (!predicate.test(e)) {
checked = true;
action.accept(e);
}
}
});
}
} else
super.forEachRemaining(action);
}
@Override
public void accept(long t) {
this.cur = t;
}
}
static final class TDOfDouble extends AbstractDoubleSpliterator implements DoubleConsumer {
private final DoublePredicate predicate;
private final boolean drop;
private final boolean inclusive;
private boolean checked;
private final Spliterator.OfDouble source;
private double cur;
TDOfDouble(Spliterator.OfDouble source, boolean drop, boolean inclusive, DoublePredicate predicate) {
super(source.estimateSize(), source.characteristics() & (ORDERED | SORTED | CONCURRENT | IMMUTABLE | NONNULL
| DISTINCT));
this.drop = drop;
this.predicate = predicate;
this.inclusive = inclusive;
this.source = source;
}
@Override
public Comparator<? super Double> getComparator() {
return source.getComparator();
}
@Override
public boolean tryAdvance(DoubleConsumer action) {
if (drop) {
if (checked)
return source.tryAdvance(action);
while (source.tryAdvance(this)) {
if (!predicate.test(cur)) {
checked = true;
action.accept(cur);
return true;
}
}
return false;
}
if (!checked && source.tryAdvance(this) && (predicate.test(cur) || (checked = inclusive))) {
action.accept(cur);
return true;
}
checked = true;
return false;
}
@Override
public void forEachRemaining(DoubleConsumer action) {
if (drop) {
if (checked)
source.forEachRemaining(action);
else {
source.forEachRemaining((double e) -> {
if (checked)
action.accept(e);
else {
if (!predicate.test(e)) {
checked = true;
action.accept(e);
}
}
});
}
} else
super.forEachRemaining(action);
}
@Override
public void accept(double t) {
this.cur = t;
}
}
}