<commit_before>/*
 * Copyright (C) 2015 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.paumard.streams;

import org.paumard.spliterators.*;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

import static java.util.function.Function.identity;

/**
 * <p>A factory class used to create streams from other streams. There are currently seven ways of rearranging streams.
 * </p>
 * <p>Here is a first example of what can be done:</p>
 * <pre>{@code
 *     // Create an example Stream
 *     Stream<String> stream = Stream.of("a0", "a1", "a2", "a3");
 *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, 2);
 *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
 *     // The collect list is [["a0", "a1"]["a2", "a3"]]
 * }</pre>
 * <p>See the documentation of each factory method for more information. </p>
 *
 * @author <NAME>
 * @since 0.1
 */
public class StreamsUtils {

    /**
     * <p>Generates a stream by repeating the elements of the provided stream forever. This stream is not bounded. </p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("tick", "tock");
     *     Stream<String> cyclingStream = StreamsUtils.cycle(stream);
     *     List<String> collect = cyclingStream.limit(9).collect(Collectors.toList());
     *     // The collect list is ["tick", "tock", "tick", "tock", "tick", "tock", "tick", "tock", "tick"]
     * }</pre>
     * <p>The returned spliterator is <code>ORDERED</code>.</p>
     *
     * @param stream The stream to cycle on. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param <E>    The type of the elements of the provided stream.
     * @return A cycling stream.
     */
    public static <E> Stream<E> cycle(Stream<E> stream) {
        Objects.requireNonNull(stream);

        CyclingSpliterator<E> spliterator = CyclingSpliterator.of(stream.spliterator());
        return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close).flatMap(identity());
    }

    /**
     * <p>Generates a stream by regrouping the elements of the provided stream and putting them in a substream. The number
     * of elements regrouped is the <code>groupingFactor</code>.</p>
     * <p>Example:</p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("a0", "a1", "a2", "a3");
     *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, 2);
     *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a0", "a1"]["a2", "a3"]]
     * }</pre>
     * <p>If the provided stream is empty, then the returned stream contains an empty stream.</p>
     * <p>The <code>groupingFactor</code> should be greater of equals than 2. A grouping factor of 0 does not make
     * sense. A grouping factor of 1 is in fact a mapping with a <code>Stream::of</code>. An
     * <code>IllegalArgumentException</code> will be thrown if a non valid <code>groupingFactor</code> is provided.</p>
     * <p>An <code>IllegalArgumentException</code> will also be thrown if the provided stream is not <code>ORDERED</code></p>
     * <p>The returned stream has the same characteristics as the provided stream, and is thus <code>ORDERED</code>.</p>
     * <p>All the returned substreams are guaranteed to produce <code>groupingFactor</code> elements. So there might be
     * elements from the provided stream that will not be consumed in the grouped stream. </p>
     *
     * @param stream         The stream to be grouped. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param groupingFactor The grouping factor, should be greater of equal than 2.
     * @param <E>            The type of the elements of the provided stream.
     * @return A grouped stream of streams.
     */
    public static <E> Stream<Stream<E>> group(Stream<E> stream, int groupingFactor) {
        Objects.requireNonNull(stream);

        GroupingSpliterator<E> spliterator = GroupingSpliterator.of(stream.spliterator(), groupingFactor);
        return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close);
    }

    /**
     * <p>Generates a stream by regrouping the elements of the provided stream and putting them in a substream.
     * This grouping operation scans the elements of the stream using the <code>open</code> predicate. If this
     * predicate is true, then it begins to add the elements of the stream in a substream. It will continue to add
     * them until an element that matches the <code>close</code> predicate is met. </p>
     * <p>The basic group operation includes the opening and the closing elements in the substreams. You can also
     * provide two booleans if you need to customize this behavior. </p>
     * <p>Example:</p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("o", "a0", "a1", "a2", "c", "a3", "a4, "o", "a5", "c");
     *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, "o"::equals, "c"::equals);
     *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["o", "a0", "a1", "a2", "c"]["o", "a5", "c"]]
     * }</pre>
     * <p>If the provided stream is empty, then the returned stream contains an empty stream.</p>
     * <p>An <code>IllegalArgumentException</code> will also be thrown if the provided stream is not <code>ORDERED</code></p>
     * <p>The returned stream has the same characteristics as the provided stream, and is thus <code>ORDERED</code>.</p>
     *
     * @param stream The stream to be grouped. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param open   The predicate used to check for an opening element.
     * @param close  The predicate used to check for an closing element.
     * @param <E>    The type of the elements of the provided stream.
     * @return A grouped stream of streams.
     */
    public static <E> Stream<Stream<E>> group(Stream<E> stream, Predicate<? super E> open, Predicate<? super E> close) {
        Objects.requireNonNull(stream);
        Objects.requireNonNull(open);
        Objects.requireNonNull(close);

        return group(stream, open, true, close, true);
    }

    /**
     * <p>Generates a stream by regrouping the elements of the provided stream and putting them in a substream.
     * This grouping operation scans the elements of the stream using the <code>open</code> predicate. If this
     * predicate is true, then it begins to add the elements of the stream in a substream. It will continue to add
     * them until an element that matches the <code>close</code> predicate is met. </p>
     * <p>Adding the opening and the closing elements is controlled by the two boolean parameters
     * <code>openingElementIncluded</code> and <code>closingElementIncluded</code>.</p>
     * <p>Example:</p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("o", "a0", "a1", "a2", "c", "a3", "a4, "o", "a5", "c");
     *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, "o"::equals, false, "c"::equals, false);
     *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a0", "a1", "a2"]["a5"]]
     * }</pre>
     * <p>If the provided stream is empty, then the returned stream contains an empty stream.</p>
     * <p>An <code>IllegalArgumentException</code> will also be thrown if the provided stream is not <code>ORDERED</code></p>
     * <p>The returned stream has the same characteristics as the provided stream, and is thus <code>ORDERED</code>.</p>
     *
     * @param stream The stream to be grouped. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param open   The predicate used to check for an opening element.
     * @param close  The predicate used to check for an closing element.
     * @param <E>    The type of the elements of the provided stream.
     * @return A grouped stream of streams.
     */
    public static <E> Stream<Stream<E>> group(
            Stream<E> stream,
            Predicate<? super E> open, boolean openingElementIncluded,
            Predicate<? super E> close, boolean closingElementIncluded) {
        Objects.requireNonNull(stream);
        Objects.requireNonNull(open);
        Objects.requireNonNull(close);<commit_msg>Added missing elements in the javadoc.<commit_after>/*
 * Copyright (C) 2015 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.paumard.streams;

import org.paumard.spliterators.*;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

import static java.util.function.Function.identity;

/**
 * <p>A factory class used to create streams from other streams. There are currently seven ways of rearranging streams.
 * </p>
 * <p>Here is a first example of what can be done:</p>
 * <pre>{@code
 *     // Create an example Stream
 *     Stream<String> stream = Stream.of("a0", "a1", "a2", "a3");
 *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, 2);
 *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
 *     // The collect list is [["a0", "a1"]["a2", "a3"]]
 * }</pre>
 * <p>See the documentation of each factory method for more information. </p>
 *
 * @author <NAME>
 * @since 0.1
 */
public class StreamsUtils {

    /**
     * <p>Generates a stream by repeating the elements of the provided stream forever. This stream is not bounded. </p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("tick", "tock");
     *     Stream<String> cyclingStream = StreamsUtils.cycle(stream);
     *     List<String> collect = cyclingStream.limit(9).collect(Collectors.toList());
     *     // The collect list is ["tick", "tock", "tick", "tock", "tick", "tock", "tick", "tock", "tick"]
     * }</pre>
     * <p>The returned spliterator is <code>ORDERED</code>.</p>
     *
     * @param stream The stream to cycle on. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param <E>    The type of the elements of the provided stream.
     * @return A cycling stream.
     */
    public static <E> Stream<E> cycle(Stream<E> stream) {
        Objects.requireNonNull(stream);

        CyclingSpliterator<E> spliterator = CyclingSpliterator.of(stream.spliterator());
        return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close).flatMap(identity());
    }

    /**
     * <p>Generates a stream by regrouping the elements of the provided stream and putting them in a substream. The number
     * of elements regrouped is the <code>groupingFactor</code>.</p>
     * <p>Example:</p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("a0", "a1", "a2", "a3");
     *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, 2);
     *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a0", "a1"]["a2", "a3"]]
     * }</pre>
     * <p>If the provided stream is empty, then the returned stream contains an empty stream.</p>
     * <p>The <code>groupingFactor</code> should be greater of equals than 2. A grouping factor of 0 does not make
     * sense. A grouping factor of 1 is in fact a mapping with a <code>Stream::of</code>. An
     * <code>IllegalArgumentException</code> will be thrown if a non valid <code>groupingFactor</code> is provided.</p>
     * <p>An <code>IllegalArgumentException</code> will also be thrown if the provided stream is not <code>ORDERED</code></p>
     * <p>The returned stream has the same characteristics as the provided stream, and is thus <code>ORDERED</code>.</p>
     * <p>All the returned substreams are guaranteed to produce <code>groupingFactor</code> elements. So there might be
     * elements from the provided stream that will not be consumed in the grouped stream. </p>
     *
     * @param stream         The stream to be grouped. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param groupingFactor The grouping factor, should be greater of equal than 2.
     * @param <E>            The type of the elements of the provided stream.
     * @return A grouped stream of streams.
     */
    public static <E> Stream<Stream<E>> group(Stream<E> stream, int groupingFactor) {
        Objects.requireNonNull(stream);

        GroupingSpliterator<E> spliterator = GroupingSpliterator.of(stream.spliterator(), groupingFactor);
        return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close);
    }

    /**
     * <p>Generates a stream by regrouping the elements of the provided stream and putting them in a substream.
     * This grouping operation scans the elements of the stream using the <code>open</code> predicate. If this
     * predicate is true, then it begins to add the elements of the stream in a substream. It will continue to add
     * them until an element that matches the <code>close</code> predicate is met. </p>
     * <p>The basic group operation includes the opening and the closing elements in the substreams. You can also
     * provide two booleans if you need to customize this behavior. </p>
     * <p>Example:</p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("o", "a0", "a1", "a2", "c", "a3", "a4, "o", "a5", "c");
     *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, "o"::equals, "c"::equals);
     *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["o", "a0", "a1", "a2", "c"]["o", "a5", "c"]]
     * }</pre>
     * <p>If the provided stream is empty, then the returned stream contains an empty stream.</p>
     * <p>An <code>IllegalArgumentException</code> will also be thrown if the provided stream is not <code>ORDERED</code></p>
     * <p>The returned stream has the same characteristics as the provided stream, and is thus <code>ORDERED</code>.</p>
     *
     * @param stream The stream to be grouped. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param open   The predicate used to check for an opening element.
     * @param close  The predicate used to check for an closing element.
     * @param <E>    The type of the elements of the provided stream.
     * @return A grouped stream of streams.
     */
    public static <E> Stream<Stream<E>> group(Stream<E> stream, Predicate<? super E> open, Predicate<? super E> close) {
        Objects.requireNonNull(stream);
        Objects.requireNonNull(open);
        Objects.requireNonNull(close);

        return group(stream, open, true, close, true);
    }

    /**
     * <p>Generates a stream by regrouping the elements of the provided stream and putting them in a substream.
     * This grouping operation scans the elements of the stream using the <code>open</code> predicate. If this
     * predicate is true, then it begins to add the elements of the stream in a substream. It will continue to add
     * them until an element that matches the <code>close</code> predicate is met. </p>
     * <p>Adding the opening and the closing elements is controlled by the two boolean parameters
     * <code>openingElementIncluded</code> and <code>closingElementIncluded</code>.</p>
     * <p>Example:</p>
     * <pre>{@code
     *     Stream<String> stream = Stream.of("o", "a0", "a1", "a2", "c", "a3", "a4, "o", "a5", "c");
     *     Stream<Stream<String>> groupingStream = StreamsUtils.group(stream, "o"::equals, false, "c"::equals, false);
     *     List<List<String>> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a0", "a1", "a2"]["a5"]]
     * }</pre>
     * <p>If the provided stream is empty, then the returned stream contains an empty stream.</p>
     * <p>An <code>IllegalArgumentException</code> will also be thrown if the provided stream is not <code>ORDERED</code></p>
     * <p>The returned stream has the same characteristics as the provided stream, and is thus <code>ORDERED</code>.</p>
     *
     * @param stream                 The stream to be grouped. Will throw a <code>NullPointerException</code> if <code>null</code>.
     * @param open                   The predicate used to check for an opening element.
     * @param openingElementIncluded if true : includes the opening element in each substream
     * @param close                  The predicate used to check for an closing element.
     * @param closingElementIncluded if true : includes the closing element in each substream
     * @param <E>                    The type of the elements of the provided stream.
     * @return A grouped stream of streams.
     */
    public static <E> Stream<Stream<E>> group(
            Stream<E> stream,
            Predicate<? super E> open, boolean openingElementIncluded,
            Predicate<? super E> close, boolean closingElementIncluded) {
        Objects.requireNonNull(stream);
        Objects.requireNonNull(open);
        Objects.requireNonNull(close);
{'fraction_non_alphanumeric': 0.12625359136987044, 'fraction_numerical': 0.005746191792703421, 'mean_word_length': 3.319363146804027, 'pattern_counts': {'":': 8, '<': 339, '<?xml version=': 0, '>': 347, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3013263', 'n_tokens_mistral': 5385, 'n_tokens_neox': 5267, 'n_words': 1938}