001/*
002 * ============================================================================
003 * Copyright © 2002-2023 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 * Licensed to the public under the agreements of the GNU Lesser General Public
007 * License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *      http://www.gnu.org/licenses/lgpl.html
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 * License for the specific language governing permissions and limitations
015 * under the License.
016 */
017
018package org.tquadrat.foundation.util.internal;
019
020import static java.util.Collections.emptyIterator;
021import static org.apiguardian.api.API.Status.INTERNAL;
022import static org.tquadrat.foundation.lang.CommonConstants.EMPTY_Object_ARRAY;
023import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
024
025import java.util.Collection;
026import java.util.Iterator;
027import java.util.Set;
028import java.util.Spliterator;
029import java.util.Spliterators;
030import java.util.function.Consumer;
031import java.util.function.Predicate;
032import java.util.function.Supplier;
033
034import org.apiguardian.api.API;
035import org.tquadrat.foundation.annotation.ClassVersion;
036import org.tquadrat.foundation.lang.Lazy;
037import org.tquadrat.foundation.util.LazySet;
038
039/**
040 *  The implementation for
041 *  {@link LazySet}.
042 *
043 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
044 *  @version $Id: LazySetImpl.java 1060 2023-09-24 19:21:40Z tquadrat $
045 *  @since 0.0.5
046 *
047 *  @param  <E> The type of elements in this set.
048 *
049 *  @UMLGraph.link
050 */
051@ClassVersion( sourceVersion = "$Id: LazySetImpl.java 1060 2023-09-24 19:21:40Z tquadrat $" )
052@API( status = INTERNAL, since = "0.0.5" )
053public final class LazySetImpl<E> implements LazySet<E>
054{
055        /*------------*\
056    ====** Attributes **=======================================================
057        \*------------*/
058    /**
059     *  The holder for the real set.
060     */
061    private final Lazy<? extends Set<E>> m_Holder;
062
063    /**
064     *  The flag that indicates whether the provided supplier will put values
065     *  to the set on initialisation.
066     */
067    private final boolean m_SupplierPopulates;
068
069        /*--------------*\
070    ====** Constructors **=====================================================
071        \*--------------*/
072    /**
073     *  Creates a new {@code LazySetImpl} instance.
074     *
075     *  @param  doPopulate  {@code true} if the provided supplier will put
076     *      values to the set on initialisation, {@code false} if it will
077     *      create an empty set.
078     *  @param  supplier    The supplier that initialises the internal set
079     *      for this instance when it is first needed.
080     */
081    public LazySetImpl( final boolean doPopulate, final Supplier<? extends Set<E>> supplier )
082    {
083        m_Holder = Lazy.use( supplier );
084        m_SupplierPopulates = doPopulate;
085    }   //  LazySetImpl()
086
087    /**
088     *  Creates a new {@code LazySetImpl} instance that is initialised with the
089     *  given value.
090     *
091     *  @param  value   The initialisation value.
092     */
093    public LazySetImpl( final Set<E> value )
094    {
095        m_Holder = Lazy.of( value );
096        m_SupplierPopulates = true;
097    }   //  LazySetImpl()
098
099        /*---------*\
100    ====** Methods **==========================================================
101        \*---------*/
102    /**
103     *  {@inheritDoc}
104     */
105    @Override
106    public final boolean add( final E e ) { return m_Holder.get().add( e ); }
107
108    /**
109     *  {@inheritDoc}
110     */
111    @Override
112    public final boolean addAll( final Collection<? extends E> c )
113    {
114        final var retValue = !c.isEmpty() && m_Holder.get().addAll( c );
115
116        //---* Done *----------------------------------------------------------
117        return retValue;
118    }   //  addAll()
119
120    /**
121     *  {@inheritDoc}
122     */
123    @Override
124    public final void clear()
125    {
126        if( m_SupplierPopulates ) init();
127        m_Holder.ifPresent( Set::clear );
128    }   //  clear()
129
130    /**
131     *  {@inheritDoc}
132     */
133    @Override
134    public final boolean contains( final Object o )
135    {
136        @SuppressWarnings( "unlikely-arg-type" )
137        final var retValue = (m_Holder.isPresent() || m_SupplierPopulates) && m_Holder.get().contains( o );
138
139        //---* Done *----------------------------------------------------------
140        return retValue;
141    }   //  contains()
142
143    /**
144     *  {@inheritDoc}
145     */
146    @Override
147    public final boolean containsAll( final Collection<?> c )
148    {
149        java.util.Objects.requireNonNull( c );
150        @SuppressWarnings( "unlikely-arg-type" )
151        final var retValue = (m_Holder.isPresent() || m_SupplierPopulates) && m_Holder.get().containsAll( c );
152
153        //---* Done *----------------------------------------------------------
154        return retValue;
155    }   //  contains()
156
157    /**
158     *  {@inheritDoc}
159     */
160    @Override
161    public final boolean equals( final Object o )
162    {
163        var retValue = o == this;
164        if( !retValue && (o instanceof final Set<?> other) )
165        {
166            /*
167             * Collections are equal if their contents is equal. Refer to the
168             * respective Javadoc for equals().
169             */
170            if( isPresent() || m_SupplierPopulates )
171            {
172                retValue = m_Holder.get().equals( other );
173            }
174            else
175            {
176                retValue = other.isEmpty();
177            }
178        }
179
180        //---* Done *----------------------------------------------------------
181        return retValue;
182    }   //  equals()
183
184    /**
185     *  {@inheritDoc}
186     */
187    @Override
188    public final void forEach( final Consumer<? super E> action )
189    {
190        if( m_SupplierPopulates ) init();
191        java.util.Objects.requireNonNull( action );
192        m_Holder.ifPresent( set -> set.forEach( action ) );
193    }   //  forEach()
194
195    /**
196     *  {@inheritDoc}
197     */
198    @Override
199    public final int hashCode() { return m_Holder.hashCode(); }
200
201    /**
202     *  {@inheritDoc}
203     */
204    @Override
205    public void ifPresent( final Consumer<? super Set<E>> consumer )
206    {
207        if( m_Holder.isPresent() ) requireNonNullArgument( consumer, "consumer" ).accept( m_Holder.get() );
208    }   //  ifPresent()
209    /**
210     *  {@inheritDoc}
211     */
212    @Override
213    public final void init() { m_Holder.get(); }
214
215    /**
216     *  {@inheritDoc}
217     */
218    @Override
219    public final boolean isEmpty() { return (!m_Holder.isPresent() && !m_SupplierPopulates) || m_Holder.get().isEmpty(); }
220
221    /**
222     *  {@inheritDoc}
223     */
224    @Override
225    public final boolean isPresent() { return m_Holder.isPresent(); }
226
227    /**
228     *  {@inheritDoc}
229     */
230    @Override
231    public final Iterator<E> iterator()
232    {
233        if( m_SupplierPopulates ) init();
234        final var retValue = m_Holder.map( Set::iterator ).orElse( emptyIterator() );
235
236        //---* Done *----------------------------------------------------------
237        return retValue;
238    }   //  iterator()
239
240    /**
241     *  {@inheritDoc}
242     */
243    @SuppressWarnings( "unlikely-arg-type" )
244    @Override
245    public final boolean remove( final Object o ) { return (m_Holder.isPresent() || m_SupplierPopulates) && m_Holder.get().remove( o ); }
246
247    /**
248     *  {@inheritDoc}
249     */
250    @SuppressWarnings( "unlikely-arg-type" )
251    @Override
252    public final boolean removeAll( final Collection<?> c )
253    {
254        java.util.Objects.requireNonNull( c );
255        final var retValue = (m_Holder.isPresent() || m_SupplierPopulates) && m_Holder.get().removeAll( c );
256
257        //---* Done *----------------------------------------------------------
258        return retValue;
259    }   //  removeAll()
260
261    /**
262     *  {@inheritDoc}
263     */
264    @Override
265    public final boolean removeIf( final Predicate<? super E> filter )
266    {
267        final var retValue = (m_Holder.isPresent() || m_SupplierPopulates) && m_Holder.get().removeIf( filter );
268
269        //---* Done *----------------------------------------------------------
270        return retValue;
271    }   //  removeIf()
272
273    /**
274     *  {@inheritDoc}
275     */
276    @Override
277    public final boolean retainAll( final Collection<?> c )
278    {
279        java.util.Objects.requireNonNull( c );
280        @SuppressWarnings( "unlikely-arg-type" )
281        final var retValue = (m_Holder.isPresent() || m_SupplierPopulates) && m_Holder.get().retainAll( c );
282
283        //---* Done *----------------------------------------------------------
284        return retValue;
285    }   //  retainAll()
286
287    /**
288     *  {@inheritDoc}
289     */
290    @Override
291    public final int size() { return (m_Holder.isPresent() || m_SupplierPopulates) ? m_Holder.get().size() : 0; }
292
293    /**
294     *  {@inheritDoc}
295     */
296    @Override
297    public final Spliterator<E> spliterator()
298    {
299        if( m_SupplierPopulates ) init();
300        final var retValue = m_Holder.map( set -> Spliterators.spliterator( set, Spliterator.DISTINCT ) ).orElse( Spliterators.emptySpliterator() );
301
302        //---* Done *----------------------------------------------------------
303        return retValue;
304    }   //  spliterator()
305
306    /**
307     *  {@inheritDoc}
308     */
309    @Override
310    public final Object [] toArray()
311    {
312        if( m_SupplierPopulates ) init();
313        final var retValue = m_Holder.map( Set::toArray ).orElse( EMPTY_Object_ARRAY );
314
315        //---* Done *----------------------------------------------------------
316        return retValue;
317    }   //  toArray()
318
319    /**
320     *  {@inheritDoc}
321     */
322    @Override
323    public final <T> T [] toArray( final T [] a )
324    {
325        var retValue = a;
326        if( m_Holder.isPresent() || m_SupplierPopulates )
327        {
328            retValue = m_Holder.get().toArray( a );
329        }
330        else
331        {
332            if( retValue.length > 0 ) //noinspection AssignmentToNull
333                retValue [0] = null;
334        }
335
336        //---* Done *----------------------------------------------------------
337        return retValue;
338    }   //  toArray()
339
340    /**
341     *  {@inheritDoc}
342     */
343    @Override
344    public final String toString()
345    {
346        final var retValue = (m_Holder.isPresent() || m_SupplierPopulates) ? m_Holder.getAsString() : "[Not initialized]";
347
348        //---* Done *----------------------------------------------------------
349        return retValue;
350    }   //  toString()
351}
352//  class LazySetImpl
353
354/*
355 *  End of File
356 */