MappingIterator.java

package pro.verron.officestamper.utils.iterator;

import org.jspecify.annotations.Nullable;

import java.util.NoSuchElementException;
import java.util.function.Function;

/// An iterator that filters and maps elements from another ResetableIterator based on user-provided filter and mapper
/// functions.
///
/// This class allows elements to be iterated through with specific filtering and transformation logic applied. The
/// iterator can also be reset to its initial state, re-evaluating the elements based on the same logic.
///
/// @param <S> the type of the source elements in the parent iterator
/// @param <T> the type of the transformed elements returned by this iterator
class MappingIterator<S, T>
        implements ResetableIterator<T> {
    private final Function<S, T> mapper;
    private final ResetableIterator<S> source;
    @Nullable T next;

    /// Constructs a MappingIterator with a parent iterator and a mapping function.
    ///
    /// @param source the underlying [ResetableIterator] containing the source elements
    /// @param mapper a function to transform the elements into a different type
    public MappingIterator(ResetableIterator<S> source, Function<S, T> mapper) {
        this.source = source;
        this.mapper = mapper;
        findNext();
    }

    private void findNext() {
        next = null;
        while (source.hasNext() && next == null) {
            var o = source.next();
            next = mapper.apply(o);
        }
    }

    @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;
    }

    @Override
    public void reset() {
        source.reset();
        findNext();
    }
}