| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package java.util; |
| |
| import java.util.function.Consumer; |
| import java.util.function.Predicate; |
| import java.util.function.UnaryOperator; |
| import jdk.internal.access.SharedSecrets; |
| import jdk.internal.util.ArraysSupport; |
| |
| /** |
| * Resizable-array implementation of the {@code List} interface. Implements |
| * all optional list operations, and permits all elements, including |
| * {@code null}. In addition to implementing the {@code List} interface, |
| * this class provides methods to manipulate the size of the array that is |
| * used internally to store the list. (This class is roughly equivalent to |
| * {@code Vector}, except that it is unsynchronized.) |
| * |
| * <p>The {@code size}, {@code isEmpty}, {@code get}, {@code set}, |
| * {@code iterator}, and {@code listIterator} operations run in constant |
| * time. The {@code add} operation runs in <i>amortized constant time</i>, |
| * that is, adding n elements requires O(n) time. All of the other operations |
| * run in linear time (roughly speaking). The constant factor is low compared |
| * to that for the {@code LinkedList} implementation. |
| * |
| * <p>Each {@code ArrayList} instance has a <i>capacity</i>. The capacity is |
| * the size of the array used to store the elements in the list. It is always |
| * at least as large as the list size. As elements are added to an ArrayList, |
| * its capacity grows automatically. The details of the growth policy are not |
| * specified beyond the fact that adding an element has constant amortized |
| * time cost. |
| * |
| * <p>An application can increase the capacity of an {@code ArrayList} instance |
| * before adding a large number of elements using the {@code ensureCapacity} |
| * operation. This may reduce the amount of incremental reallocation. |
| * |
| * <p><strong>Note that this implementation is not synchronized.</strong> |
| * If multiple threads access an {@code ArrayList} instance concurrently, |
| * and at least one of the threads modifies the list structurally, it |
| * <i>must</i> be synchronized externally. (A structural modification is |
| * any operation that adds or deletes one or more elements, or explicitly |
| * resizes the backing array; merely setting the value of an element is not |
| * a structural modification.) This is typically accomplished by |
| * synchronizing on some object that naturally encapsulates the list. |
| * |
| * If no such object exists, the list should be "wrapped" using the |
| * {@link Collections#synchronizedList Collections.synchronizedList} |
| * method. This is best done at creation time, to prevent accidental |
| * unsynchronized access to the list:<pre> |
| * List list = Collections.synchronizedList(new ArrayList(...));</pre> |
| * |
| * <p id="fail-fast"> |
| * The iterators returned by this class's {@link #iterator() iterator} and |
| * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>: |
| * if the list is structurally modified at any time after the iterator is |
| * created, in any way except through the iterator's own |
| * {@link ListIterator#remove() remove} or |
| * {@link ListIterator#add(Object) add} methods, the iterator will throw a |
| * {@link ConcurrentModificationException}. Thus, in the face of |
| * concurrent modification, the iterator fails quickly and cleanly, rather |
| * than risking arbitrary, non-deterministic behavior at an undetermined |
| * time in the future. |
| * |
| * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed |
| * as it is, generally speaking, impossible to make any hard guarantees in the |
| * presence of unsynchronized concurrent modification. Fail-fast iterators |
| * throw {@code ConcurrentModificationException} on a best-effort basis. |
| * Therefore, it would be wrong to write a program that depended on this |
| * exception for its correctness: <i>the fail-fast behavior of iterators |
| * should be used only to detect bugs.</i> |
| * |
| * <p>This class is a member of the |
| * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework"> |
| * Java Collections Framework</a>. |
| * |
| * @param <E> the type of elements in this list |
| * |
| * @author Josh Bloch |
| * @author Neal Gafter |
| * @see Collection |
| * @see List |
| * @see LinkedList |
| * @see Vector |
| * @since 1.2 |
| */ |
| // Android-changed: CME in iterators; |
| /* |
| * - AOSP commit b10b2a3ab693cfd6156d06ffe4e00ce69b9c9194 |
| * Fix ConcurrentModificationException in ArrayList iterators. |
| */ |
| public class ArrayList<E> extends AbstractList<E> |
| implements List<E>, RandomAccess, Cloneable, java.io.Serializable |
| { |
| @java.io.Serial |
| private static final long serialVersionUID = 8683452581122892189L; |
| |
| /** |
| * Default initial capacity. |
| */ |
| private static final int DEFAULT_CAPACITY = 10; |
| |
| /** |
| * Shared empty array instance used for empty instances. |
| */ |
| private static final Object[] EMPTY_ELEMENTDATA = {}; |
| |
| /** |
| * Shared empty array instance used for default sized empty instances. We |
| * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when |
| * first element is added. |
| */ |
| private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; |
| |
| /** |
| * The array buffer into which the elements of the ArrayList are stored. |
| * The capacity of the ArrayList is the length of this array buffer. Any |
| * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA |
| * will be expanded to DEFAULT_CAPACITY when the first element is added. |
| */ |
| // Android-note: Also accessed from java.util.Collections |
| transient Object[] elementData; // non-private to simplify nested class access |
| |
| /** |
| * The size of the ArrayList (the number of elements it contains). |
| * |
| * @serial |
| */ |
| private int size; |
| |
| /** |
| * Constructs an empty list with the specified initial capacity. |
| * |
| * @param initialCapacity the initial capacity of the list |
| * @throws IllegalArgumentException if the specified initial capacity |
| * is negative |
| */ |
| public ArrayList(int initialCapacity) { |
| if (initialCapacity > 0) { |
| this.elementData = new Object[initialCapacity]; |
| } else if (initialCapacity == 0) { |
| this.elementData = EMPTY_ELEMENTDATA; |
| } else { |
| throw new IllegalArgumentException("Illegal Capacity: "+ |
| initialCapacity); |
| } |
| } |
| |
| /** |
| * Constructs an empty list with an initial capacity of ten. |
| */ |
| public ArrayList() { |
| this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; |
| } |
| |
| /** |
| * Constructs a list containing the elements of the specified |
| * collection, in the order they are returned by the collection's |
| * iterator. |
| * |
| * @param c the collection whose elements are to be placed into this list |
| * @throws NullPointerException if the specified collection is null |
| */ |
| public ArrayList(Collection<? extends E> c) { |
| Object[] a = c.toArray(); |
| if ((size = a.length) != 0) { |
| if (c.getClass() == ArrayList.class) { |
| elementData = a; |
| } else { |
| elementData = Arrays.copyOf(a, size, Object[].class); |
| } |
| } else { |
| // replace with empty array. |
| elementData = EMPTY_ELEMENTDATA; |
| } |
| } |
| |
| /** |
| * Trims the capacity of this {@code ArrayList} instance to be the |
| * list's current size. An application can use this operation to minimize |
| * the storage of an {@code ArrayList} instance. |
| */ |
| public void trimToSize() { |
| modCount++; |
| if (size < elementData.length) { |
| elementData = (size == 0) |
| ? EMPTY_ELEMENTDATA |
| : Arrays.copyOf(elementData, size); |
| } |
| } |
| |
| /** |
| * Increases the capacity of this {@code ArrayList} instance, if |
| * necessary, to ensure that it can hold at least the number of elements |
| * specified by the minimum capacity argument. |
| * |
| * @param minCapacity the desired minimum capacity |
| */ |
| public void ensureCapacity(int minCapacity) { |
| if (minCapacity > elementData.length |
| && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA |
| && minCapacity <= DEFAULT_CAPACITY)) { |
| modCount++; |
| grow(minCapacity); |
| } |
| } |
| |
| /** |
| * Increases the capacity to ensure that it can hold at least the |
| * number of elements specified by the minimum capacity argument. |
| * |
| * @param minCapacity the desired minimum capacity |
| * @throws OutOfMemoryError if minCapacity is less than zero |
| */ |
| private Object[] grow(int minCapacity) { |
| int oldCapacity = elementData.length; |
| if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { |
| int newCapacity = ArraysSupport.newLength(oldCapacity, |
| minCapacity - oldCapacity, /* minimum growth */ |
| oldCapacity >> 1 /* preferred growth */); |
| return elementData = Arrays.copyOf(elementData, newCapacity); |
| } else { |
| return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)]; |
| } |
| } |
| |
| private Object[] grow() { |
| return grow(size + 1); |
| } |
| |
| /** |
| * Returns the number of elements in this list. |
| * |
| * @return the number of elements in this list |
| */ |
| public int size() { |
| return size; |
| } |
| |
| /** |
| * Returns {@code true} if this list contains no elements. |
| * |
| * @return {@code true} if this list contains no elements |
| */ |
| public boolean isEmpty() { |
| return size == 0; |
| } |
| |
| /** |
| * Returns {@code true} if this list contains the specified element. |
| * More formally, returns {@code true} if and only if this list contains |
| * at least one element {@code e} such that |
| * {@code Objects.equals(o, e)}. |
| * |
| * @param o element whose presence in this list is to be tested |
| * @return {@code true} if this list contains the specified element |
| */ |
| public boolean contains(Object o) { |
| return indexOf(o) >= 0; |
| } |
| |
| /** |
| * Returns the index of the first occurrence of the specified element |
| * in this list, or -1 if this list does not contain the element. |
| * More formally, returns the lowest index {@code i} such that |
| * {@code Objects.equals(o, get(i))}, |
| * or -1 if there is no such index. |
| */ |
| public int indexOf(Object o) { |
| return indexOfRange(o, 0, size); |
| } |
| |
| int indexOfRange(Object o, int start, int end) { |
| Object[] es = elementData; |
| if (o == null) { |
| for (int i = start; i < end; i++) { |
| if (es[i] == null) { |
| return i; |
| } |
| } |
| } else { |
| for (int i = start; i < end; i++) { |
| if (o.equals(es[i])) { |
| return i; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Returns the index of the last occurrence of the specified element |
| * in this list, or -1 if this list does not contain the element. |
| * More formally, returns the highest index {@code i} such that |
| * {@code Objects.equals(o, get(i))}, |
| * or -1 if there is no such index. |
| */ |
| public int lastIndexOf(Object o) { |
| return lastIndexOfRange(o, 0, size); |
| } |
| |
| int lastIndexOfRange(Object o, int start, int end) { |
| Object[] es = elementData; |
| if (o == null) { |
| for (int i = end - 1; i >= start; i--) { |
| if (es[i] == null) { |
| return i; |
| } |
| } |
| } else { |
| for (int i = end - 1; i >= start; i--) { |
| if (o.equals(es[i])) { |
| return i; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Returns a shallow copy of this {@code ArrayList} instance. (The |
| * elements themselves are not copied.) |
| * |
| * @return a clone of this {@code ArrayList} instance |
| */ |
| public Object clone() { |
| try { |
| ArrayList<?> v = (ArrayList<?>) super.clone(); |
| v.elementData = Arrays.copyOf(elementData, size); |
| v.modCount = 0; |
| return v; |
| } catch (CloneNotSupportedException e) { |
| // this shouldn't happen, since we are Cloneable |
| throw new InternalError(e); |
| } |
| } |
| |
| /** |
| * Returns an array containing all of the elements in this list |
| * in proper sequence (from first to last element). |
| * |
| * <p>The returned array will be "safe" in that no references to it are |
| * maintained by this list. (In other words, this method must allocate |
| * a new array). The caller is thus free to modify the returned array. |
| * |
| * <p>This method acts as bridge between array-based and collection-based |
| * APIs. |
| * |
| * @return an array containing all of the elements in this list in |
| * proper sequence |
| */ |
| public Object[] toArray() { |
| return Arrays.copyOf(elementData, size); |
| } |
| |
| /** |
| * Returns an array containing all of the elements in this list in proper |
| * sequence (from first to last element); the runtime type of the returned |
| * array is that of the specified array. If the list fits in the |
| * specified array, it is returned therein. Otherwise, a new array is |
| * allocated with the runtime type of the specified array and the size of |
| * this list. |
| * |
| * <p>If the list fits in the specified array with room to spare |
| * (i.e., the array has more elements than the list), the element in |
| * the array immediately following the end of the collection is set to |
| * {@code null}. (This is useful in determining the length of the |
| * list <i>only</i> if the caller knows that the list does not contain |
| * any null elements.) |
| * |
| * @param a the array into which the elements of the list are to |
| * be stored, if it is big enough; otherwise, a new array of the |
| * same runtime type is allocated for this purpose. |
| * @return an array containing the elements of the list |
| * @throws ArrayStoreException if the runtime type of the specified array |
| * is not a supertype of the runtime type of every element in |
| * this list |
| * @throws NullPointerException if the specified array is null |
| */ |
| @SuppressWarnings("unchecked") |
| public <T> T[] toArray(T[] a) { |
| if (a.length < size) |
| // Make a new array of a's runtime type, but my contents: |
| return (T[]) Arrays.copyOf(elementData, size, a.getClass()); |
| System.arraycopy(elementData, 0, a, 0, size); |
| if (a.length > size) |
| a[size] = null; |
| return a; |
| } |
| |
| // Positional Access Operations |
| |
| @SuppressWarnings("unchecked") |
| E elementData(int index) { |
| return (E) elementData[index]; |
| } |
| |
| @SuppressWarnings("unchecked") |
| static <E> E elementAt(Object[] es, int index) { |
| return (E) es[index]; |
| } |
| |
| /** |
| * Returns the element at the specified position in this list. |
| * |
| * @param index index of the element to return |
| * @return the element at the specified position in this list |
| * @throws IndexOutOfBoundsException {@inheritDoc} |
| */ |
| public E get(int index) { |
| Objects.checkIndex(index, size); |
| return elementData(index); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @throws NoSuchElementException {@inheritDoc} |
| * @since 21 |
| */ |
| public E getFirst() { |
| if (size == 0) { |
| throw new NoSuchElementException(); |
| } else { |
| return elementData(0); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @throws NoSuchElementException {@inheritDoc} |
| * @since 21 |
| */ |
| public E getLast() { |
| int last = size - 1; |
| if (last < 0) { |
| throw new NoSuchElementException(); |
| } else { |
| return elementData(last); |
| } |
| } |
| |
| /** |
| * Replaces the element at the specified position in this list with |
| * the specified element. |
| * |
| * @param index index of the element to replace |
| * @param element element to be stored at the specified position |
| * @return the element previously at the specified position |
| * @throws IndexOutOfBoundsException {@inheritDoc} |
| */ |
| public E set(int index, E element) { |
| Objects.checkIndex(index, size); |
| E oldValue = elementData(index); |
| elementData[index] = element; |
| return oldValue; |
| } |
| |
| /** |
| * This helper method split out from add(E) to keep method |
| * bytecode size under 35 (the -XX:MaxInlineSize default value), |
| * which helps when add(E) is called in a C1-compiled loop. |
| */ |
| private void add(E e, Object[] elementData, int s) { |
| if (s == elementData.length) |
| elementData = grow(); |
| elementData[s] = e; |
| size = s + 1; |
| } |
| |
| /** |
| * Appends the specified element to the end of this list. |
| * |
| * @param e element to be appended to this list |
| * @return {@code true} (as specified by {@link Collection#add}) |
| */ |
| public boolean add(E e) { |
| modCount++; |
| add(e, elementData, size); |
| return true; |
| } |
| |
| /** |
| * Inserts the specified element at the specified position in this |
| * list. Shifts the element currently at that position (if any) and |
| * any subsequent elements to the right (adds one to their indices). |
| * |
| * @param index index at which the specified element is to be inserted |
| * @param element element to be inserted |
| * @throws IndexOutOfBoundsException {@inheritDoc} |
| */ |
| public void add(int index, E element) { |
| rangeCheckForAdd(index); |
| modCount++; |
| final int s; |
| Object[] elementData; |
| if ((s = size) == (elementData = this.elementData).length) |
| elementData = grow(); |
| System.arraycopy(elementData, index, |
| elementData, index + 1, |
| s - index); |
| elementData[index] = element; |
| size = s + 1; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @since 21 |
| */ |
| public void addFirst(E element) { |
| add(0, element); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @since 21 |
| */ |
| public void addLast(E element) { |
| add(element); |
| } |
| |
| /** |
| * Removes the element at the specified position in this list. |
| * Shifts any subsequent elements to the left (subtracts one from their |
| * indices). |
| * |
| * @param index the index of the element to be removed |
| * @return the element that was removed from the list |
| * @throws IndexOutOfBoundsException {@inheritDoc} |
| */ |
| public E remove(int index) { |
| Objects.checkIndex(index, size); |
| final Object[] es = elementData; |
| |
| @SuppressWarnings("unchecked") E oldValue = (E) es[index]; |
| fastRemove(es, index); |
| |
| return oldValue; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @throws NoSuchElementException {@inheritDoc} |
| * @since 21 |
| */ |
| public E removeFirst() { |
| if (size == 0) { |
| throw new NoSuchElementException(); |
| } else { |
| Object[] es = elementData; |
| @SuppressWarnings("unchecked") E oldValue = (E) es[0]; |
| fastRemove(es, 0); |
| return oldValue; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @throws NoSuchElementException {@inheritDoc} |
| * @since 21 |
| */ |
| public E removeLast() { |
| int last = size - 1; |
| if (last < 0) { |
| throw new NoSuchElementException(); |
| } else { |
| Object[] es = elementData; |
| @SuppressWarnings("unchecked") E oldValue = (E) es[last]; |
| fastRemove(es, last); |
| return oldValue; |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean equals(Object o) { |
| if (o == this) { |
| return true; |
| } |
| |
| if (!(o instanceof List)) { |
| return false; |
| } |
| |
| final int expectedModCount = modCount; |
| // ArrayList can be subclassed and given arbitrary behavior, but we can |
| // still deal with the common case where o is ArrayList precisely |
| boolean equal = (o.getClass() == ArrayList.class) |
| ? equalsArrayList((ArrayList<?>) o) |
| : equalsRange((List<?>) o, 0, size); |
| |
| checkForComodification(expectedModCount); |
| return equal; |
| } |
| |
| boolean equalsRange(List<?> other, int from, int to) { |
| final Object[] es = elementData; |
| if (to > es.length) { |
| throw new ConcurrentModificationException(); |
| } |
| var oit = other.iterator(); |
| for (; from < to; from++) { |
| if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) { |
| return false; |
| } |
| } |
| return !oit.hasNext(); |
| } |
| |
| private boolean equalsArrayList(ArrayList<?> other) { |
| final int otherModCount = other.modCount; |
| final int s = size; |
| boolean equal; |
| if (equal = (s == other.size)) { |
| final Object[] otherEs = other.elementData; |
| final Object[] es = elementData; |
| if (s > es.length || s > otherEs.length) { |
| throw new ConcurrentModificationException(); |
| } |
| for (int i = 0; i < s; i++) { |
| if (!Objects.equals(es[i], otherEs[i])) { |
| equal = false; |
| break; |
| } |
| } |
| } |
| other.checkForComodification(otherModCount); |
| return equal; |
| } |
| |
| private void checkForComodification(final int expectedModCount) { |
| if (modCount != expectedModCount) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public int hashCode() { |
| int expectedModCount = modCount; |
| int hash = hashCodeRange(0, size); |
| checkForComodification(expectedModCount); |
| return hash; |
| } |
| |
| int hashCodeRange(int from, int to) { |
| final Object[] es = elementData; |
| if (to > es.length) { |
| throw new ConcurrentModificationException(); |
| } |
| int hashCode = 1; |
| for (int i = from; i < to; i++) { |
| Object e = es[i]; |
| hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode()); |
| } |
| return hashCode; |
| } |
| |
| /** |
| * Removes the first occurrence of the specified element from this list, |
| * if it is present. If the list does not contain the element, it is |
| * unchanged. More formally, removes the element with the lowest index |
| * {@code i} such that |
| * {@code Objects.equals(o, get(i))} |
| * (if such an element exists). Returns {@code true} if this list |
| * contained the specified element (or equivalently, if this list |
| * changed as a result of the call). |
| * |
| * @param o element to be removed from this list, if present |
| * @return {@code true} if this list contained the specified element |
| */ |
| public boolean remove(Object o) { |
| final Object[] es = elementData; |
| final int size = this.size; |
| int i = 0; |
| found: { |
| if (o == null) { |
| for (; i < size; i++) |
| if (es[i] == null) |
| break found; |
| } else { |
| for (; i < size; i++) |
| if (o.equals(es[i])) |
| break found; |
| } |
| return false; |
| } |
| fastRemove(es, i); |
| return true; |
| } |
| |
| /** |
| * Private remove method that skips bounds checking and does not |
| * return the value removed. |
| */ |
| private void fastRemove(Object[] es, int i) { |
| modCount++; |
| final int newSize; |
| if ((newSize = size - 1) > i) |
| System.arraycopy(es, i + 1, es, i, newSize - i); |
| es[size = newSize] = null; |
| } |
| |
| /** |
| * Removes all of the elements from this list. The list will |
| * be empty after this call returns. |
| */ |
| public void clear() { |
| modCount++; |
| final Object[] es = elementData; |
| for (int to = size, i = size = 0; i < to; i++) |
| es[i] = null; |
| } |
| |
| /** |
| * Appends all of the elements in the specified collection to the end of |
| * this list, in the order that they are returned by the |
| * specified collection's Iterator. The behavior of this operation is |
| * undefined if the specified collection is modified while the operation |
| * is in progress. (This implies that the behavior of this call is |
| * undefined if the specified collection is this list, and this |
| * list is nonempty.) |
| * |
| * @param c collection containing elements to be added to this list |
| * @return {@code true} if this list changed as a result of the call |
| * @throws NullPointerException if the specified collection is null |
| */ |
| public boolean addAll(Collection<? extends E> c) { |
| Object[] a = c.toArray(); |
| modCount++; |
| int numNew = a.length; |
| if (numNew == 0) |
| return false; |
| Object[] elementData; |
| final int s; |
| if (numNew > (elementData = this.elementData).length - (s = size)) |
| elementData = grow(s + numNew); |
| System.arraycopy(a, 0, elementData, s, numNew); |
| size = s + numNew; |
| return true; |
| } |
| |
| /** |
| * Inserts all of the elements in the specified collection into this |
| * list, starting at the specified position. Shifts the element |
| * currently at that position (if any) and any subsequent elements to |
| * the right (increases their indices). The new elements will appear |
| * in the list in the order that they are returned by the |
| * specified collection's iterator. |
| * |
| * @param index index at which to insert the first element from the |
| * specified collection |
| * @param c collection containing elements to be added to this list |
| * @return {@code true} if this list changed as a result of the call |
| * @throws IndexOutOfBoundsException {@inheritDoc} |
| * @throws NullPointerException if the specified collection is null |
| */ |
| public boolean addAll(int index, Collection<? extends E> c) { |
| rangeCheckForAdd(index); |
| |
| Object[] a = c.toArray(); |
| modCount++; |
| int numNew = a.length; |
| if (numNew == 0) |
| return false; |
| Object[] elementData; |
| final int s; |
| if (numNew > (elementData = this.elementData).length - (s = size)) |
| elementData = grow(s + numNew); |
| |
| int numMoved = s - index; |
| if (numMoved > 0) |
| System.arraycopy(elementData, index, |
| elementData, index + numNew, |
| numMoved); |
| System.arraycopy(a, 0, elementData, index, numNew); |
| size = s + numNew; |
| return true; |
| } |
| |
| /** |
| * Removes from this list all of the elements whose index is between |
| * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. |
| * Shifts any succeeding elements to the left (reduces their index). |
| * This call shortens the list by {@code (toIndex - fromIndex)} elements. |
| * (If {@code toIndex==fromIndex}, this operation has no effect.) |
| * |
| * @throws IndexOutOfBoundsException if {@code fromIndex} or |
| * {@code toIndex} is out of range |
| * ({@code fromIndex < 0 || |
| * toIndex > size() || |
| * toIndex < fromIndex}) |
| */ |
| protected void removeRange(int fromIndex, int toIndex) { |
| if (fromIndex > toIndex) { |
| throw new IndexOutOfBoundsException( |
| outOfBoundsMsg(fromIndex, toIndex)); |
| } |
| modCount++; |
| shiftTailOverGap(elementData, fromIndex, toIndex); |
| } |
| |
| /** Erases the gap from lo to hi, by sliding down following elements. */ |
| private void shiftTailOverGap(Object[] es, int lo, int hi) { |
| System.arraycopy(es, hi, es, lo, size - hi); |
| for (int to = size, i = (size -= hi - lo); i < to; i++) |
| es[i] = null; |
| } |
| |
| /** |
| * A version of rangeCheck used by add and addAll. |
| */ |
| private void rangeCheckForAdd(int index) { |
| if (index > size || index < 0) |
| throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); |
| } |
| |
| /** |
| * Constructs an IndexOutOfBoundsException detail message. |
| * Of the many possible refactorings of the error handling code, |
| * this "outlining" performs best with both server and client VMs. |
| */ |
| private String outOfBoundsMsg(int index) { |
| return "Index: "+index+", Size: "+size; |
| } |
| |
| /** |
| * A version used in checking (fromIndex > toIndex) condition |
| */ |
| private static String outOfBoundsMsg(int fromIndex, int toIndex) { |
| return "From Index: " + fromIndex + " > To Index: " + toIndex; |
| } |
| |
| /** |
| * Removes from this list all of its elements that are contained in the |
| * specified collection. |
| * |
| * @param c collection containing elements to be removed from this list |
| * @return {@code true} if this list changed as a result of the call |
| * @throws ClassCastException if the class of an element of this list |
| * is incompatible with the specified collection |
| * (<a href="Collection.html#optional-restrictions">optional</a>) |
| * @throws NullPointerException if this list contains a null element and the |
| * specified collection does not permit null elements |
| * (<a href="Collection.html#optional-restrictions">optional</a>), |
| * or if the specified collection is null |
| * @see Collection#contains(Object) |
| */ |
| public boolean removeAll(Collection<?> c) { |
| return batchRemove(c, false, 0, size); |
| } |
| |
| /** |
| * Retains only the elements in this list that are contained in the |
| * specified collection. In other words, removes from this list all |
| * of its elements that are not contained in the specified collection. |
| * |
| * @param c collection containing elements to be retained in this list |
| * @return {@code true} if this list changed as a result of the call |
| * @throws ClassCastException if the class of an element of this list |
| * is incompatible with the specified collection |
| * (<a href="Collection.html#optional-restrictions">optional</a>) |
| * @throws NullPointerException if this list contains a null element and the |
| * specified collection does not permit null elements |
| * (<a href="Collection.html#optional-restrictions">optional</a>), |
| * or if the specified collection is null |
| * @see Collection#contains(Object) |
| */ |
| public boolean retainAll(Collection<?> c) { |
| return batchRemove(c, true, 0, size); |
| } |
| |
| boolean batchRemove(Collection<?> c, boolean complement, |
| final int from, final int end) { |
| Objects.requireNonNull(c); |
| final Object[] es = elementData; |
| int r; |
| // Optimize for initial run of survivors |
| for (r = from;; r++) { |
| if (r == end) |
| return false; |
| if (c.contains(es[r]) != complement) |
| break; |
| } |
| int w = r++; |
| try { |
| for (Object e; r < end; r++) |
| if (c.contains(e = es[r]) == complement) |
| es[w++] = e; |
| } catch (Throwable ex) { |
| // Preserve behavioral compatibility with AbstractCollection, |
| // even if c.contains() throws. |
| System.arraycopy(es, r, es, w, end - r); |
| w += end - r; |
| throw ex; |
| } finally { |
| modCount += end - w; |
| shiftTailOverGap(es, w, end); |
| } |
| return true; |
| } |
| |
| /** |
| * Saves the state of the {@code ArrayList} instance to a stream |
| * (that is, serializes it). |
| * |
| * @param s the stream |
| * @throws java.io.IOException if an I/O error occurs |
| * @serialData The length of the array backing the {@code ArrayList} |
| * instance is emitted (int), followed by all of its elements |
| * (each an {@code Object}) in the proper order. |
| */ |
| @java.io.Serial |
| private void writeObject(java.io.ObjectOutputStream s) |
| throws java.io.IOException { |
| // Write out element count, and any hidden stuff |
| int expectedModCount = modCount; |
| s.defaultWriteObject(); |
| |
| // Write out size as capacity for behavioral compatibility with clone() |
| s.writeInt(size); |
| |
| // Write out all elements in the proper order. |
| for (int i=0; i<size; i++) { |
| s.writeObject(elementData[i]); |
| } |
| |
| if (modCount != expectedModCount) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| /** |
| * Reconstitutes the {@code ArrayList} instance from a stream (that is, |
| * deserializes it). |
| * @param s the stream |
| * @throws ClassNotFoundException if the class of a serialized object |
| * could not be found |
| * @throws java.io.IOException if an I/O error occurs |
| */ |
| @java.io.Serial |
| private void readObject(java.io.ObjectInputStream s) |
| throws java.io.IOException, ClassNotFoundException { |
| |
| // Read in size, and any hidden stuff |
| s.defaultReadObject(); |
| |
| // Read in capacity |
| s.readInt(); // ignored |
| |
| if (size > 0) { |
| // like clone(), allocate array based upon size not capacity |
| SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size); |
| Object[] elements = new Object[size]; |
| |
| // Read in all elements in the proper order. |
| for (int i = 0; i < size; i++) { |
| elements[i] = s.readObject(); |
| } |
| |
| elementData = elements; |
| } else if (size == 0) { |
| elementData = EMPTY_ELEMENTDATA; |
| } else { |
| throw new java.io.InvalidObjectException("Invalid size: " + size); |
| } |
| } |
| |
| /** |
| * Returns a list iterator over the elements in this list (in proper |
| * sequence), starting at the specified position in the list. |
| * The specified index indicates the first element that would be |
| * returned by an initial call to {@link ListIterator#next next}. |
| * An initial call to {@link ListIterator#previous previous} would |
| * return the element with the specified index minus one. |
| * |
| * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>. |
| * |
| * @throws IndexOutOfBoundsException {@inheritDoc} |
| */ |
| public ListIterator<E> listIterator(int index) { |
| rangeCheckForAdd(index); |
| return new ListItr(index); |
| } |
| |
| /** |
| * Returns a list iterator over the elements in this list (in proper |
| * sequence). |
| * |
| * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>. |
| * |
| * @see #listIterator(int) |
| */ |
| public ListIterator<E> listIterator() { |
| return new ListItr(0); |
| } |
| |
| /** |
| * Returns an iterator over the elements in this list in proper sequence. |
| * |
| * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>. |
| * |
| * @return an iterator over the elements in this list in proper sequence |
| */ |
| public Iterator<E> iterator() { |
| return new Itr(); |
| } |
| |
| /** |
| * An optimized version of AbstractList.Itr |
| */ |
| private class Itr implements Iterator<E> { |
| // Android-changed: Add "limit" field to detect end of iteration. |
| // The "limit" of this iterator. This is the size of the list at the time the |
| // iterator was created. Adding & removing elements will invalidate the iteration |
| // anyway (and cause next() to throw) so saving this value will guarantee that the |
| // value of hasNext() remains stable and won't flap between true and false when elements |
| // are added and removed from the list. |
| protected int limit = ArrayList.this.size; |
| |
| int cursor; // index of next element to return |
| int lastRet = -1; // index of last element returned; -1 if no such |
| int expectedModCount = modCount; |
| |
| // prevent creating a synthetic constructor |
| Itr() {} |
| |
| public boolean hasNext() { |
| return cursor < limit; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public E next() { |
| checkForComodification(); |
| int i = cursor; |
| if (i >= limit) |
| throw new NoSuchElementException(); |
| Object[] elementData = ArrayList.this.elementData; |
| if (i >= elementData.length) |
| throw new ConcurrentModificationException(); |
| cursor = i + 1; |
| return (E) elementData[lastRet = i]; |
| } |
| |
| public void remove() { |
| if (lastRet < 0) |
| throw new IllegalStateException(); |
| checkForComodification(); |
| |
| try { |
| ArrayList.this.remove(lastRet); |
| cursor = lastRet; |
| lastRet = -1; |
| expectedModCount = modCount; |
| limit--; |
| } catch (IndexOutOfBoundsException ex) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| @Override |
| public void forEachRemaining(Consumer<? super E> action) { |
| Objects.requireNonNull(action); |
| final int size = ArrayList.this.size; |
| int i = cursor; |
| if (i < size) { |
| final Object[] es = elementData; |
| if (i >= es.length) |
| throw new ConcurrentModificationException(); |
| for (; i < size && modCount == expectedModCount; i++) |
| action.accept(elementAt(es, i)); |
| // update once at end to reduce heap write traffic |
| cursor = i; |
| lastRet = i - 1; |
| checkForComodification(); |
| } |
| } |
| |
| final void checkForComodification() { |
| if (modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| /** |
| * An optimized version of AbstractList.ListItr |
| */ |
| private class ListItr extends Itr implements ListIterator<E> { |
| ListItr(int index) { |
| super(); |
| cursor = index; |
| } |
| |
| public boolean hasPrevious() { |
| return cursor != 0; |
| } |
| |
| public int nextIndex() { |
| return cursor; |
| } |
| |
| public int previousIndex() { |
| return cursor - 1; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public E previous() { |
| checkForComodification(); |
| int i = cursor - 1; |
| if (i < 0) |
| throw new NoSuchElementException(); |
| Object[] elementData = ArrayList.this.elementData; |
| if (i >= elementData.length) |
| throw new ConcurrentModificationException(); |
| cursor = i; |
| return (E) elementData[lastRet = i]; |
| } |
| |
| public void set(E e) { |
| if (lastRet < 0) |
| throw new IllegalStateException(); |
| checkForComodification(); |
| |
| try { |
| ArrayList.this.set(lastRet, e); |
| } catch (IndexOutOfBoundsException ex) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| public void add(E e) { |
| checkForComodification(); |
| |
| try { |
| int i = cursor; |
| ArrayList.this.add(i, e); |
| cursor = i + 1; |
| lastRet = -1; |
| expectedModCount = modCount; |
| limit++; |
| } catch (IndexOutOfBoundsException ex) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| } |
| |
| /** |
| * Returns a view of the portion of this list between the specified |
| * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. (If |
| * {@code fromIndex} and {@code toIndex} are equal, the returned list is |
| * empty.) The returned list is backed by this list, so non-structural |
| * changes in the returned list are reflected in this list, and vice-versa. |
| * The returned list supports all of the optional list operations. |
| * |
| * <p>This method eliminates the need for explicit range operations (of |
| * the sort that commonly exist for arrays). Any operation that expects |
| * a list can be used as a range operation by passing a subList view |
| * instead of a whole list. For example, the following idiom |
| * removes a range of elements from a list: |
| * <pre> |
| * list.subList(from, to).clear(); |
| * </pre> |
| * Similar idioms may be constructed for {@link #indexOf(Object)} and |
| * {@link #lastIndexOf(Object)}, and all of the algorithms in the |
| * {@link Collections} class can be applied to a subList. |
| * |
| * <p>The semantics of the list returned by this method become undefined if |
| * the backing list (i.e., this list) is <i>structurally modified</i> in |
| * any way other than via the returned list. (Structural modifications are |
| * those that change the size of this list, or otherwise perturb it in such |
| * a fashion that iterations in progress may yield incorrect results.) |
| * |
| * @throws IndexOutOfBoundsException {@inheritDoc} |
| * @throws IllegalArgumentException {@inheritDoc} |
| */ |
| public List<E> subList(int fromIndex, int toIndex) { |
| subListRangeCheck(fromIndex, toIndex, size); |
| return new SubList<>(this, fromIndex, toIndex); |
| } |
| |
| private static class SubList<E> extends AbstractList<E> implements RandomAccess { |
| private final ArrayList<E> root; |
| private final SubList<E> parent; |
| private final int offset; |
| private int size; |
| |
| /** |
| * Constructs a sublist of an arbitrary ArrayList. |
| */ |
| public SubList(ArrayList<E> root, int fromIndex, int toIndex) { |
| this.root = root; |
| this.parent = null; |
| this.offset = fromIndex; |
| this.size = toIndex - fromIndex; |
| this.modCount = root.modCount; |
| } |
| |
| /** |
| * Constructs a sublist of another SubList. |
| */ |
| private SubList(SubList<E> parent, int fromIndex, int toIndex) { |
| this.root = parent.root; |
| this.parent = parent; |
| this.offset = parent.offset + fromIndex; |
| this.size = toIndex - fromIndex; |
| this.modCount = parent.modCount; |
| } |
| |
| public E set(int index, E element) { |
| Objects.checkIndex(index, size); |
| checkForComodification(); |
| E oldValue = root.elementData(offset + index); |
| root.elementData[offset + index] = element; |
| return oldValue; |
| } |
| |
| public E get(int index) { |
| Objects.checkIndex(index, size); |
| checkForComodification(); |
| return root.elementData(offset + index); |
| } |
| |
| public int size() { |
| checkForComodification(); |
| return size; |
| } |
| |
| public void add(int index, E element) { |
| rangeCheckForAdd(index); |
| checkForComodification(); |
| root.add(offset + index, element); |
| updateSizeAndModCount(1); |
| } |
| |
| public E remove(int index) { |
| Objects.checkIndex(index, size); |
| checkForComodification(); |
| E result = root.remove(offset + index); |
| updateSizeAndModCount(-1); |
| return result; |
| } |
| |
| protected void removeRange(int fromIndex, int toIndex) { |
| checkForComodification(); |
| root.removeRange(offset + fromIndex, offset + toIndex); |
| updateSizeAndModCount(fromIndex - toIndex); |
| } |
| |
| public boolean addAll(Collection<? extends E> c) { |
| return addAll(this.size, c); |
| } |
| |
| public boolean addAll(int index, Collection<? extends E> c) { |
| rangeCheckForAdd(index); |
| int cSize = c.size(); |
| if (cSize==0) |
| return false; |
| checkForComodification(); |
| root.addAll(offset + index, c); |
| updateSizeAndModCount(cSize); |
| return true; |
| } |
| |
| public void replaceAll(UnaryOperator<E> operator) { |
| root.replaceAllRange(operator, offset, offset + size); |
| } |
| |
| public boolean removeAll(Collection<?> c) { |
| return batchRemove(c, false); |
| } |
| |
| public boolean retainAll(Collection<?> c) { |
| return batchRemove(c, true); |
| } |
| |
| private boolean batchRemove(Collection<?> c, boolean complement) { |
| checkForComodification(); |
| int oldSize = root.size; |
| boolean modified = |
| root.batchRemove(c, complement, offset, offset + size); |
| if (modified) |
| updateSizeAndModCount(root.size - oldSize); |
| return modified; |
| } |
| |
| public boolean removeIf(Predicate<? super E> filter) { |
| checkForComodification(); |
| int oldSize = root.size; |
| boolean modified = root.removeIf(filter, offset, offset + size); |
| if (modified) |
| updateSizeAndModCount(root.size - oldSize); |
| return modified; |
| } |
| |
| public Object[] toArray() { |
| checkForComodification(); |
| return Arrays.copyOfRange(root.elementData, offset, offset + size); |
| } |
| |
| @SuppressWarnings("unchecked") |
| public <T> T[] toArray(T[] a) { |
| checkForComodification(); |
| if (a.length < size) |
| return (T[]) Arrays.copyOfRange( |
| root.elementData, offset, offset + size, a.getClass()); |
| System.arraycopy(root.elementData, offset, a, 0, size); |
| if (a.length > size) |
| a[size] = null; |
| return a; |
| } |
| |
| public boolean equals(Object o) { |
| if (o == this) { |
| return true; |
| } |
| |
| if (!(o instanceof List)) { |
| return false; |
| } |
| |
| boolean equal = root.equalsRange((List<?>)o, offset, offset + size); |
| checkForComodification(); |
| return equal; |
| } |
| |
| public int hashCode() { |
| int hash = root.hashCodeRange(offset, offset + size); |
| checkForComodification(); |
| return hash; |
| } |
| |
| public int indexOf(Object o) { |
| int index = root.indexOfRange(o, offset, offset + size); |
| checkForComodification(); |
| return index >= 0 ? index - offset : -1; |
| } |
| |
| public int lastIndexOf(Object o) { |
| int index = root.lastIndexOfRange(o, offset, offset + size); |
| checkForComodification(); |
| return index >= 0 ? index - offset : -1; |
| } |
| |
| public boolean contains(Object o) { |
| return indexOf(o) >= 0; |
| } |
| |
| public Iterator<E> iterator() { |
| return listIterator(); |
| } |
| |
| public ListIterator<E> listIterator(int index) { |
| checkForComodification(); |
| rangeCheckForAdd(index); |
| |
| return new ListIterator<E>() { |
| int cursor = index; |
| int lastRet = -1; |
| int expectedModCount = SubList.this.modCount; |
| |
| public boolean hasNext() { |
| return cursor != SubList.this.size; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public E next() { |
| checkForComodification(); |
| int i = cursor; |
| if (i >= SubList.this.size) |
| throw new NoSuchElementException(); |
| Object[] elementData = root.elementData; |
| if (offset + i >= elementData.length) |
| throw new ConcurrentModificationException(); |
| cursor = i + 1; |
| return (E) elementData[offset + (lastRet = i)]; |
| } |
| |
| public boolean hasPrevious() { |
| return cursor != 0; |
| } |
| |
| @SuppressWarnings("unchecked") |
| public E previous() { |
| checkForComodification(); |
| int i = cursor - 1; |
| if (i < 0) |
| throw new NoSuchElementException(); |
| Object[] elementData = root.elementData; |
| if (offset + i >= elementData.length) |
| throw new ConcurrentModificationException(); |
| cursor = i; |
| return (E) elementData[offset + (lastRet = i)]; |
| } |
| |
| public void forEachRemaining(Consumer<? super E> action) { |
| Objects.requireNonNull(action); |
| final int size = SubList.this.size; |
| int i = cursor; |
| if (i < size) { |
| final Object[] es = root.elementData; |
| if (offset + i >= es.length) |
| throw new ConcurrentModificationException(); |
| for (; i < size && root.modCount == expectedModCount; i++) |
| action.accept(elementAt(es, offset + i)); |
| // update once at end to reduce heap write traffic |
| cursor = i; |
| lastRet = i - 1; |
| checkForComodification(); |
| } |
| } |
| |
| public int nextIndex() { |
| return cursor; |
| } |
| |
| public int previousIndex() { |
| return cursor - 1; |
| } |
| |
| public void remove() { |
| if (lastRet < 0) |
| throw new IllegalStateException(); |
| checkForComodification(); |
| |
| try { |
| SubList.this.remove(lastRet); |
| cursor = lastRet; |
| lastRet = -1; |
| expectedModCount = SubList.this.modCount; |
| } catch (IndexOutOfBoundsException ex) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| public void set(E e) { |
| if (lastRet < 0) |
| throw new IllegalStateException(); |
| checkForComodification(); |
| |
| try { |
| root.set(offset + lastRet, e); |
| } catch (IndexOutOfBoundsException ex) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| public void add(E e) { |
| checkForComodification(); |
| |
| try { |
| int i = cursor; |
| SubList.this.add(i, e); |
| cursor = i + 1; |
| lastRet = -1; |
| expectedModCount = SubList.this.modCount; |
| } catch (IndexOutOfBoundsException ex) { |
| throw new ConcurrentModificationException(); |
| } |
| } |
| |
| final void checkForComodification() { |
| if (root.modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| } |
| }; |
| } |
| |
| public List<E> subList(int fromIndex, int toIndex) { |
| subListRangeCheck(fromIndex, toIndex, size); |
| return new SubList<>(this, fromIndex, toIndex); |
| } |
| |
| private void rangeCheckForAdd(int index) { |
| if (index < 0 || index > this.size) |
| throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); |
| } |
| |
| private String outOfBoundsMsg(int index) { |
| return "Index: "+index+", Size: "+this.size; |
| } |
| |
| private void checkForComodification() { |
| if (root.modCount != modCount) |
| throw new ConcurrentModificationException(); |
| } |
| |
| private void updateSizeAndModCount(int sizeChange) { |
| SubList<E> slist = this; |
| do { |
| slist.size += sizeChange; |
| slist.modCount = root.modCount; |
| slist = slist.parent; |
| } while (slist != null); |
| } |
| |
| public Spliterator<E> spliterator() { |
| checkForComodification(); |
| |
| // This Spliterator needs to late-bind to the subList, not the outer |
| // ArrayList. Note that it is legal for structural changes to be made |
| // to a subList after spliterator() is called but before any spliterator |
| // operations that would causing binding are performed. |
| return new Spliterator<E>() { |
| private int index = offset; // current index, modified on advance/split |
| private int fence = -1; // -1 until used; then one past last index |
| private int expectedModCount; // initialized when fence set |
| |
| private int getFence() { // initialize fence to size on first use |
| int hi; // (a specialized variant appears in method forEach) |
| if ((hi = fence) < 0) { |
| expectedModCount = modCount; |
| hi = fence = offset + size; |
| } |
| return hi; |
| } |
| |
| public ArrayList<E>.ArrayListSpliterator trySplit() { |
| int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; |
| // ArrayListSpliterator can be used here as the source is already bound |
| return (lo >= mid) ? null : // divide range in half unless too small |
| root.new ArrayListSpliterator(lo, index = mid, expectedModCount); |
| } |
| |
| public boolean tryAdvance(Consumer<? super E> action) { |
| Objects.requireNonNull(action); |
| int hi = getFence(), i = index; |
| if (i < hi) { |
| index = i + 1; |
| @SuppressWarnings("unchecked") E e = (E)root.elementData[i]; |
| action.accept(e); |
| if (root.modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| return true; |
| } |
| return false; |
| } |
| |
| public void forEachRemaining(Consumer<? super E> action) { |
| Objects.requireNonNull(action); |
| int i, hi, mc; // hoist accesses and checks from loop |
| ArrayList<E> lst = root; |
| Object[] a; |
| if ((a = lst.elementData) != null) { |
| if ((hi = fence) < 0) { |
| mc = modCount; |
| hi = offset + size; |
| } |
| else |
| mc = expectedModCount; |
| if ((i = index) >= 0 && (index = hi) <= a.length) { |
| for (; i < hi; ++i) { |
| @SuppressWarnings("unchecked") E e = (E) a[i]; |
| action.accept(e); |
| } |
| if (lst.modCount == mc) |
| return; |
| } |
| } |
| throw new ConcurrentModificationException(); |
| } |
| |
| public long estimateSize() { |
| return getFence() - index; |
| } |
| |
| public int characteristics() { |
| return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; |
| } |
| }; |
| } |
| } |
| |
| /** |
| * @throws NullPointerException {@inheritDoc} |
| */ |
| @Override |
| public void forEach(Consumer<? super E> action) { |
| Objects.requireNonNull(action); |
| final int expectedModCount = modCount; |
| final Object[] es = elementData; |
| final int size = this.size; |
| for (int i = 0; modCount == expectedModCount && i < size; i++) |
| action.accept(elementAt(es, i)); |
| if (modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| } |
| |
| /** |
| * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em> |
| * and <em>fail-fast</em> {@link Spliterator} over the elements in this |
| * list. |
| * |
| * <p>The {@code Spliterator} reports {@link Spliterator#SIZED}, |
| * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}. |
| * Overriding implementations should document the reporting of additional |
| * characteristic values. |
| * |
| * @return a {@code Spliterator} over the elements in this list |
| * @since 1.8 |
| */ |
| @Override |
| public Spliterator<E> spliterator() { |
| return new ArrayListSpliterator(0, -1, 0); |
| } |
| |
| /** Index-based split-by-two, lazily initialized Spliterator */ |
| final class ArrayListSpliterator implements Spliterator<E> { |
| |
| /* |
| * If ArrayLists were immutable, or structurally immutable (no |
| * adds, removes, etc), we could implement their spliterators |
| * with Arrays.spliterator. Instead we detect as much |
| * interference during traversal as practical without |
| * sacrificing much performance. We rely primarily on |
| * modCounts. These are not guaranteed to detect concurrency |
| * violations, and are sometimes overly conservative about |
| * within-thread interference, but detect enough problems to |
| * be worthwhile in practice. To carry this out, we (1) lazily |
| * initialize fence and expectedModCount until the latest |
| * point that we need to commit to the state we are checking |
| * against; thus improving precision. (2) We perform only a single |
| * ConcurrentModificationException check at the end of forEach |
| * (the most performance-sensitive method). When using forEach |
| * (as opposed to iterators), we can normally only detect |
| * interference after actions, not before. Further |
| * CME-triggering checks apply to all other possible |
| * violations of assumptions for example null or too-small |
| * elementData array given its size(), that could only have |
| * occurred due to interference. This allows the inner loop |
| * of forEach to run without any further checks, and |
| * simplifies lambda-resolution. While this does entail a |
| * number of checks, note that in the common case of |
| * list.stream().forEach(a), no checks or other computation |
| * occur anywhere other than inside forEach itself. The other |
| * less-often-used methods cannot take advantage of most of |
| * these streamlinings. |
| */ |
| |
| private int index; // current index, modified on advance/split |
| private int fence; // -1 until used; then one past last index |
| private int expectedModCount; // initialized when fence set |
| |
| /** Creates new spliterator covering the given range. */ |
| ArrayListSpliterator(int origin, int fence, int expectedModCount) { |
| this.index = origin; |
| this.fence = fence; |
| this.expectedModCount = expectedModCount; |
| } |
| |
| private int getFence() { // initialize fence to size on first use |
| int hi; // (a specialized variant appears in method forEach) |
| if ((hi = fence) < 0) { |
| expectedModCount = modCount; |
| hi = fence = size; |
| } |
| return hi; |
| } |
| |
| public ArrayListSpliterator trySplit() { |
| int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; |
| return (lo >= mid) ? null : // divide range in half unless too small |
| new ArrayListSpliterator(lo, index = mid, expectedModCount); |
| } |
| |
| public boolean tryAdvance(Consumer<? super E> action) { |
| if (action == null) |
| throw new NullPointerException(); |
| int hi = getFence(), i = index; |
| if (i < hi) { |
| index = i + 1; |
| @SuppressWarnings("unchecked") E e = (E)elementData[i]; |
| action.accept(e); |
| if (modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| return true; |
| } |
| return false; |
| } |
| |
| public void forEachRemaining(Consumer<? super E> action) { |
| int i, hi, mc; // hoist accesses and checks from loop |
| Object[] a; |
| if (action == null) |
| throw new NullPointerException(); |
| if ((a = elementData) != null) { |
| if ((hi = fence) < 0) { |
| mc = modCount; |
| hi = size; |
| } |
| else |
| mc = expectedModCount; |
| if ((i = index) >= 0 && (index = hi) <= a.length) { |
| for (; i < hi; ++i) { |
| @SuppressWarnings("unchecked") E e = (E) a[i]; |
| action.accept(e); |
| } |
| if (modCount == mc) |
| return; |
| } |
| } |
| throw new ConcurrentModificationException(); |
| } |
| |
| public long estimateSize() { |
| return getFence() - index; |
| } |
| |
| public int characteristics() { |
| return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; |
| } |
| } |
| |
| // A tiny bit set implementation |
| |
| private static long[] nBits(int n) { |
| return new long[((n - 1) >> 6) + 1]; |
| } |
| private static void setBit(long[] bits, int i) { |
| bits[i >> 6] |= 1L << i; |
| } |
| private static boolean isClear(long[] bits, int i) { |
| return (bits[i >> 6] & (1L << i)) == 0; |
| } |
| |
| /** |
| * @throws NullPointerException {@inheritDoc} |
| */ |
| @Override |
| public boolean removeIf(Predicate<? super E> filter) { |
| return removeIf(filter, 0, size); |
| } |
| |
| /** |
| * Removes all elements satisfying the given predicate, from index |
| * i (inclusive) to index end (exclusive). |
| */ |
| boolean removeIf(Predicate<? super E> filter, int i, final int end) { |
| Objects.requireNonNull(filter); |
| int expectedModCount = modCount; |
| final Object[] es = elementData; |
| // Optimize for initial run of survivors |
| for (; i < end && !filter.test(elementAt(es, i)); i++) |
| ; |
| // Tolerate predicates that reentrantly access the collection for |
| // read (but writers still get CME), so traverse once to find |
| // elements to delete, a second pass to physically expunge. |
| if (i < end) { |
| final int beg = i; |
| final long[] deathRow = nBits(end - beg); |
| deathRow[0] = 1L; // set bit 0 |
| for (i = beg + 1; i < end; i++) |
| if (filter.test(elementAt(es, i))) |
| setBit(deathRow, i - beg); |
| if (modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| modCount++; |
| int w = beg; |
| for (i = beg; i < end; i++) |
| if (isClear(deathRow, i - beg)) |
| es[w++] = es[i]; |
| shiftTailOverGap(es, w, end); |
| return true; |
| } else { |
| if (modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| return false; |
| } |
| } |
| |
| @Override |
| public void replaceAll(UnaryOperator<E> operator) { |
| replaceAllRange(operator, 0, size); |
| // TODO(8203662): remove increment of modCount from ... |
| modCount++; |
| } |
| |
| private void replaceAllRange(UnaryOperator<E> operator, int i, int end) { |
| Objects.requireNonNull(operator); |
| final int expectedModCount = modCount; |
| final Object[] es = elementData; |
| for (; modCount == expectedModCount && i < end; i++) |
| es[i] = operator.apply(elementAt(es, i)); |
| if (modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public void sort(Comparator<? super E> c) { |
| final int expectedModCount = modCount; |
| Arrays.sort((E[]) elementData, 0, size, c); |
| if (modCount != expectedModCount) |
| throw new ConcurrentModificationException(); |
| modCount++; |
| } |
| |
| void checkInvariants() { |
| // assert size >= 0; |
| // assert size == elementData.length || elementData[size] == null; |
| } |
| } |