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 static org.apiguardian.api.API.Status.INTERNAL; 030import static org.tquadrat.foundation.lang.Objects.isNull; 031import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 032 033import java.util.Spliterator; 034import java.util.function.Consumer; 035import java.util.function.Function; 036import java.util.function.Predicate; 037import java.util.function.Supplier; 038import java.util.stream.Stream; 039 040import org.apiguardian.api.API; 041import org.tquadrat.foundation.annotation.ClassVersion; 042import org.tquadrat.foundation.stream.Selector; 043 044/** 045 * A selector function takes an array of values and returns the respective 046 * array index for the selected value. See 047 * {@link org.tquadrat.foundation.stream.Selectors} 048 * for some implementations of this interface. 049 * 050 * @author Dominic Fox 051 * @modified Thomas Thrien - thomas.thrien@tquadrat.org 052 * @version $Id: InterleavingSpliterator.java 1060 2023-09-24 19:21:40Z tquadrat $ 053 * @since 0.0.7 054 * 055 * @param <T> The type of the values to select from. 056 * 057 * @UMLGraph.link 058 */ 059@ClassVersion( sourceVersion = "$Id: InterleavingSpliterator.java 1060 2023-09-24 19:21:40Z tquadrat $" ) 060@API( status = INTERNAL, since = "0.0.7" ) 061public final class InterleavingSpliterator<T> implements Spliterator<T> 062{ 063 /*------------*\ 064 ====** Attributes **======================================================= 065 \*------------*/ 066 /** 067 * The element buffer. 068 */ 069 private T [] m_Buffer = null; 070 071 /** 072 * The supplier for the element buffer. 073 */ 074 private final Supplier<T []> m_BufferSupplier; 075 076 /** 077 * The selector function. 078 */ 079 private final Function<T [],Integer> m_Selector; 080 081 /** 082 * The source spliterators. 083 */ 084 private final Spliterator<T> [] m_Spliterators; 085 086 /*--------------*\ 087 ====** Constructors **===================================================== 088 \*--------------*/ 089 /** 090 * Creates a new {@code InterleavingSpliterator} instance. 091 * 092 * @param spliterators The source spliterators. 093 * @param bufferSupplier The supplier for the element buffer. 094 * @param selector The selector function. 095 */ 096 private InterleavingSpliterator( final Spliterator<T> [] spliterators, final Supplier<T []> bufferSupplier, final Function<T [],Integer> selector ) 097 { 098 m_Spliterators = spliterators; 099 m_BufferSupplier = bufferSupplier; 100 m_Selector = selector; 101 } // InterleavingSpliterator() 102 103 /*---------*\ 104 ====** Methods **========================================================== 105 \*---------*/ 106 /** 107 * {@inheritDoc} 108 */ 109 @Override 110 public final int characteristics() 111 { 112 @SuppressWarnings( "ConstantExpression" ) 113 final var retValue = NONNULL & ORDERED & IMMUTABLE; 114 115 //---* Done *---------------------------------------------------------- 116 return retValue; 117 } // characteristics() 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override 123 public final long estimateSize() 124 { 125 final var retValue = Stream.of( m_Spliterators ).anyMatch( spliterator -> spliterator.estimateSize() == Long.MAX_VALUE ) 126 ? Long.MAX_VALUE 127 : Stream.of( m_Spliterators ).mapToLong( Spliterator::estimateSize ).sum(); 128 129 //---* Done *---------------------------------------------------------- 130 return retValue; 131 } // estimateSize() 132 133 /** 134 * {@inheritDoc} 135 */ 136 @Override 137 public final long getExactSizeIfKnown() 138 { 139 final var retValue = Stream.of( m_Spliterators ).allMatch( spliterator -> spliterator.hasCharacteristics( Spliterator.SIZED ) ) 140 ? Stream.of( m_Spliterators ).mapToLong( Spliterator::getExactSizeIfKnown ).sum() 141 : -1; 142 143 //---* Done *---------------------------------------------------------- 144 return retValue; 145 } // getExactSizeIfKnown() 146 147 /** 148 * Factory method for instances of {@code InterleavingSpliterator}. 149 * 150 * @param <T> The type of the values to select from. 151 * @param spliterators The source spliterators. 152 * @param selector The selector function. 153 * @return The interleaving spliterator. 154 */ 155 public static final <T> Spliterator<T> interleaving( final Spliterator<T> [] spliterators, final Selector<T> selector ) 156 { 157 final var bufferedValues = (Supplier<T[]>) () -> 158 { 159 @SuppressWarnings( {"unchecked", "SuspiciousArrayCast"} ) 160 final var values = (T []) new Object [spliterators.length]; 161 162 for( var i = 0; i < spliterators.length; ++i ) 163 { 164 final var stableIndex = i; 165 spliterators [i].tryAdvance( t -> values [stableIndex] = t ); 166 } 167 168 return values; 169 }; 170 171 final Spliterator<T> retValue = new InterleavingSpliterator<>( spliterators, bufferedValues, selector ); 172 173 //---* Done *---------------------------------------------------------- 174 return retValue; 175 } 176 177 /** 178 * {@inheritDoc} 179 */ 180 @Override 181 public final boolean tryAdvance( final Consumer<? super T> action ) 182 { 183 requireNonNullArgument( action, "action" ); 184 185 if( isNull( m_Buffer ) ) m_Buffer = m_BufferSupplier.get(); 186 187 final var retValue = !Stream.of( m_Buffer ).allMatch( Predicate.isEqual( null ) ); 188 189 if( retValue ) 190 { 191 final var selected = m_Selector.apply( m_Buffer ); 192 action.accept( m_Buffer [selected] ); 193 194 if( !m_Spliterators [selected].tryAdvance( t -> m_Buffer [selected] = t ) ) 195 { 196 //noinspection AssignmentToNull 197 m_Buffer [selected] = null; 198 } 199 } 200 201 //---* Done *---------------------------------------------------------- 202 return retValue; 203 } // tryAdvance() 204 205 /** 206 * {@inheritDoc} 207 */ 208 @Override 209 public final Spliterator<T> trySplit() { return null; } 210} 211// class InterleavingSpliterator 212 213/* 214 * End of File 215 */