one.util.streamex.IfEmptySpliterator Maven / Gradle / Ivy
/*
* Copyright 2015, 2017 StreamEx contributors
*
* 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.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
/* package */ class IfEmptySpliterator extends StreamExInternals.CloneableSpliterator> {
// alt == null --> decision is made
private Spliterator spltr, alt;
// positive = number of non-exhausted spliterators; negative = surely non-empty
private final AtomicInteger state = new AtomicInteger(1);
public IfEmptySpliterator(Spliterator spltr, Spliterator alt) {
this.spltr = spltr;
this.alt = alt;
}
void tryInit() {
if (alt != null && spltr.hasCharacteristics(SIZED)) {
if (spltr.estimateSize() == 0) {
spltr = alt;
}
alt = null;
}
}
@Override
public boolean tryAdvance(Consumer action) {
if (alt != null) {
if (spltr.tryAdvance(action)) {
state.set(-1);
alt = null;
return true;
}
if (drawState()) {
spltr = alt;
}
alt = null;
}
return spltr.tryAdvance(action);
}
@Override
public void forEachRemaining(Consumer action) {
tryInit();
if (alt == null) {
spltr.forEachRemaining(action);
} else {
boolean[] empty = {true};
spltr.forEachRemaining(e -> {
empty[0] = false;
action.accept(e);
});
if (empty[0]) {
if (drawState()) {
(spltr = alt).forEachRemaining(action);
}
} else {
state.set(-1);
}
alt = null;
}
}
boolean drawState() {
return state.updateAndGet(x -> x > 0 ? x - 1 : x) == 0;
}
@Override
public Spliterator trySplit() {
Spliterator prefix = spltr.trySplit();
if (prefix == null) {
return null;
}
tryInit();
if (alt != null) {
state.updateAndGet(x -> x > 0 ? x + 1 : x);
}
IfEmptySpliterator clone = doClone();
clone.spltr = prefix;
return clone;
}
@Override
public long estimateSize() {
tryInit();
long size = spltr.estimateSize();
return alt != null && size == 0 ? alt.estimateSize() : size;
}
@Override
public int characteristics() {
if(alt == null) {
return spltr.characteristics() & (~SORTED);
}
return (spltr.characteristics() & alt.characteristics() & (~SORTED)) |
((spltr.characteristics() | alt.characteristics()) & (ORDERED));
}
}