001/*
002 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025package Torello.Java.ReadOnly;
026
027import Torello.Java.Additional.RemoveUnsupportedIterator;
028
029import java.util.function.Predicate;
030import java.util.function.UnaryOperator;
031
032import java.util.*;
033
034import java.io.Serializable;
035
036/**
037 * A Copy of Java's {@code ArrayList} class; used for building a {@link ReadOnlyArrayList}.
038 * Maintains <I>an internal and inaccessible {@code ArrayList<E>} instance</I>.
039 * 
040 * <EMBED CLASS=globalDefs DATA-JDK=ArrayList>
041 * <EMBED CLASS='external-html' DATA-A_AN=an DATA-FILE-ID=BUILDERS>
042 * 
043 * @param <E> the type of elements in this list
044 * @see ReadOnlyArrayList
045 */
046@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_BUILDER")
047public final class ROArrayListBuilder<E>
048    extends ArrayList<E>
049    implements RandomAccess, Cloneable, Serializable
050{
051    // ********************************************************************************************
052    // ********************************************************************************************
053    // Fields & Builder Stuff
054    // ********************************************************************************************
055    // ********************************************************************************************
056
057
058    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
059    protected static final long serialVersionUID = 1;
060
061    // Exception messages need this
062    private static final String ROAL = "ArrayList";
063
064    private boolean built = false;
065
066    // Mimics the C++ Concept of "Friend Class".  This badge is utilized by the "build()" method
067    // directly below this inner-class declaration.  It is the only place where this declaration is
068    // actually used anywhere.  This prohibits access to the constructor that is used to anybody
069    // else
070
071    static class AccessBadge { private AccessBadge() { } }
072    private static final AccessBadge friendClassBadge = new AccessBadge();
073
074    /**
075     * Simply transfers {@code 'this'} instance' internal {@code ArrayList} to the 
076     * {@code ReadOnlyArrayList} Wrapper-Class.
077     * 
078     * @return a newly constructed {@code ReadOnlyArrayList} "Wrapper-Class", shielding the
079     * internal {@code 'arrayList'} private-field from any modification.
080     */
081    public ReadOnlyArrayList<E> build()
082    {
083        super.trimToSize();
084        this.built = true;
085
086        return (size() == 0)
087            ? ReadOnlyArrayList.emptyROAL()
088            : new ReadOnlyArrayList<>(this, friendClassBadge);
089    }
090
091
092    // ********************************************************************************************
093    // ********************************************************************************************
094    // Modified Constructors
095    // ********************************************************************************************
096    // ********************************************************************************************
097
098
099    /**
100     * Constructs an empty {@code ROArrayListBuilder} with the specified initial capacity.
101     * @param  initialCapacity  the initial capacity of the list
102     * @throws IllegalArgumentException if the specified initial capacity is negative
103     */
104    public ROArrayListBuilder(int initialCapacity)
105    { super(initialCapacity); }
106
107    /** Constructs an empty list with an initial capacity of ten. */
108    public ROArrayListBuilder()
109    { super(); }
110
111    /**
112     * Constructs a {@code ROArrayListBuilder} containing the elements of the specified collection,
113     * in the order they are returned by the collection's iterator.
114     *
115     * @param c the collection whose elements are to be placed into this list
116     * @throws NullPointerException if the specified collection is null
117     */
118    public ROArrayListBuilder(Collection<? extends E> c)
119    { super(c); }
120
121
122    // ********************************************************************************************
123    // ********************************************************************************************
124    // Original JDK Methods
125    // ********************************************************************************************
126    // ********************************************************************************************
127
128
129    /**
130     * Trims the capacity of this {@code ArrayList} instance to be the list's current size.  An
131     * application can use this operation to minimize the storage of an {@code ArrayList} instance.
132     * 
133     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
134     */
135    public void trimToSize()
136    {
137        if (this.built) throw new AttemptedModificationException(ROAL);
138        super.trimToSize(); 
139    }
140
141    /**
142     * Increases the capacity of this {@code ArrayList} instance, if necessary, to ensure that it
143     * can hold at least the number of elements specified by the minimum capacity argument.
144     * 
145     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
146     *
147     * @param minCapacity the desired minimum capacity
148     */
149    public void ensureCapacity(int minCapacity)
150    {
151        if (this.built) throw new AttemptedModificationException(ROAL);
152        super.ensureCapacity(minCapacity); 
153    }
154
155    /**
156     * Replaces the element at the specified position in this list with the specified element.
157     * 
158     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
159     * 
160     * @param index index of the element to replace
161     * @param element element to be stored at the specified position
162     * @return the element previously at the specified position
163     * 
164     * @throws IndexOutOfBoundsException if the index is out of range
165     * {@code (index < 0 || index > size())}
166     */
167    public E set(int index, E element)
168    {
169        if (this.built) throw new AttemptedModificationException(ROAL);
170        return super.set(index, element); 
171    }
172
173    /**
174     * Appends the specified element to the end of this list.
175     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
176     * @param e element to be appended to this list
177     * @return {@code TRUE} (as specified by {@code Collection.add})
178     */
179    public boolean add(E e)
180    {
181        if (this.built) throw new AttemptedModificationException(ROAL);
182        return super.add(e); 
183    }
184
185    /**
186     * Inserts the specified element at the specified position in this list. Shifts the element
187     * currently at that position (if any) and any subsequent elements to the right (adds one to
188     * their indices).
189     * 
190     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
191     *
192     * @param index index at which the specified element is to be inserted
193     * @param element element to be inserted
194     * 
195     * @throws IndexOutOfBoundsException if the index is out of range
196     * {@code (index < 0 || index >= size())}
197     */
198    public void add(int index, E element)
199    {
200        if (this.built) throw new AttemptedModificationException(ROAL);
201        super.add(index, element); 
202    }
203
204    /**
205     * Removes the element at the specified position in this list.  Shifts any subsequent elements
206     * to the left (subtracts one from their indices).
207     * 
208     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
209     * 
210     * @param index the index of the element to be removed
211     * @return the element that was removed from the list
212     * 
213     * @throws IndexOutOfBoundsException if the index is out of range
214     * {@code (index < 0 || index >= size())}
215     */
216    public E remove(int index)
217    {
218        if (this.built) throw new AttemptedModificationException(ROAL);
219        return super.remove(index); 
220    }
221
222    /**
223     * Removes the first occurrence of the specified element from this list, if it is present.  If
224     * the list does not contain the element, it is unchanged.  More formally, removes the element
225     * with the lowest index {@code i} such that {@code Objects.equals(o, get(i))} (if such an
226     * element exists).  Returns {@code TRUE} if this list contained the specified element (or
227     * equivalently, if this list changed as a result of the call).
228     * 
229     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
230     *
231     * @param o element to be removed from this list, if present
232     * @return {@code TRUE} if this list contained the specified element
233     */
234    public boolean remove(Object o)
235    {
236        if (this.built) throw new AttemptedModificationException(ROAL);
237        return super.remove(o); 
238    }
239
240    /**
241     * Removes all of the elements from this list.  The list will be empty after this call returns.
242     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
243     */
244    public void clear()
245    {
246        if (this.built) throw new AttemptedModificationException(ROAL);
247        super.clear(); 
248    }
249
250    /**
251     * Appends all of the elements in the specified collection to the end of this list, in the
252     * order that they are returned by the specified collection's Iterator.  The behavior of this
253     * operation is undefined if the specified collection is modified while the operation is in
254     * progress.  (This implies that the behavior of this call is undefined if the specified
255     * collection is this list, and this list is nonempty.)
256     * 
257     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
258     * 
259     * @param c collection containing elements to be added to this list
260     * @return {@code TRUE} if this list changed as a result of the call
261     * @throws NullPointerException if the specified collection is null
262     */
263    public boolean addAll(Collection<? extends E> c)
264    {
265        if (this.built) throw new AttemptedModificationException(ROAL);
266        return super.addAll(c); 
267    }
268
269    /**
270     * Inserts all of the elements in the specified collection into this list, starting at the
271     * specified position.  Shifts the element currently at that position (if any) and any
272     * subsequent elements to the right (increases their indices).  The new elements will appear in
273     * the list in the order that they are returned by the specified collection's iterator.
274     * 
275     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
276     *
277     * @param index index at which to insert the first element from the specified collection
278     * @param c collection containing elements to be added to this list
279     * @return {@code TRUE} if this list changed as a result of the call
280     * @throws NullPointerException if the specified collection is null
281     * 
282     * @throws IndexOutOfBoundsException if the index is out of range
283     * {@code (index < 0 || index > size())}
284     */
285    public boolean addAll(int index, Collection<? extends E> c)
286    {
287        if (this.built) throw new AttemptedModificationException(ROAL);
288        return super.addAll(index, c); 
289    }
290
291    /**
292     * Removes from this list all of its elements that are contained in the specified collection.
293     * 
294     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
295     * 
296     * @param c collection containing elements to be removed from this list
297     * @return {@code TRUE} if this list changed as a result of the call
298     * 
299     * @throws ClassCastException if the class of an element of this list is incompatible with the
300     * specified collection
301     * (<a href="Collection.html#optional-restrictions">optional</a>)
302     * 
303     * @throws NullPointerException if this list contains a null element and the specified
304     * collection does not permit null elements
305     * (<a href="Collection.html#optional-restrictions">optional</a>),
306     * or if the specified collection is null
307     * 
308     * @see ReadOnlyCollection#contains(Object)
309     */
310    public boolean removeAll(Collection<?> c)
311    {
312        if (this.built) throw new AttemptedModificationException(ROAL);
313        return super.removeAll(c); 
314    }
315
316    /**
317     * Retains only the elements in this list that are contained in the specified collection.  In
318     * other words, removes from this list all of its elements that are not contained in the
319     * specified collection.
320     * 
321     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
322     *
323     * @param c collection containing elements to be retained in this list
324     * @return {@code TRUE} if this list changed as a result of the call
325     * 
326     * @throws ClassCastException if the class of an element of this list is incompatible with the
327     * specified collection
328     * (<a href="Collection.html#optional-restrictions">optional</a>)
329     * 
330     * @throws NullPointerException if this list contains a null element and the specified
331     * collection does not permit null elements
332     * (<a href="Collection.html#optional-restrictions">optional</a>),
333     * or if the specified collection is null
334     * 
335     * @see ReadOnlyCollection#contains(Object)
336     */
337    public boolean retainAll(Collection<?> c)
338    {
339        if (this.built) throw new AttemptedModificationException(ROAL);
340        return super.retainAll(c); 
341    }
342
343    /**
344     * Removes all of the elements of this collection that satisfy the given predicate. Errors or
345     * runtime exceptions thrown during iteration or by the predicate are relayed to the caller.
346     * 
347     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
348     * 
349     * @param filter a predicate which returns true for elements to be removed
350     * @return {@code TRUE} if any elements were removed
351     * @throws NullPointerException If parameter {@code 'filter'} has been passed null.
352     */
353    public boolean removeIf(Predicate<? super E> filter)
354    {
355        if (this.built) throw new AttemptedModificationException(ROAL);
356        return super.removeIf(filter); 
357    }
358
359    /**
360     * Replaces each element of this list with the result of applying the operator to that element.
361     * Errors or runtime exceptions thrown by the operator are relayed to the caller.
362     * 
363     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
364     * 
365     * @param operator the operator to apply to each element
366     * 
367     * @throws NullPointerException - if the specified operator is null or if the operator result
368     * is a null value and this list does not permit null elements (optional)
369     */
370    public void replaceAll(UnaryOperator<E> operator)
371    {
372        if (this.built) throw new AttemptedModificationException(ROAL);
373        super.replaceAll(operator); 
374    }
375
376    /**
377     * Sorts this list according to the order induced by the specified Comparator. The sort is
378     * stable: this method must not reorder equal elements.
379     * 
380     * <BR /><BR />All elements in this list must be mutually comparable using the specified
381     * comparator (that is, {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
382     * for any elements e1 and e2 in the list).
383     * 
384     * <BR /><BR />If the specified comparator is null then all elements in this list must
385     * implement the Comparable interface and the elements' natural ordering should be used.
386     * 
387     * <BR /><BR />This list must be modifiable, but need not be resizable.
388     * 
389     * <EMBED DATA-TYPE=ArrayList CLASS='external-html' DATA-FILE-ID=MUTATOR>
390     * 
391     * @param c the Comparator used to compare list elements. A null value indicates that the
392     * elements' natural ordering should be used
393     * 
394     * @throws ClassCastException if the list contains elements that are not mutually comparable
395     * using the specified comparator
396     * 
397     * @throws IllegalArgumentException  (optional) if the comparator is found to violate the
398     * {@code Comparator} contract
399     */
400    public void sort(Comparator<? super E> c)
401    {
402        if (this.built) throw new AttemptedModificationException(ROAL);
403        super.sort(c); 
404    }
405
406
407    // ********************************************************************************************
408    // ********************************************************************************************
409    // Methods inherited from class java.util.ArrayList
410    // ********************************************************************************************
411    // ********************************************************************************************
412
413
414    // clone, forEach, hashCode, iterator, listIterator, listIterator, removeRange, spliterator,
415    // subList, toArray, toArray
416    //
417    // Introspection Only:              clone, forEach, hashCode, spliterator, toArray, toArray
418    // Mutator or Potential Mutator:    ilterator, listIterator, listIterator, subList
419    // Protected (not-needed) Mutator:  removeRange
420    //
421    // *** OTHER INHERITED METHODS - ALL READ-ONLY METHODS ***
422    //
423    // Methods inherited from class java.util.AbstractCollection:   containsAll, toString
424    // Methods inherited from interface java.util.Collection:       parallelStream, stream, toArray
425    // Methods inherited from interface java.util.List:             containsAll
426
427    /**
428     * Restricts a back-door into the underlying data-structure.
429     * <EMBED CLASS='external-html'DATA-RET_TYPE=Iterator DATA-FILE-ID=UNMODIFIABLE>
430     * @return a {@code java.util.Iterator} that cannot modify this {@code ArrayList-Builder}
431     */
432    public RemoveUnsupportedIterator<E> iterator()
433    { return new RemoveUnsupportedIterator<>(super.iterator()); }
434
435    /**
436     * Restricts a back-door into the underlying data-structure.
437     * <EMBED CLASS='external-html'DATA-RET_TYPE=ListIterator DATA-FILE-ID=UNMODIFIABLE>
438     * @return a {@code java.util.ListIterator} that cannot modify this {@code ArrayList-Builder}
439     */
440    public ListIterator<E> listIterator()
441    { return ROHelpers.removeUnsupportedListIterator(super.listIterator()); }
442
443    ListIterator<E> _listIterator(ReadOnlyArrayList.AccessBadge friendClassBadge)
444    { return super.listIterator(); }
445
446    /**
447     * Restricts a back-door into the underlying data-structure.
448     * <EMBED CLASS='external-html'DATA-RET_TYPE=ListIterator DATA-FILE-ID=UNMODIFIABLE>
449     * @return a {@code java.util.ListIterator} that cannot modify this {@code ArrayList-Builder}
450     */
451    public ListIterator<E> listIterator(int index)
452    { return ROHelpers.removeUnsupportedListIterator(super.listIterator(index)); }
453
454    ListIterator<E> _listIterator(int index, ReadOnlyArrayList.AccessBadge friendClassBadge)
455    { return super.listIterator(index); }
456
457    /**
458     * Restricts a back-door into the underlying data-structure.
459     * <EMBED CLASS='external-html'DATA-RET_TYPE=List DATA-FILE-ID=UNMODIFIABLE>
460     * @return a {@code java.util.List} that cannot modify this {@code ArrayList-Builder}
461     */
462    public List<E> subList(int fromIndex, int toIndex)
463    { return Collections.unmodifiableList(super.subList(fromIndex, toIndex)); }
464
465    List<E> _subList(int fromIndex, int toIndex, ReadOnlyArrayList.AccessBadge friendClassBadge)
466    { return super.subList(fromIndex, toIndex); }
467
468
469    // ********************************************************************************************
470    // ********************************************************************************************
471    // java.lang.Object & Cloneable
472    // ********************************************************************************************
473    // ********************************************************************************************
474
475
476    /**
477     * Compares the specified Object with this Builder for equality, as per the definition in the
478     * original class {@code java.util.ArrayList}.  Ignores the private field {@code 'built'}.  If
479     * {@code 'this'} has not been built, but {@code 'o'} has been, that fact is ignored during the
480     * equality-comparison.
481     *
482     * @param  o object to be compared for equality with this {@code ROArrayListBuilder} instance
483     * @return true if the specified Object is equal to this Builder
484     */
485    public boolean equals(Object o)
486    {
487        if (this == o) return true;
488        if (! (o instanceof ROArrayListBuilder)) return false;
489        return super.equals((ArrayList) o);
490    }
491
492    /**
493     * Clones this instance' of {@code ROArrayListBuilder}.
494     * 
495     * <BR /><BR />The clone that's returned has had it's internal {@code 'built'} boolean-flag set
496     * {@code FALSE}
497     * 
498     * @return a clone of this builder
499     */
500    public synchronized ROArrayListBuilder<E> clone()
501    { return new ROArrayListBuilder<>(this); }
502
503    private ROArrayListBuilder(ROArrayListBuilder<E> roalb)
504    { super(roalb); this.built=false; }
505}