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; |
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 |
|
/** |
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; |
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; |
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 |
|
/** |
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 |
|
/** |
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 |
|
/** |
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 |
|
/** |
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; |
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 |
|
} |
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 |
|
} |
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; |
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 |
|
} |
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 |
|
|
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 |
|
} |
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 |
|
} |
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 |
|
|
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); |
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; |
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 |
|
} |
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 |
|
} |
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) |
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 |
|
} |
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++) |
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); |
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 |
|
|
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 |
|
/** |
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 |
|
* |
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 |
|
/** |
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 |
|
/** |
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() { |
1086 |
|
} |
1087 |
|
|
1088 |
|
public int previousIndex() { |
1089 |
< |
return cursor-1; |
1089 |
> |
return cursor - 1; |
1090 |
|
} |
1091 |
|
|
1092 |
|
/** |
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 |
|
|
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) |
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; |
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 |
|
|
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); |
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() { |
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 |
|
} |