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

Comparing jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java (file contents):
Revision 1.147 by jsr166, Sun Jan 7 22:00:39 2018 UTC vs.
Revision 1.148 by jsr166, Tue Apr 3 16:32:40 2018 UTC

# Line 17 | Line 17
17   package java.util.concurrent;
18  
19   import java.lang.reflect.Field;
20 import java.util.AbstractList;
20   import java.util.Arrays;
21   import java.util.Collection;
22   import java.util.Comparator;
# Line 116 | Line 115 | public class CopyOnWriteArrayList<E>
115       * @throws NullPointerException if the specified collection is null
116       */
117      public CopyOnWriteArrayList(Collection<? extends E> c) {
118 <        Object[] elements;
118 >        Object[] es;
119          if (c.getClass() == CopyOnWriteArrayList.class)
120 <            elements = ((CopyOnWriteArrayList<?>)c).getArray();
120 >            es = ((CopyOnWriteArrayList<?>)c).getArray();
121          else {
122 <            elements = c.toArray();
122 >            es = c.toArray();
123              // defend against c.toArray (incorrectly) not returning Object[]
124              // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
125 <            if (elements.getClass() != Object[].class)
126 <                elements = Arrays.copyOf(elements, elements.length, Object[].class);
125 >            if (es.getClass() != Object[].class)
126 >                es = Arrays.copyOf(es, es.length, Object[].class);
127          }
128 <        setArray(elements);
128 >        setArray(es);
129      }
130  
131      /**
# Line 162 | Line 161 | public class CopyOnWriteArrayList<E>
161       * static version of indexOf, to allow repeated calls without
162       * needing to re-acquire array each time.
163       * @param o element to search for
164 <     * @param elements the array
165 <     * @param index first index to search
166 <     * @param fence one past last index to search
164 >     * @param es the array
165 >     * @param from first index to search
166 >     * @param to one past last index to search
167       * @return index of element, or -1 if absent
168       */
169 <    private static int indexOf(Object o, Object[] elements,
171 <                               int index, int fence) {
169 >    private static int indexOfRange(Object o, Object[] es, int from, int to) {
170          if (o == null) {
171 <            for (int i = index; i < fence; i++)
172 <                if (elements[i] == null)
171 >            for (int i = from; i < to; i++)
172 >                if (es[i] == null)
173                      return i;
174          } else {
175 <            for (int i = index; i < fence; i++)
176 <                if (o.equals(elements[i]))
175 >            for (int i = from; i < to; i++)
176 >                if (o.equals(es[i]))
177                      return i;
178          }
179          return -1;
# Line 184 | Line 182 | public class CopyOnWriteArrayList<E>
182      /**
183       * static version of lastIndexOf.
184       * @param o element to search for
185 <     * @param elements the array
186 <     * @param index first index to search
185 >     * @param es the array
186 >     * @param from index of first element of range, last element to search
187 >     * @param to one past last element of range, first element to search
188       * @return index of element, or -1 if absent
189       */
190 <    private static int lastIndexOf(Object o, Object[] elements, int index) {
190 >    private static int lastIndexOfRange(Object o, Object[] es, int from, int to) {
191          if (o == null) {
192 <            for (int i = index; i >= 0; i--)
193 <                if (elements[i] == null)
192 >            for (int i = to - 1; i >= from; i--)
193 >                if (es[i] == null)
194                      return i;
195          } else {
196 <            for (int i = index; i >= 0; i--)
197 <                if (o.equals(elements[i]))
196 >            for (int i = to - 1; i >= from; i--)
197 >                if (o.equals(es[i]))
198                      return i;
199          }
200          return -1;
# Line 210 | Line 209 | public class CopyOnWriteArrayList<E>
209       * @return {@code true} if this list contains the specified element
210       */
211      public boolean contains(Object o) {
212 <        Object[] elements = getArray();
214 <        return indexOf(o, elements, 0, elements.length) >= 0;
212 >        return indexOf(o) >= 0;
213      }
214  
215      /**
216       * {@inheritDoc}
217       */
218      public int indexOf(Object o) {
219 <        Object[] elements = getArray();
220 <        return indexOf(o, elements, 0, elements.length);
219 >        Object[] es = getArray();
220 >        return indexOfRange(o, es, 0, es.length);
221      }
222  
223      /**
# Line 238 | Line 236 | public class CopyOnWriteArrayList<E>
236       * @throws IndexOutOfBoundsException if the specified index is negative
237       */
238      public int indexOf(E e, int index) {
239 <        Object[] elements = getArray();
240 <        return indexOf(e, elements, index, elements.length);
239 >        Object[] es = getArray();
240 >        return indexOfRange(e, es, index, es.length);
241      }
242  
243      /**
244       * {@inheritDoc}
245       */
246      public int lastIndexOf(Object o) {
247 <        Object[] elements = getArray();
248 <        return lastIndexOf(o, elements, elements.length - 1);
247 >        Object[] es = getArray();
248 >        return lastIndexOfRange(o, es, 0, es.length);
249      }
250  
251      /**
# Line 267 | Line 265 | public class CopyOnWriteArrayList<E>
265       *         than or equal to the current size of this list
266       */
267      public int lastIndexOf(E e, int index) {
268 <        Object[] elements = getArray();
269 <        return lastIndexOf(e, elements, index);
268 >        Object[] es = getArray();
269 >        return lastIndexOfRange(e, es, 0, index + 1);
270      }
271  
272      /**
# Line 304 | Line 302 | public class CopyOnWriteArrayList<E>
302       * @return an array containing all the elements in this list
303       */
304      public Object[] toArray() {
305 <        Object[] elements = getArray();
308 <        return Arrays.copyOf(elements, elements.length);
305 >        return getArray().clone();
306      }
307  
308      /**
# Line 348 | Line 345 | public class CopyOnWriteArrayList<E>
345       */
346      @SuppressWarnings("unchecked")
347      public <T> T[] toArray(T[] a) {
348 <        Object[] elements = getArray();
349 <        int len = elements.length;
348 >        Object[] es = getArray();
349 >        int len = es.length;
350          if (a.length < len)
351 <            return (T[]) Arrays.copyOf(elements, len, a.getClass());
351 >            return (T[]) Arrays.copyOf(es, len, a.getClass());
352          else {
353 <            System.arraycopy(elements, 0, a, 0, len);
353 >            System.arraycopy(es, 0, a, 0, len);
354              if (a.length > len)
355                  a[len] = null;
356              return a;
# Line 388 | Line 385 | public class CopyOnWriteArrayList<E>
385       */
386      public E set(int index, E element) {
387          synchronized (lock) {
388 <            Object[] elements = getArray();
389 <            E oldValue = elementAt(elements, index);
388 >            Object[] es = getArray();
389 >            E oldValue = elementAt(es, index);
390  
391              if (oldValue != element) {
392 <                int len = elements.length;
393 <                Object[] newElements = Arrays.copyOf(elements, len);
394 <                newElements[index] = element;
398 <                setArray(newElements);
399 <            } else {
400 <                // Not quite a no-op; ensures volatile write semantics
401 <                setArray(elements);
392 >                es = es.clone();
393 >                es[index] = element;
394 >                setArray(es);
395              }
396              return oldValue;
397          }
# Line 412 | Line 405 | public class CopyOnWriteArrayList<E>
405       */
406      public boolean add(E e) {
407          synchronized (lock) {
408 <            Object[] elements = getArray();
409 <            int len = elements.length;
410 <            Object[] newElements = Arrays.copyOf(elements, len + 1);
411 <            newElements[len] = e;
412 <            setArray(newElements);
408 >            Object[] es = getArray();
409 >            int len = es.length;
410 >            es = Arrays.copyOf(es, len + 1);
411 >            es[len] = e;
412 >            setArray(es);
413              return true;
414          }
415      }
# Line 430 | Line 423 | public class CopyOnWriteArrayList<E>
423       */
424      public void add(int index, E element) {
425          synchronized (lock) {
426 <            Object[] elements = getArray();
427 <            int len = elements.length;
426 >            Object[] es = getArray();
427 >            int len = es.length;
428              if (index > len || index < 0)
429                  throw new IndexOutOfBoundsException(outOfBounds(index, len));
430              Object[] newElements;
431              int numMoved = len - index;
432              if (numMoved == 0)
433 <                newElements = Arrays.copyOf(elements, len + 1);
433 >                newElements = Arrays.copyOf(es, len + 1);
434              else {
435                  newElements = new Object[len + 1];
436 <                System.arraycopy(elements, 0, newElements, 0, index);
437 <                System.arraycopy(elements, index, newElements, index + 1,
436 >                System.arraycopy(es, 0, newElements, 0, index);
437 >                System.arraycopy(es, index, newElements, index + 1,
438                                   numMoved);
439              }
440              newElements[index] = element;
# Line 458 | Line 451 | public class CopyOnWriteArrayList<E>
451       */
452      public E remove(int index) {
453          synchronized (lock) {
454 <            Object[] elements = getArray();
455 <            int len = elements.length;
456 <            E oldValue = elementAt(elements, index);
454 >            Object[] es = getArray();
455 >            int len = es.length;
456 >            E oldValue = elementAt(es, index);
457              int numMoved = len - index - 1;
458 +            Object[] newElements;
459              if (numMoved == 0)
460 <                setArray(Arrays.copyOf(elements, len - 1));
460 >                newElements = Arrays.copyOf(es, len - 1);
461              else {
462 <                Object[] newElements = new Object[len - 1];
463 <                System.arraycopy(elements, 0, newElements, 0, index);
464 <                System.arraycopy(elements, index + 1, newElements, index,
462 >                newElements = new Object[len - 1];
463 >                System.arraycopy(es, 0, newElements, 0, index);
464 >                System.arraycopy(es, index + 1, newElements, index,
465                                   numMoved);
472                setArray(newElements);
466              }
467 +            setArray(newElements);
468              return oldValue;
469          }
470      }
# Line 489 | Line 483 | public class CopyOnWriteArrayList<E>
483       */
484      public boolean remove(Object o) {
485          Object[] snapshot = getArray();
486 <        int index = indexOf(o, snapshot, 0, snapshot.length);
486 >        int index = indexOfRange(o, snapshot, 0, snapshot.length);
487          return index >= 0 && remove(o, snapshot, index);
488      }
489  
# Line 514 | Line 508 | public class CopyOnWriteArrayList<E>
508                      return false;
509                  if (current[index] == o)
510                      break findIndex;
511 <                index = indexOf(o, current, index, len);
511 >                index = indexOfRange(o, current, index, len);
512                  if (index < 0)
513                      return false;
514              }
# Line 542 | Line 536 | public class CopyOnWriteArrayList<E>
536       */
537      void removeRange(int fromIndex, int toIndex) {
538          synchronized (lock) {
539 <            Object[] elements = getArray();
540 <            int len = elements.length;
539 >            Object[] es = getArray();
540 >            int len = es.length;
541  
542              if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
543                  throw new IndexOutOfBoundsException();
544              int newlen = len - (toIndex - fromIndex);
545              int numMoved = len - toIndex;
546              if (numMoved == 0)
547 <                setArray(Arrays.copyOf(elements, newlen));
547 >                setArray(Arrays.copyOf(es, newlen));
548              else {
549                  Object[] newElements = new Object[newlen];
550 <                System.arraycopy(elements, 0, newElements, 0, fromIndex);
551 <                System.arraycopy(elements, toIndex, newElements,
550 >                System.arraycopy(es, 0, newElements, 0, fromIndex);
551 >                System.arraycopy(es, toIndex, newElements,
552                                   fromIndex, numMoved);
553                  setArray(newElements);
554              }
# Line 569 | Line 563 | public class CopyOnWriteArrayList<E>
563       */
564      public boolean addIfAbsent(E e) {
565          Object[] snapshot = getArray();
566 <        return indexOf(e, snapshot, 0, snapshot.length) < 0
566 >        return indexOfRange(e, snapshot, 0, snapshot.length) < 0
567              && addIfAbsent(e, snapshot);
568      }
569  
# Line 588 | Line 582 | public class CopyOnWriteArrayList<E>
582                      if (current[i] != snapshot[i]
583                          && Objects.equals(e, current[i]))
584                          return false;
585 <                if (indexOf(e, current, common, len) >= 0)
585 >                if (indexOfRange(e, current, common, len) >= 0)
586                          return false;
587              }
588              Object[] newElements = Arrays.copyOf(current, len + 1);
# Line 609 | Line 603 | public class CopyOnWriteArrayList<E>
603       * @see #contains(Object)
604       */
605      public boolean containsAll(Collection<?> c) {
606 <        Object[] elements = getArray();
607 <        int len = elements.length;
606 >        Object[] es = getArray();
607 >        int len = es.length;
608          for (Object e : c) {
609 <            if (indexOf(e, elements, 0, len) < 0)
609 >            if (indexOfRange(e, es, 0, len) < 0)
610                  return false;
611          }
612          return true;
# Line 676 | Line 670 | public class CopyOnWriteArrayList<E>
670          if (cs.length == 0)
671              return 0;
672          synchronized (lock) {
673 <            Object[] elements = getArray();
674 <            int len = elements.length;
673 >            Object[] es = getArray();
674 >            int len = es.length;
675              int added = 0;
676              // uniquify and compact elements in cs
677              for (int i = 0; i < cs.length; ++i) {
678                  Object e = cs[i];
679 <                if (indexOf(e, elements, 0, len) < 0 &&
680 <                    indexOf(e, cs, 0, added) < 0)
679 >                if (indexOfRange(e, es, 0, len) < 0 &&
680 >                    indexOfRange(e, cs, 0, added) < 0)
681                      cs[added++] = e;
682              }
683              if (added > 0) {
684 <                Object[] newElements = Arrays.copyOf(elements, len + added);
684 >                Object[] newElements = Arrays.copyOf(es, len + added);
685                  System.arraycopy(cs, 0, newElements, len, added);
686                  setArray(newElements);
687              }
# Line 721 | Line 715 | public class CopyOnWriteArrayList<E>
715          if (cs.length == 0)
716              return false;
717          synchronized (lock) {
718 <            Object[] elements = getArray();
719 <            int len = elements.length;
718 >            Object[] es = getArray();
719 >            int len = es.length;
720 >            Object[] newElements;
721              if (len == 0 && cs.getClass() == Object[].class)
722 <                setArray(cs);
722 >                newElements = cs;
723              else {
724 <                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
724 >                newElements = Arrays.copyOf(es, len + cs.length);
725                  System.arraycopy(cs, 0, newElements, len, cs.length);
731                setArray(newElements);
726              }
727 +            setArray(newElements);
728              return true;
729          }
730      }
# Line 753 | Line 748 | public class CopyOnWriteArrayList<E>
748      public boolean addAll(int index, Collection<? extends E> c) {
749          Object[] cs = c.toArray();
750          synchronized (lock) {
751 <            Object[] elements = getArray();
752 <            int len = elements.length;
751 >            Object[] es = getArray();
752 >            int len = es.length;
753              if (index > len || index < 0)
754                  throw new IndexOutOfBoundsException(outOfBounds(index, len));
755              if (cs.length == 0)
# Line 762 | Line 757 | public class CopyOnWriteArrayList<E>
757              int numMoved = len - index;
758              Object[] newElements;
759              if (numMoved == 0)
760 <                newElements = Arrays.copyOf(elements, len + cs.length);
760 >                newElements = Arrays.copyOf(es, len + cs.length);
761              else {
762                  newElements = new Object[len + cs.length];
763 <                System.arraycopy(elements, 0, newElements, 0, index);
764 <                System.arraycopy(elements, index,
763 >                System.arraycopy(es, 0, newElements, 0, index);
764 >                System.arraycopy(es, index,
765                                   newElements, index + cs.length,
766                                   numMoved);
767              }
# Line 850 | Line 845 | public class CopyOnWriteArrayList<E>
845      public void replaceAll(UnaryOperator<E> operator) {
846          Objects.requireNonNull(operator);
847          synchronized (lock) {
848 <            replaceAll(operator, 0, getArray().length);
848 >            replaceAllRange(operator, 0, getArray().length);
849          }
850      }
851  
852 <    void replaceAll(UnaryOperator<E> operator, int i, int end) {
852 >    void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
853          // assert Thread.holdsLock(lock);
854          final Object[] es = getArray().clone();
855          for (; i < end; i++)
# Line 864 | Line 859 | public class CopyOnWriteArrayList<E>
859  
860      public void sort(Comparator<? super E> c) {
861          synchronized (lock) {
862 <            sort(c, 0, getArray().length);
862 >            sortRange(c, 0, getArray().length);
863          }
864      }
865  
866      @SuppressWarnings("unchecked")
867 <    void sort(Comparator<? super E> c, int i, int end) {
867 >    void sortRange(Comparator<? super E> c, int i, int end) {
868          // assert Thread.holdsLock(lock);
869          final Object[] es = getArray().clone();
870          Arrays.sort(es, i, end, (Comparator<Object>)c);
# Line 890 | Line 885 | public class CopyOnWriteArrayList<E>
885  
886          s.defaultWriteObject();
887  
888 <        Object[] elements = getArray();
888 >        Object[] es = getArray();
889          // Write out array length
890 <        s.writeInt(elements.length);
890 >        s.writeInt(es.length);
891  
892          // Write out all elements in the proper order.
893 <        for (Object element : elements)
893 >        for (Object element : es)
894              s.writeObject(element);
895      }
896  
# Line 917 | Line 912 | public class CopyOnWriteArrayList<E>
912          // Read in array length and allocate array
913          int len = s.readInt();
914          SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
915 <        Object[] elements = new Object[len];
915 >        Object[] es = new Object[len];
916  
917          // Read in all elements in the proper order.
918          for (int i = 0; i < len; i++)
919 <            elements[i] = s.readObject();
920 <        setArray(elements);
919 >            es[i] = s.readObject();
920 >        setArray(es);
921      }
922  
923      /**
# Line 968 | Line 963 | public class CopyOnWriteArrayList<E>
963          return !it.hasNext();
964      }
965  
966 +    private static int hashCodeOfRange(Object[] es, int from, int to) {
967 +        int hashCode = 1;
968 +        for (int i = from; i < to; i++) {
969 +            Object x = es[i];
970 +            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
971 +        }
972 +        return hashCode;
973 +    }
974 +
975      /**
976       * Returns the hash code value for this list.
977       *
# Line 976 | Line 980 | public class CopyOnWriteArrayList<E>
980       * @return the hash code value for this list
981       */
982      public int hashCode() {
983 <        int hashCode = 1;
984 <        for (Object x : getArray())
981 <            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
982 <        return hashCode;
983 >        Object[] es = getArray();
984 >        return hashCodeOfRange(es, 0, es.length);
985      }
986  
987      /**
# Line 1019 | Line 1021 | public class CopyOnWriteArrayList<E>
1021       * @throws IndexOutOfBoundsException {@inheritDoc}
1022       */
1023      public ListIterator<E> listIterator(int index) {
1024 <        Object[] elements = getArray();
1025 <        int len = elements.length;
1024 >        Object[] es = getArray();
1025 >        int len = es.length;
1026          if (index < 0 || index > len)
1027              throw new IndexOutOfBoundsException(outOfBounds(index, len));
1028  
1029 <        return new COWIterator<E>(elements, index);
1029 >        return new COWIterator<E>(es, index);
1030      }
1031  
1032      /**
# Line 1052 | Line 1054 | public class CopyOnWriteArrayList<E>
1054          /** Index of element to be returned by subsequent call to next.  */
1055          private int cursor;
1056  
1057 <        COWIterator(Object[] elements, int initialCursor) {
1057 >        COWIterator(Object[] es, int initialCursor) {
1058              cursor = initialCursor;
1059 <            snapshot = elements;
1059 >            snapshot = es;
1060          }
1061  
1062          public boolean hasNext() {
# Line 1084 | Line 1086 | public class CopyOnWriteArrayList<E>
1086          }
1087  
1088          public int previousIndex() {
1089 <            return cursor-1;
1089 >            return cursor - 1;
1090          }
1091  
1092          /**
# Line 1115 | Line 1117 | public class CopyOnWriteArrayList<E>
1117          }
1118  
1119          @Override
1118        @SuppressWarnings("unchecked")
1120          public void forEachRemaining(Consumer<? super E> action) {
1121              Objects.requireNonNull(action);
1122              final int size = snapshot.length;
1123 <            for (int i = cursor; i < size; i++) {
1123 <                action.accept((E) snapshot[i]);
1124 <            }
1123 >            int i = cursor;
1124              cursor = size;
1125 +            for (; i < size; i++)
1126 +                action.accept(elementAt(snapshot, i));
1127          }
1128      }
1129  
# Line 1143 | Line 1144 | public class CopyOnWriteArrayList<E>
1144       */
1145      public List<E> subList(int fromIndex, int toIndex) {
1146          synchronized (lock) {
1147 <            Object[] elements = getArray();
1148 <            int len = elements.length;
1149 <            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
1147 >            Object[] es = getArray();
1148 >            int len = es.length;
1149 >            int size = toIndex - fromIndex;
1150 >            if (fromIndex < 0 || toIndex > len || size < 0)
1151                  throw new IndexOutOfBoundsException();
1152 <            return new COWSubList<E>(this, fromIndex, toIndex);
1152 >            return new COWSubList(es, fromIndex, size);
1153          }
1154      }
1155  
1156      /**
1157       * Sublist for CopyOnWriteArrayList.
1158       */
1159 <    private static class COWSubList<E>
1158 <        extends AbstractList<E>
1159 <        implements RandomAccess
1160 <    {
1161 <        private final CopyOnWriteArrayList<E> l;
1159 >    private class COWSubList implements List<E>, RandomAccess {
1160          private final int offset;
1161          private int size;
1162          private Object[] expectedArray;
1163  
1164 <        // only call this holding l's lock
1165 <        COWSubList(CopyOnWriteArrayList<E> list,
1166 <                   int fromIndex, int toIndex) {
1167 <            // assert Thread.holdsLock(list.lock);
1168 <            l = list;
1171 <            expectedArray = l.getArray();
1172 <            offset = fromIndex;
1173 <            size = toIndex - fromIndex;
1164 >        COWSubList(Object[] es, int offset, int size) {
1165 >            // assert Thread.holdsLock(lock);
1166 >            expectedArray = es;
1167 >            this.offset = offset;
1168 >            this.size = size;
1169          }
1170  
1176        // only call this holding l's lock
1171          private void checkForComodification() {
1172 <            // assert Thread.holdsLock(l.lock);
1173 <            if (l.getArray() != expectedArray)
1172 >            // assert Thread.holdsLock(lock);
1173 >            if (getArray() != expectedArray)
1174                  throw new ConcurrentModificationException();
1175          }
1176  
1177          private Object[] getArrayChecked() {
1178 <            // assert Thread.holdsLock(l.lock);
1179 <            Object[] a = l.getArray();
1178 >            // assert Thread.holdsLock(lock);
1179 >            Object[] a = getArray();
1180              if (a != expectedArray)
1181                  throw new ConcurrentModificationException();
1182              return a;
1183          }
1184  
1191        // only call this holding l's lock
1185          private void rangeCheck(int index) {
1186 <            // assert Thread.holdsLock(l.lock);
1186 >            // assert Thread.holdsLock(lock);
1187              if (index < 0 || index >= size)
1188                  throw new IndexOutOfBoundsException(outOfBounds(index, size));
1189          }
1190  
1191 +        public Object[] toArray() {
1192 +            final Object[] es;
1193 +            final int offset;
1194 +            final int size;
1195 +            synchronized (lock) {
1196 +                es = getArrayChecked();
1197 +                offset = this.offset;
1198 +                size = this.size;
1199 +            }
1200 +            return Arrays.copyOfRange(es, offset, offset + size);
1201 +        }
1202 +
1203 +        @SuppressWarnings("unchecked")
1204 +        public <T> T[] toArray(T[] a) {
1205 +            final Object[] es;
1206 +            final int offset;
1207 +            final int size;
1208 +            synchronized (lock) {
1209 +                es = getArrayChecked();
1210 +                offset = this.offset;
1211 +                size = this.size;
1212 +            }
1213 +            if (a.length < size)
1214 +                return (T[]) Arrays.copyOfRange(
1215 +                        es, offset, offset + size, a.getClass());
1216 +            else {
1217 +                System.arraycopy(es, offset, a, 0, size);
1218 +                if (a.length > size)
1219 +                    a[size] = null;
1220 +                return a;
1221 +            }
1222 +        }
1223 +
1224 +        public int indexOf(Object o) {
1225 +            final Object[] es;
1226 +            final int offset;
1227 +            final int size;
1228 +            synchronized (lock) {
1229 +                es = getArrayChecked();
1230 +                offset = this.offset;
1231 +                size = this.size;
1232 +            }
1233 +            int i = indexOfRange(o, es, offset, offset + size);
1234 +            return (i == -1) ? -1 : i - offset;
1235 +        }
1236 +
1237 +        public int lastIndexOf(Object o) {
1238 +            final Object[] es;
1239 +            final int offset;
1240 +            final int size;
1241 +            synchronized (lock) {
1242 +                es = getArrayChecked();
1243 +                offset = this.offset;
1244 +                size = this.size;
1245 +            }
1246 +            int i = lastIndexOfRange(o, es, offset, offset + size);
1247 +            return (i == -1) ? -1 : i - offset;
1248 +        }
1249 +
1250 +        public boolean contains(Object o) {
1251 +            return indexOf(o) >= 0;
1252 +        }
1253 +
1254 +        public boolean containsAll(Collection<?> c) {
1255 +            final Object[] es;
1256 +            final int offset;
1257 +            final int size;
1258 +            synchronized (lock) {
1259 +                es = getArrayChecked();
1260 +                offset = this.offset;
1261 +                size = this.size;
1262 +            }
1263 +            for (Object o : c)
1264 +                if (indexOfRange(o, es, offset, offset + size) < 0)
1265 +                    return false;
1266 +            return true;
1267 +        }
1268 +
1269 +        public boolean isEmpty() {
1270 +            return size() == 0;
1271 +        }
1272 +
1273 +        public String toString() {
1274 +            return Arrays.toString(toArray());
1275 +        }
1276 +
1277 +        public int hashCode() {
1278 +            final Object[] es;
1279 +            final int offset;
1280 +            final int size;
1281 +            synchronized (lock) {
1282 +                es = getArrayChecked();
1283 +                offset = this.offset;
1284 +                size = this.size;
1285 +            }
1286 +            return hashCodeOfRange(es, offset, offset + size);
1287 +        }
1288 +
1289 +        public boolean equals(Object o) {
1290 +            if (o == this)
1291 +                return true;
1292 +            if (!(o instanceof List))
1293 +                return false;
1294 +
1295 +            final Object[] es;
1296 +            final int offset;
1297 +            final int size;
1298 +            synchronized (lock) {
1299 +                es = getArrayChecked();
1300 +                offset = this.offset;
1301 +                size = this.size;
1302 +            }
1303 +
1304 +            List<?> list = (List<?>)o;
1305 +            Iterator<?> it = list.iterator();
1306 +            for (int i = offset, end = offset + size; i < end; i++)
1307 +                if (!it.hasNext() || !Objects.equals(es[i], it.next()))
1308 +                    return false;
1309 +            return !it.hasNext();
1310 +        }
1311 +
1312          public E set(int index, E element) {
1313 <            synchronized (l.lock) {
1313 >            synchronized (lock) {
1314                  rangeCheck(index);
1315                  checkForComodification();
1316 <                E x = l.set(offset + index, element);
1317 <                expectedArray = l.getArray();
1316 >                E x = CopyOnWriteArrayList.this.set(offset + index, element);
1317 >                expectedArray = getArray();
1318                  return x;
1319              }
1320          }
1321  
1322          public E get(int index) {
1323 <            synchronized (l.lock) {
1323 >            synchronized (lock) {
1324                  rangeCheck(index);
1325                  checkForComodification();
1326 <                return l.get(offset + index);
1326 >                return CopyOnWriteArrayList.this.get(offset + index);
1327              }
1328          }
1329  
1330          public int size() {
1331 <            synchronized (l.lock) {
1331 >            synchronized (lock) {
1332                  checkForComodification();
1333                  return size;
1334              }
1335          }
1336  
1337          public boolean add(E element) {
1338 <            synchronized (l.lock) {
1338 >            synchronized (lock) {
1339                  checkForComodification();
1340 <                l.add(offset + size, element);
1341 <                expectedArray = l.getArray();
1340 >                CopyOnWriteArrayList.this.add(offset + size, element);
1341 >                expectedArray = getArray();
1342                  size++;
1343              }
1344              return true;
1345          }
1346  
1347          public void add(int index, E element) {
1348 <            synchronized (l.lock) {
1348 >            synchronized (lock) {
1349                  checkForComodification();
1350                  if (index < 0 || index > size)
1351 <                    throw new IndexOutOfBoundsException
1352 <                        (outOfBounds(index, size));
1353 <                l.add(offset + index, element);
1354 <                expectedArray = l.getArray();
1351 >                    throw new IndexOutOfBoundsException(
1352 >                            outOfBounds(index, size));
1353 >                CopyOnWriteArrayList.this.add(offset + index, element);
1354 >                expectedArray = getArray();
1355                  size++;
1356              }
1357          }
1358  
1359          public boolean addAll(Collection<? extends E> c) {
1360 <            synchronized (l.lock) {
1360 >            synchronized (lock) {
1361                  final Object[] oldArray = getArrayChecked();
1362 <                boolean modified = l.addAll(offset + size, c);
1363 <                size += (expectedArray = l.getArray()).length - oldArray.length;
1362 >                boolean modified =
1363 >                    CopyOnWriteArrayList.this.addAll(offset + size, c);
1364 >                size += (expectedArray = getArray()).length - oldArray.length;
1365 >                return modified;
1366 >            }
1367 >        }
1368 >
1369 >        public boolean addAll(int index, Collection<? extends E> c) {
1370 >            synchronized (lock) {
1371 >                if (index < 0 || index > size)
1372 >                    throw new IndexOutOfBoundsException(
1373 >                            outOfBounds(index, size));
1374 >                final Object[] oldArray = getArrayChecked();
1375 >                boolean modified =
1376 >                    CopyOnWriteArrayList.this.addAll(offset + index, c);
1377 >                size += (expectedArray = getArray()).length - oldArray.length;
1378                  return modified;
1379              }
1380          }
1381  
1382          public void clear() {
1383 <            synchronized (l.lock) {
1383 >            synchronized (lock) {
1384                  checkForComodification();
1385 <                l.removeRange(offset, offset + size);
1386 <                expectedArray = l.getArray();
1385 >                removeRange(offset, offset + size);
1386 >                expectedArray = getArray();
1387                  size = 0;
1388              }
1389          }
1390  
1391          public E remove(int index) {
1392 <            synchronized (l.lock) {
1392 >            synchronized (lock) {
1393                  rangeCheck(index);
1394                  checkForComodification();
1395 <                E result = l.remove(offset + index);
1396 <                expectedArray = l.getArray();
1395 >                E result = CopyOnWriteArrayList.this.remove(offset + index);
1396 >                expectedArray = getArray();
1397                  size--;
1398                  return result;
1399              }
1400          }
1401  
1402          public boolean remove(Object o) {
1403 <            synchronized (l.lock) {
1403 >            synchronized (lock) {
1404                  checkForComodification();
1405                  int index = indexOf(o);
1406                  if (index == -1)
# Line 1283 | Line 1411 | public class CopyOnWriteArrayList<E>
1411          }
1412  
1413          public Iterator<E> iterator() {
1414 <            synchronized (l.lock) {
1415 <                checkForComodification();
1416 <                return new COWSubListIterator<E>(l, 0, offset, size);
1417 <            }
1414 >            return listIterator(0);
1415 >        }
1416 >
1417 >        public ListIterator<E> listIterator() {
1418 >            return listIterator(0);
1419          }
1420  
1421          public ListIterator<E> listIterator(int index) {
1422 <            synchronized (l.lock) {
1422 >            synchronized (lock) {
1423                  checkForComodification();
1424                  if (index < 0 || index > size)
1425                      throw new IndexOutOfBoundsException
1426                          (outOfBounds(index, size));
1427 <                return new COWSubListIterator<E>(l, index, offset, size);
1427 >                return new COWSubListIterator<E>(
1428 >                    CopyOnWriteArrayList.this, index, offset, size);
1429              }
1430          }
1431  
1432          public List<E> subList(int fromIndex, int toIndex) {
1433 <            synchronized (l.lock) {
1433 >            synchronized (lock) {
1434                  checkForComodification();
1435                  if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
1436                      throw new IndexOutOfBoundsException();
1437 <                return new COWSubList<E>(l, fromIndex + offset,
1308 <                                         toIndex + offset);
1437 >                return new COWSubList(expectedArray, fromIndex + offset, toIndex - fromIndex);
1438              }
1439          }
1440  
1441          public void forEach(Consumer<? super E> action) {
1442              Objects.requireNonNull(action);
1443              int i, end; final Object[] es;
1444 <            synchronized (l.lock) {
1444 >            synchronized (lock) {
1445                  es = getArrayChecked();
1446                  i = offset;
1447                  end = i + size;
# Line 1323 | Line 1452 | public class CopyOnWriteArrayList<E>
1452  
1453          public void replaceAll(UnaryOperator<E> operator) {
1454              Objects.requireNonNull(operator);
1455 <            synchronized (l.lock) {
1455 >            synchronized (lock) {
1456                  checkForComodification();
1457 <                l.replaceAll(operator, offset, offset + size);
1458 <                expectedArray = l.getArray();
1457 >                replaceAllRange(operator, offset, offset + size);
1458 >                expectedArray = getArray();
1459              }
1460          }
1461  
1462          public void sort(Comparator<? super E> c) {
1463 <            synchronized (l.lock) {
1463 >            synchronized (lock) {
1464                  checkForComodification();
1465 <                l.sort(c, offset, offset + size);
1466 <                expectedArray = l.getArray();
1465 >                sortRange(c, offset, offset + size);
1466 >                expectedArray = getArray();
1467              }
1468          }
1469  
# Line 1354 | Line 1483 | public class CopyOnWriteArrayList<E>
1483          }
1484  
1485          private boolean bulkRemove(Predicate<? super E> filter) {
1486 <            synchronized (l.lock) {
1486 >            synchronized (lock) {
1487                  final Object[] oldArray = getArrayChecked();
1488 <                boolean modified = l.bulkRemove(filter, offset, offset + size);
1489 <                size += (expectedArray = l.getArray()).length - oldArray.length;
1488 >                boolean modified = CopyOnWriteArrayList.this.bulkRemove(
1489 >                    filter, offset, offset + size);
1490 >                size += (expectedArray = getArray()).length - oldArray.length;
1491                  return modified;
1492              }
1493          }
1494  
1495          public Spliterator<E> spliterator() {
1496 <            synchronized (l.lock) {
1496 >            synchronized (lock) {
1497                  return Spliterators.spliterator(
1498                          getArrayChecked(), offset, offset + size,
1499                          Spliterator.IMMUTABLE | Spliterator.ORDERED);
# Line 1380 | Line 1510 | public class CopyOnWriteArrayList<E>
1510          COWSubListIterator(List<E> l, int index, int offset, int size) {
1511              this.offset = offset;
1512              this.size = size;
1513 <            it = l.listIterator(index+offset);
1513 >            it = l.listIterator(index + offset);
1514          }
1515  
1516          public boolean hasNext() {
# Line 1429 | Line 1559 | public class CopyOnWriteArrayList<E>
1559          @SuppressWarnings("unchecked")
1560          public void forEachRemaining(Consumer<? super E> action) {
1561              Objects.requireNonNull(action);
1562 <            while (nextIndex() < size) {
1562 >            while (hasNext()) {
1563                  action.accept(it.next());
1564              }
1565          }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines