001/*
002 * Copyright (c) 1994, 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 */
025package Torello.Java.ReadOnly;
026
027import Torello.Java.Additional.RemoveUnsupportedIterator;
028import Torello.Java.ReadOnly.ROVectorBuilder;
029import Torello.JavaDoc.LinkJavaSource;
030
031import java.io.IOException;
032import java.io.ObjectInputStream;
033import java.io.StreamCorruptedException;
034
035import java.util.*;
036
037import java.util.stream.Collector;
038
039import java.util.function.Consumer;
040import java.util.function.Function;
041import java.util.function.Supplier;
042import java.util.function.Predicate;
043
044/**
045 * Immutable Wrapper for <CODE>java&#46;util&#46;Vector</CODE>, found in the "Java Collections
046 * Framework".
047 * 
048 * <EMBED CLASS=globalDefs DATA-JDK=Vector>
049 * <EMBED CLASS='external-html' DATA-FILE-ID=MUCHOS_CONSTRUCTORS>
050 * <EMBED CLASS='external-html' DATA-FILE-ID=DATA_CLASS>
051 * <EMBED CLASS='external-html' DATA-FILE-ID=RO_SYNCHRONIZED>
052 *
053 * @param <E> Type of component elements
054 */
055@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_MAIN")
056@SuppressWarnings("unchecked")
057public class ReadOnlyVector<E>
058    // extends AbstractReadOnlyList<E>
059    implements ReadOnlyList<E>, RandomAccess, java.io.Serializable
060{
061    // ********************************************************************************************
062    // ********************************************************************************************
063    // Protected & Private Fields, Methods, Statics
064    // ********************************************************************************************
065    // ********************************************************************************************
066
067
068    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
069    protected static final long serialVersionUID = 1;
070
071    // Minor Optimization where new Vector's that have no contents always re-use this static
072    // instance.  Since this instance is completely empty, the Raw-Types things is irrelevant.
073
074    @SuppressWarnings("rawtypes")
075    private static final Vector EMPTY_VECTOR = new Vector(0);
076
077    // Singleton & Empty ReadOnlyVector, Uses the "Supplier Constructor"
078    @SuppressWarnings("rawtypes")
079    private static final ReadOnlyVector EMPTY_READONLY_VECTOR =
080        new ReadOnlyVector(0, () -> null);
081
082    // The actual Vector used by this instance.
083    private final Vector<E> vector;
084
085    // TRUE     => This was built using the class ROVectorBuilder
086    // FALSE    => This was built using the clone() of a standard java.util.Vector constructor
087
088    private final boolean fromBuilderOrVector;
089
090    // Mimics the C++ Keyword/Concept of "Friend Class".   Is "Friends With" ROVectorBuilder
091    static class AccessBadge { private AccessBadge() { } }
092    private static final AccessBadge friendClassBadge = new AccessBadge();
093
094    /**
095     * Returns an empty, <B STYLE='color: red;'>singleton</B>, instance of {@code ReadOnlyVector}.
096     * @param <T> Returned {@link ReadOnlyList}'s Data-Type.
097     * 
098     * @return An empty list.  Since this list is both empty &amp; read-only, a raw-type singleton 
099     * will suffice for all operations offered by this clas.
100     * 
101     * <EMBED CLASS='external-html' DATA-FILE-ID=EMPTY_SYNCHRONIZED>
102     */
103    public static <T> ReadOnlyVector<T> emptyROV()
104    { return (ReadOnlyVector<T>) EMPTY_READONLY_VECTOR; }
105
106
107    // ********************************************************************************************
108    // ********************************************************************************************
109    // Basic Constructors
110    // ********************************************************************************************
111    // ********************************************************************************************
112
113
114    // To all the readers out there following along: The "AccessBadge" thing is just a slightly
115    // wimpier substitute for the C++ keyword / concept 'friend' or "Friend Class".  It means this
116    // constructor is (for all intents and purposes) a private-constructor, except for the class
117    // ROVectorBuilder
118    //
119    // This is the Constructor used by the Builder.  It has a "Zero-Size" Optimization
120
121    ReadOnlyVector(ROVectorBuilder<E> rovb, ROVectorBuilder.AccessBadge badge)
122    {
123        Objects.requireNonNull(badge, "Access Badge is null.  Requires Friend-Class Badge");
124
125        this.fromBuilderOrVector = true;
126        this.vector = rovb;
127    }
128
129    /**
130     * Copies parameter {@code 'c'} (and saves it) in order to guarantee that {@code 'this'}
131     * instance is Read-Only, and shielded from outside modification.
132     * 
133     * @param c The {@code Collection} to be copied and saved into this instance internal
134     * and private {@code 'vector'} field.
135     */
136    public ReadOnlyVector(Collection<E> c)
137    {
138        this.fromBuilderOrVector = false;
139
140        // Empty Optimization (throw away, completely, the reference, use static-constant)
141        this.vector = (c.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : new Vector<>(c);
142    }
143
144    /**
145     * Use a {@code Supplier<E>} to provide an arbitrary number of elements of type {@code 'E'} 
146     * directly to this constructor.  This constructor will request elements from the
147     * {@code Supplier} provided to parameter {@code 's'} until {@code 's'} returns null.
148     *
149     * @param quantityIfKnown If the number of elements to be supplied is known, that number may be
150     * provided so that the internal {@code Vector} is adequately initialized at the beginning
151     * of the constructor, without any need for resizing during construction.
152     * 
153     * <BR /><BR />If this parameter is passed null, it will be ignored.  When this happens, the
154     * initialization of the internal {@code Vector} will be done by Java's default (Zero
155     * Argument) {@code Vector}-Constructor.
156     * 
157     * <BR /><BR />It is not mandatory that the value provided be accurate, as ought be seen in the
158     * code below, this value is solely used for the {@code 'initialCapacity'} parameter to the
159     * {@code Vector} constructor.
160     * 
161     * @param s Any Java {@code Supplier<E>}
162     * 
163     * @throws IllegalArgumentException if the specified quantity / capacity is negative
164     */
165    public ReadOnlyVector(Integer quantityIfKnown, Supplier<E> s)
166    {
167        fromBuilderOrVector = false;
168
169        Vector<E>vector = (quantityIfKnown != null)
170            ? new Vector<>(quantityIfKnown)
171            : new Vector<>();
172
173        E e;
174        while ((e = s.get()) != null) vector.add(e);
175
176        // Empty Optimization (throw away, completely, the reference, use static-constant)
177        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
178    }
179
180
181    // ********************************************************************************************
182    // ********************************************************************************************
183    // Iterable & Array Based Constructors - **NO FILTER**
184    // ********************************************************************************************
185    // ********************************************************************************************
186
187
188    /**
189     * If only a small amount of processing needs to be done on the contents of some Java
190     * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this
191     * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyVector}, using
192     * a simple {@code 'mapper'}</I>.
193     * 
194     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
195     * 
196     * @param <T>           <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM>
197     * @param i             Any Java {@code Iterable<T>}
198     * @param mapper        <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER>
199     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
200     * 
201     * @throws NullPointerException If either {@code 'i'} or {@code 'mapper'} are passed null.
202     */
203    public <T> ReadOnlyVector(
204            Iterable<T>                         i,
205            Function<? super T, ? extends E>    mapper,
206            Integer                             sizeIfKnown
207        )
208    {
209        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
210
211        fromBuilderOrVector = false;
212
213        Vector<E> vector = (sizeIfKnown != null)
214            ? new Vector<>(sizeIfKnown)
215            : new Vector<>();
216
217        for (T t : i) vector.add(mapper.apply(t));
218
219        // Empty Optimization (throw away, completely, the reference, use static-constant)
220        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
221    }
222
223    /**
224     * If a Standard Java {@code Iterable} can be directly mapped into a {@code Vector}
225     * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will
226     * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyVector<E>}
227     * with just this single invocation</I>.
228     *
229     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
230     * 
231     * @param i             Any Java {@code Iteratable<E>}
232     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
233     * 
234     * @throws IllegalArgumentException if the specified initial capacity is negative
235     */
236    public ReadOnlyVector(Iterable<E> i, Integer sizeIfKnown)
237    {
238        fromBuilderOrVector = false;
239
240        Vector<E> vector = (sizeIfKnown != null)
241            ? new Vector<>(sizeIfKnown)
242            : new Vector<>();
243
244        for (E element : i) vector.add(element);
245
246        // Empty Optimization (throw away, completely, the reference, use static-constant)
247        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
248    }
249
250    /**
251     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
252     * {@code 'elements'}.
253     * 
254     * @param elementsType  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE>
255     * @param elements      <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
256     * 
257     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=CCEX>
258     * @throws NullPointerException If {@code 'elementsType'} is passed null.
259     */
260    public ReadOnlyVector(Class<E> elementsType, Object... elements)
261    {
262        Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'");
263
264        fromBuilderOrVector = false;
265
266        if (elements.length == 0)
267            this.vector = (Vector<E>) EMPTY_VECTOR;
268
269        else 
270        {
271            this.vector = new Vector<>(elements.length);
272            for (Object element : elements) this.vector.add(elementsType.cast(element));
273        }
274    }
275
276    /**
277     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
278     * {@code 'elements'}.
279     * 
280     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER>
281     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
282     * 
283     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=CCEX>
284     * @throws NullPointerException If {@code 'mapper'} is passed null.
285     */
286    public ReadOnlyVector(Function<Object, ? extends E> mapper, Object... elements)
287    {
288        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
289
290        fromBuilderOrVector = false;
291
292        if (elements.length == 0)
293            this.vector = (Vector<E>) EMPTY_VECTOR;
294
295        else 
296        {
297            this.vector = new Vector<>(elements.length);
298            for (Object element : elements) this.vector.add(mapper.apply(element));
299        }
300    }
301
302
303    // ********************************************************************************************
304    // ********************************************************************************************
305    // Iterable & Array Based Constructors - **INCLUDES ELEMENT FILTER**
306    // ********************************************************************************************
307    // ********************************************************************************************
308
309
310    /**
311     * If only a small amount of processing needs to be done on the contents of some Java
312     * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this
313     * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyVector}, using
314     * a simple {@code 'mapper'}</I>.
315     * 
316     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
317     * 
318     * @param <T>           <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM>
319     * @param i             Any Java {@code Iterable<T>}
320     * @param mapper        <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER>
321     * @param filter        <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER>
322     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
323     * 
324     * @throws NullPointerException If any of {@code 'i'}, {@code 'mapper'} or {@code 'filter'} are
325     * passed null.
326     */
327    public <T> ReadOnlyVector(
328            Iterable<T>                         i,
329            Function<? super T, ? extends E>    mapper,
330            Predicate<? super T>                filter,
331            Integer                             sizeIfKnown
332        )
333    {
334        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
335        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
336
337        fromBuilderOrVector = false;
338
339        Vector<E> vector = (sizeIfKnown != null)
340            ? new Vector<>(sizeIfKnown)
341            : new Vector<>();
342
343        for (T t : i) if (filter.test(t)) vector.add(mapper.apply(t));
344
345        // Empty Optimization (throw away, completely, the reference, use static-constant)
346        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
347    }
348
349    /**
350     * If a Standard Java {@code Iterable} can be directly mapped into an {@code Vector}
351     * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will
352     * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyVector<E>}
353     * with just this single invocation</I>.
354     *
355     * <EMBED CLASS=defs DATA-SOURCE=Iterable>
356     * 
357     * @param i             Any Java {@code Iteratable<E>}
358     * @param filter        <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER>
359     * @param sizeIfKnown   <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY>
360     * 
361     * @throws IllegalArgumentException if the specified initial capacity is negative
362     * @throws NullPointerException     If either {@code 'i'} or {@code 'filter'} are passed null.
363     */
364    public ReadOnlyVector(Iterable<E> i, Predicate<? super E> filter, Integer sizeIfKnown)
365    {
366        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
367
368        fromBuilderOrVector = false;
369
370        Vector<E> vector = (sizeIfKnown != null)
371            ? new Vector<>(sizeIfKnown)
372            : new Vector<>();
373
374        for (E element : i) if (filter.test(element)) vector.add(element);
375
376        // Empty Optimization (throw away, completely, the reference, use static-constant)
377        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
378    }
379
380    /**
381     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
382     * {@code 'elements'}.
383     * 
384     * @param elementsType  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE>
385     * @param filter        <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER>
386     * @param elements      <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
387     * 
388     * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX>
389     * 
390     * @throws NullPointerException If either {@code 'elementsType'} or {@code 'filter'} are passed
391     * null.
392     */
393    public ReadOnlyVector
394        (Class<E> elementsType, Predicate<? super E> filter, Object... elements)
395    {
396        Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'");
397        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
398
399        fromBuilderOrVector = false;
400
401        Vector<E> vector = new Vector<>(elements.length);
402
403        E e;
404        for (Object element : elements)
405            if (filter.test(e = elementsType.cast(element)))
406                vector.add(e);
407
408        // Empty Optimization (throw away, completely, the reference, use static-constant)
409        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
410    }
411
412    /**
413     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
414     * {@code 'elements'}.
415     * 
416     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER>
417     * @param filter    <EMBED CLASS='external-html' DATA-FTP=Object DATA-FILE-ID=PREDICATE_FILTER>
418     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
419     * 
420     * @throws NullPointerException If either {@code 'mapper'}  or {@code 'filter'} are passed null
421     */
422    public ReadOnlyVector(
423            Function<Object, ? extends E>   mapper,
424            Predicate<Object>               filter,
425            Object...                       elements
426        )
427    {
428        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
429        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
430
431        fromBuilderOrVector = false;
432
433        Vector<E> vector = new Vector<>(elements.length);
434
435        for (Object element : elements)
436            if (filter.test(element))
437                vector.add(mapper.apply(element));
438
439        // Empty Optimization (throw away, completely, the reference, use static-constant)
440        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
441    }
442
443
444    // ********************************************************************************************
445    // ********************************************************************************************
446    // @SafeVarargs / Variable-Arity / VarArgs: with Parameterized / Generic Type's
447    // ********************************************************************************************
448    // ********************************************************************************************
449
450
451    /**
452     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
453     * {@code 'elements'}.
454     * 
455     * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
456     */
457    @SafeVarargs
458    public ReadOnlyVector(E... elements)
459    {
460        fromBuilderOrVector = false;
461
462        if (elements.length == 0)
463            this.vector = (Vector<E>) EMPTY_VECTOR;
464
465        else 
466        {
467            this.vector = new Vector<>(elements.length);
468            for (E e : elements) this.vector.add(e);
469        }
470    }
471
472    /**
473     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
474     * {@code 'elements'}.
475     * 
476     * @param <T>       <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM>
477     * @param dummy     <EMBED CLASS='external-html' DATA-FILE-ID=DUMMY_INT>
478     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER>
479     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
480     * 
481     * @throws NullPointerException If {@code 'mapper'} is null.
482     */
483    @SafeVarargs
484    public <T> ReadOnlyVector
485        (int dummy, Function<? super T, ? extends E> mapper, T... elements)
486    {
487        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
488
489        fromBuilderOrVector = false;
490
491        if (elements.length == 0)
492            this.vector = (Vector<E>) EMPTY_VECTOR;
493
494        else 
495        {
496            this.vector = new Vector<>(elements.length);
497            for (T t : elements) this.vector.add(mapper.apply(t));
498        }
499    }
500
501    /**
502     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
503     * {@code 'elements'}.
504     * 
505     * @param filter    <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER>
506     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
507     * 
508     * @throws NullPointerException If {@code 'elementsType'} is null.
509     */
510    @SafeVarargs
511    public ReadOnlyVector(Predicate<? super E> filter, E... elements)
512    {
513        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
514
515        fromBuilderOrVector = false;
516
517        Vector<E> vector = new Vector<>(elements.length);
518        for (E e : elements) if (filter.test(e)) vector.add(e);
519
520        // Empty Optimization (throw away, completely, the reference, use static-constant)
521        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
522    }
523
524    /**
525     * Builds {@code ReadOnlyVector<E>} instance having Generic-Type {@code 'E'}, and contents
526     * {@code 'elements'}.
527     * 
528     * @param <T>       <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM>
529     * @param filter    <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER>
530     * @param mapper    <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER>
531     * @param elements  <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS>
532     * 
533     * @throws NullPointerException If {@code 'mapper'} or {@code 'filter'} is null.
534     */
535    @SafeVarargs
536    public <T> ReadOnlyVector(
537            Predicate<? super T> filter,
538            Function<? super T, ? extends E> mapper,
539            T... elements
540        )
541    {
542        Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'");
543        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
544
545        fromBuilderOrVector = false;
546
547        Vector<E> vector = new Vector<>(elements.length);
548        for (T t : elements) if (filter.test(t)) vector.add(mapper.apply(t));
549
550        // Empty Optimization (throw away, completely, the reference, use static-constant)
551        this.vector = (vector.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : vector;
552    }
553
554
555    // ********************************************************************************************
556    // ********************************************************************************************
557    // PRIMITIVE-ARRAY INPUT
558    // ********************************************************************************************
559    // ********************************************************************************************
560
561
562    /**
563     * Converts a Java Primitive-Array to a {@code ReadOnlyVector<E>}, where {@code 'E'} is the
564     * Java Boxed-Type which corresponds to the Primitive-Array's Type.
565     * 
566     * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC>
567     * @param primitiveArray        <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY>
568     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX>
569     * @throws NullPointerException If {@code 'primitiveArray'} is passed null;
570     */
571    @LinkJavaSource(handle="ROHelperPrimitiveArrays", name="buildROListOrSet")
572    public ReadOnlyVector(Object primitiveArray)
573    {
574        fromBuilderOrVector = false;
575
576        Vector<E> v = ROHelperPrimitiveArrays.buildROListOrSet(
577            primitiveArray,
578            (int arrayLen) -> new Vector<E>(arrayLen),
579            null
580        );
581
582        // Empty Optimization (throw away, completely, the reference, use static-constant)
583        this.vector = (v.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : v;
584    }
585
586    /**
587     * Converts a Java Primitive-Array to a {@code ReadOnlyVector<E>}, where {@code 'E'} is the
588     * Java Boxed-Type which corresponds to the Primitive-Array's Type - <I>but also accepts a 
589     * {@code 'filter'} that can remove any array-entries that need to be removed</I>.
590     * 
591     * 
592     * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC>
593     * @param primitiveArray        <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY>
594     * @param filter                <EMBED CLASS='external-html' DATA-FILE-ID=PRED_FILT_PRIM>
595     * @throws ClassCastException   <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX>
596     * @throws NullPointerException If {@code 'primitiveArray'} is passed null;
597     */
598    @LinkJavaSource(handle="ROHelperPrimitiveArrays", name="buildROListOrSet")
599    public ReadOnlyVector(
600            Object          primitiveArray,
601            Predicate<?>    filter
602        )
603    {
604        Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'");
605
606        fromBuilderOrVector = false;
607
608        Vector<E> v = ROHelperPrimitiveArrays.buildROListOrSet(
609            primitiveArray,
610            (int arrayLen) -> new Vector<E>(arrayLen),
611            filter
612        );
613
614        // Empty Optimization (throw away, completely, the reference, use static-constant)
615        this.vector = (v.size() == 0) ? ((Vector<E>) EMPTY_VECTOR) : v;
616    }
617
618
619    // ********************************************************************************************
620    // ********************************************************************************************
621    // java.util.stream.Stream HELPER
622    // ********************************************************************************************
623    // ********************************************************************************************
624
625
626    /**
627     * For use with a the Java Stream method {@code 'collect(Collector c)'}.
628     * 
629     * <EMBED CLASS='external-html' DATA-ABBREV=v DATA-FILE-ID=STREAM_COLLECTOR>
630     * 
631     * @param <T> This is the Generic-Type of the Input-Stream.  It will also be the Generic-Type
632     * of the {@code ReadOnlyVector} that's returned from the stream's {@code collect} method.
633     * 
634     * @param characteristics Optional Characteristics List.  See Java Stream-API Documentation on
635     * {@code Collector.Characteristics} inner-class for more details.
636     * 
637     * @return This returns a collector that may be piped into a stream's {@code 'collect'} method,
638     * as in the example, above.
639     */
640    public static <T> java.util.stream.Collector
641        <T, ROVectorBuilder<T>, ReadOnlyVector<T>>
642        streamCollector(Collector.Characteristics... characteristics)
643    {
644        return Collector.of(
645            ROVectorBuilder<T>::new,    // The "Supplier"    (builds a new ROVectorBuilder)
646            ROVectorBuilder<T>::add,    // The "Accumulator" (adds elements to the builder)
647
648            // Oracle Making Life Difficult - It should be the line below, but, alas, it is not!
649            // ROVectorBuilder<T>::addAll, // The "Combiner"    (combines multiple ROVectorBuilders)
650            //
651            // In Stream.collect(), the 3rd parameter - the "combiner" - is a "BiConsumer<R, R>"
652            // NOTE: A "BiConsumer" is a FunctionalInterface that does not return anything - it is
653            // (obviously) a "void" return method!
654            //
655            // **BUT**
656            //
657            // In Collector.of, the 3rd parameter - the "combiner" - is a "BinaryOperation<R>"
658    
659            (ROVectorBuilder<T> rovb1, ROVectorBuilder<T> rovb2) ->
660            {
661                rovb1.addAll(rovb2);
662                return rovb1;
663            },
664
665            ROVectorBuilder<T>::build,  // The "Finisher"    (Converts Builder to ReadOnlyVector)
666            characteristics
667        );
668    }
669
670
671    // ********************************************************************************************
672    // ********************************************************************************************
673    // Convert to java.util Types
674    // ********************************************************************************************
675    // ********************************************************************************************
676
677
678    /**
679     * Clone's {@code 'this'} instance internal {@code Vector<E>} field, and returns it. 
680     * <EMBED CLASS='external-html' DATA-TYPE=Vector DATA-FILE-ID=CLONE_TO>
681     * 
682     * @return An independent, mutable copy of {@code 'this'} instance' internal {@code Vector<E>}
683     * data-structure.
684     */
685    public Vector<E> cloneToVector()
686    {
687        return fromBuilderOrVector
688            ? new Vector<E>(this.vector)
689            : (Vector<E>) this.vector.clone(); 
690    }
691
692    /**
693     * <BR>Same: Identical to the method {@link #cloneToVector()}.
694     * <BR>Returns: Has Return-Type {@code List<E>}, instead.
695     * <BR>Implements: Parent-Class {@link ReadOnlyList#cloneToList}
696     */
697    @Torello.JavaDoc.IntoHTMLTable(title="Converts this ReadOnlyVector to a java.util.Vector")
698    public List<E> cloneToList() { return cloneToVector(); }
699
700    // Documented in the Implemented-Interface ReadOnlyList
701    public List<E> wrapToImmutableList()
702    { return Collections.unmodifiableList(this.vector); }
703
704
705    // ********************************************************************************************
706    // ********************************************************************************************
707    // Original JDK Methods, java.util.Vectpr
708    // ********************************************************************************************
709    // ********************************************************************************************
710
711
712    /**
713     * Copies the components of this {@code Vector} into the specified array.  The item at
714     * index{@code k} in this {@code Vector} is copied into component {@code k} of {@code anArray}.
715     *
716     * @param  anArray the array into which the components get copied
717     * 
718     * @throws NullPointerException if the given array is null
719     * 
720     * @throws IndexOutOfBoundsException if the specified array is not large enough to hold all the
721     * components of this {@code Vector}
722     * 
723     * @throws ArrayStoreException if a component of this {@code Vector} is not of a runtime type
724     * that can be stored in the specified array
725     * 
726     * @see #toArray(Object[])
727     */
728    public void copyInto(Object[] anArray)
729    { this.vector.copyInto(anArray); }
730
731    /**
732     * Returns the current capacity of this {@code Vector}.
733     *
734     * @return  the current capacity (the length of its internal data array, kept in the field
735     * {@code elementData} of this {@code Vector})
736     */
737    public int capacity()
738    { return this.vector.capacity(); }
739
740    /**
741     * Returns the number of components in this {@code Vector}.
742     * 
743     * @return  the number of components in this {@code Vector}
744     */
745    public int size()
746    { return this.vector.size(); }
747
748    /**
749     * Tests if this {@code Vector} has no components.
750     *
751     * @return  {@code TRUE} if and only if this {@code Vector} has no components, that is, its
752     * size is zero; {@code FALSE} otherwise.
753     */
754    public boolean isEmpty()
755    { return this.vector.isEmpty(); }
756
757    /**
758     * Returns an enumeration of the components of this {@code Vector}. The returned
759     * {@code Enumeration} object will generate all items in this {@code Vector}. The first item
760     * generated is the item at index {@code 0}, then the item at index {@code 1}, and so on. If
761     * the {@code Vector} is structurally modified while enumerating over the elements then the
762     * results of enumerating are undefined.
763     *
764     * @return an enumeration of the components of this {@code Vector}
765     */
766    public Enumeration<E> elements()
767    { return this.vector.elements(); }
768
769    /**
770     * Returns {@code TRUE} if this {@code Vector} contains the specified element.  More formally,
771     * returns {@code TRUE} if and only if this {@code Vector} contains at least one element
772     * {@code e} such that {@code Objects.equals(o, e)}.
773     *
774     * @param o element whose presence in this {@code Vector} is to be tested
775     * 
776     * @return {@code TRUE} if this {@code Vector} contains the specified element
777     */
778    public boolean contains(Object o)
779    { return this.vector.contains(o); }
780
781    /**
782     * Returns the index of the first occurrence of the specified element in this {@code Vector},
783     * or {@code -1} if this {@code Vector} does not contain the element.  More formally, returns
784     * the lowest index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if
785     * there is no such index.
786     *
787     * @param o element to search for
788     * 
789     * @return the index of the first occurrence of the specified element in this {@code Vector},
790     * or {@code -1} if this {@code Vector} does not contain the element
791     */
792    public int indexOf(Object o)
793    { return this.vector.indexOf(o); }
794
795    /**
796     * Returns the index of the first occurrence of the specified element in this {@code Vector},
797     * searching forwards from {@code index}, or returns {@code -1} if the element is not found.
798     * More formally, returns the lowest index {@code i} such that
799     * {@code (i >= index && Objects.equals(o, get(i)))}, or {@code -1} if there is no such index.
800     *
801     * @param o element to search for
802     * 
803     * @param index index to start searching from
804     * 
805     * @return the index of the first occurrence of the element in this {@code Vector} at position
806     * {@code index} or later in the {@code Vector}; {@code -1} if the element is not found.
807     * 
808     * @throws IndexOutOfBoundsException if the specified index is negative
809     */
810    public int indexOf(Object o, int index)
811    { return this.vector.indexOf(o, index); }
812
813    /**
814     * Returns the index of the last occurrence of the specified element in this {@code Vector}, or
815     * {@code -1} if this {@code Vector} does not contain the element.  More formally, returns the
816     * highest index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if there
817     * is no such index.
818     *
819     * @param o element to search for
820     * 
821     * @return the index of the last occurrence of the specified element in this {@code Vector}, or
822     * {@code -1} if this {@code Vector} does not contain the element
823     */
824    public int lastIndexOf(Object o)
825    { return this.vector.lastIndexOf(o); }
826
827    /**
828     * Returns the index of the last occurrence of the specified element in this {@code Vector},
829     * searching backwards from {@code index}, or returns {@code -1} if the element is not found.
830     * More formally, returns the highest index {@code i} such that
831     * {@code (i <= index && Objects.equals(o, get(i)))}, or {@code -1} if there is no such index.
832     *
833     * @param o element to search for
834     * 
835     * @param index index to start searching backwards from
836     * 
837     * @return the index of the last occurrence of the element at position less than or equal to
838     * {@code index} in this {@code Vector}; {@code -1} if the element is not found.
839     * 
840     * @throws IndexOutOfBoundsException if the specified index is greater than or equal to the
841     * current size of this {@code Vector}
842     */
843    public int lastIndexOf(Object o, int index)
844    { return this.vector.lastIndexOf(index); }
845
846    /**
847     * Returns the component at the specified index.
848     *
849     * <BR /><BR />This method is identical in functionality to the {@link #get(int)}
850     * method (which is part of the {@link ReadOnlyList} interface).
851     *
852     * @param index an index into this {@code Vector}
853     * 
854     * @return the component at the specified index
855     * 
856     * @throws ArrayIndexOutOfBoundsException if the index is out of range
857     * ({@code index < 0 || index >= size()})
858     */
859    public E elementAt(int index)
860    { return this.vector.elementAt(index); }
861
862    /**
863     * Returns the first component (the item at index {@code 0}) of this {@code Vector}.
864     * 
865     * @return the first component of this {@code Vector}
866     * 
867     * @throws NoSuchElementException if this {@code Vector} has no components
868     */
869    public E firstElement()
870    { return this.vector.firstElement(); }
871
872    /**
873     * Returns the last component of the {@code Vector}.
874     * 
875     * @return  the last component of the {@code Vector}, i.e., the component at index
876     * {@code size() - 1}
877     * 
878     * @throws NoSuchElementException if this {@code Vector} is empty
879     */
880    public E lastElement()
881    { return this.vector.lastElement(); }
882
883    /** Returns an array containing all of the elements in this {@code Vector} in the correct order. */
884    public Object[] toArray()
885    { return this.vector.toArray(); }
886
887    /**
888     * Returns an array containing all of the elements in this {@code Vector} in the correct order;
889     * the runtime type of the returned array is that of the specified array.  If the
890     * {@code Vector} fits in the specified array, it is returned therein.  Otherwise, a new array
891     * is allocated with the runtime type of the specified array and the size of this
892     * {@code Vector}.
893     *
894     * <BR /><BR />If the {@code Vector} fits in the specified array with room to spare (i.e., the
895     * array has more elements than the {@code Vector}), the element in the array immediately
896     * following the end of the {@code Vector} is set to null.  (This is useful in determining the
897     * length of the {@code Vector} <em>only</em> if the caller knows that the {@code Vector} does
898     * not contain any null elements.)
899     *
900     * @param <T> type of array elements. The same type as {@code <E>} or a supertype of
901     * {@code <E>}.
902     * 
903     * @param a the array into which the elements of the {@code Vector} are to be stored, if it is
904     * big enough; otherwise, a new array of the same runtime type is allocated for this purpose.
905     * 
906     * @return an array containing the elements of the {@code Vector}
907     * 
908     * @throws ArrayStoreException if the runtime type of a, {@code <T>}, is not a supertype of the
909     * runtime type, {@code <E>}, of every element in this {@code Vector}
910     * 
911     * @throws NullPointerException if the given array is null
912     */
913    public <T> T[] toArray(T[] a)
914    { return this.vector.toArray(a); }
915
916    /**
917     * Returns the element at the specified position in this {@code Vector}.
918     *
919     * @param index index of the element to return
920     * 
921     * @return object at the specified index
922     * 
923     * @throws ArrayIndexOutOfBoundsException if the index is out of range
924     * ({@code index < 0 || index >= size()})
925     */
926    public E get(int index)
927    { return this.vector.get(index); }
928
929    /**
930     * Returns {@code TRUE} if this {@code Vector} contains all of the elements in the specified
931     * Collection
932     * 
933     * @param c a collection whose elements will be tested for containment in this {@code Vector}
934     * 
935     * @return {@code TRUE} if this {@code Vector} contains all of the elements in the specified
936     * collection
937     * 
938     * @throws NullPointerException if the specified collection is null
939     */
940    public boolean containsAll(Collection<?> c)
941    { return this.vector.containsAll(c); }
942
943    /**
944     * Returns a view of the portion of this List between {@code 'fromIndex'}, inclusive, and
945     * {@code 'toIndex'}, exclusive.  (If {@code 'fromIndex'} and {@code 'toIndex'} are equal, the
946     * returned List is empty.)  The returned List supports all of the optional
947     * {@code ReadOnlyList} operations supported by this {@code ReadOnlyList}.
948     *
949     * <BR /><BR />This method eliminates the need for explicit range operations (of the sort that
950     * commonly exist for arrays).  Any operation that expects a List can be used as a range
951     * operation by operating on a subList view instead of a whole List.  Idioms may be constructed
952     * for indexOf and lastIndexOf, and all of the algorithms in the Collections class can be
953     * applied to a subList.
954     *
955     * @param fromIndex low endpoint (inclusive) of the subList
956     * @param toIndex high endpoint (exclusive) of the subList
957     * @return a view of the specified range within this List
958     * 
959     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
960     * {@code (fromIndex < 0 || toIndex > size)}
961     * 
962     * @throws IllegalArgumentException if the endpoint indices are out of order
963     * {@code (fromIndex > toIndex)}
964     */
965    @LinkJavaSource(handle="JavaHTMLReadOnlyList")
966    public ReadOnlyList<E> subList(int fromIndex, int toIndex)
967    {
968        // return new ReadOnlyVector<>(
969        return new JavaHTMLReadOnlyList<>(
970            fromBuilderOrVector
971                ? ((ROVectorBuilder<E>) this.vector)._subList(fromIndex, toIndex, friendClassBadge)
972                : this.vector.subList(fromIndex, toIndex)
973        );
974    }
975
976    /**
977     * Returns a list iterator over the elements in this list (in proper sequence), starting at the
978     * specified position in the list. The specified index indicates the first element that would
979     * be returned by an initial call to {@link ReadOnlyListIterator#next next}.  An initial call
980     * to {@link ReadOnlyListIterator#previous previous} would return the element with the
981     * specified index minus one.
982     *
983     * @throws IndexOutOfBoundsException if the index is out of range
984     * {@code (index < 0 || index > size())}
985     */
986    @LinkJavaSource(handle="JavaHTMLReadOnlyListIterator")
987    public ReadOnlyListIterator<E> listIterator(int index)
988    {
989        return new JavaHTMLReadOnlyListIterator<>(
990            fromBuilderOrVector
991                ? ((ROVectorBuilder<E>) this.vector)._listIterator(index, friendClassBadge)
992                : this.vector.listIterator(index)
993        );
994    }
995
996    /**
997     * Returns a list iterator over the elements in this list (in proper sequence).
998     * @see #listIterator(int)
999     */
1000    @LinkJavaSource(handle="JavaHTMLReadOnlyListIterator")
1001    public ReadOnlyListIterator<E> listIterator()
1002    {
1003        return new JavaHTMLReadOnlyListIterator<>(
1004            fromBuilderOrVector
1005                ? ((ROVectorBuilder<E>) this.vector)._listIterator(friendClassBadge)
1006                : this.vector.listIterator()
1007        );
1008    }
1009
1010    /**
1011     * Returns an iterator over the elements in this list in proper sequence.
1012     * 
1013     * @return an iterator over the elements in this list in proper sequence
1014     */
1015    public RemoveUnsupportedIterator<E> iterator()
1016    { return new RemoveUnsupportedIterator<>(this.vector.iterator()); }
1017
1018    /** @throws NullPointerException {@inheritDoc} */
1019    @Override
1020    public void forEach(Consumer<? super E> action)
1021    { this.vector.forEach(action); }
1022
1023    /**
1024     * Uses the private and internal {@code 'vector'} field to build a {@code 'Spliterator'}
1025     * @return a {@code Spliterator} over the elements in this list
1026     */
1027    @Override
1028    public Spliterator<E> spliterator()
1029    { return this.vector.spliterator(); }
1030
1031
1032    // ********************************************************************************************
1033    // ********************************************************************************************
1034    // java.lang.Object
1035    // ********************************************************************************************
1036    // ********************************************************************************************
1037
1038
1039    /**
1040     * Returns a {@code String} representation of this {@code Vector}. The {@code String}
1041     * representation consists of a list of the collection's elements in the order they are
1042     * returned by its iterator, enclosed in square brackets ({@code "[]"}). Adjacent elements are
1043     * separated by the characters {@code ", "} (comma and space). Elements are converted to
1044     * {@code String's} as by {@code String.valueOf(Object)}.
1045     * 
1046     * @return a {@code String} representation of this {@code Vector}
1047     */
1048    public String toString()
1049    { return this.vector.toString(); }
1050
1051    /**
1052     * Compares the specified Object with this List for equality, as per the definition in the 
1053     * class {@code java.util.Vector}.
1054     *
1055     * @param  o object to be compared for equality with this {@code ReadOnlyVector}.
1056     * @return {@code TRUE} if the specified Object is equal to this list
1057     */
1058    @LinkJavaSource(handle="ROHelperEquals", name="roListEq")
1059    public boolean equals(Object o)
1060    { return ROHelperEquals.roListEq(this, o); }
1061
1062    /**
1063     * Returns the hash code value for this List as per the definition in the class
1064     * {@code java.util.Vector}.
1065     */
1066    public int hashCode() 
1067    { return this.vector.hashCode(); }
1068}
1069