    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.io.function;
    019
    020import java.io.IOException;
    021import java.io.UncheckedIOException;
    022import java.util.Objects;
    023import java.util.Spliterator;
    024import java.util.function.Consumer;
    025
    026/**
    027 * Like {@link Spliterator} but throws {@link IOException}.
    028 *
    029 * @param <T> the type of elements returned by this IOSpliterator.
    030 * @since 2.12.0
    031 */
    032public interface IOSpliterator<T> {
    033
    034    /**
    035     * Adapts the given Spliterator as an IOSpliterator.
    036     *
    037     * @param <E> the type of the stream elements.
    038     * @param iterator The iterator to adapt
    039     * @return A new IOSpliterator
    040     */
    041    static <E> IOSpliterator<E> adapt(final Spliterator<E> iterator) {
    042        return IOSpliteratorAdapter.adapt(iterator);
    043    }
    044
    045    /**
    046     * Constructs a {@link Spliterator} for this instance that throws {@link UncheckedIOException} instead of
    047     * {@link IOException}.
    048     *
    049     * @return an {@link UncheckedIOException} {@link Spliterator}.
    050     */
    051    default Spliterator<T> asSpliterator() {
    052        return new UncheckedIOSpliterator<>(this);
    053    }
    054
    055    /**
    056     * Like {@link Spliterator#characteristics()}.
    057     *
    058     * @return a representation of characteristics
    059     */
    060    default int characteristics() {
    061        return unwrap().characteristics();
    062    }
    063
    064    /**
    065     * Like {@link Spliterator#estimateSize()}.
    066     *
    067     *
    068     * @return the estimated size, or {@code Long.MAX_VALUE} if infinite, unknown, or too expensive to compute.
    069     */
    070    default long estimateSize() {
    071        return unwrap().estimateSize();
    072    }
    073
    074    /**
    075     * Like {@link Spliterator#forEachRemaining(Consumer)}.
    076     *
    077     * @param action The action
    078     * @throws NullPointerException if the specified action is null
    079     */
    080    default void forEachRemaining(final IOConsumer<? super T> action) {
    081        while (tryAdvance(action)) { // NOPMD
    082        }
    083    }
    084
    085    /**
    086     * Like {@link Spliterator#getComparator()}.
    087     *
    088     * @return a Comparator, or {@code null} if the elements are sorted in the natural order.
    089     * @throws IllegalStateException if the spliterator does not report a characteristic of {@code SORTED}.
    090     */
    091    @SuppressWarnings("unchecked")
    092    default IOComparator<? super T> getComparator() {
    093        return (IOComparator<T>) unwrap().getComparator();
    094    }
    095
    096    /**
    097     * Like {@link Spliterator#getExactSizeIfKnown()}.
    098     *
    099     * @return the exact size, if known, else {@code -1}.
    100     */
    101    default long getExactSizeIfKnown() {
    102        return unwrap().getExactSizeIfKnown();
    103    }
    104
    105    /**
    106     * Like {@link Spliterator#hasCharacteristics(int)}.
    107     *
    108     * @param characteristics the characteristics to check for
    109     * @return {@code true} if all the specified characteristics are present, else {@code false}
    110     */
    111    default boolean hasCharacteristics(final int characteristics) {
    112        return unwrap().hasCharacteristics(characteristics);
    113    }
    114
    115    /**
    116     * Like {@link Spliterator#tryAdvance(Consumer)}.
    117     *
    118     * @param action The action
    119     * @return {@code false} if no remaining elements existed upon entry to this method, else {@code true}.
    120     * @throws NullPointerException if the specified action is null
    121     */
    122    default boolean tryAdvance(final IOConsumer<? super T> action) {
    123        return unwrap().tryAdvance(Objects.requireNonNull(action, "action").asConsumer());
    124    }
    125
    126    /**
    127     * Like {@link Spliterator#trySplit()}.
    128     *
    129     * @return a {@code Spliterator} covering some portion of the elements, or {@code null} if this spliterator cannot be
    130     *         split
    131     */
    132    default IOSpliterator<T> trySplit() {
    133        return adapt(unwrap().trySplit());
    134    }
    135
    136    /**
    137     * Unwraps this instance and returns the underlying {@link Spliterator}.
    138     * <p>
    139     * Implementations may not have anything to unwrap and that behavior is undefined for now.
    140     * </p>
    141     *
    142     * @return the underlying Spliterator.
    143     */
    144    Spliterator<T> unwrap();
    145
    146}