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.requireNonNullArgument;
031
032import java.util.ArrayList;
033import java.util.List;
034import java.util.Spliterator;
035import java.util.function.BiPredicate;
036import java.util.function.Consumer;
037
038import org.apiguardian.api.API;
039import org.tquadrat.foundation.annotation.ClassVersion;
040
041/**
042 *  An implementation of
043 *  {@link Spliterator}
044 *  that aggregates the elements of the stream based on a provided
045 *  {@link BiPredicate Predicate}.
046 *
047 *  @author Dominic Fox
048 *  @modified Thomas Thrien - thomas.thrien@tquadrat.org
049 *  @version $Id: AggregatingSpliterator.java 1060 2023-09-24 19:21:40Z tquadrat $
050 *  @since 0.0.7
051 *
052 *  @param  <I> The type of the stream elements.
053 *
054 *  @UMLGraph.link
055 */
056@ClassVersion( sourceVersion = "$Id: AggregatingSpliterator.java 1060 2023-09-24 19:21:40Z tquadrat $" )
057@API( status = INTERNAL, since = "0.0.7" )
058public class AggregatingSpliterator<I> implements Spliterator<List<I>>
059{
060        /*------------*\
061    ====** Attributes **=======================================================
062        \*------------*/
063    /**
064     *  The predicate.
065     */
066    private final BiPredicate<List<I>,I> m_Condition;
067
068    /**
069     *  The current slide.
070     */
071    private List<I> m_CurrentSlide = new ArrayList<>();
072
073    /**
074     *  The source.
075     */
076    private final Spliterator<I> m_Source;
077
078        /*--------------*\
079    ====** Constructors **=====================================================
080        \*--------------*/
081    /**
082     *  Creates a new {@code AggregatingSpliterator} instance.
083     *
084     *  @param  source  The source.
085     *  @param  predicate   The predicate.
086     */
087    public AggregatingSpliterator( final Spliterator<I> source, final BiPredicate<List<I>,I> predicate )
088    {
089        m_Source = requireNonNullArgument( source, "source" );
090        m_Condition = requireNonNullArgument( predicate, "predicate" );
091    }   //  AggregatingSpliterator()
092
093        /*---------*\
094    ====** Methods **==========================================================
095        \*---------*/
096    /**
097     *  {@inheritDoc}
098     */
099    @Override
100    public final int characteristics()
101    {
102        @SuppressWarnings( "ConstantExpression" )
103        final var retValue = m_Source.characteristics() & ~SIZED & ~CONCURRENT;
104
105        //---* Done *----------------------------------------------------------
106        return retValue;
107    }   //  characteristics()
108
109    /**
110     *  {@inheritDoc}
111     */
112    @Override
113    public final long estimateSize() { return m_Source.estimateSize(); }
114
115    /**
116     *  Checks whether the current element is on the current slide.
117     *
118     *  @param  currentElement  The current element.
119     *  @return {@code true} if the current element is on the current slide.
120     */
121    private boolean isSameSlide( final I currentElement )
122    {
123        return m_CurrentSlide.isEmpty() || m_Condition.test( m_CurrentSlide, currentElement );
124    }   //  isSameSlide()
125
126    /**
127     *  {@inheritDoc}
128     */
129    @Override
130    public final boolean tryAdvance( final Consumer<? super List<I>> action )
131    {
132        final var retValue = m_Source.tryAdvance( currentElement ->
133        {
134            if( !isSameSlide( currentElement ) )
135            {
136                action.accept( m_CurrentSlide );
137                m_CurrentSlide = new ArrayList<>();
138            }
139            m_CurrentSlide.add( currentElement );
140        });
141
142        if( !retValue && !m_CurrentSlide.isEmpty() )
143        {
144            action.accept( m_CurrentSlide );
145            m_CurrentSlide = new ArrayList<>();
146        }
147
148        //---* Done *----------------------------------------------------------
149        return retValue;
150    }   //  tryAdvance()
151
152    /**
153     *  {@inheritDoc}
154     */
155    @Override
156    public final Spliterator<List<I>> trySplit() { return null; }
157}
158//  class AggregatingSpliterator
159
160/*
161 *  End of File
162 */