001/*-
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.util;
021
022import com.google.common.collect.Iterators;
023import com.google.common.collect.UnmodifiableIterator;
024
025import java.util.Iterator;
026import java.util.List;
027import java.util.Spliterator;
028import java.util.Spliterators;
029import java.util.stream.Stream;
030import java.util.stream.StreamSupport;
031
032public class StreamUtil {
033        /** Static util class */
034        private StreamUtil() {}
035
036        /**
037         * Chunk the stream into Lists of size theChunkSize.
038         * The last chunk will be smaller unless the stream size is evenly divisible.
039         * Closes the underlying stream when done.
040         *
041         * @param theStream the input stream
042         * @param theChunkSize the chunk size.
043         * @return a stream of chunks
044         */
045        public static <T> Stream<List<T>> partition(Stream<T> theStream, int theChunkSize) {
046                Spliterator<T> spliterator = theStream.spliterator();
047                Iterator<T> iterator = Spliterators.iterator(spliterator);
048                UnmodifiableIterator<List<T>> partition = Iterators.partition(iterator, theChunkSize);
049
050                // we could be fancier here and support parallel, and sizes; but serial-only is fine for now.
051                Spliterator<List<T>> partitionedSpliterator = Spliterators.spliteratorUnknownSize(partition, 0);
052                Stream<List<T>> result = StreamSupport.stream(partitionedSpliterator, false);
053
054                // we lose close() via the Iterator.  Add it back.
055                return result.onClose(theStream::close);
056        }
057}