--- jsr166/src/main/java/util/ArrayList.java 2018/05/06 01:14:25 1.59
+++ jsr166/src/main/java/util/ArrayList.java 2020/07/24 20:57:26 1.71
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -28,7 +28,8 @@ package java.util;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
-import jdk.internal.misc.SharedSecrets;
+// OPENJDK import jdk.internal.access.SharedSecrets;
+import jdk.internal.util.ArraysSupport;
/**
* Resizable-array implementation of the {@code List} interface. Implements
@@ -92,7 +93,7 @@ import jdk.internal.misc.SharedSecrets;
* 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
@@ -108,6 +109,7 @@ import jdk.internal.misc.SharedSecrets;
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
{
+ // OPENJDK @java.io.Serial
private static final long serialVersionUID = 8683452581122892189L;
/**
@@ -176,15 +178,16 @@ public class ArrayList extends Abstra
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection extends E> 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);
+ 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.
- this.elementData = EMPTY_ELEMENTDATA;
+ elementData = EMPTY_ELEMENTDATA;
}
}
@@ -219,14 +222,6 @@ public class ArrayList extends Abstra
}
/**
- * The maximum size of array to allocate (unless necessary).
- * Some VMs reserve some header words in an array.
- * Attempts to allocate larger arrays may result in
- * OutOfMemoryError: Requested array size exceeds VM limit
- */
- private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
@@ -234,8 +229,15 @@ public class ArrayList extends Abstra
* @throws OutOfMemoryError if minCapacity is less than zero
*/
private Object[] grow(int minCapacity) {
- return elementData = Arrays.copyOf(elementData,
- newCapacity(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() {
@@ -243,39 +245,6 @@ public class ArrayList extends Abstra
}
/**
- * Returns a capacity at least as large as the given minimum capacity.
- * Returns the current capacity increased by 50% if that suffices.
- * Will not return a capacity greater than MAX_ARRAY_SIZE unless
- * the given minimum capacity is greater than MAX_ARRAY_SIZE.
- *
- * @param minCapacity the desired minimum capacity
- * @throws OutOfMemoryError if minCapacity is less than zero
- */
- private int newCapacity(int minCapacity) {
- // overflow-conscious code
- int oldCapacity = elementData.length;
- int newCapacity = oldCapacity + (oldCapacity >> 1);
- if (newCapacity - minCapacity <= 0) {
- if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
- return Math.max(DEFAULT_CAPACITY, minCapacity);
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return minCapacity;
- }
- return (newCapacity - MAX_ARRAY_SIZE <= 0)
- ? newCapacity
- : hugeCapacity(minCapacity);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE)
- ? Integer.MAX_VALUE
- : MAX_ARRAY_SIZE;
- }
-
- /**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
@@ -314,14 +283,23 @@ public class ArrayList extends Abstra
* 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 = 0; i < size; i++)
- if (elementData[i]==null)
+ for (int i = start; i < end; i++) {
+ if (es[i] == null) {
return i;
+ }
+ }
} else {
- for (int i = 0; i < size; i++)
- if (o.equals(elementData[i]))
+ for (int i = start; i < end; i++) {
+ if (o.equals(es[i])) {
return i;
+ }
+ }
}
return -1;
}
@@ -334,14 +312,23 @@ public class ArrayList extends Abstra
* 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 = size-1; i >= 0; i--)
- if (elementData[i]==null)
+ for (int i = end - 1; i >= start; i--) {
+ if (es[i] == null) {
return i;
+ }
+ }
} else {
- for (int i = size-1; i >= 0; i--)
- if (o.equals(elementData[i]))
+ for (int i = end - 1; i >= start; i--) {
+ if (o.equals(es[i])) {
return i;
+ }
+ }
}
return -1;
}
@@ -526,6 +513,93 @@ public class ArrayList extends Abstra
}
/**
+ * {@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
@@ -783,6 +857,7 @@ public class ArrayList extends Abstra
* instance is emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
*/
+ // OPENJDK @java.io.Serial
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
@@ -810,6 +885,7 @@ public class ArrayList extends Abstra
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
+ // OPENJDK @java.io.Serial
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
@@ -821,7 +897,7 @@ public class ArrayList extends Abstra
if (size > 0) {
// like clone(), allocate array based upon size not capacity
- SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
+ jsr166.Platform.checkArray(s, Object[].class, size);
Object[] elements = new Object[size];
// Read in all elements in the proper order.
@@ -1064,7 +1140,7 @@ public class ArrayList extends Abstra
this.parent = parent;
this.offset = parent.offset + fromIndex;
this.size = toIndex - fromIndex;
- this.modCount = root.modCount;
+ this.modCount = parent.modCount;
}
public E set(int index, E element) {
@@ -1170,6 +1246,42 @@ public class ArrayList extends Abstra
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();
}
@@ -1181,7 +1293,7 @@ public class ArrayList extends Abstra
return new ListIterator() {
int cursor = index;
int lastRet = -1;
- int expectedModCount = root.modCount;
+ int expectedModCount = SubList.this.modCount;
public boolean hasNext() {
return cursor != SubList.this.size;
@@ -1225,7 +1337,7 @@ public class ArrayList extends Abstra
final Object[] es = root.elementData;
if (offset + i >= es.length)
throw new ConcurrentModificationException();
- for (; i < size && modCount == expectedModCount; i++)
+ for (; i < size && root.modCount == expectedModCount; i++)
action.accept(elementAt(es, offset + i));
// update once at end to reduce heap write traffic
cursor = i;
@@ -1251,7 +1363,7 @@ public class ArrayList extends Abstra
SubList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
- expectedModCount = root.modCount;
+ expectedModCount = SubList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
@@ -1277,7 +1389,7 @@ public class ArrayList extends Abstra
SubList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
- expectedModCount = root.modCount;
+ expectedModCount = SubList.this.modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
@@ -1596,6 +1708,8 @@ public class ArrayList extends Abstra
@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) {