ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/ArrayList.java
(Generate patch)

Comparing jsr166/src/main/java/util/ArrayList.java (file contents):
Revision 1.38 by jsr166, Sat Nov 12 20:51:59 2016 UTC vs.
Revision 1.71 by jsr166, Fri Jul 24 20:57:26 2020 UTC

# Line 1 | Line 1
1   /*
2 < * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
2 > * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
3   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4   *
5   * This code is free software; you can redistribute it and/or modify it
# Line 28 | Line 28 | package java.util;
28   import java.util.function.Consumer;
29   import java.util.function.Predicate;
30   import java.util.function.UnaryOperator;
31 + // OPENJDK import jdk.internal.access.SharedSecrets;
32 + import jdk.internal.util.ArraysSupport;
33  
34   /**
35   * Resizable-array implementation of the {@code List} interface.  Implements
# Line 91 | Line 93 | import java.util.function.UnaryOperator;
93   * should be used only to detect bugs.</i>
94   *
95   * <p>This class is a member of the
96 < * <a href="{@docRoot}/../technotes/guides/collections/index.html">
96 > * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
97   * Java Collections Framework</a>.
98   *
99   * @param <E> the type of elements in this list
# Line 107 | Line 109 | import java.util.function.UnaryOperator;
109   public class ArrayList<E> extends AbstractList<E>
110          implements List<E>, RandomAccess, Cloneable, java.io.Serializable
111   {
112 +    // OPENJDK @java.io.Serial
113      private static final long serialVersionUID = 8683452581122892189L;
114  
115      /**
# Line 175 | Line 178 | public class ArrayList<E> extends Abstra
178       * @throws NullPointerException if the specified collection is null
179       */
180      public ArrayList(Collection<? extends E> c) {
181 <        elementData = c.toArray();
182 <        if ((size = elementData.length) != 0) {
183 <            // defend against c.toArray (incorrectly) not returning Object[]
184 <            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
185 <            if (elementData.getClass() != Object[].class)
186 <                elementData = Arrays.copyOf(elementData, size, Object[].class);
181 >        Object[] a = c.toArray();
182 >        if ((size = a.length) != 0) {
183 >            if (c.getClass() == ArrayList.class) {
184 >                elementData = a;
185 >            } else {
186 >                elementData = Arrays.copyOf(a, size, Object[].class);
187 >            }
188          } else {
189              // replace with empty array.
190 <            this.elementData = EMPTY_ELEMENTDATA;
190 >            elementData = EMPTY_ELEMENTDATA;
191          }
192      }
193  
# Line 218 | Line 222 | public class ArrayList<E> extends Abstra
222      }
223  
224      /**
221     * The maximum size of array to allocate (unless necessary).
222     * Some VMs reserve some header words in an array.
223     * Attempts to allocate larger arrays may result in
224     * OutOfMemoryError: Requested array size exceeds VM limit
225     */
226    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
227
228    /**
225       * Increases the capacity to ensure that it can hold at least the
226       * number of elements specified by the minimum capacity argument.
227       *
# Line 233 | Line 229 | public class ArrayList<E> extends Abstra
229       * @throws OutOfMemoryError if minCapacity is less than zero
230       */
231      private Object[] grow(int minCapacity) {
232 <        return elementData = Arrays.copyOf(elementData,
233 <                                           newCapacity(minCapacity));
232 >        int oldCapacity = elementData.length;
233 >        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
234 >            int newCapacity = ArraysSupport.newLength(oldCapacity,
235 >                    minCapacity - oldCapacity, /* minimum growth */
236 >                    oldCapacity >> 1           /* preferred growth */);
237 >            return elementData = Arrays.copyOf(elementData, newCapacity);
238 >        } else {
239 >            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
240 >        }
241      }
242  
243      private Object[] grow() {
# Line 242 | Line 245 | public class ArrayList<E> extends Abstra
245      }
246  
247      /**
245     * Returns a capacity at least as large as the given minimum capacity.
246     * Returns the current capacity increased by 50% if that suffices.
247     * Will not return a capacity greater than MAX_ARRAY_SIZE unless
248     * the given minimum capacity is greater than MAX_ARRAY_SIZE.
249     *
250     * @param minCapacity the desired minimum capacity
251     * @throws OutOfMemoryError if minCapacity is less than zero
252     */
253    private int newCapacity(int minCapacity) {
254        // overflow-conscious code
255        int oldCapacity = elementData.length;
256        int newCapacity = oldCapacity + (oldCapacity >> 1);
257        if (newCapacity - minCapacity <= 0) {
258            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
259                return Math.max(DEFAULT_CAPACITY, minCapacity);
260            if (minCapacity < 0) // overflow
261                throw new OutOfMemoryError();
262            return minCapacity;
263        }
264        return (newCapacity - MAX_ARRAY_SIZE <= 0)
265            ? newCapacity
266            : hugeCapacity(minCapacity);
267    }
268
269    private static int hugeCapacity(int minCapacity) {
270        if (minCapacity < 0) // overflow
271            throw new OutOfMemoryError();
272        return (minCapacity > MAX_ARRAY_SIZE)
273            ? Integer.MAX_VALUE
274            : MAX_ARRAY_SIZE;
275    }
276
277    /**
248       * Returns the number of elements in this list.
249       *
250       * @return the number of elements in this list
# Line 313 | Line 283 | public class ArrayList<E> extends Abstra
283       * or -1 if there is no such index.
284       */
285      public int indexOf(Object o) {
286 +        return indexOfRange(o, 0, size);
287 +    }
288 +
289 +    int indexOfRange(Object o, int start, int end) {
290 +        Object[] es = elementData;
291          if (o == null) {
292 <            for (int i = 0; i < size; i++)
293 <                if (elementData[i]==null)
292 >            for (int i = start; i < end; i++) {
293 >                if (es[i] == null) {
294                      return i;
295 +                }
296 +            }
297          } else {
298 <            for (int i = 0; i < size; i++)
299 <                if (o.equals(elementData[i]))
298 >            for (int i = start; i < end; i++) {
299 >                if (o.equals(es[i])) {
300                      return i;
301 +                }
302 +            }
303          }
304          return -1;
305      }
# Line 333 | Line 312 | public class ArrayList<E> extends Abstra
312       * or -1 if there is no such index.
313       */
314      public int lastIndexOf(Object o) {
315 +        return lastIndexOfRange(o, 0, size);
316 +    }
317 +
318 +    int lastIndexOfRange(Object o, int start, int end) {
319 +        Object[] es = elementData;
320          if (o == null) {
321 <            for (int i = size-1; i >= 0; i--)
322 <                if (elementData[i]==null)
321 >            for (int i = end - 1; i >= start; i--) {
322 >                if (es[i] == null) {
323                      return i;
324 +                }
325 +            }
326          } else {
327 <            for (int i = size-1; i >= 0; i--)
328 <                if (o.equals(elementData[i]))
327 >            for (int i = end - 1; i >= start; i--) {
328 >                if (o.equals(es[i])) {
329                      return i;
330 +                }
331 +            }
332          }
333          return -1;
334      }
# Line 423 | Line 411 | public class ArrayList<E> extends Abstra
411          return (E) elementData[index];
412      }
413  
414 +    @SuppressWarnings("unchecked")
415 +    static <E> E elementAt(Object[] es, int index) {
416 +        return (E) es[index];
417 +    }
418 +
419      /**
420       * Returns the element at the specified position in this list.
421       *
# Line 496 | Line 489 | public class ArrayList<E> extends Abstra
489                           s - index);
490          elementData[index] = element;
491          size = s + 1;
492 +        // checkInvariants();
493      }
494  
495      /**
# Line 509 | Line 503 | public class ArrayList<E> extends Abstra
503       */
504      public E remove(int index) {
505          Objects.checkIndex(index, size);
506 +        final Object[] es = elementData;
507  
508 <        modCount++;
509 <        E oldValue = elementData(index);
515 <
516 <        int numMoved = size - index - 1;
517 <        if (numMoved > 0)
518 <            System.arraycopy(elementData, index+1, elementData, index,
519 <                             numMoved);
520 <        elementData[--size] = null; // clear to let GC do its work
508 >        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
509 >        fastRemove(es, index);
510  
511 +        // checkInvariants();
512          return oldValue;
513      }
514  
515      /**
516 +     * {@inheritDoc}
517 +     */
518 +    public boolean equals(Object o) {
519 +        if (o == this) {
520 +            return true;
521 +        }
522 +
523 +        if (!(o instanceof List)) {
524 +            return false;
525 +        }
526 +
527 +        final int expectedModCount = modCount;
528 +        // ArrayList can be subclassed and given arbitrary behavior, but we can
529 +        // still deal with the common case where o is ArrayList precisely
530 +        boolean equal = (o.getClass() == ArrayList.class)
531 +            ? equalsArrayList((ArrayList<?>) o)
532 +            : equalsRange((List<?>) o, 0, size);
533 +
534 +        checkForComodification(expectedModCount);
535 +        return equal;
536 +    }
537 +
538 +    boolean equalsRange(List<?> other, int from, int to) {
539 +        final Object[] es = elementData;
540 +        if (to > es.length) {
541 +            throw new ConcurrentModificationException();
542 +        }
543 +        var oit = other.iterator();
544 +        for (; from < to; from++) {
545 +            if (!oit.hasNext() || !Objects.equals(es[from], oit.next())) {
546 +                return false;
547 +            }
548 +        }
549 +        return !oit.hasNext();
550 +    }
551 +
552 +    private boolean equalsArrayList(ArrayList<?> other) {
553 +        final int otherModCount = other.modCount;
554 +        final int s = size;
555 +        boolean equal;
556 +        if (equal = (s == other.size)) {
557 +            final Object[] otherEs = other.elementData;
558 +            final Object[] es = elementData;
559 +            if (s > es.length || s > otherEs.length) {
560 +                throw new ConcurrentModificationException();
561 +            }
562 +            for (int i = 0; i < s; i++) {
563 +                if (!Objects.equals(es[i], otherEs[i])) {
564 +                    equal = false;
565 +                    break;
566 +                }
567 +            }
568 +        }
569 +        other.checkForComodification(otherModCount);
570 +        return equal;
571 +    }
572 +
573 +    private void checkForComodification(final int expectedModCount) {
574 +        if (modCount != expectedModCount) {
575 +            throw new ConcurrentModificationException();
576 +        }
577 +    }
578 +
579 +    /**
580 +     * {@inheritDoc}
581 +     */
582 +    public int hashCode() {
583 +        int expectedModCount = modCount;
584 +        int hash = hashCodeRange(0, size);
585 +        checkForComodification(expectedModCount);
586 +        return hash;
587 +    }
588 +
589 +    int hashCodeRange(int from, int to) {
590 +        final Object[] es = elementData;
591 +        if (to > es.length) {
592 +            throw new ConcurrentModificationException();
593 +        }
594 +        int hashCode = 1;
595 +        for (int i = from; i < to; i++) {
596 +            Object e = es[i];
597 +            hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
598 +        }
599 +        return hashCode;
600 +    }
601 +
602 +    /**
603       * Removes the first occurrence of the specified element from this list,
604       * if it is present.  If the list does not contain the element, it is
605       * unchanged.  More formally, removes the element with the lowest index
# Line 536 | Line 613 | public class ArrayList<E> extends Abstra
613       * @return {@code true} if this list contained the specified element
614       */
615      public boolean remove(Object o) {
616 <        if (o == null) {
617 <            for (int index = 0; index < size; index++)
618 <                if (elementData[index] == null) {
619 <                    fastRemove(index);
620 <                    return true;
621 <                }
622 <        } else {
623 <            for (int index = 0; index < size; index++)
624 <                if (o.equals(elementData[index])) {
625 <                    fastRemove(index);
626 <                    return true;
627 <                }
616 >        final Object[] es = elementData;
617 >        final int size = this.size;
618 >        int i = 0;
619 >        found: {
620 >            if (o == null) {
621 >                for (; i < size; i++)
622 >                    if (es[i] == null)
623 >                        break found;
624 >            } else {
625 >                for (; i < size; i++)
626 >                    if (o.equals(es[i]))
627 >                        break found;
628 >            }
629 >            return false;
630          }
631 <        return false;
631 >        fastRemove(es, i);
632 >        return true;
633      }
634  
635 <    /*
635 >    /**
636       * Private remove method that skips bounds checking and does not
637       * return the value removed.
638       */
639 <    private void fastRemove(int index) {
639 >    private void fastRemove(Object[] es, int i) {
640          modCount++;
641 <        int numMoved = size - index - 1;
642 <        if (numMoved > 0)
643 <            System.arraycopy(elementData, index+1, elementData, index,
644 <                             numMoved);
565 <        elementData[--size] = null; // clear to let GC do its work
641 >        final int newSize;
642 >        if ((newSize = size - 1) > i)
643 >            System.arraycopy(es, i + 1, es, i, newSize - i);
644 >        es[size = newSize] = null;
645      }
646  
647      /**
# Line 571 | Line 650 | public class ArrayList<E> extends Abstra
650       */
651      public void clear() {
652          modCount++;
653 <
654 <        // clear to let GC do its work
655 <        for (int i = 0; i < size; i++)
577 <            elementData[i] = null;
578 <
579 <        size = 0;
653 >        final Object[] es = elementData;
654 >        for (int to = size, i = size = 0; i < to; i++)
655 >            es[i] = null;
656      }
657  
658      /**
# Line 604 | Line 680 | public class ArrayList<E> extends Abstra
680              elementData = grow(s + numNew);
681          System.arraycopy(a, 0, elementData, s, numNew);
682          size = s + numNew;
683 +        // checkInvariants();
684          return true;
685      }
686  
# Line 642 | Line 719 | public class ArrayList<E> extends Abstra
719                               numMoved);
720          System.arraycopy(a, 0, elementData, index, numNew);
721          size = s + numNew;
722 +        // checkInvariants();
723          return true;
724      }
725  
# Line 664 | Line 742 | public class ArrayList<E> extends Abstra
742                      outOfBoundsMsg(fromIndex, toIndex));
743          }
744          modCount++;
745 <        int numMoved = size - toIndex;
746 <        System.arraycopy(elementData, toIndex, elementData, fromIndex,
747 <                         numMoved);
748 <
749 <        // clear to let GC do its work
750 <        int newSize = size - (toIndex-fromIndex);
751 <        for (int i = newSize; i < size; i++) {
752 <            elementData[i] = null;
753 <        }
676 <        size = newSize;
745 >        shiftTailOverGap(elementData, fromIndex, toIndex);
746 >        // checkInvariants();
747 >    }
748 >
749 >    /** Erases the gap from lo to hi, by sliding down following elements. */
750 >    private void shiftTailOverGap(Object[] es, int lo, int hi) {
751 >        System.arraycopy(es, hi, es, lo, size - hi);
752 >        for (int to = size, i = (size -= hi - lo); i < to; i++)
753 >            es[i] = null;
754      }
755  
756      /**
# Line 716 | Line 793 | public class ArrayList<E> extends Abstra
793       * @see Collection#contains(Object)
794       */
795      public boolean removeAll(Collection<?> c) {
796 <        return batchRemove(c, false);
796 >        return batchRemove(c, false, 0, size);
797      }
798  
799      /**
# Line 736 | Line 813 | public class ArrayList<E> extends Abstra
813       * @see Collection#contains(Object)
814       */
815      public boolean retainAll(Collection<?> c) {
816 <        return batchRemove(c, true);
816 >        return batchRemove(c, true, 0, size);
817      }
818  
819 <    private boolean batchRemove(Collection<?> c, boolean complement) {
819 >    boolean batchRemove(Collection<?> c, boolean complement,
820 >                        final int from, final int end) {
821          Objects.requireNonNull(c);
822          final Object[] es = elementData;
745        final int size = this.size;
746        final boolean modified;
823          int r;
824          // Optimize for initial run of survivors
825 <        for (r = 0; r < size && c.contains(es[r]) == complement; r++)
826 <            ;
827 <        if (modified = (r < size)) {
828 <            int w = r++;
829 <            try {
754 <                for (Object e; r < size; r++)
755 <                    if (c.contains(e = es[r]) == complement)
756 <                        es[w++] = e;
757 <            } catch (Throwable ex) {
758 <                // Preserve behavioral compatibility with AbstractCollection,
759 <                // even if c.contains() throws.
760 <                System.arraycopy(es, r, es, w, size - r);
761 <                w += size - r;
762 <                throw ex;
763 <            } finally {
764 <                modCount += size - w;
765 <                Arrays.fill(es, (this.size = w), size, null);
766 <            }
825 >        for (r = from;; r++) {
826 >            if (r == end)
827 >                return false;
828 >            if (c.contains(es[r]) != complement)
829 >                break;
830          }
831 <        return modified;
831 >        int w = r++;
832 >        try {
833 >            for (Object e; r < end; r++)
834 >                if (c.contains(e = es[r]) == complement)
835 >                    es[w++] = e;
836 >        } catch (Throwable ex) {
837 >            // Preserve behavioral compatibility with AbstractCollection,
838 >            // even if c.contains() throws.
839 >            System.arraycopy(es, r, es, w, end - r);
840 >            w += end - r;
841 >            throw ex;
842 >        } finally {
843 >            modCount += end - w;
844 >            shiftTailOverGap(es, w, end);
845 >        }
846 >        // checkInvariants();
847 >        return true;
848      }
849  
850      /**
851 <     * Save the state of the {@code ArrayList} instance to a stream (that
852 <     * is, serialize it).
851 >     * Saves the state of the {@code ArrayList} instance to a stream
852 >     * (that is, serializes it).
853       *
854 +     * @param s the stream
855 +     * @throws java.io.IOException if an I/O error occurs
856       * @serialData The length of the array backing the {@code ArrayList}
857       *             instance is emitted (int), followed by all of its elements
858       *             (each an {@code Object}) in the proper order.
859       */
860 +    // OPENJDK @java.io.Serial
861      private void writeObject(java.io.ObjectOutputStream s)
862 <        throws java.io.IOException{
862 >        throws java.io.IOException {
863          // Write out element count, and any hidden stuff
864          int expectedModCount = modCount;
865          s.defaultWriteObject();
866  
867 <        // Write out size as capacity for behavioural compatibility with clone()
867 >        // Write out size as capacity for behavioral compatibility with clone()
868          s.writeInt(size);
869  
870          // Write out all elements in the proper order.
# Line 796 | Line 878 | public class ArrayList<E> extends Abstra
878      }
879  
880      /**
881 <     * Reconstitute the {@code ArrayList} instance from a stream (that is,
882 <     * deserialize it).
881 >     * Reconstitutes the {@code ArrayList} instance from a stream (that is,
882 >     * deserializes it).
883 >     * @param s the stream
884 >     * @throws ClassNotFoundException if the class of a serialized object
885 >     *         could not be found
886 >     * @throws java.io.IOException if an I/O error occurs
887       */
888 +    // OPENJDK @java.io.Serial
889      private void readObject(java.io.ObjectInputStream s)
890          throws java.io.IOException, ClassNotFoundException {
891  
# Line 810 | Line 897 | public class ArrayList<E> extends Abstra
897  
898          if (size > 0) {
899              // like clone(), allocate array based upon size not capacity
900 +            jsr166.Platform.checkArray(s, Object[].class, size);
901              Object[] elements = new Object[size];
902  
903              // Read in all elements in the proper order.
# Line 909 | Line 997 | public class ArrayList<E> extends Abstra
997          }
998  
999          @Override
1000 <        @SuppressWarnings("unchecked")
1001 <        public void forEachRemaining(Consumer<? super E> consumer) {
914 <            Objects.requireNonNull(consumer);
1000 >        public void forEachRemaining(Consumer<? super E> action) {
1001 >            Objects.requireNonNull(action);
1002              final int size = ArrayList.this.size;
1003              int i = cursor;
1004 <            if (i >= size) {
1005 <                return;
1006 <            }
1007 <            final Object[] elementData = ArrayList.this.elementData;
1008 <            if (i >= elementData.length) {
1009 <                throw new ConcurrentModificationException();
1010 <            }
1011 <            while (i != size && modCount == expectedModCount) {
1012 <                consumer.accept((E) elementData[i++]);
1004 >            if (i < size) {
1005 >                final Object[] es = elementData;
1006 >                if (i >= es.length)
1007 >                    throw new ConcurrentModificationException();
1008 >                for (; i < size && modCount == expectedModCount; i++)
1009 >                    action.accept(elementAt(es, i));
1010 >                // update once at end to reduce heap write traffic
1011 >                cursor = i;
1012 >                lastRet = i - 1;
1013 >                checkForComodification();
1014              }
927            // update once at end of iteration to reduce heap write traffic
928            cursor = i;
929            lastRet = i - 1;
930            checkForComodification();
1015          }
1016  
1017          final void checkForComodification() {
# Line 1056 | Line 1140 | public class ArrayList<E> extends Abstra
1140              this.parent = parent;
1141              this.offset = parent.offset + fromIndex;
1142              this.size = toIndex - fromIndex;
1143 <            this.modCount = root.modCount;
1143 >            this.modCount = parent.modCount;
1144          }
1145  
1146          public E set(int index, E element) {
# Line 1114 | Line 1198 | public class ArrayList<E> extends Abstra
1198              return true;
1199          }
1200  
1201 +        public void replaceAll(UnaryOperator<E> operator) {
1202 +            root.replaceAllRange(operator, offset, offset + size);
1203 +        }
1204 +
1205 +        public boolean removeAll(Collection<?> c) {
1206 +            return batchRemove(c, false);
1207 +        }
1208 +
1209 +        public boolean retainAll(Collection<?> c) {
1210 +            return batchRemove(c, true);
1211 +        }
1212 +
1213 +        private boolean batchRemove(Collection<?> c, boolean complement) {
1214 +            checkForComodification();
1215 +            int oldSize = root.size;
1216 +            boolean modified =
1217 +                root.batchRemove(c, complement, offset, offset + size);
1218 +            if (modified)
1219 +                updateSizeAndModCount(root.size - oldSize);
1220 +            return modified;
1221 +        }
1222 +
1223 +        public boolean removeIf(Predicate<? super E> filter) {
1224 +            checkForComodification();
1225 +            int oldSize = root.size;
1226 +            boolean modified = root.removeIf(filter, offset, offset + size);
1227 +            if (modified)
1228 +                updateSizeAndModCount(root.size - oldSize);
1229 +            return modified;
1230 +        }
1231 +
1232 +        public Object[] toArray() {
1233 +            checkForComodification();
1234 +            return Arrays.copyOfRange(root.elementData, offset, offset + size);
1235 +        }
1236 +
1237 +        @SuppressWarnings("unchecked")
1238 +        public <T> T[] toArray(T[] a) {
1239 +            checkForComodification();
1240 +            if (a.length < size)
1241 +                return (T[]) Arrays.copyOfRange(
1242 +                        root.elementData, offset, offset + size, a.getClass());
1243 +            System.arraycopy(root.elementData, offset, a, 0, size);
1244 +            if (a.length > size)
1245 +                a[size] = null;
1246 +            return a;
1247 +        }
1248 +
1249 +        public boolean equals(Object o) {
1250 +            if (o == this) {
1251 +                return true;
1252 +            }
1253 +
1254 +            if (!(o instanceof List)) {
1255 +                return false;
1256 +            }
1257 +
1258 +            boolean equal = root.equalsRange((List<?>)o, offset, offset + size);
1259 +            checkForComodification();
1260 +            return equal;
1261 +        }
1262 +
1263 +        public int hashCode() {
1264 +            int hash = root.hashCodeRange(offset, offset + size);
1265 +            checkForComodification();
1266 +            return hash;
1267 +        }
1268 +
1269 +        public int indexOf(Object o) {
1270 +            int index = root.indexOfRange(o, offset, offset + size);
1271 +            checkForComodification();
1272 +            return index >= 0 ? index - offset : -1;
1273 +        }
1274 +
1275 +        public int lastIndexOf(Object o) {
1276 +            int index = root.lastIndexOfRange(o, offset, offset + size);
1277 +            checkForComodification();
1278 +            return index >= 0 ? index - offset : -1;
1279 +        }
1280 +
1281 +        public boolean contains(Object o) {
1282 +            return indexOf(o) >= 0;
1283 +        }
1284 +
1285          public Iterator<E> iterator() {
1286              return listIterator();
1287          }
# Line 1125 | Line 1293 | public class ArrayList<E> extends Abstra
1293              return new ListIterator<E>() {
1294                  int cursor = index;
1295                  int lastRet = -1;
1296 <                int expectedModCount = root.modCount;
1296 >                int expectedModCount = SubList.this.modCount;
1297  
1298                  public boolean hasNext() {
1299                      return cursor != SubList.this.size;
# Line 1161 | Line 1329 | public class ArrayList<E> extends Abstra
1329                      return (E) elementData[offset + (lastRet = i)];
1330                  }
1331  
1332 <                @SuppressWarnings("unchecked")
1333 <                public void forEachRemaining(Consumer<? super E> consumer) {
1166 <                    Objects.requireNonNull(consumer);
1332 >                public void forEachRemaining(Consumer<? super E> action) {
1333 >                    Objects.requireNonNull(action);
1334                      final int size = SubList.this.size;
1335                      int i = cursor;
1336 <                    if (i >= size) {
1337 <                        return;
1338 <                    }
1339 <                    final Object[] elementData = root.elementData;
1340 <                    if (offset + i >= elementData.length) {
1341 <                        throw new ConcurrentModificationException();
1342 <                    }
1343 <                    while (i != size && modCount == expectedModCount) {
1344 <                        consumer.accept((E) elementData[offset + (i++)]);
1336 >                    if (i < size) {
1337 >                        final Object[] es = root.elementData;
1338 >                        if (offset + i >= es.length)
1339 >                            throw new ConcurrentModificationException();
1340 >                        for (; i < size && root.modCount == expectedModCount; i++)
1341 >                            action.accept(elementAt(es, offset + i));
1342 >                        // update once at end to reduce heap write traffic
1343 >                        cursor = i;
1344 >                        lastRet = i - 1;
1345 >                        checkForComodification();
1346                      }
1179                    // update once at end of iteration to reduce heap write traffic
1180                    lastRet = cursor = i;
1181                    checkForComodification();
1347                  }
1348  
1349                  public int nextIndex() {
# Line 1198 | Line 1363 | public class ArrayList<E> extends Abstra
1363                          SubList.this.remove(lastRet);
1364                          cursor = lastRet;
1365                          lastRet = -1;
1366 <                        expectedModCount = root.modCount;
1366 >                        expectedModCount = SubList.this.modCount;
1367                      } catch (IndexOutOfBoundsException ex) {
1368                          throw new ConcurrentModificationException();
1369                      }
# Line 1224 | Line 1389 | public class ArrayList<E> extends Abstra
1389                          SubList.this.add(i, e);
1390                          cursor = i + 1;
1391                          lastRet = -1;
1392 <                        expectedModCount = root.modCount;
1392 >                        expectedModCount = SubList.this.modCount;
1393                      } catch (IndexOutOfBoundsException ex) {
1394                          throw new ConcurrentModificationException();
1395                      }
# Line 1268 | Line 1433 | public class ArrayList<E> extends Abstra
1433          public Spliterator<E> spliterator() {
1434              checkForComodification();
1435  
1436 <            // ArrayListSpliterator is not used because late-binding logic
1437 <            // is different here
1273 <            return new Spliterator<>() {
1436 >            // ArrayListSpliterator not used here due to late-binding
1437 >            return new Spliterator<E>() {
1438                  private int index = offset; // current index, modified on advance/split
1439                  private int fence = -1; // -1 until used; then one past last index
1440                  private int expectedModCount; // initialized when fence set
# Line 1284 | Line 1448 | public class ArrayList<E> extends Abstra
1448                      return hi;
1449                  }
1450  
1451 <                public ArrayListSpliterator<E> trySplit() {
1451 >                public ArrayList<E>.ArrayListSpliterator trySplit() {
1452                      int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
1453 <                    // ArrayListSpliterator could be used here as the source is already bound
1453 >                    // ArrayListSpliterator can be used here as the source is already bound
1454                      return (lo >= mid) ? null : // divide range in half unless too small
1455 <                        new ArrayListSpliterator<>(root, lo, index = mid,
1292 <                                                   expectedModCount);
1455 >                        root.new ArrayListSpliterator(lo, index = mid, expectedModCount);
1456                  }
1457  
1458                  public boolean tryAdvance(Consumer<? super E> action) {
# Line 1331 | Line 1494 | public class ArrayList<E> extends Abstra
1494                  }
1495  
1496                  public long estimateSize() {
1497 <                    return (long) (getFence() - index);
1497 >                    return getFence() - index;
1498                  }
1499  
1500                  public int characteristics() {
# Line 1341 | Line 1504 | public class ArrayList<E> extends Abstra
1504          }
1505      }
1506  
1507 +    /**
1508 +     * @throws NullPointerException {@inheritDoc}
1509 +     */
1510      @Override
1511      public void forEach(Consumer<? super E> action) {
1512          Objects.requireNonNull(action);
1513          final int expectedModCount = modCount;
1514 <        @SuppressWarnings("unchecked")
1349 <        final E[] elementData = (E[]) this.elementData;
1514 >        final Object[] es = elementData;
1515          final int size = this.size;
1516 <        for (int i=0; modCount == expectedModCount && i < size; i++) {
1517 <            action.accept(elementData[i]);
1518 <        }
1354 <        if (modCount != expectedModCount) {
1516 >        for (int i = 0; modCount == expectedModCount && i < size; i++)
1517 >            action.accept(elementAt(es, i));
1518 >        if (modCount != expectedModCount)
1519              throw new ConcurrentModificationException();
1356        }
1520      }
1521  
1522      /**
# Line 1371 | Line 1534 | public class ArrayList<E> extends Abstra
1534       */
1535      @Override
1536      public Spliterator<E> spliterator() {
1537 <        return new ArrayListSpliterator<>(this, 0, -1, 0);
1537 >        return new ArrayListSpliterator(0, -1, 0);
1538      }
1539  
1540      /** Index-based split-by-two, lazily initialized Spliterator */
1541 <    static final class ArrayListSpliterator<E> implements Spliterator<E> {
1541 >    final class ArrayListSpliterator implements Spliterator<E> {
1542  
1543          /*
1544           * If ArrayLists were immutable, or structurally immutable (no
# Line 1409 | Line 1572 | public class ArrayList<E> extends Abstra
1572           * these streamlinings.
1573           */
1574  
1412        private final ArrayList<E> list;
1575          private int index; // current index, modified on advance/split
1576          private int fence; // -1 until used; then one past last index
1577          private int expectedModCount; // initialized when fence set
1578  
1579 <        /** Create new spliterator covering the given  range */
1580 <        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
1419 <                             int expectedModCount) {
1420 <            this.list = list; // OK if null unless traversed
1579 >        /** Creates new spliterator covering the given range. */
1580 >        ArrayListSpliterator(int origin, int fence, int expectedModCount) {
1581              this.index = origin;
1582              this.fence = fence;
1583              this.expectedModCount = expectedModCount;
# Line 1425 | Line 1585 | public class ArrayList<E> extends Abstra
1585  
1586          private int getFence() { // initialize fence to size on first use
1587              int hi; // (a specialized variant appears in method forEach)
1428            ArrayList<E> lst;
1588              if ((hi = fence) < 0) {
1589 <                if ((lst = list) == null)
1590 <                    hi = fence = 0;
1432 <                else {
1433 <                    expectedModCount = lst.modCount;
1434 <                    hi = fence = lst.size;
1435 <                }
1589 >                expectedModCount = modCount;
1590 >                hi = fence = size;
1591              }
1592              return hi;
1593          }
1594  
1595 <        public ArrayListSpliterator<E> trySplit() {
1595 >        public ArrayListSpliterator trySplit() {
1596              int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
1597              return (lo >= mid) ? null : // divide range in half unless too small
1598 <                new ArrayListSpliterator<>(list, lo, index = mid,
1444 <                                           expectedModCount);
1598 >                new ArrayListSpliterator(lo, index = mid, expectedModCount);
1599          }
1600  
1601          public boolean tryAdvance(Consumer<? super E> action) {
# Line 1450 | Line 1604 | public class ArrayList<E> extends Abstra
1604              int hi = getFence(), i = index;
1605              if (i < hi) {
1606                  index = i + 1;
1607 <                @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
1607 >                @SuppressWarnings("unchecked") E e = (E)elementData[i];
1608                  action.accept(e);
1609 <                if (list.modCount != expectedModCount)
1609 >                if (modCount != expectedModCount)
1610                      throw new ConcurrentModificationException();
1611                  return true;
1612              }
# Line 1461 | Line 1615 | public class ArrayList<E> extends Abstra
1615  
1616          public void forEachRemaining(Consumer<? super E> action) {
1617              int i, hi, mc; // hoist accesses and checks from loop
1618 <            ArrayList<E> lst; Object[] a;
1618 >            Object[] a;
1619              if (action == null)
1620                  throw new NullPointerException();
1621 <            if ((lst = list) != null && (a = lst.elementData) != null) {
1621 >            if ((a = elementData) != null) {
1622                  if ((hi = fence) < 0) {
1623 <                    mc = lst.modCount;
1624 <                    hi = lst.size;
1623 >                    mc = modCount;
1624 >                    hi = size;
1625                  }
1626                  else
1627                      mc = expectedModCount;
# Line 1476 | Line 1630 | public class ArrayList<E> extends Abstra
1630                          @SuppressWarnings("unchecked") E e = (E) a[i];
1631                          action.accept(e);
1632                      }
1633 <                    if (lst.modCount == mc)
1633 >                    if (modCount == mc)
1634                          return;
1635                  }
1636              }
# Line 1484 | Line 1638 | public class ArrayList<E> extends Abstra
1638          }
1639  
1640          public long estimateSize() {
1641 <            return (long) (getFence() - index);
1641 >            return getFence() - index;
1642          }
1643  
1644          public int characteristics() {
# Line 1492 | Line 1646 | public class ArrayList<E> extends Abstra
1646          }
1647      }
1648  
1649 <    @SuppressWarnings("unchecked")
1649 >    // A tiny bit set implementation
1650 >
1651 >    private static long[] nBits(int n) {
1652 >        return new long[((n - 1) >> 6) + 1];
1653 >    }
1654 >    private static void setBit(long[] bits, int i) {
1655 >        bits[i >> 6] |= 1L << i;
1656 >    }
1657 >    private static boolean isClear(long[] bits, int i) {
1658 >        return (bits[i >> 6] & (1L << i)) == 0;
1659 >    }
1660 >
1661 >    /**
1662 >     * @throws NullPointerException {@inheritDoc}
1663 >     */
1664      @Override
1665      public boolean removeIf(Predicate<? super E> filter) {
1666 +        return removeIf(filter, 0, size);
1667 +    }
1668 +
1669 +    /**
1670 +     * Removes all elements satisfying the given predicate, from index
1671 +     * i (inclusive) to index end (exclusive).
1672 +     */
1673 +    boolean removeIf(Predicate<? super E> filter, int i, final int end) {
1674          Objects.requireNonNull(filter);
1675          int expectedModCount = modCount;
1676          final Object[] es = elementData;
1501        final int size = this.size;
1502        final boolean modified;
1503        int r;
1677          // Optimize for initial run of survivors
1678 <        for (r = 0; r < size && !filter.test((E) es[r]); r++)
1678 >        for (; i < end && !filter.test(elementAt(es, i)); i++)
1679              ;
1680 <        if (modified = (r < size)) {
1681 <            expectedModCount++;
1680 >        // Tolerate predicates that reentrantly access the collection for
1681 >        // read (but writers still get CME), so traverse once to find
1682 >        // elements to delete, a second pass to physically expunge.
1683 >        if (i < end) {
1684 >            final int beg = i;
1685 >            final long[] deathRow = nBits(end - beg);
1686 >            deathRow[0] = 1L;   // set bit 0
1687 >            for (i = beg + 1; i < end; i++)
1688 >                if (filter.test(elementAt(es, i)))
1689 >                    setBit(deathRow, i - beg);
1690 >            if (modCount != expectedModCount)
1691 >                throw new ConcurrentModificationException();
1692              modCount++;
1693 <            int w = r++;
1694 <            try {
1695 <                for (E e; r < size; r++)
1696 <                    if (!filter.test(e = (E) es[r]))
1697 <                        es[w++] = e;
1698 <            } catch (Throwable ex) {
1699 <                // copy remaining elements
1700 <                System.arraycopy(es, r, es, w, size - r);
1701 <                w += size - r;
1702 <                throw ex;
1703 <            } finally {
1704 <                Arrays.fill(es, (this.size = w), size, null);
1522 <            }
1693 >            int w = beg;
1694 >            for (i = beg; i < end; i++)
1695 >                if (isClear(deathRow, i - beg))
1696 >                    es[w++] = es[i];
1697 >            shiftTailOverGap(es, w, end);
1698 >            // checkInvariants();
1699 >            return true;
1700 >        } else {
1701 >            if (modCount != expectedModCount)
1702 >                throw new ConcurrentModificationException();
1703 >            // checkInvariants();
1704 >            return false;
1705          }
1524        if (modCount != expectedModCount)
1525            throw new ConcurrentModificationException();
1526        return modified;
1706      }
1707  
1708      @Override
1530    @SuppressWarnings("unchecked")
1709      public void replaceAll(UnaryOperator<E> operator) {
1710 +        replaceAllRange(operator, 0, size);
1711 +        // TODO(8203662): remove increment of modCount from ...
1712 +        modCount++;
1713 +    }
1714 +
1715 +    private void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
1716          Objects.requireNonNull(operator);
1717          final int expectedModCount = modCount;
1718 <        final int size = this.size;
1719 <        for (int i=0; modCount == expectedModCount && i < size; i++) {
1720 <            elementData[i] = operator.apply((E) elementData[i]);
1721 <        }
1538 <        if (modCount != expectedModCount) {
1718 >        final Object[] es = elementData;
1719 >        for (; modCount == expectedModCount && i < end; i++)
1720 >            es[i] = operator.apply(elementAt(es, i));
1721 >        if (modCount != expectedModCount)
1722              throw new ConcurrentModificationException();
1723 <        }
1541 <        modCount++;
1723 >        // checkInvariants();
1724      }
1725  
1726      @Override
# Line 1546 | Line 1728 | public class ArrayList<E> extends Abstra
1728      public void sort(Comparator<? super E> c) {
1729          final int expectedModCount = modCount;
1730          Arrays.sort((E[]) elementData, 0, size, c);
1731 <        if (modCount != expectedModCount) {
1731 >        if (modCount != expectedModCount)
1732              throw new ConcurrentModificationException();
1551        }
1733          modCount++;
1734 +        // checkInvariants();
1735 +    }
1736 +
1737 +    void checkInvariants() {
1738 +        // assert size >= 0;
1739 +        // assert size == elementData.length || elementData[size] == null;
1740      }
1741   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines