diff --git a/test/micro/org/openjdk/bench/valhalla/corelibs/InlineCursor.java b/test/micro/org/openjdk/bench/valhalla/corelibs/InlineCursor.java new file mode 100644 index 00000000000..1af8e5f228c --- /dev/null +++ b/test/micro/org/openjdk/bench/valhalla/corelibs/InlineCursor.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + */ + +package org.openjdk.bench.valhalla.corelibs; + +import java.util.ConcurrentModificationException; +import java.util.NoSuchElementException; + +/** + * An inline cursor is a reference to an existing or non-existent element + * of a collection. + *

+ * Cursor values are immutable, the reference to an element + * does not change but the state of the collection can change + * so the element is no longer accessible. + * Calling {@link #get()} throws a {@link ConcurrentModificationException}. + * Iterating through a Collection proceeds by creating new Cursor + * from the Collection or advancing to the next or retreating to previous elements. + * Advancing past the end of the Collection or retreating before the beginning + * results in Cursor values that are non-existent. + * A Cursor for an empty Collection does not refer to an element and + * throws {@link NoSuchElementException}. + * Modifications to the Collection invalidate every Cursor that was created + * before the modification. + * The typical traversal pattern is: + *

{@code
+ *  Collection c = ...;
+ *  for (var cursor = c.cursor(); cursor.exists(); cursor = cursor.advance()) {
+ *      var el = cursor.get();
+ *  }
+ * }
+ * 
+ *

+ * Cursors can be used to {@link #remove()} remove an element from the collection. + * Removing an element modifies the collection making that cursor invalid. + * The cursor returned from the {@link #remove()} method is a placeholder + * for the position, the element occupied, between the next and previous elements. + * It can be moved to the next or previous element to continue the iteration. + *

+ * The typical traversal and remove pattern follows; when an element is + * removed, the cursor returned from the remove is used to continue the iteration: + *

{@code
+ *  Collection c = ...;
+ *  for (var cursor = c.cursor(); cursor.exists(); cursor = cursor.advance()) {
+ *      var el = cursor.get();
+ *      if (el.equals(...)) {
+ *          cursor = cursor.remove();
+ *      }
+ *  }
+ * }
+ * 
+ *

+ * @param the type of the element. + */ +public interface InlineCursor { + /** + * Return true if the Cursor refers to an element. + * + * If the collection has been modified since the Cursor was created + * the element can not be known to exist. + * This method does not throw {@link ConcurrentModificationException} + * if the collection has been modified but returns false. + * + * @return true if this Cursor refers to an element in the collection and + * the collection has not been modified since the cursor was created; + * false otherwise + */ + boolean exists(); + + /** + * Return a Cursor for the next element after the current element. + * If there is no element following this element the returned + * Cursor will be non-existent. To wit: {@code Cursor.exists() == false}. + * + * @return return a cursor for the next element after this element + * @throws ConcurrentModificationException if the collection + * has been modified since this Cursor was created + */ + InlineCursor advance(); + + /** + * Return the current element referred to by the Cursor. + * + * The behavior must be consistent with {@link #exists()} + * as long as the collection has not been modified. + * + * @return return the element in the collection if the collection + * has not been modified since the cursor was created + * @throws NoSuchElementException if the referenced element does not exist + * or no longer exists + * @throws ConcurrentModificationException if the collection + * has been modified since this Cursor was created + */ + T get(); +} diff --git a/test/micro/org/openjdk/bench/valhalla/corelibs/XArrayList.java b/test/micro/org/openjdk/bench/valhalla/corelibs/XArrayList.java new file mode 100644 index 00000000000..041f311f579 --- /dev/null +++ b/test/micro/org/openjdk/bench/valhalla/corelibs/XArrayList.java @@ -0,0 +1,1906 @@ +/* + * Copyright (c) 1997, 2020, 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 org.openjdk.bench.valhalla.corelibs; + +import java.util.AbstractList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.RandomAccess; +import java.util.Spliterator; + +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.) + * + *

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 amortized constant time, + * 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. + * + *

Each {@code XArrayList} instance has a capacity. 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 XArrayList, + * 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. + * + *

An application can increase the capacity of an {@code XArrayList} instance + * before adding a large number of elements using the {@code ensureCapacity} + * operation. This may reduce the amount of incremental reallocation. + * + *

Note that this implementation is not synchronized. + * If multiple threads access an {@code XArrayList} instance concurrently, + * and at least one of the threads modifies the list structurally, it + * must 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:

+ *   List list = Collections.synchronizedList(new XArrayList(...));
+ * + *

+ * The iterators returned by this class's {@link #iterator() iterator} and + * {@link #listIterator(int) listIterator} methods are fail-fast: + * 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. + * + *

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: the fail-fast behavior of iterators + * should be used only to detect bugs. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements in this list + * + * @author Josh Bloch + * @author Neal Gafter + * @see Collection + * @see List + * @see LinkedList + * @see Vector + * @since 1.2 + */ +public class XArrayList extends AbstractList + implements List, RandomAccess, Cloneable, java.io.Serializable +{ + 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. + */ + transient Object[] elementData; // non-private to simplify nested class access + + /** + * The size of the ArrayList (the number of elements it contains). + * + * @serial + */ + 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 XArrayList(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 XArrayList() { + 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 XArrayList(Collection c) { + elementData = c.toArray(); + if ((size = elementData.length) != 0) { + // defend against c.toArray (incorrectly) not returning Object[] + // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652) + if (elementData.getClass() != Object[].class) + elementData = Arrays.copyOf(elementData, size, Object[].class); + } else { + // replace with empty array. + this.elementData = EMPTY_ELEMENTDATA; + } + } + + /** + * Trims the capacity of this {@code XArrayList} instance to be the + * list's current size. An application can use this operation to minimize + * the storage of an {@code XArrayList} instance. + */ + public void trimToSize() { + modCount++; + if (size < elementData.length) { + elementData = (size == 0) + ? EMPTY_ELEMENTDATA + : Arrays.copyOf(elementData, size); + } + } + + /** + * Increases the capacity of this {@code XArrayList} 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 = 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 XArrayList} instance. (The + * elements themselves are not copied.) + * + * @return a clone of this {@code XArrayList} instance + */ + public Object clone() { + try { + XArrayList v = (XArrayList) 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). + * + *

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. + * + *

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. + * + *

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 only 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[] 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 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); + } + + /** + * 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; + } + + /** + * 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} + */ + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof List)) { + return false; + } + + final int expectedModCount = modCount; + // XArrayList can be subclassed and given arbitrary behavior, but we can + // still deal with the common case where o is XArrayList precisely + boolean equal = (o.getClass() == XArrayList.class) + ? equalsArrayList((XArrayList) 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(XArrayList 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 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 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 + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * 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 + * (optional) + * @throws NullPointerException if this list contains a null element and the + * specified collection does not permit null elements + * (optional), + * 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 XArrayList} 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 XArrayList} + * instance is emitted (int), followed by all of its elements + * (each an {@code Object}) in the proper order. + */ + 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

