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}