001/* 002 * ============================================================================ 003 * Copyright © 2014 by Dominic Fox. 004 * All Rights Reserved. 005 * ============================================================================ 006 * The MIT License (MIT) 007 * 008 * Permission is hereby granted, free of charge, to any person obtaining a copy 009 * of this software and associated documentation files (the "Software"), to 010 * deal in the Software without restriction, including without limitation the 011 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 012 * sell copies of the Software, and to permit persons to whom the Software is 013 * furnished to do so, subject to the following conditions: 014 * 015 * The above copyright notice and this permission notice shall be included in 016 * all copies or substantial portions of the Software. 017 * 018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 020 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE 021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 022 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 023 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 024 * IN THE SOFTWARE. 025 */ 026 027package org.tquadrat.foundation.stream.internal; 028 029import org.apiguardian.api.API; 030import org.tquadrat.foundation.annotation.ClassVersion; 031 032import java.util.ArrayList; 033import java.util.List; 034import java.util.Spliterator; 035import java.util.function.BiFunction; 036import java.util.function.Consumer; 037import java.util.function.Supplier; 038import java.util.stream.Stream; 039 040import static org.apiguardian.api.API.Status.INTERNAL; 041import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 042 043/** 044 * An implementation of 045 * {@link Spliterator} 046 * that merges streams. 047 * 048 * @author Dominic Fox 049 * @modified Thomas Thrien - thomas.thrien@tquadrat.org 050 * @version $Id: MergingSpliterator.java 1119 2024-03-16 09:03:57Z tquadrat $ 051 * @since 0.0.7 052 * 053 * @param <T> The type over which the merged streams stream. 054 * @param <O> The type of the accumulator, over which the constructed 055 * stream streams. 056 * 057 * @UMLGraph.link 058 */ 059@ClassVersion( sourceVersion = "$Id: MergingSpliterator.java 1119 2024-03-16 09:03:57Z tquadrat $" ) 060@API( status = INTERNAL, since = "0.0.7" ) 061public final class MergingSpliterator<T,O> implements Spliterator<O> 062{ 063 /*------------*\ 064 ====** Attributes **======================================================= 065 \*------------*/ 066 /** 067 * The merger function. 068 */ 069 private final BiFunction<O,T,O> m_Merger; 070 071 /** 072 * The sources. 073 */ 074 private final Spliterator<T> [] m_Sources; 075 076 /** 077 * The unit supplier. 078 */ 079 private final Supplier<O> m_UnitSupplier; 080 081 /*--------------*\ 082 ====** Constructors **===================================================== 083 \*--------------*/ 084 /** 085 * Creates a new {@code MergingSpliterator} instance. 086 * 087 * @param sources The sources. 088 * @param unitSupplier Supplies the initial "zero" or 089 * "unit" value for the accumulator. 090 * @param merger Merges each item from the collection of values taken 091 * from the source streams into the accumulator value. 092 */ 093 private MergingSpliterator( final Spliterator<T> [] sources, final Supplier<O> unitSupplier, final BiFunction<O,T,O> merger ) 094 { 095 m_Sources = requireNonNullArgument( sources, "sources" ); 096 m_UnitSupplier = requireNonNullArgument( unitSupplier, "unitSupplier" ); 097 m_Merger = requireNonNullArgument( merger, "merger" ); 098 } // MergingSpliterator() 099 100 /*---------*\ 101 ====** Methods **========================================================== 102 \*---------*/ 103 /** 104 * {@inheritDoc} 105 */ 106 @Override 107 public final int characteristics() 108 { 109 @SuppressWarnings( "ConstantExpression" ) 110 final var retValue = NONNULL & ORDERED & IMMUTABLE; 111 112 //---* Done *---------------------------------------------------------- 113 return retValue; 114 } // characteristics() 115 116 /** 117 * {@inheritDoc} 118 */ 119 @Override 120 public final long estimateSize() 121 { 122 final long retValue = Stream.of( m_Sources ) 123 .map( Spliterator::estimateSize ) 124 .max( Long::compare ) 125 .orElse( 0L ); 126 127 //---* Done *---------------------------------------------------------- 128 return retValue; 129 } // estimateSize() 130 131 /** 132 * Factory method for instances of {@code MergingSpliterator}. 133 * 134 * @param <O> The type of the elements in the resulting spliterator. 135 * @param <T> The type of the elements in the source spliterators. 136 * @param sources The sources. 137 * @param unitSupplier Supplies the initial "zero" or 138 * "unit" value for the accumulator. 139 * @param merger Merges each item from the collection of values taken 140 * from the source streams into the accumulator value. 141 * @return The new instance. 142 */ 143 public static final <T,O> Spliterator<O> merging( final Spliterator<T> [] sources, final Supplier<O> unitSupplier, final BiFunction<O,T,O> merger ) 144 { 145 final Spliterator<O> retValue = new MergingSpliterator<>( sources, unitSupplier, merger ); 146 147 //---* Done *---------------------------------------------------------- 148 return retValue; 149 } // merging() 150 151 /** 152 * {@inheritDoc} 153 */ 154 @Override 155 public final boolean tryAdvance( final Consumer<? super O> action ) 156 { 157 final List<T> mergeables = new ArrayList<>( m_Sources.length ); 158 Stream.of( m_Sources ) 159 .forEach( spliterator -> spliterator.tryAdvance( mergeables::add ) ); 160 161 final var retValue = !mergeables.isEmpty(); 162 if( retValue ) 163 { 164 final var unit = m_UnitSupplier.get(); 165 166 //---* We never do this in parallel, so fuck it *------------------ 167 action.accept( mergeables.stream().reduce( unit, m_Merger, (l1,l2) -> l1 ) ); 168 } 169 170 //---* Done *---------------------------------------------------------- 171 return retValue; 172 } // tryAdvance() 173 174 /** 175 * {@inheritDoc} 176 */ 177 @Override 178 public final Spliterator<O> trySplit() { return null; } 179} 180// class MergingSpliterator 181 182/* 183 * End of File 184 */