1 /*
2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.awt.util;
27 
28 import java.util.AbstractList;
29 import java.util.Arrays;
30 import java.util.Collection;
31 import java.util.ConcurrentModificationException;
32 import java.util.List;
33 import java.util.RandomAccess;
34 
35 /**
36  * Resizable-array implementation of the {@code List} interface.  Implements
37  * all optional list operations, and permits all elements, including
38  * {@code null}.  In addition to implementing the {@code List} interface,
39  * this class provides methods to manipulate the size of the array that is
40  * used internally to store the list.  (This class is roughly equivalent to
41  * {@code Vector}, except that it is unsynchronized.)<p>
42  *
43  * The {@code size}, {@code isEmpty}, {@code get}, {@code set},
44  * {@code iterator}, and {@code listIterator} operations run in constant
45  * time.  The {@code add} operation runs in <i>amortized constant time</i>,
46  * that is, adding n elements requires O(n) time.  All of the other operations
47  * run in linear time (roughly speaking).  The constant factor is low compared
48  * to that for the {@code LinkedList} implementation.<p>
49  *
50  * Each {@code IdentityArrayList} instance has a <i>capacity</i>.  The capacity is
51  * the size of the array used to store the elements in the list.  It is always
52  * at least as large as the list size.  As elements are added to an IdentityArrayList,
53  * its capacity grows automatically.  The details of the growth policy are not
54  * specified beyond the fact that adding an element has constant amortized
55  * time cost.<p>
56  *
57  * An application can increase the capacity of an {@code IdentityArrayList} instance
58  * before adding a large number of elements using the {@code ensureCapacity}
59  * operation.  This may reduce the amount of incremental reallocation.
60  *
61  * <p><strong>Note that this implementation is not synchronized.</strong>
62  * If multiple threads access an {@code IdentityArrayList} instance concurrently,
63  * and at least one of the threads modifies the list structurally, it
64  * <i>must</i> be synchronized externally.  (A structural modification is
65  * any operation that adds or deletes one or more elements, or explicitly
66  * resizes the backing array; merely setting the value of an element is not
67  * a structural modification.)  This is typically accomplished by
68  * synchronizing on some object that naturally encapsulates the list.
69  *
70  * If no such object exists, the list should be "wrapped" using the
71  * {@link java.util.Collections#synchronizedList Collections.synchronizedList}
72  * method.  This is best done at creation time, to prevent accidental
73  * unsynchronized access to the list:<pre>
74  *   List list = Collections.synchronizedList(new IdentityArrayList(...));</pre>
75  *
76  * <p>The iterators returned by this class's {@code iterator} and
77  * {@code listIterator} methods are <i>fail-fast</i>: if the list is
78  * structurally modified at any time after the iterator is created, in any way
79  * except through the iterator's own {@code remove} or {@code add} methods,
80  * the iterator will throw a {@link ConcurrentModificationException}.  Thus, in
81  * the face of concurrent modification, the iterator fails quickly and cleanly,
82  * rather than risking arbitrary, non-deterministic behavior at an undetermined
83  * time in the future.<p>
84  *
85  * Note that the fail-fast behavior of an iterator cannot be guaranteed
86  * as it is, generally speaking, impossible to make any hard guarantees in the
87  * presence of unsynchronized concurrent modification.  Fail-fast iterators
88  * throw {@code ConcurrentModificationException} on a best-effort basis.
89  * Therefore, it would be wrong to write a program that depended on this
90  * exception for its correctness: <i>the fail-fast behavior of iterators
91  * should be used only to detect bugs.</i><p>
92  *
93  */
94 
95 public class IdentityArrayList<E> extends AbstractList<E>
96         implements List<E>, RandomAccess
97 {
98 
99     /**
100      * The array buffer into which the elements of the IdentityArrayList are stored.
101      * The capacity of the IdentityArrayList is the length of this array buffer.
102      */
103     private transient Object[] elementData;
104 
105     /**
106      * The size of the IdentityArrayList (the number of elements it contains).
107      *
108      * @serial
109      */
110     private int size;
111 
112     /**
113      * Constructs an empty list with the specified initial capacity.
114      *
115      * @param   initialCapacity   the initial capacity of the list
116      * @exception IllegalArgumentException if the specified initial capacity
117      *            is negative
118      */
IdentityArrayList(int initialCapacity)119     public IdentityArrayList(int initialCapacity) {
120         super();
121         if (initialCapacity < 0)
122             throw new IllegalArgumentException("Illegal Capacity: "+
123                     initialCapacity);
124         this.elementData = new Object[initialCapacity];
125     }
126 
127     /**
128      * Constructs an empty list with an initial capacity of ten.
129      */
IdentityArrayList()130     public IdentityArrayList() {
131         this(10);
132     }
133 
134     /**
135      * Constructs a list containing the elements of the specified
136      * collection, in the order they are returned by the collection's
137      * iterator.
138      *
139      * @param c the collection whose elements are to be placed into this list
140      * @throws NullPointerException if the specified collection is null
141      */
IdentityArrayList(Collection<? extends E> c)142     public IdentityArrayList(Collection<? extends E> c) {
143         elementData = c.toArray();
144         size = elementData.length;
145         // defend against c.toArray (incorrectly) not returning Object[]
146         // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
147         if (elementData.getClass() != Object[].class)
148             elementData = Arrays.copyOf(elementData, size, Object[].class);
149     }
150 
151     /**
152      * Trims the capacity of this {@code IdentityArrayList} instance to be the
153      * list's current size.  An application can use this operation to minimize
154      * the storage of an {@code IdentityArrayList} instance.
155      */
trimToSize()156     public void trimToSize() {
157         modCount++;
158         int oldCapacity = elementData.length;
159         if (size < oldCapacity) {
160             elementData = Arrays.copyOf(elementData, size);
161         }
162     }
163 
164     /**
165      * Increases the capacity of this {@code IdentityArrayList} instance, if
166      * necessary, to ensure that it can hold at least the number of elements
167      * specified by the minimum capacity argument.
168      *
169      * @param   minCapacity   the desired minimum capacity
170      */
ensureCapacity(int minCapacity)171     public void ensureCapacity(int minCapacity) {
172         modCount++;
173         int oldCapacity = elementData.length;
174         if (minCapacity > oldCapacity) {
175             Object[] oldData = elementData;
176             int newCapacity = (oldCapacity * 3)/2 + 1;
177             if (newCapacity < minCapacity)
178                 newCapacity = minCapacity;
179             // minCapacity is usually close to size, so this is a win:
180             elementData = Arrays.copyOf(elementData, newCapacity);
181         }
182     }
183 
184     /**
185      * Returns the number of elements in this list.
186      *
187      * @return the number of elements in this list
188      */
size()189     public int size() {
190         return size;
191     }
192 
193     /**
194      * Returns {@code true} if this list contains no elements.
195      *
196      * @return {@code true} if this list contains no elements
197      */
isEmpty()198     public boolean isEmpty() {
199         return size == 0;
200     }
201 
202     /**
203      * Returns {@code true} if this list contains the specified element.
204      * More formally, returns {@code true} if and only if this list contains
205      * at least one element {@code e} such that
206      * {@code Objects.equals(o, e)}.
207      *
208      * @param o element whose presence in this list is to be tested
209      * @return {@code true} if this list contains the specified element
210      */
contains(Object o)211     public boolean contains(Object o) {
212         return indexOf(o) >= 0;
213     }
214 
215     /**
216      * Returns the index of the first occurrence of the specified element
217      * in this list, or -1 if this list does not contain the element.
218      * More formally, returns the lowest index {@code i} such that
219      * {@code Objects.equals(o, get(i))},
220      * or -1 if there is no such index.
221      */
indexOf(Object o)222     public int indexOf(Object o) {
223         for (int i = 0; i < size; i++) {
224             if (o == elementData[i]) {
225                 return i;
226             }
227         }
228         return -1;
229     }
230 
231     /**
232      * Returns the index of the last occurrence of the specified element
233      * in this list, or -1 if this list does not contain the element.
234      * More formally, returns the highest index {@code i} such that
235      * {@code Objects.equals(o, get(i))},
236      * or -1 if there is no such index.
237      */
lastIndexOf(Object o)238     public int lastIndexOf(Object o) {
239         for (int i = size-1; i >= 0; i--) {
240             if (o == elementData[i]) {
241                 return i;
242             }
243         }
244         return -1;
245     }
246 
247     /**
248      * Returns an array containing all of the elements in this list
249      * in proper sequence (from first to last element).
250      *
251      * <p>The returned array will be "safe" in that no references to it are
252      * maintained by this list.  (In other words, this method must allocate
253      * a new array).  The caller is thus free to modify the returned array.
254      *
255      * <p>This method acts as bridge between array-based and collection-based
256      * APIs.
257      *
258      * @return an array containing all of the elements in this list in
259      *         proper sequence
260      */
toArray()261     public Object[] toArray() {
262         return Arrays.copyOf(elementData, size);
263     }
264 
265     /**
266      * Returns an array containing all of the elements in this list in proper
267      * sequence (from first to last element); the runtime type of the returned
268      * array is that of the specified array.  If the list fits in the
269      * specified array, it is returned therein.  Otherwise, a new array is
270      * allocated with the runtime type of the specified array and the size of
271      * this list.
272      *
273      * <p>If the list fits in the specified array with room to spare
274      * (i.e., the array has more elements than the list), the element in
275      * the array immediately following the end of the collection is set to
276      * {@code null}.  (This is useful in determining the length of the
277      * list <i>only</i> if the caller knows that the list does not contain
278      * any null elements.)
279      *
280      * @param a the array into which the elements of the list are to
281      *          be stored, if it is big enough; otherwise, a new array of the
282      *          same runtime type is allocated for this purpose.
283      * @return an array containing the elements of the list
284      * @throws ArrayStoreException if the runtime type of the specified array
285      *         is not a supertype of the runtime type of every element in
286      *         this list
287      * @throws NullPointerException if the specified array is null
288      */
289     @SuppressWarnings("unchecked")
toArray(T[] a)290     public <T> T[] toArray(T[] a) {
291         if (a.length < size)
292             // Make a new array of a's runtime type, but my contents:
293             return (T[]) Arrays.copyOf(elementData, size, a.getClass());
294         System.arraycopy(elementData, 0, a, 0, size);
295         if (a.length > size)
296             a[size] = null;
297         return a;
298     }
299 
300     // Positional Access Operations
301 
302     /**
303      * Returns the element at the specified position in this list.
304      *
305      * @param  index index of the element to return
306      * @return the element at the specified position in this list
307      * @throws IndexOutOfBoundsException {@inheritDoc}
308      */
get(int index)309     public E get(int index) {
310         rangeCheck(index);
311 
312         @SuppressWarnings("unchecked")
313         E rv = (E) elementData[index];
314         return rv;
315     }
316 
317     /**
318      * Replaces the element at the specified position in this list with
319      * the specified element.
320      *
321      * @param index index of the element to replace
322      * @param element element to be stored at the specified position
323      * @return the element previously at the specified position
324      * @throws IndexOutOfBoundsException {@inheritDoc}
325      */
set(int index, E element)326     public E set(int index, E element) {
327         rangeCheck(index);
328 
329         @SuppressWarnings("unchecked")
330         E oldValue = (E) elementData[index];
331         elementData[index] = element;
332         return oldValue;
333     }
334 
335     /**
336      * Appends the specified element to the end of this list.
337      *
338      * @param e element to be appended to this list
339      * @return {@code true} (as specified by {@link Collection#add})
340      */
add(E e)341     public boolean add(E e) {
342         ensureCapacity(size + 1);  // Increments modCount!!
343         elementData[size++] = e;
344         return true;
345     }
346 
347     /**
348      * Inserts the specified element at the specified position in this
349      * list. Shifts the element currently at that position (if any) and
350      * any subsequent elements to the right (adds one to their indices).
351      *
352      * @param index index at which the specified element is to be inserted
353      * @param element element to be inserted
354      * @throws IndexOutOfBoundsException {@inheritDoc}
355      */
add(int index, E element)356     public void add(int index, E element) {
357         rangeCheckForAdd(index);
358 
359         ensureCapacity(size+1);  // Increments modCount!!
360         System.arraycopy(elementData, index, elementData, index + 1,
361                 size - index);
362         elementData[index] = element;
363         size++;
364     }
365 
366     /**
367      * Removes the element at the specified position in this list.
368      * Shifts any subsequent elements to the left (subtracts one from their
369      * indices).
370      *
371      * @param index the index of the element to be removed
372      * @return the element that was removed from the list
373      * @throws IndexOutOfBoundsException {@inheritDoc}
374      */
remove(int index)375     public E remove(int index) {
376         rangeCheck(index);
377 
378         modCount++;
379         @SuppressWarnings("unchecked")
380         E oldValue = (E) elementData[index];
381 
382         int numMoved = size - index - 1;
383         if (numMoved > 0)
384             System.arraycopy(elementData, index+1, elementData, index,
385                     numMoved);
386         elementData[--size] = null; // Let gc do its work
387 
388         return oldValue;
389     }
390 
391     /**
392      * Removes the first occurrence of the specified element from this list,
393      * if it is present.  If the list does not contain the element, it is
394      * unchanged.  More formally, removes the element with the lowest index
395      * {@code i} such that {@code Objects.equals(o, get(i))}
396      * (if such an element exists).  Returns {@code true} if this list
397      * contained the specified element (or equivalently, if this list
398      * changed as a result of the call).
399      *
400      * @param o element to be removed from this list, if present
401      * @return {@code true} if this list contained the specified element
402      */
remove(Object o)403     public boolean remove(Object o) {
404         for (int index = 0; index < size; index++) {
405             if (o == elementData[index]) {
406                 fastRemove(index);
407                 return true;
408             }
409         }
410         return false;
411     }
412 
413     /*
414      * Private remove method that skips bounds checking and does not
415      * return the value removed.
416      */
fastRemove(int index)417     private void fastRemove(int index) {
418         modCount++;
419         int numMoved = size - index - 1;
420         if (numMoved > 0)
421             System.arraycopy(elementData, index+1, elementData, index,
422                     numMoved);
423         elementData[--size] = null; // Let gc do its work
424     }
425 
426     /**
427      * Removes all of the elements from this list.  The list will
428      * be empty after this call returns.
429      */
clear()430     public void clear() {
431         modCount++;
432 
433         // Let gc do its work
434         for (int i = 0; i < size; i++)
435             elementData[i] = null;
436 
437         size = 0;
438     }
439 
440     /**
441      * Appends all of the elements in the specified collection to the end of
442      * this list, in the order that they are returned by the
443      * specified collection's Iterator.  The behavior of this operation is
444      * undefined if the specified collection is modified while the operation
445      * is in progress.  (This implies that the behavior of this call is
446      * undefined if the specified collection is this list, and this
447      * list is nonempty.)
448      *
449      * @param c collection containing elements to be added to this list
450      * @return {@code true} if this list changed as a result of the call
451      * @throws NullPointerException if the specified collection is null
452      */
addAll(Collection<? extends E> c)453     public boolean addAll(Collection<? extends E> c) {
454         Object[] a = c.toArray();
455         int numNew = a.length;
456         ensureCapacity(size + numNew);  // Increments modCount
457         System.arraycopy(a, 0, elementData, size, numNew);
458         size += numNew;
459         return numNew != 0;
460     }
461 
462     /**
463      * Inserts all of the elements in the specified collection into this
464      * list, starting at the specified position.  Shifts the element
465      * currently at that position (if any) and any subsequent elements to
466      * the right (increases their indices).  The new elements will appear
467      * in the list in the order that they are returned by the
468      * specified collection's iterator.
469      *
470      * @param index index at which to insert the first element from the
471      *              specified collection
472      * @param c collection containing elements to be added to this list
473      * @return {@code true} if this list changed as a result of the call
474      * @throws IndexOutOfBoundsException {@inheritDoc}
475      * @throws NullPointerException if the specified collection is null
476      */
addAll(int index, Collection<? extends E> c)477     public boolean addAll(int index, Collection<? extends E> c) {
478         rangeCheckForAdd(index);
479 
480         Object[] a = c.toArray();
481         int numNew = a.length;
482         ensureCapacity(size + numNew);  // Increments modCount
483 
484         int numMoved = size - index;
485         if (numMoved > 0) {
486             System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
487         }
488 
489         System.arraycopy(a, 0, elementData, index, numNew);
490         size += numNew;
491         return numNew != 0;
492     }
493 
494     /**
495      * Removes from this list all of the elements whose index is between
496      * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
497      * Shifts any succeeding elements to the left (reduces their index).
498      * This call shortens the list by {@code (toIndex - fromIndex)} elements.
499      * (If {@code toIndex==fromIndex}, this operation has no effect.)
500      *
501      * @param fromIndex index of first element to be removed
502      * @param toIndex index after last element to be removed
503      * @throws IndexOutOfBoundsException if fromIndex or toIndex out of
504      *              range (fromIndex &lt; 0 || fromIndex &gt;= size() || toIndex
505      *              &gt; size() || toIndex &lt; fromIndex)
506      */
removeRange(int fromIndex, int toIndex)507     protected void removeRange(int fromIndex, int toIndex) {
508         modCount++;
509         int numMoved = size - toIndex;
510         System.arraycopy(elementData, toIndex, elementData, fromIndex,
511                 numMoved);
512 
513         // Let gc do its work
514         int newSize = size - (toIndex-fromIndex);
515         while (size != newSize)
516             elementData[--size] = null;
517     }
518 
519     /**
520      * Checks if the given index is in range.  If not, throws an appropriate
521      * runtime exception.  This method does *not* check if the index is
522      * negative: It is always used immediately prior to an array access,
523      * which throws an ArrayIndexOutOfBoundsException if index is negative.
524      */
rangeCheck(int index)525     private void rangeCheck(int index) {
526         if (index >= size)
527             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
528     }
529 
530     /**
531      * A version of rangeCheck used by add and addAll.
532      */
rangeCheckForAdd(int index)533     private void rangeCheckForAdd(int index) {
534         if (index > size || index < 0)
535             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
536     }
537 
538     /**
539      * Constructs an IndexOutOfBoundsException detail message.
540      * Of the many possible refactorings of the error handling code,
541      * this "outlining" performs best with both server and client VMs.
542      */
outOfBoundsMsg(int index)543     private String outOfBoundsMsg(int index) {
544         return "Index: "+index+", Size: "+size;
545     }
546 }
547