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.Optional;
033import java.util.Spliterator;
034import java.util.function.Consumer;
035import java.util.function.Function;
036
037import org.apiguardian.api.API;
038import org.tquadrat.foundation.annotation.ClassVersion;
039
040/**
041 *  An implementation of
042 *  {@link Spliterator}
043 *  that which takes a seed value and applies a generator to create the next
044 *  value, feeding each new value back into the generator to create subsequent
045 *  values. If the generator returns
046 *  {@link Optional#empty()},
047 *  then there are no more values.
048 *
049 *  @author Dominic Fox
050 *  @modified Thomas Thrien - thomas.thrien@tquadrat.org
051 *  @version $Id: UnfoldSpliterator.java 1060 2023-09-24 19:21:40Z tquadrat $
052 *  @since 0.0.7
053 *
054 *  @param  <T> The type of the stream elements.
055 *
056 *  @UMLGraph.link
057 */
058@ClassVersion( sourceVersion = "$Id: UnfoldSpliterator.java 1060 2023-09-24 19:21:40Z tquadrat $" )
059@API( status = INTERNAL, since = "0.0.7" )
060public final class UnfoldSpliterator<T> implements Spliterator<T>
061{
062        /*------------*\
063    ====** Attributes **=======================================================
064        \*------------*/
065    /**
066     *  The current value.
067     */
068    @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" )
069    private Optional<T> m_Current;
070
071    /**
072     *  The generator.
073     */
074    private final Function<T,Optional<T>> m_Generator;
075
076        /*--------------*\
077    ====** Constructors **=====================================================
078        \*--------------*/
079    /**
080     *  Creates a new {@code UnfoldSpliterator} instance.
081     *
082     *  @param  seed    The initial value;may be {@code null}.
083     *  @param  generator   The generator.
084     */
085    private UnfoldSpliterator( final T seed, final Function<T,Optional<T>> generator )
086    {
087        m_Current = Optional.of( seed );
088        m_Generator = requireNonNullArgument( generator, "generator" );
089    }   //  UnfoldSpliterator()
090
091        /*---------*\
092    ====** Methods **==========================================================
093        \*---------*/
094    /**
095     *  {@inheritDoc}
096     */
097    @Override
098    public final int characteristics()
099    {
100        @SuppressWarnings( "ConstantExpression" )
101        final var retValue = IMMUTABLE & NONNULL & ORDERED;
102
103        //---* Done *----------------------------------------------------------
104        return retValue;
105    }   //  characteristics()
106
107    /**
108     *  {@inheritDoc}
109     */
110    @Override
111    public final long estimateSize() { return Long.MAX_VALUE; }
112
113    /**
114     *  Factory for instances of {@code UnfoldSpliterator}.
115     *
116     *  @param  <T> The type of the stream elements.
117     *  @param  seed    The initial value;may be {@code null}.
118     *  @param  generator   The generator.
119     *  @return The new instance.
120     */
121    public static final <T> UnfoldSpliterator<T> over( final T seed, final Function<T,Optional<T>> generator )
122    {
123        final var retValue = new UnfoldSpliterator<>( seed, generator );
124
125        //---* Done *----------------------------------------------------------
126        return retValue;
127    }   //  over
128
129    /**
130     *  {@inheritDoc}
131     */
132    @Override
133    public final boolean tryAdvance( final Consumer<? super T> action )
134    {
135        m_Current.ifPresent( action );
136        m_Current = m_Current.flatMap( m_Generator );
137        final var retValue = m_Current.isPresent();
138
139        //---* Done *----------------------------------------------------------
140        return retValue;
141    }   //  tryAdvance()
142
143    /**
144     *  {@inheritDoc}
145     */
146    @Override
147    public Spliterator<T> trySplit() { return null; }
148}
149//  class UnfoldSpliterator
150
151/*
152 *  End of File
153 */