All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
nl.vpro.util.MaxOffsetIterator Maven / Gradle / Ivy
package nl.vpro.util;
import lombok.Getter;
import lombok.Singular;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.function.Predicate;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.meeuw.functional.Predicates;
import com.google.common.collect.PeekingIterator;
/**
* An iterator implementing offset and max, for another iterator.
*
* @author Michiel Meeuwissen
* @since 3.1
*/
@SuppressWarnings("UnusedReturnValue")
@Slf4j
public class MaxOffsetIterator implements CloseablePeekingIterator {
protected final CloseableIterator wrapped;
protected PeekingIterator peekingWrapped;
/**
* The maximal value of count. I.e. offset + max;
*/
protected final long offsetmax;
final long max;
@Getter
private final long offset;
private final Predicate countPredicate;
/**
* The count of the next element. First value will be the supplied value of offset.
*/
protected long count = 0;
protected Boolean hasNext = null;
protected T next;
private RuntimeException exception;
private Runnable callback;
public MaxOffsetIterator(Iterator wrapped, Number max, boolean countNulls) {
this(wrapped, max, 0L, countNulls);
}
public MaxOffsetIterator(Iterator wrapped, Number max) {
this(wrapped, max, 0L, true);
}
public MaxOffsetIterator(Iterator wrapped, Number max, Number offset) {
this(wrapped, max, offset, true);
}
public MaxOffsetIterator(Iterator wrapped, Number max, Number offset, boolean countNulls) {
this(wrapped, max, offset, null, countNulls, null, false);
}
@lombok.Builder(builderClassName = "Builder")
protected MaxOffsetIterator(
@NonNull Iterator wrapped,
@Nullable Number max,
@Nullable Number offset,
@Nullable Predicate countPredicate,
boolean countNulls,
@Nullable @Singular List callbacks,
boolean autoClose) {
//noinspection ConstantConditions
if (wrapped == null) {
throw new IllegalArgumentException("Cannot wrap null");
}
this.wrapped = CloseableIterator.of(wrapped);
this.offset = offset == null ? 0L : offset.longValue();
this.max = max == null ? Long.MAX_VALUE : max.longValue();
this.offsetmax = max == null ? Long.MAX_VALUE : max.longValue() + this.offset;
this.countPredicate = effectiveCountPredicate(countPredicate, countNulls);
this.callback = () -> {
if (callbacks != null) {
for (Runnable r : callbacks) {
try {
r.run();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
};
if (autoClose) {
autoClose();
}
}
protected static Predicate effectiveCountPredicate(Predicate countPredicate, boolean countNulls) {
Predicate effective = countPredicate == null ? Predicates.alwaysTrue() : countPredicate;
if (! countNulls) {
effective = ((Predicate) Objects::nonNull).and(effective);
}
return effective;
}
public MaxOffsetIterator callBack(Runnable run) {
callback = run;
return this;
}
public MaxOffsetIterator autoClose(AutoCloseable... closeables) {
final Runnable prev = callback;
callback = () -> {
try {
if (prev != null) {
prev.run();
}
} finally {
for (AutoCloseable closeable : closeables) {
try {
closeable.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
};
return this;
}
public MaxOffsetIterator autoClose() {
final Runnable prev = callback;
callback = () -> {
try {
if (prev != null) {
prev.run();
}
} finally {
try {
wrapped.close();
} catch(Exception e){
log.error(e.getMessage(), e);
}
}
};
return this;
}
@Override
public boolean hasNext() {
return findNext();
}
@Override
public T peek() {
if (!findNext()) {
throw new NoSuchElementException();
}
if (exception != null) {
throw exception;
}
return next;
}
@Override
public T next() {
if (!findNext()) {
throw new NoSuchElementException();
}
hasNext = null;
if (exception != null) {
throw exception;
}
return next;
}
protected boolean findNext() {
if (hasNext == null) {
hasNext = false;
while(count < offset && wrapped.hasNext()) {
T n;
try {
n = wrapped.next();
} catch(RuntimeException runtimeException) {
n = null;
}
if (countPredicate.test(n)) {
count++;
}
}
if (count < offsetmax && wrapped.hasNext()) {
try {
exception = null;
next = wrapped.next();
} catch (RuntimeException e) {
exception = e;
next = null;
}
if (countPredicate.test(next)) {
count++;
}
hasNext = true;
}
if(!hasNext && callback != null) {
callback.run();
}
}
return hasNext;
}
@Override
public void remove() {
wrapped.remove();
}
@Override
public void close() throws Exception {
wrapped.close();
}
@Override
public String toString() {
return wrapped + "[" + offset + "," + (max < Long.MAX_VALUE ? max : "") + "]";
}
/**
* Access to the (peeking) wrapped iterator.
* This may be used to look 'beyond' max, to check what would have been the next one.
*/
public PeekingIterator peekingWrapped() {
if (peekingWrapped == null) {
peekingWrapped = wrapped.peeking();
}
return peekingWrapped;
}
public static CountedMaxOffsetIterator.Builder countedBuilder() {
return CountedMaxOffsetIterator._countedBuilder();
}
}