1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.util;
19 
20 import java.io.IOException;
21 import java.io.InvalidObjectException;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.Serializable;
25 import java.lang.reflect.Array;
26 import libcore.util.EmptyArray;
27 
28 /**
29  * ArrayList is an implementation of {@link List}, backed by an array.
30  * All optional operations including adding, removing, and replacing elements are supported.
31  *
32  * <p>All elements are permitted, including null.
33  *
34  * <p>This class is a good choice as your default {@code List} implementation.
35  * {@link Vector} synchronizes all operations, but not necessarily in a way that's
36  * meaningful to your application: synchronizing each call to {@code get}, for example, is not
37  * equivalent to synchronizing the list and iterating over it (which is probably what you intended).
38  * {@link java.util.concurrent.CopyOnWriteArrayList} is intended for the special case of very high
39  * concurrency, frequent traversals, and very rare mutations.
40  *
41  * @param <E> The element type of this list.
42  * @since 1.2
43  */
44 public class ArrayList<E> extends AbstractList<E> implements Cloneable, Serializable, RandomAccess {
45     /**
46      * The minimum amount by which the capacity of an ArrayList will increase.
47      * This tuning parameter controls a time-space tradeoff. This value (12)
48      * gives empirically good results and is arguably consistent with the
49      * RI's specified default initial capacity of 10: instead of 10, we start
50      * with 0 (sans allocation) and jump to 12.
51      */
52     private static final int MIN_CAPACITY_INCREMENT = 12;
53 
54     /**
55      * The number of elements in this list.
56      */
57     int size;
58 
59     /**
60      * The elements in this list, followed by nulls.
61      */
62     transient Object[] array;
63 
64     /**
65      * Constructs a new instance of {@code ArrayList} with the specified
66      * initial capacity.
67      *
68      * @param capacity
69      *            the initial capacity of this {@code ArrayList}.
70      */
ArrayList(int capacity)71     public ArrayList(int capacity) {
72         if (capacity < 0) {
73             throw new IllegalArgumentException("capacity < 0: " + capacity);
74         }
75         array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
76     }
77 
78     /**
79      * Constructs a new {@code ArrayList} instance with zero initial capacity.
80      */
ArrayList()81     public ArrayList() {
82         array = EmptyArray.OBJECT;
83     }
84 
85     /**
86      * Constructs a new instance of {@code ArrayList} containing the elements of
87      * the specified collection.
88      *
89      * @param collection
90      *            the collection of elements to add.
91      */
ArrayList(Collection<? extends E> collection)92     public ArrayList(Collection<? extends E> collection) {
93         if (collection == null) {
94             throw new NullPointerException("collection == null");
95         }
96 
97         Object[] a = collection.toArray();
98         if (a.getClass() != Object[].class) {
99             Object[] newArray = new Object[a.length];
100             System.arraycopy(a, 0, newArray, 0, a.length);
101             a = newArray;
102         }
103         array = a;
104         size = a.length;
105     }
106 
107     /**
108      * Adds the specified object at the end of this {@code ArrayList}.
109      *
110      * @param object
111      *            the object to add.
112      * @return always true
113      */
add(E object)114     @Override public boolean add(E object) {
115         Object[] a = array;
116         int s = size;
117         if (s == a.length) {
118             Object[] newArray = new Object[s +
119                     (s < (MIN_CAPACITY_INCREMENT / 2) ?
120                      MIN_CAPACITY_INCREMENT : s >> 1)];
121             System.arraycopy(a, 0, newArray, 0, s);
122             array = a = newArray;
123         }
124         a[s] = object;
125         size = s + 1;
126         modCount++;
127         return true;
128     }
129 
130     /**
131      * Inserts the specified object into this {@code ArrayList} at the specified
132      * location. The object is inserted before any previous element at the
133      * specified location. If the location is equal to the size of this
134      * {@code ArrayList}, the object is added at the end.
135      *
136      * @param index
137      *            the index at which to insert the object.
138      * @param object
139      *            the object to add.
140      * @throws IndexOutOfBoundsException
141      *             when {@code location < 0 || location > size()}
142      */
add(int index, E object)143     @Override public void add(int index, E object) {
144         Object[] a = array;
145         int s = size;
146         if (index > s || index < 0) {
147             throwIndexOutOfBoundsException(index, s);
148         }
149 
150         if (s < a.length) {
151             System.arraycopy(a, index, a, index + 1, s - index);
152         } else {
153             // assert s == a.length;
154             Object[] newArray = new Object[newCapacity(s)];
155             System.arraycopy(a, 0, newArray, 0, index);
156             System.arraycopy(a, index, newArray, index + 1, s - index);
157             array = a = newArray;
158         }
159         a[index] = object;
160         size = s + 1;
161         modCount++;
162     }
163 
164     /**
165      * This method controls the growth of ArrayList capacities.  It represents
166      * a time-space tradeoff: we don't want to grow lists too frequently
167      * (which wastes time and fragments storage), but we don't want to waste
168      * too much space in unused excess capacity.
169      *
170      * NOTE: This method is inlined into {@link #add(Object)} for performance.
171      * If you change the method, change it there too!
172      */
newCapacity(int currentCapacity)173     private static int newCapacity(int currentCapacity) {
174         int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
175                 MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
176         return currentCapacity + increment;
177     }
178 
179     /**
180      * Adds the objects in the specified collection to this {@code ArrayList}.
181      *
182      * @param collection
183      *            the collection of objects.
184      * @return {@code true} if this {@code ArrayList} is modified, {@code false}
185      *         otherwise.
186      */
addAll(Collection<? extends E> collection)187     @Override public boolean addAll(Collection<? extends E> collection) {
188         Object[] newPart = collection.toArray();
189         int newPartSize = newPart.length;
190         if (newPartSize == 0) {
191             return false;
192         }
193         Object[] a = array;
194         int s = size;
195         int newSize = s + newPartSize; // If add overflows, arraycopy will fail
196         if (newSize > a.length) {
197             int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
198             Object[] newArray = new Object[newCapacity];
199             System.arraycopy(a, 0, newArray, 0, s);
200             array = a = newArray;
201         }
202         System.arraycopy(newPart, 0, a, s, newPartSize);
203         size = newSize;
204         modCount++;
205         return true;
206     }
207 
208     /**
209      * Inserts the objects in the specified collection at the specified location
210      * in this List. The objects are added in the order they are returned from
211      * the collection's iterator.
212      *
213      * @param index
214      *            the index at which to insert.
215      * @param collection
216      *            the collection of objects.
217      * @return {@code true} if this {@code ArrayList} is modified, {@code false}
218      *         otherwise.
219      * @throws IndexOutOfBoundsException
220      *             when {@code location < 0 || location > size()}
221      */
222     @Override
addAll(int index, Collection<? extends E> collection)223     public boolean addAll(int index, Collection<? extends E> collection) {
224         int s = size;
225         if (index > s || index < 0) {
226             throwIndexOutOfBoundsException(index, s);
227         }
228         Object[] newPart = collection.toArray();
229         int newPartSize = newPart.length;
230         if (newPartSize == 0) {
231             return false;
232         }
233         Object[] a = array;
234         int newSize = s + newPartSize; // If add overflows, arraycopy will fail
235         if (newSize <= a.length) {
236              System.arraycopy(a, index, a, index + newPartSize, s - index);
237         } else {
238             int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
239             Object[] newArray = new Object[newCapacity];
240             System.arraycopy(a, 0, newArray, 0, index);
241             System.arraycopy(a, index, newArray, index + newPartSize, s-index);
242             array = a = newArray;
243         }
244         System.arraycopy(newPart, 0, a, index, newPartSize);
245         size = newSize;
246         modCount++;
247         return true;
248     }
249 
250     /**
251      * This method was extracted to encourage VM to inline callers.
252      * TODO: when we have a VM that can actually inline, move the test in here too!
253      */
throwIndexOutOfBoundsException(int index, int size)254     static IndexOutOfBoundsException throwIndexOutOfBoundsException(int index, int size) {
255         throw new IndexOutOfBoundsException("Invalid index " + index + ", size is " + size);
256     }
257 
258     /**
259      * Removes all elements from this {@code ArrayList}, leaving it empty.
260      *
261      * @see #isEmpty
262      * @see #size
263      */
clear()264     @Override public void clear() {
265         if (size != 0) {
266             Arrays.fill(array, 0, size, null);
267             size = 0;
268             modCount++;
269         }
270     }
271 
272     /**
273      * Returns a new {@code ArrayList} with the same elements, the same size and
274      * the same capacity as this {@code ArrayList}.
275      *
276      * @return a shallow copy of this {@code ArrayList}
277      * @see java.lang.Cloneable
278      */
clone()279     @Override public Object clone() {
280         try {
281             ArrayList<?> result = (ArrayList<?>) super.clone();
282             result.array = array.clone();
283             return result;
284         } catch (CloneNotSupportedException e) {
285            throw new AssertionError();
286         }
287     }
288 
289     /**
290      * Ensures that after this operation the {@code ArrayList} can hold the
291      * specified number of elements without further growing.
292      *
293      * @param minimumCapacity
294      *            the minimum capacity asked for.
295      */
ensureCapacity(int minimumCapacity)296     public void ensureCapacity(int minimumCapacity) {
297         Object[] a = array;
298         if (a.length < minimumCapacity) {
299             Object[] newArray = new Object[minimumCapacity];
300             System.arraycopy(a, 0, newArray, 0, size);
301             array = newArray;
302             modCount++;
303         }
304     }
305 
get(int index)306     @SuppressWarnings("unchecked") @Override public E get(int index) {
307         if (index >= size) {
308             throwIndexOutOfBoundsException(index, size);
309         }
310         return (E) array[index];
311     }
312 
313     /**
314      * Returns the number of elements in this {@code ArrayList}.
315      *
316      * @return the number of elements in this {@code ArrayList}.
317      */
size()318     @Override public int size() {
319         return size;
320     }
321 
isEmpty()322     @Override public boolean isEmpty() {
323         return size == 0;
324     }
325 
326     /**
327      * Searches this {@code ArrayList} for the specified object.
328      *
329      * @param object
330      *            the object to search for.
331      * @return {@code true} if {@code object} is an element of this
332      *         {@code ArrayList}, {@code false} otherwise
333      */
contains(Object object)334     @Override public boolean contains(Object object) {
335         Object[] a = array;
336         int s = size;
337         if (object != null) {
338             for (int i = 0; i < s; i++) {
339                 if (object.equals(a[i])) {
340                     return true;
341                 }
342             }
343         } else {
344             for (int i = 0; i < s; i++) {
345                 if (a[i] == null) {
346                     return true;
347                 }
348             }
349         }
350         return false;
351     }
352 
indexOf(Object object)353     @Override public int indexOf(Object object) {
354         Object[] a = array;
355         int s = size;
356         if (object != null) {
357             for (int i = 0; i < s; i++) {
358                 if (object.equals(a[i])) {
359                     return i;
360                 }
361             }
362         } else {
363             for (int i = 0; i < s; i++) {
364                 if (a[i] == null) {
365                     return i;
366                 }
367             }
368         }
369         return -1;
370     }
371 
lastIndexOf(Object object)372     @Override public int lastIndexOf(Object object) {
373         Object[] a = array;
374         if (object != null) {
375             for (int i = size - 1; i >= 0; i--) {
376                 if (object.equals(a[i])) {
377                     return i;
378                 }
379             }
380         } else {
381             for (int i = size - 1; i >= 0; i--) {
382                 if (a[i] == null) {
383                     return i;
384                 }
385             }
386         }
387         return -1;
388     }
389 
390     /**
391      * Removes the object at the specified location from this list.
392      *
393      * @param index
394      *            the index of the object to remove.
395      * @return the removed object.
396      * @throws IndexOutOfBoundsException
397      *             when {@code location < 0 || location >= size()}
398      */
remove(int index)399     @Override public E remove(int index) {
400         Object[] a = array;
401         int s = size;
402         if (index >= s) {
403             throwIndexOutOfBoundsException(index, s);
404         }
405         @SuppressWarnings("unchecked") E result = (E) a[index];
406         System.arraycopy(a, index + 1, a, index, --s - index);
407         a[s] = null;  // Prevent memory leak
408         size = s;
409         modCount++;
410         return result;
411     }
412 
remove(Object object)413     @Override public boolean remove(Object object) {
414         Object[] a = array;
415         int s = size;
416         if (object != null) {
417             for (int i = 0; i < s; i++) {
418                 if (object.equals(a[i])) {
419                     System.arraycopy(a, i + 1, a, i, --s - i);
420                     a[s] = null;  // Prevent memory leak
421                     size = s;
422                     modCount++;
423                     return true;
424                 }
425             }
426         } else {
427             for (int i = 0; i < s; i++) {
428                 if (a[i] == null) {
429                     System.arraycopy(a, i + 1, a, i, --s - i);
430                     a[s] = null;  // Prevent memory leak
431                     size = s;
432                     modCount++;
433                     return true;
434                 }
435             }
436         }
437         return false;
438     }
439 
removeRange(int fromIndex, int toIndex)440     @Override protected void removeRange(int fromIndex, int toIndex) {
441         if (fromIndex == toIndex) {
442             return;
443         }
444         Object[] a = array;
445         int s = size;
446         if (fromIndex >= s) {
447             throw new IndexOutOfBoundsException("fromIndex " + fromIndex
448                     + " >= size " + size);
449         }
450         if (toIndex > s) {
451             throw new IndexOutOfBoundsException("toIndex " + toIndex
452                     + " > size " + size);
453         }
454         if (fromIndex > toIndex) {
455             throw new IndexOutOfBoundsException("fromIndex " + fromIndex
456                     + " > toIndex " + toIndex);
457         }
458 
459         System.arraycopy(a, toIndex, a, fromIndex, s - toIndex);
460         int rangeSize = toIndex - fromIndex;
461         Arrays.fill(a, s - rangeSize, s, null);
462         size = s - rangeSize;
463         modCount++;
464     }
465 
466     /**
467      * Replaces the element at the specified location in this {@code ArrayList}
468      * with the specified object.
469      *
470      * @param index
471      *            the index at which to put the specified object.
472      * @param object
473      *            the object to add.
474      * @return the previous element at the index.
475      * @throws IndexOutOfBoundsException
476      *             when {@code location < 0 || location >= size()}
477      */
set(int index, E object)478     @Override public E set(int index, E object) {
479         Object[] a = array;
480         if (index >= size) {
481             throwIndexOutOfBoundsException(index, size);
482         }
483         @SuppressWarnings("unchecked") E result = (E) a[index];
484         a[index] = object;
485         return result;
486     }
487 
488     /**
489      * Returns a new array containing all elements contained in this
490      * {@code ArrayList}.
491      *
492      * @return an array of the elements from this {@code ArrayList}
493      */
toArray()494     @Override public Object[] toArray() {
495         int s = size;
496         Object[] result = new Object[s];
497         System.arraycopy(array, 0, result, 0, s);
498         return result;
499     }
500 
501     /**
502      * Returns an array containing all elements contained in this
503      * {@code ArrayList}. If the specified array is large enough to hold the
504      * elements, the specified array is used, otherwise an array of the same
505      * type is created. If the specified array is used and is larger than this
506      * {@code ArrayList}, the array element following the collection elements
507      * is set to null.
508      *
509      * @param contents
510      *            the array.
511      * @return an array of the elements from this {@code ArrayList}.
512      * @throws ArrayStoreException
513      *             when the type of an element in this {@code ArrayList} cannot
514      *             be stored in the type of the specified array.
515      */
toArray(T[] contents)516     @Override public <T> T[] toArray(T[] contents) {
517         int s = size;
518         if (contents.length < s) {
519             @SuppressWarnings("unchecked") T[] newArray
520                 = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
521             contents = newArray;
522         }
523         System.arraycopy(this.array, 0, contents, 0, s);
524         if (contents.length > s) {
525             contents[s] = null;
526         }
527         return contents;
528     }
529 
530     /**
531      * Sets the capacity of this {@code ArrayList} to be the same as the current
532      * size.
533      *
534      * @see #size
535      */
trimToSize()536     public void trimToSize() {
537         int s = size;
538         if (s == array.length) {
539             return;
540         }
541         if (s == 0) {
542             array = EmptyArray.OBJECT;
543         } else {
544             Object[] newArray = new Object[s];
545             System.arraycopy(array, 0, newArray, 0, s);
546             array = newArray;
547         }
548         modCount++;
549     }
550 
iterator()551     @Override public Iterator<E> iterator() {
552         return new ArrayListIterator();
553     }
554 
555     private class ArrayListIterator implements Iterator<E> {
556         /** Number of elements remaining in this iteration */
557         private int remaining = size;
558 
559         /** Index of element that remove() would remove, or -1 if no such elt */
560         private int removalIndex = -1;
561 
562         /** The expected modCount value */
563         private int expectedModCount = modCount;
564 
hasNext()565         public boolean hasNext() {
566             return remaining != 0;
567         }
568 
next()569         @SuppressWarnings("unchecked") public E next() {
570             ArrayList<E> ourList = ArrayList.this;
571             int rem = remaining;
572             if (ourList.modCount != expectedModCount) {
573                 throw new ConcurrentModificationException();
574             }
575             if (rem == 0) {
576                 throw new NoSuchElementException();
577             }
578             remaining = rem - 1;
579             return (E) ourList.array[removalIndex = ourList.size - rem];
580         }
581 
remove()582         public void remove() {
583             Object[] a = array;
584             int removalIdx = removalIndex;
585             if (modCount != expectedModCount) {
586                 throw new ConcurrentModificationException();
587             }
588             if (removalIdx < 0) {
589                 throw new IllegalStateException();
590             }
591             System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
592             a[--size] = null;  // Prevent memory leak
593             removalIndex = -1;
594             expectedModCount = ++modCount;
595         }
596     }
597 
hashCode()598     @Override public int hashCode() {
599         Object[] a = array;
600         int hashCode = 1;
601         for (int i = 0, s = size; i < s; i++) {
602             Object e = a[i];
603             hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
604         }
605         return hashCode;
606     }
607 
equals(Object o)608     @Override public boolean equals(Object o) {
609         if (o == this) {
610             return true;
611         }
612         if (!(o instanceof List)) {
613             return false;
614         }
615         List<?> that = (List<?>) o;
616         int s = size;
617         if (that.size() != s) {
618             return false;
619         }
620         Object[] a = array;
621         if (that instanceof RandomAccess) {
622             for (int i = 0; i < s; i++) {
623                 Object eThis = a[i];
624                 Object ethat = that.get(i);
625                 if (eThis == null ? ethat != null : !eThis.equals(ethat)) {
626                     return false;
627                 }
628             }
629         } else {  // Argument list is not random access; use its iterator
630             Iterator<?> it = that.iterator();
631             for (int i = 0; i < s; i++) {
632                 Object eThis = a[i];
633                 Object eThat = it.next();
634                 if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
635                     return false;
636                 }
637             }
638         }
639         return true;
640     }
641 
642     private static final long serialVersionUID = 8683452581122892189L;
643 
writeObject(ObjectOutputStream stream)644     private void writeObject(ObjectOutputStream stream) throws IOException {
645         stream.defaultWriteObject();
646         stream.writeInt(array.length);
647         for (int i = 0; i < size; i++) {
648             stream.writeObject(array[i]);
649         }
650     }
651 
readObject(ObjectInputStream stream)652     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
653         stream.defaultReadObject();
654         int cap = stream.readInt();
655         if (cap < size) {
656             throw new InvalidObjectException(
657                     "Capacity: " + cap + " < size: " + size);
658         }
659         array = (cap == 0 ? EmptyArray.OBJECT : new Object[cap]);
660         for (int i = 0; i < size; i++) {
661             array[i] = stream.readObject();
662         }
663     }
664  }
665