001/*
002* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
003* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004*
005* This code is free software; you can redistribute it and/or modify it
006* under the terms of the GNU General Public License version 2 only, as
007* published by the Free Software Foundation.  Oracle designates this
008* particular file as subject to the "Classpath" exception as provided
009* by Oracle in the LICENSE file that accompanied this code.
010*
011* This code is distributed in the hope that it will be useful, but WITHOUT
012* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014* version 2 for more details (a copy is included in the LICENSE file that
015* accompanied this code).
016*
017* You should have received a copy of the GNU General Public License version
018* 2 along with this work; if not, write to the Free Software Foundation,
019* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020*
021* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022* or visit www.oracle.com if you need additional information or have any
023* questions.
024*/
025
026package Torello.Java.ReadOnly;
027
028import Torello.Java.Additional.RemoveUnsupportedIterator;
029import Torello.JavaDoc.LinkJavaSource;
030
031import java.util.function.*;
032
033import java.util.*;
034
035import java.util.stream.Collector;
036
037import java.io.Serializable;
038
039/**
040 * Immutable Wrapper for <CODE>java&#46;util&#46;ArrayList</CODE>, found in the "Java Collections
041 * Framework".
042 * 
043 * <EMBED CLASS=globalDefs DATA-JDK=ArrayList>
044 * <EMBED CLASS='external-html' DATA-FILE-ID=MUCHOS_CONSTRUCTORS>
045 * <EMBED CLASS='external-html' DATA-FILE-ID=DATA_CLASS>
046 * 
047 * @param <E> the type of elements in this list
048 */
049@SuppressWarnings("unchecked")
050@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_MAIN")
051public class ReadOnlyArrayList<E> implements ReadOnlyList<E>, RandomAccess, Serializable
052{
053    // ********************************************************************************************
054    // ********************************************************************************************
055    // Protected & Private Fields, Methods, Statics
056    // ********************************************************************************************
057    // ********************************************************************************************
058
059
060    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
061    protected static final long serialVersionUID = 1;
062
063    // Minor Optimization where new ArrayList's that have no contents always re-use this static
064    // instance.  Since this instance is completely empty, the Raw-Types things is irrelevant.
065
066    @SuppressWarnings("rawtypes")
067    private static final ArrayList EMPTY_ARRAY_LIST = new ArrayList(0);
068
069    // Singleton & Empty ReadOnlyArrayList, Uses the "Supplier Constructor"
070    @SuppressWarnings("rawtypes")
071    private static final ReadOnlyArrayList EMPTY_READONLY_ARRAY_LIST =
072        new ReadOnlyArrayList(0, () -> null);
073
074    // The actual ArrayList used by this instance.
075    private final ArrayList<E> arrayList;
076
077    // TRUE     => This was built using the class ROArrayListBuilder
078    // FALSE    => This was built using the clone() of a standard java.util.ArrayList constructor
079
080    private final boolean fromBuilderOrArrayList;
081
082    // Mimics the C++ Keyword/Concept of "Friend Class".   Is "Friends With" ROArrayListBuilder
083    static class AccessBadge { private AccessBadge() { } }
084    private static final AccessBadge friendClassBadge = new AccessBadge();
085
086    /**
087     * Returns an empty, <B STYLE='color: red;'>singleton</B>, instance of
088     * {@code ReadOnlyArrayList}.
089     * 
090     * @param <T> Returned {@link ReadOnlyList}'s Data-Type.
091     * 
092     * @return An empty list.  Since this list is both empty &amp; read-only, a raw-type singleton 
093     * will suffice for all operations offered by this clas.
094     * 
095     * <EMBED CLASS='external-html' DATA-FILE-ID=EMPTY_SYNCHRONIZED>
096     */
097    public static <T> ReadOnlyArrayList<T> emptyROAL()
098    { return (ReadOnlyArrayList<T>) EMPTY_READONLY_ARRAY_LIST; }
099
100
101    // ********************************************************************************************
102    // ********************************************************************************************
103    // Basic Constructors
104    // ********************************************************************************************
105    // ********************************************************************************************
106
107
108    // To all the readers out there following along: The "AccessBadge" thing is just a slightly
109    // wimpier substitute for the C++ keyword / concept 'friend' or "Friend Class".  It means this
110    // constructor is (for all intents and purposes) a private-constructor, except for the class
111    // ROArrayListBuilder
112    //
113    // This is the Constructor used by the Builder.  It has a "Zero-Size" Optimization
114
115    ReadOnlyArrayList(ROArrayListBuilder<E> roalb, ROArrayListBuilder.AccessBadge badge)
116    {
117        Objects.requireNonNull(badge, "Access Badge is null.  Requires Friend-Class Badge");
118
119        fromBuilderOrArrayList = true;
120        this.arrayList = roalb;
121    }
122
123    /**
124     * Copies parameter {@code 'c'} (and saves it) in order to guarantee that {@code 'this'}
125     * instance is Read-Only, and shielded from outside modification.
126     * 
127     * @param c The {@code Collection} to be copied and saved into this instance internal
128     * and private {@code 'arrayList'} field.
129     */
130    public ReadOnlyArrayList(Collection<E> c)
131    {
132        fromBuilderOrArrayList = false;
133
134        // Empty Optimization (throw away, completely, the reference, use static-constant)
135        this.arrayList = (c.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : new ArrayList<>(c);
136    }
137
138    /**
139     * Use a {@code Supplier<E>} to provide an arbitrary number of elements of type {@code 'E'} 
140     * directly to this constructor.  This constructor will request elements from the
141     * {@code Supplier} provided to parameter {@code 's'} until {@code 's'} returns null.
142     *
143     * <EMBED CLASS=defs DATA-SOURCE=Supplier>
144     * 
145     * @param quantityIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
146     * @param s Any Java {@code Supplier<E>}
147     * @throws IllegalArgumentException if the specified quantity / capacity is negative
148     */
149    public ReadOnlyArrayList(Integer quantityIfKnown, Supplier<E> s)
150    {
151        fromBuilderOrArrayList = false;
152
153        final ArrayList<E> arrayList = (quantityIfKnown != null)
154            ? new ArrayList<>(quantityIfKnown)
155            : new ArrayList<>();
156
157        E e;
158        while ((e = s.get()) != null) arrayList.add(e);
159
160        // Empty Optimization (throw away, completely, the reference, use static-constant)
161        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
162    }
163
164
165    // ********************************************************************************************
166    // ********************************************************************************************
167    // Iterable & Array Based Constructors - **NO FILTER**
168    // ********************************************************************************************
169    // ********************************************************************************************
170
171
172    /**
173     * If only a small amount of processing needs to be done on the contents of some Java
174     * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this
175     * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyArrayList}, using
176     * a simple {@code 'mapper'}</I>.
177     * 
178     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
179     * 
180     * @param <T>           <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM>
181     * @param i             Any Java {@code Iterable<T>}
182     * @param mapper        <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER>
183     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
184     * 
185     * @throws NullPointerException if either {@code 'i'} or {@code 'mapper'} are passed null
186     */
187    public <T> ReadOnlyArrayList(
188            Iterable<T> i,
189            Function<? super T, ? extends E> mapper,
190            Integer sizeIfKnown)
191    {
192        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
193
194        fromBuilderOrArrayList = false;
195
196        final ArrayList<E> arrayList = (sizeIfKnown != null)
197            ? new ArrayList<>(sizeIfKnown)
198            : new ArrayList<>();
199
200        for (T t : i) arrayList.add(mapper.apply(t));
201
202        // Empty Optimization (throw away, completely, the reference, use static-constant)
203        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
204    }
205
206    /**
207     * If a Standard Java {@code Iterable} can be directly mapped into an {@code ArrayList}
208     * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will
209     * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyArrayList<E>}
210     * with just this single invocation</I>.
211     *
212     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
213     * 
214     * @param i             Any Java {@code Iterable<E>}
215     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
216     * 
217     * @throws IllegalArgumentException if the specified initial capacity is negative
218     */
219    public ReadOnlyArrayList(Iterable<E> i, Integer sizeIfKnown)
220    {
221        fromBuilderOrArrayList = false;
222
223        final ArrayList<E> arrayList = (sizeIfKnown != null)
224            ? new ArrayList<>(sizeIfKnown)
225            : new ArrayList<>();
226
227        for (E element : i) arrayList.add(element);
228
229        // Empty Optimization (throw away, completely, the reference, use static-constant)
230        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
231    }
232
233    /**
234     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
235     * {@code 'elements'}.
236     * 
237     * @param elementsType  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE>
238     * @param elements      <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
239     * 
240     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=CCEX>
241     * @throws NullPointerException If {@code 'elementsType'} is passed null.
242     */
243    public ReadOnlyArrayList(Class<E> elementsType, Object... elements)
244    {
245        Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'");
246
247        fromBuilderOrArrayList = false;
248
249        if (elements.length == 0)
250            this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST;
251
252        else 
253        {
254            this.arrayList = new ArrayList<>(elements.length);
255            for (Object element : elements) this.arrayList.add(elementsType.cast(element));
256        }
257    }
258
259    /**
260     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
261     * {@code 'elements'}.
262     * 
263     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER>
264     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
265     * 
266     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=CCEX>
267     * @throws NullPointerException If {@code 'mapper'} is passed null.
268     */
269    public ReadOnlyArrayList(Function<Object, ? extends E> mapper, Object... elements)
270    {
271        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
272
273        fromBuilderOrArrayList = false;
274
275        if (elements.length == 0)
276            this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST;
277
278        else 
279        {
280            this.arrayList = new ArrayList<>(elements.length);
281            for (Object element : elements) this.arrayList.add(mapper.apply(element));
282        }
283    }
284
285
286    // ********************************************************************************************
287    // ********************************************************************************************
288    // Iterable & Array Based Constructors - **INCLUDES ELEMENT FILTER**
289    // ********************************************************************************************
290    // ********************************************************************************************
291
292
293    /**
294     * If only a small amount of processing needs to be done on the contents of some Java
295     * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this
296     * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyArrayList}, using
297     * a simple {@code 'mapper'}</I>.
298     * 
299     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
300     * 
301     * @param <T>           <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM>
302     * @param i             Any Java {@code Iterable<T>}
303     * @param mapper        <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER>
304     * @param filter        <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER>
305     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
306     * 
307     * @throws NullPointerException if any of {@code 'i'}, {@code 'mapper'} or {@code 'filter'}
308     * are passed null.
309     */
310    public <T> ReadOnlyArrayList(
311            Iterable<T>                         i,
312            Function<? super T, ? extends E>    mapper,
313            Predicate<? super T>                filter,
314            Integer                             sizeIfKnown
315        )
316    {
317        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
318        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
319
320        fromBuilderOrArrayList = false;
321
322        final ArrayList<E> arrayList = (sizeIfKnown != null)
323            ? new ArrayList<>(sizeIfKnown)
324            : new ArrayList<>();
325
326        for (T t : i) if (filter.test(t)) arrayList.add(mapper.apply(t));
327
328        // Empty Optimization (throw away, completely, the reference, use static-constant)
329        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
330    }
331
332    /**
333     * If a Standard Java {@code Iterable} can be directly mapped into an {@code ArrayList}
334     * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will
335     * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyArrayList<E>}
336     * with just this single invocation</I>.
337     *
338     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
339     * 
340     * @param i             Any Java {@code Iteratable<E>}
341     * @param filter        <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER>
342     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
343     * 
344     * @throws IllegalArgumentException if the specified initial capacity is negative
345     * @throws NullPointerException     if either {'i'} or {@code 'filter'} are passed null
346     */
347    public ReadOnlyArrayList(Iterable<E> i, Predicate<? super E> filter, Integer sizeIfKnown)
348    {
349        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
350
351        fromBuilderOrArrayList = false;
352
353        final ArrayList<E> arrayList = (sizeIfKnown != null)
354            ? new ArrayList<>(sizeIfKnown)
355            : new ArrayList<>();
356
357        for (E element : i) if (filter.test(element)) arrayList.add(element);
358
359        // Empty Optimization (throw away, completely, the reference, use static-constant)
360        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
361    }
362
363    /**
364     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
365     * {@code 'elements'}.
366     * 
367     * @param elementsType  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE>
368     * @param filter        <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER>
369     * @param elements      <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
370     * 
371     * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX>
372     * 
373     * @throws NullPointerException If either {@code 'elementsType'} or {@code 'filter'} are
374     * passsed null.
375     */
376    public ReadOnlyArrayList
377        (Class<E> elementsType, Predicate<? super E> filter, Object... elements)
378    {
379        Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'");
380        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
381
382        fromBuilderOrArrayList = false;
383
384        final ArrayList<E> arrayList = new ArrayList<>(elements.length);
385
386        E e;
387        for (Object element : elements)
388            if (filter.test(e = elementsType.cast(element)))
389                arrayList.add(e);
390
391        // Empty Optimization (throw away, completely, the reference, use static-constant)
392        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
393    }
394
395    /**
396     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
397     * {@code 'elements'}.
398     * 
399     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER>
400     * @param filter    <EMBED CLASS='external-html' DATA-FTP=Object DATA-FILE-ID=PREDICATE_FILTER>
401     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
402     * 
403     * @throws NullPointerException If either {@code 'mapper'} or {@code 'filter'} are passed null
404     */
405    public ReadOnlyArrayList
406        (Function<Object, ? extends E> mapper, Predicate<Object> filter, Object... elements)
407    {
408        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
409        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
410
411        fromBuilderOrArrayList = false;
412
413        final ArrayList<E> arrayList = new ArrayList<>(elements.length);
414
415        for (Object element : elements)
416            if (filter.test(element))
417                arrayList.add(mapper.apply(element));
418
419        // Empty Optimization (throw away, completely, the reference, use static-constant)
420        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
421    }
422
423
424    // ********************************************************************************************
425    // ********************************************************************************************
426    // @SafeVarargs / Variable-Arity / VarArgs: with Parameterized / Generic Type's
427    // ********************************************************************************************
428    // ********************************************************************************************
429
430
431    /**
432     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
433     * {@code 'elements'}.
434     * 
435     * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
436     */
437    @SafeVarargs
438    public ReadOnlyArrayList(E... elements)
439    {
440        fromBuilderOrArrayList = false;
441
442        if (elements.length == 0)
443            this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST;
444
445        else 
446        {
447            this.arrayList = new ArrayList<>(elements.length);
448            for (E e : elements) this.arrayList.add(e);
449        }
450    }
451
452    /**
453     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
454     * {@code 'elements'}.
455     * 
456     * @param <T>       <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM>
457     * @param dummy     <EMBED CLASS='external-html' DATA-FILE-ID=DUMMY_INT>
458     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER>
459     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
460     * 
461     * @throws NullPointerException If {@code 'mapper'} is passed null.
462     */
463    @SafeVarargs
464    public <T> ReadOnlyArrayList(
465            int                                 dummy,
466            Function<? super T, ? extends E>    mapper,
467            T...                                elements
468        )
469    {
470        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
471
472        fromBuilderOrArrayList = false;
473
474        if (elements.length == 0)
475            this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST;
476
477        else 
478        {
479            this.arrayList = new ArrayList<>(elements.length);
480            for (T t : elements) this.arrayList.add(mapper.apply(t));
481        }
482    }
483
484    /**
485     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
486     * {@code 'elements'}.
487     * 
488     * @param filter    <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER>
489     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
490     * 
491     * @throws NullPointerException If {@code 'filter'} is passsed null.
492     */
493    @SafeVarargs
494    public ReadOnlyArrayList(Predicate<? super E> filter, E... elements)
495    {
496        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
497
498        fromBuilderOrArrayList = false;
499
500        final ArrayList<E> arrayList = new ArrayList<>(elements.length);
501        for (E e : elements) if (filter.test(e)) arrayList.add(e);
502
503        // Empty Optimization (throw away, completely, the reference, use static-constant)
504        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
505    }
506
507    /**
508     * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents
509     * {@code 'elements'}.
510     * 
511     * @param <T>       <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM>
512     * @param filter    <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER>
513     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER>
514     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
515     * 
516     * @throws NullPointerException If either {@code 'mapper'} or {@code 'filter'} are passed null
517     */
518    @SafeVarargs
519    public <T> ReadOnlyArrayList(
520            Predicate<? super T>                filter,
521            Function<? super T, ? extends E>    mapper,
522            T...                                elements
523        )
524    {
525        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
526        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
527
528        fromBuilderOrArrayList = false;
529
530        final ArrayList<E> arrayList = new ArrayList<>(elements.length);
531        for (T t : elements) if (filter.test(t)) arrayList.add(mapper.apply(t));
532
533        // Empty Optimization (throw away, completely, the reference, use static-constant)
534        this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList;
535    }
536
537
538    // ********************************************************************************************
539    // ********************************************************************************************
540    // PRIMITIVE-ARRAY INPUT
541    // ********************************************************************************************
542    // ********************************************************************************************
543
544
545    /**
546     * Converts a Java Primitive-Array to a {@code ReadOnlyArrayList<E>}, where {@code 'E'} is the
547     * Java Boxed-Type which corresponds to the Primitive-Array's Type.
548     * 
549     * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC>
550     * @param primitiveArray        <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY>
551     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX>
552     * @throws NullPointerException If {@code 'primitiveArray'} is passed null;
553     */
554    @LinkJavaSource(handle="ROHelperPrimitiveArrays", name="buildROListOrSet")
555    public ReadOnlyArrayList(Object primitiveArray)
556    {
557        fromBuilderOrArrayList = false;
558
559        final ArrayList<E> al = ROHelperPrimitiveArrays.buildROListOrSet(
560            primitiveArray,
561            (int arrayLen) -> new ArrayList<E>(arrayLen),
562            null
563        );
564
565        // Empty Optimization (throw away, completely, the reference, use static-constant)
566        this.arrayList = (al.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : al;
567    }
568
569    /**
570     * Converts a Java Primitive-Array to a {@code ReadOnlyArrayList<E>}, where {@code 'E'} is the
571     * Java Boxed-Type which corresponds to the Primitive-Array's Type - <I>but also accepts a 
572     * {@code 'filter'} that can remove any array-entries that need to be removed</I>.
573     * 
574     * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC>
575     * @param primitiveArray        <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY>
576     * @param filter                <EMBED CLASS='external-html' DATA-FILE-ID=PRED_FILT_PRIM>
577     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX>
578     * @throws NullPointerException If {@code 'primitiveArray'} is passed null;
579     */
580    @LinkJavaSource(handle="ROHelperPrimitiveArrays", name="buildROListOrSet")
581    public ReadOnlyArrayList(
582            Object          primitiveArray,
583            Predicate<?>    filter
584        )
585    {
586        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
587
588        fromBuilderOrArrayList = false;
589
590        final ArrayList<E> al = ROHelperPrimitiveArrays.buildROListOrSet(
591            primitiveArray,
592            (int arrayLen) -> new ArrayList<E>(arrayLen),
593            filter
594        );
595
596        // Empty Optimization (throw away, completely, the reference, use static-constant)
597        this.arrayList = (al.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : al;
598    }
599
600
601    // ********************************************************************************************
602    // ********************************************************************************************
603    // java.util.stream.Stream HELPER
604    // ********************************************************************************************
605    // ********************************************************************************************
606
607
608    /**
609     * For use with a the Java Stream method {@code 'collect(Collector c)'}.
610     * 
611     * <EMBED CLASS='external-html' DATA-ABBREV=al DATA-FILE-ID=STREAM_COLLECTOR>
612     * 
613     * @param <T> This is the Generic-Type of the Input-Stream.  It will also be the Generic-Type
614     * of the {@code ReadOnlyArrayList} that's returned from the stream's {@code collect} method.
615     * 
616     * @param characteristics Optional Characteristics List.  See Java Stream-API Documentation on
617     * {@code Collector.Characteristics} inner-class for more details.
618     * 
619     * @return This returns a collector that may be piped into a stream's {@code 'collect'} method,
620     * as in the example, above.
621     */
622    public static <T> java.util.stream.Collector
623        <T, ROArrayListBuilder<T>, ReadOnlyArrayList<T>>
624        streamCollector(Collector.Characteristics... characteristics)
625    {
626        return Collector.of(
627            ROArrayListBuilder<T>::new,    // The "Supplier"    (builds a new ROArrayListBuilder)
628            ROArrayListBuilder<T>::add,    // The "Accumulator" (adds elements to the builder)
629
630            // Oracle Making Life Difficult - It should be the line below, but, alas, it is not!
631            // ROArrayListBuilder<T>::addAll, // The "Combiner" (combines two  ROArrayListBuilders)
632            //
633            // In Stream.collect(), the 3rd parameter - the "combiner" - is a "BiConsumer<R, R>"
634            // NOTE: A "BiConsumer" is a FunctionalInterface that does not return anything - it is
635            // (obviously) a "void" return method!
636            //
637            // **BUT**
638            //
639            // In Collector.of, the 3rd parameter - the "combiner" - is a "BinaryOperation<R>"
640
641            (ROArrayListBuilder<T> roalb1, ROArrayListBuilder<T> roalb2) ->
642            {
643                roalb1.addAll(roalb2);
644                return roalb1;
645            },
646
647            ROArrayListBuilder<T>::build,  // The "Finisher"    (Converts Builder to ReadOnlyArrayList)
648            characteristics
649        );
650    }
651
652
653    // ********************************************************************************************
654    // ********************************************************************************************
655    // Convert to java.util Types
656    // ********************************************************************************************
657    // ********************************************************************************************
658
659
660    /**
661     * Clone's {@code 'this'} instance internal {@code ArrayList<E>} field, and returns it. 
662     * <EMBED CLASS='external-html' DATA-TYPE=ArrayList DATA-FILE-ID=CLONE_TO>
663     * 
664     * @return An independent, mutable copy of {@code 'this'} instance' internal
665     * {@code ArrayList<E>} data-structure.
666     */
667    public ArrayList<E> cloneToArrayList()
668    {
669        return fromBuilderOrArrayList
670            ? new ArrayList<E>(this.arrayList)
671            : (ArrayList<E>) this.arrayList.clone();
672    }
673
674    /**
675     * <BR>Same: Identical to the method {@link #cloneToArrayList()}.
676     * <BR>Returns: Has Return-Type {@code List<E>}, instead.
677     * <BR>Implements: Parent-Class {@link ReadOnlyList#cloneToList}
678     */
679    @Torello.JavaDoc.IntoHTMLTable(title="Converts this ReadOnlyArrayList to a java.util.ArrayList")
680    public List<E> cloneToList() { return cloneToArrayList(); }
681
682    // Documented in the Implemented-Interface ReadOnlyList
683    public List<E> wrapToImmutableList()
684    { return Collections.unmodifiableList(this.arrayList); }
685
686
687    // ********************************************************************************************
688    // ********************************************************************************************
689    // Original JDK Methods, java.util.ArrayList
690    // ********************************************************************************************
691    // ********************************************************************************************
692
693
694    /**
695     * Returns the number of elements in this list.
696     * @return the number of elements in this list
697     */
698    public int size()
699    { return this.arrayList.size(); }
700
701    /**
702     * Returns {@code TRUE} if this list contains no elements.
703     * @return {@code TRUE} if this list contains no elements
704     */
705    public boolean isEmpty()
706    { return this.arrayList.isEmpty(); }
707
708    /**
709     * Returns {@code TRUE} if this list contains the specified element.  More formally, returns
710     * {@code TRUE} if and only if this list contains at least one element {@code e} such that
711     * {@code Objects.equals(o, e)}.
712     *
713     * @param o element whose presence in this list is to be tested
714     * @return {@code TRUE} if this list contains the specified element
715     */
716    public boolean contains(Object o)
717    { return this.arrayList.contains(o); }
718
719    /**
720     * Returns the index of the first occurrence of the specified element in this list, or
721     * {@code -1} if this list does not contain the element.  More formally, returns the lowest
722     * index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if there is no
723     * such index.
724     */
725    public int indexOf(Object o)
726    { return this.arrayList.indexOf(o); }
727
728    /**
729     * Returns the index of the last occurrence of the specified element in this list, or
730     * {@code -1} if this list does not contain the element.  More formally, returns the highest
731     * index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if there is no
732     * such index.
733     */
734    public int lastIndexOf(Object o)
735    { return this.arrayList.lastIndexOf(o); }
736
737    /**
738     * Returns an array containing all of the elements in this list in proper sequence (from first
739     * to last element).
740     *
741     * <BR /><BR />The returned array will be "safe" in that no references to it are maintained by
742     * this list.  (In other words, this method must allocate a new array).  The caller is thus
743     * free to modify the returned array.
744     *
745     * <BR /><BR />This method acts as bridge between array-based and collection-based APIs.
746     *
747     * @return an array containing all of the elements in this list in proper sequence
748     */
749    public Object[] toArray()
750    { return this.arrayList.toArray(); }
751
752    /**
753     * Returns an array containing all of the elements in this list in proper sequence (from first
754     * to last element); the runtime type of the returned array is that of the specified array.  If
755     * the list fits in the specified array, it is returned therein.  Otherwise, a new array is
756     * allocated with the runtime type of the specified array and the size of this list.
757     *
758     * <BR /><BR />If the list fits in the specified array with room to spare (i.e., the array has
759     * more elements than the list), the element in the array immediately following the end of the
760     * collection is set to {@code null}.  (This is useful in determining the length of the list
761     * <i>only</i> if the caller knows that the list does not contain any null elements.)
762     *
763     * @param a the array into which the elements of the list are to be stored, if it is big enough;
764     * otherwise, a new array of the same runtime type is allocated for this purpose.
765     * 
766     * @return an array containing the elements of the list
767     * 
768     * @throws ArrayStoreException if the runtime type of the specified array is not a supertype of
769     * the runtime type of every element in this list
770     * 
771     * @throws NullPointerException if the specified array is null
772     */
773    public <T> T[] toArray(T[] a)
774    { return this.arrayList.toArray(a); }
775
776    /**
777     * Returns the element at the specified position in this list.
778     * @param  index index of the element to return
779     * @return the element at the specified position in this list
780     * @throws IndexOutOfBoundsException {@inheritDoc}
781     */
782    public E get(int index)
783    { return this.arrayList.get(index); }
784
785    /** @throws NullPointerException {@inheritDoc} */
786    @Override
787    public void forEach(Consumer<? super E> action)
788    { this.arrayList.forEach(action); }
789
790    /**
791     * Utilizes this class private, internal {@code 'arrayList'} field to generate a
792     * {@code Spliterator}.
793     * 
794     * @return a {@code Spliterator} over the elements in this list
795     */
796    @Override
797    public Spliterator<E> spliterator()
798    { return this.arrayList.spliterator(); }
799
800
801    // ********************************************************************************************
802    // ********************************************************************************************
803    // The Builder AccessDenied Issue
804    // ********************************************************************************************
805    // ********************************************************************************************
806
807
808   /**
809    * Returns a list iterator over the elements in this list (in proper sequence), starting at the
810    * specified position in the list.  The specified index indicates the first element that would
811    * be returned by an initial call to {@link ReadOnlyListIterator#next next}.  An initial call to
812    * {@link ReadOnlyListIterator#previous previous} would return the element with the specified
813    * index minus one.
814    *
815    * @throws IndexOutOfBoundsException {@inheritDoc}
816    */
817    @LinkJavaSource(handle="JavaHTMLReadOnlyListIterator")
818    public ReadOnlyListIterator<E> listIterator(int index)
819    {
820        return new JavaHTMLReadOnlyListIterator<>(
821            fromBuilderOrArrayList 
822                ? ((ROArrayListBuilder<E>) this.arrayList)._listIterator(index, friendClassBadge)
823                : this.arrayList.listIterator(index)
824        );
825    }
826
827    /**
828     * Returns a list iterator over the elements in this list (in proper sequence).
829     * @see #listIterator(int)
830     */
831    @LinkJavaSource(handle="JavaHTMLReadOnlyListIterator")
832    public ReadOnlyListIterator<E> listIterator()
833    {
834        return new JavaHTMLReadOnlyListIterator<>(
835            fromBuilderOrArrayList 
836                ? ((ROArrayListBuilder<E>) this.arrayList)._listIterator(friendClassBadge)
837                : this.arrayList.listIterator()
838        );
839    }
840
841    /**
842     * Returns an iterator over the elements in this list in proper sequence.
843     * @return an iterator over the elements in this list in proper sequence
844     */
845    public RemoveUnsupportedIterator<E> iterator()
846    {
847        return fromBuilderOrArrayList
848            ? (RemoveUnsupportedIterator<E>) this.arrayList.iterator()
849            : new RemoveUnsupportedIterator<E>(this.arrayList.iterator());
850    }
851
852    /**
853     * Returns a view of the portion of this list between the specified {@code 'fromIndex'},
854     * inclusive, and {@code toIndex}, exclusive.  (If {@code 'fromIndex'} and {@code 'toIndex'}
855     * are equal, the returned list is empty.) 
856     * 
857     * @throws IndexOutOfBoundsException {@inheritDoc}
858     * @throws IllegalArgumentException {@inheritDoc}
859     */
860    @LinkJavaSource(handle="JavaHTMLReadOnlyList")
861    public ReadOnlyList<E> subList(int fromIndex, int toIndex)
862    {
863        return new JavaHTMLReadOnlyList<>(
864            fromBuilderOrArrayList 
865                ? ((ROArrayListBuilder<E>) this.arrayList).
866                    _subList(fromIndex, toIndex, friendClassBadge)
867                : this.arrayList.subList(fromIndex, toIndex)
868        );
869    }
870
871
872    // ********************************************************************************************
873    // ********************************************************************************************
874    // Original JDK Methods, java.util.AbstractList
875    // ********************************************************************************************
876    // ********************************************************************************************
877
878
879    public boolean containsAll(Collection<?> c)
880    { return this.arrayList.containsAll(c); }
881
882
883    // ********************************************************************************************
884    // ********************************************************************************************
885    // java.lang.Object
886    // ********************************************************************************************
887    // ********************************************************************************************
888
889
890    /**
891     * Returns a {@code String} representation of this {@code ArrayList}. The {@code String}
892     * representation consists of a list of the collection's elements in the order they are
893     * returned by its iterator, enclosed in square brackets ({@code "[]"}). Adjacent elements are
894     * separated by the characters {@code ", "} (comma and space). Elements are converted to
895     * {@code String's} as by {@code String.valueOf(Object)}.
896     * 
897     * @return a {@code String} representation of this {@code ArrayList}
898     */
899    public String toString()
900    { return this.arrayList.toString(); }
901
902    /**
903     * Compares the specified Object with this List for equality, as per the definition in the 
904     * class {@code java.util.ArrayList}.
905     *
906     * @param  o object to be compared for equality with this {@code ReadOnlyArrayList}
907     * @return {@code TRUE} if the specified Object is equal to this List
908     */
909    @LinkJavaSource(handle="ROHelperEquals", name="roListEq")
910    public boolean equals(Object o)
911    { return ROHelperEquals.roListEq(this, o); }
912
913    /**
914     * Returns the hash code value for this List as per the definition in the class
915     * {@code java.util.ArrayList}.
916     */
917    public int hashCode()
918    { return this.arrayList.hashCode(); }
919}