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