SlicingIterator.java

package pro.verron.officestamper.utils.iterator;

import org.jspecify.annotations.Nullable;

import java.util.NoSuchElementException;

/// A [ResetableIterator] implementation that provides a sliced view of another iterator. It allows iteration over a
/// subset of elements from a source iterator, defined by a start and end element.
///
/// @param <T> the type of elements returned by this iterator
public class SlicingIterator<T>
        implements ResetableIterator<T> {
    private final ResetableIterator<T> source;
    private final T start;
    private final T end;
    private @Nullable T next;
    private boolean foundStart = false;
    private boolean foundEnd = false;


    /// Constructs a new SlicingIterator with the specified source iterator and boundaries.
    ///
    /// @param source the underlying [ResetableIterator] to slice
    /// @param start the starting element (inclusive) for iteration
    /// @param end the ending element (inclusive) for iteration
    public SlicingIterator(ResetableIterator<T> source, T start, T end) {
        this.source = source;
        this.start = start;
        this.end = end;
        findNext();
    }

    private void findNext() {
        next = null;
        while (source.hasNext() && !foundStart) {
            var o = source.next();
            if (o == start) {
                foundStart = true;
                next = o;
            }
        }

        if (source.hasNext() && !foundEnd) {
            next = source.next();
            if (next == end) foundEnd = true;
        }
    }

    @Override
    public void reset() {
        source.reset();
        foundStart = false;
        foundEnd = false;
        findNext();
    }

    @Override
    public boolean hasNext() {
        return next != null;
    }

    @Override
    public T next() {
        if (next == null) throw new NoSuchElementException("No more elements to iterate");
        T result = next;
        findNext();
        return result;
    }
}