The returned list iterator is fail-fast. + * + * @throws IndexOutOfBoundsException {@inheritDoc} + */ + public ListIterator listIterator(int index) { + rangeCheckForAdd(index); + return new ListItr(index); + } + + /** + * Returns a list iterator over the elements in this list (in proper + * sequence). + * + *

The returned list iterator is fail-fast. + * + * @see #listIterator(int) + */ + public ListIterator listIterator() { + return new ListItr(0); + } + + /** + * Returns an iterator over the elements in this list in proper sequence. + * + *

The returned iterator is fail-fast. + * + * @return an iterator over the elements in this list in proper sequence + */ + public Iterator iterator() { + return new Itr(); + } + + /** + * An optimized version of AbstractList.Itr + */ + private class Itr implements Iterator { + 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 != size; + } + + @SuppressWarnings("unchecked") + public E next() { + checkForComodification(); + int i = cursor; + if (i >= size) + throw new NoSuchElementException(); + Object[] elementData = XArrayList.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 { + XArrayList.this.remove(lastRet); + cursor = lastRet; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + @Override + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + final int size = XArrayList.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 { + 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 = XArrayList.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 { + XArrayList.this.set(lastRet, e); + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + public void add(E e) { + checkForComodification(); + + try { + int i = cursor; + XArrayList.this.add(i, e); + cursor = i + 1; + lastRet = -1; + expectedModCount = modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + } + + /** + * Return a new cursor for this XArrayList. + * @return a cursor + */ + public InlineCursor cursor() { + return new AListCursor<>(0); + } + + /** + * Create an inline cursor for this XArrayList. + */ + private inline class AListCursor implements InlineCursor { + // Inner class field 'this' is initialized + int index; + int expectedModCount; + + /** + * Create a new Cursor for this XArrayList. + * + * @param cursor index + */ + public AListCursor(int cursor) { + this.index = cursor; + this.expectedModCount = XArrayList.this.modCount; + } + + @Override + public boolean exists() { + return index < XArrayList.this.size; + } + + @SuppressWarnings("unchecked") + public E get() { + if (exists()) { + checkForComodification(); + try { + return (E) XArrayList.this.elementData[index]; + } catch (ArrayIndexOutOfBoundsException aioobe) { + throw new ConcurrentModificationException(); + } + } + throw new NoSuchElementException(); + } + + @Override + public AListCursor advance() { + // new Cursor will have a current expectedModCount + // TBD: Saturate index? So calling adv, adv, adv, prev == last + return new AListCursor<>(Math.min(index + 1, size)); + } + + final void checkForComodification() { + if (XArrayList.this.modCount != expectedModCount) + throw new ConcurrentModificationException(); + } + } + + /** + * Returns a iterator (Using an InlineCursor) over the elements in this list in proper sequence. + * + *

The returned iterator is fail-fast. + * + * @return an iterator over the elements in this list in proper sequence + */ + public Iterator iteratorCurs() { + return new CurItr(); + } + + /** + * Iterate using a Cursor. + */ + private class CurItr implements Iterator { + AListCursor cursor; + AListCursor lastRet; + + // prevent creating a synthetic constructor + CurItr() { + this.cursor = new AListCursor(0); + this.lastRet = this.cursor; + } + + public boolean hasNext() { + return cursor.advance().exists(); + } + + @SuppressWarnings("unchecked") + public E next() { + E val = cursor.get(); + lastRet = cursor; + cursor = cursor.advance(); + return val; + } + + @Override + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + + AListCursor cur = cursor; + while (cur.exists()) { + E val = cur.get(); + action.accept(val); + cur = cur.advance(); + } + cursor = cur; + } + + public String toString() { + return "cur: " + cursor; + } + } + + + /** + * 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. + * + *

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: + *

+     *      list.subList(from, to).clear();
+     * 
+ * 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. + * + *

The semantics of the list returned by this method become undefined if + * the backing list (i.e., this list) is structurally modified 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 subList(int fromIndex, int toIndex) { + subListRangeCheck(fromIndex, toIndex, size); + return new SubList<>(this, fromIndex, toIndex); + } + + private static class SubList extends AbstractList implements RandomAccess { + private final XArrayList root; + private final SubList parent; + private final int offset; + private int size; + + /** + * Constructs a sublist of an arbitrary XArrayList. + */ + public SubList(XArrayList 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 parent, int fromIndex, int toIndex) { + this.root = parent.root; + this.parent = parent; + this.offset = parent.offset + fromIndex; + this.size = toIndex - fromIndex; + this.modCount = root.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 c) { + return addAll(this.size, c); + } + + public boolean addAll(int index, Collection 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 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 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[] 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 iterator() { + return listIterator(); + } + + public ListIterator listIterator(int index) { + checkForComodification(); + rangeCheckForAdd(index); + + return new ListIterator() { + int cursor = index; + int lastRet = -1; + int expectedModCount = root.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 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 && 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 = root.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 = root.modCount; + } catch (IndexOutOfBoundsException ex) { + throw new ConcurrentModificationException(); + } + } + + final void checkForComodification() { + if (root.modCount != expectedModCount) + throw new ConcurrentModificationException(); + } + }; + } + + public List 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 slist = this; + do { + slist.size += sizeChange; + slist.modCount = root.modCount; + slist = slist.parent; + } while (slist != null); + } + + public Spliterator spliterator() { + checkForComodification(); + + // ArrayListSpliterator not used here due to late-binding + return new Spliterator() { + 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 XArrayList.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 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 action) { + Objects.requireNonNull(action); + int i, hi, mc; // hoist accesses and checks from loop + XArrayList 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 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 late-binding + * and fail-fast {@link Spliterator} over the elements in this + * list. + * + *

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 spliterator() { + return new ArrayListSpliterator(0, -1, 0); + } + + /** Index-based split-by-two, lazily initialized Spliterator */ + final class ArrayListSpliterator implements Spliterator { + + /* + * If XArrayLists 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. (This doesn't apply to + * SubLists, that create spliterators with current non-lazy + * values). (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 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 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 filter) { + return removeIf(filter, 0, size); + } + + /** + * Removes all elements satisfying the given predicate, from index + * i (inclusive) to index end (exclusive). + */ + boolean removeIf(Predicate 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 operator) { + replaceAllRange(operator, 0, size); + // TODO(8203662): remove increment of modCount from ... + modCount++; + } + + private void replaceAllRange(UnaryOperator 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 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; + } + + /** + * Calculates a new array length given an array's current length, a preferred + * growth value, and a minimum growth value. If the preferred growth value + * is less than the minimum growth value, the minimum growth value is used in + * its place. If the sum of the current length and the preferred growth + * value does not exceed {@link #MAX_ARRAY_LENGTH}, that sum is returned. + * If the sum of the current length and the minimum growth value does not + * exceed {@code MAX_ARRAY_LENGTH}, then {@code MAX_ARRAY_LENGTH} is returned. + * If the sum does not overflow an int, then {@code Integer.MAX_VALUE} is + * returned. Otherwise, {@code OutOfMemoryError} is thrown. + * + * @param oldLength current length of the array (must be non negative) + * @param minGrowth minimum required growth of the array length (must be + * positive) + * @param prefGrowth preferred growth of the array length (ignored, if less + * then {@code minGrowth}) + * @return the new length of the array + * @throws OutOfMemoryError if increasing {@code oldLength} by + * {@code minGrowth} overflows. + */ + private static int newLength(int oldLength, int minGrowth, int prefGrowth) { + // assert oldLength >= 0 + // assert minGrowth > 0 + + int newLength = Math.max(minGrowth, prefGrowth) + oldLength; + if (newLength - MAX_ARRAY_LENGTH <= 0) { + return newLength; + } + return hugeLength(oldLength, minGrowth); + } + + private static int hugeLength(int oldLength, int minGrowth) { + int minLength = oldLength + minGrowth; + if (minLength < 0) { // overflow + throw new OutOfMemoryError("Required array length too large"); + } + if (minLength <= MAX_ARRAY_LENGTH) { + return MAX_ARRAY_LENGTH; + } + return Integer.MAX_VALUE; + } + + private static final int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8; + + private static void subListRangeCheck(int fromIndex, int toIndex, int size) { + if (fromIndex < 0) + throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); + if (toIndex > size) + throw new IndexOutOfBoundsException("toIndex = " + toIndex); + if (fromIndex > toIndex) + throw new IllegalArgumentException("fromIndex(" + fromIndex + + ") > toIndex(" + toIndex + ")"); + } +} diff --git a/test/micro/org/openjdk/bench/valhalla/corelibs/XArrayListCursorTest.java b/test/micro/org/openjdk/bench/valhalla/corelibs/XArrayListCursorTest.java new file mode 100644 index 00000000000..1f15d1761f5 --- /dev/null +++ b/test/micro/org/openjdk/bench/valhalla/corelibs/XArrayListCursorTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + */ +package org.openjdk.bench.valhalla.corelibs; + +import java.util.List; +import java.util.Iterator; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +@Fork(1) +@Warmup(iterations = 3, time = 1) +@Measurement(iterations = 5, time = 3) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@BenchmarkMode(Mode.AverageTime) +@State(Scope.Thread) +public class XArrayListCursorTest { + @Param({"100000"}) + public static int size; + + private static final String constantString = "abc"; + + private static XArrayList list; + + @Setup + public void setup() { + list = new XArrayList<>(); + for (int i = 0; i < size; i++) { + list.add(constantString); + } + } + + @Benchmark + public void getViaCursorWhileLoop(Blackhole blackhole) { + InlineCursor cur = list.cursor(); + while (cur.exists()) { + blackhole.consume(cur.get()); + cur = cur.advance(); + } + } + + @Benchmark + public void getViaCursorForLoop(Blackhole blackhole) { + for (InlineCursor cur = list.cursor(); + cur.exists(); + cur = cur.advance()) { + blackhole.consume(cur.get()); + } + } + + @Benchmark + public void getViaIterator(Blackhole blackhole) { + Iterator it = list.iterator(); + while (it.hasNext()) { + blackhole.consume(it.next()); + } + } + + @Benchmark + public void getViaIteratorCurs(Blackhole blackhole) { + Iterator it = list.iteratorCurs(); + while (it.hasNext()) { + blackhole.consume(it.next()); + } + } + + @Benchmark + public void getViaArray(Blackhole blackhole) { + for (int i = 0; i < list.size(); i++) { + blackhole.consume(list.get(i)); + } + } + +}