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