1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package java.util.concurrent; 18 19import java.io.IOException; 20import java.io.ObjectInputStream; 21import java.io.ObjectOutputStream; 22import java.io.Serializable; 23import java.util.AbstractList; 24import java.util.Arrays; 25import java.util.Collection; 26import java.util.ConcurrentModificationException; 27import java.util.Iterator; 28import java.util.List; 29import java.util.ListIterator; 30import java.util.NoSuchElementException; 31import java.util.RandomAccess; 32import libcore.util.EmptyArray; 33import libcore.util.Objects; 34 35/** 36 * A thread-safe random-access list. 37 * 38 * <p>Read operations (including {@link #get}) do not block and may overlap with 39 * update operations. Reads reflect the results of the most recently completed 40 * operations. Aggregate operations like {@link #addAll} and {@link #clear} are 41 * atomic; they never expose an intermediate state. 42 * 43 * <p>Iterators of this list never throw {@link 44 * ConcurrentModificationException}. When an iterator is created, it keeps a 45 * copy of the list's contents. It is always safe to iterate this list, but 46 * iterations may not reflect the latest state of the list. 47 * 48 * <p>Iterators returned by this list and its sub lists cannot modify the 49 * underlying list. In particular, {@link Iterator#remove}, {@link 50 * ListIterator#add} and {@link ListIterator#set} all throw {@link 51 * UnsupportedOperationException}. 52 * 53 * <p>This class offers extended API beyond the {@link List} interface. It 54 * includes additional overloads for indexed search ({@link #indexOf} and {@link 55 * #lastIndexOf}) and methods for conditional adds ({@link #addIfAbsent} and 56 * {@link #addAllAbsent}). 57 */ 58public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable { 59 60 private static final long serialVersionUID = 8673264195747942595L; 61 62 /** 63 * Holds the latest snapshot of the list's data. This field is volatile so 64 * that data can be read without synchronization. As a consequence, all 65 * writes to this field must be atomic; it is an error to modify the 66 * contents of an array after it has been assigned to this field. 67 * 68 * Synchronization is required by all update operations. This defends 69 * against one update clobbering the result of another operation. For 70 * example, 100 threads simultaneously calling add() will grow the list's 71 * size by 100 when they have completed. No update operations are lost! 72 * 73 * Maintainers should be careful to read this field only once in 74 * non-blocking read methods. Write methods must be synchronized to avoid 75 * clobbering concurrent writes. 76 */ 77 private transient volatile Object[] elements; 78 79 /** 80 * Creates a new empty instance. 81 */ 82 public CopyOnWriteArrayList() { 83 elements = EmptyArray.OBJECT; 84 } 85 86 /** 87 * Creates a new instance containing the elements of {@code collection}. 88 */ 89 @SuppressWarnings("unchecked") 90 public CopyOnWriteArrayList(Collection<? extends E> collection) { 91 this((E[]) collection.toArray()); 92 } 93 94 /** 95 * Creates a new instance containing the elements of {@code array}. 96 */ 97 public CopyOnWriteArrayList(E[] array) { 98 this.elements = Arrays.copyOf(array, array.length, Object[].class); 99 } 100 101 @Override public Object clone() { 102 try { 103 CopyOnWriteArrayList result = (CopyOnWriteArrayList) super.clone(); 104 result.elements = result.elements.clone(); 105 return result; 106 } catch (CloneNotSupportedException e) { 107 throw new AssertionError(e); 108 } 109 } 110 111 public int size() { 112 return elements.length; 113 } 114 115 @SuppressWarnings("unchecked") 116 public E get(int index) { 117 return (E) elements[index]; 118 } 119 120 public boolean contains(Object o) { 121 return indexOf(o) != -1; 122 } 123 124 public boolean containsAll(Collection<?> collection) { 125 Object[] snapshot = elements; 126 return containsAll(collection, snapshot, 0, snapshot.length); 127 } 128 129 static boolean containsAll(Collection<?> collection, Object[] snapshot, int from, int to) { 130 for (Object o : collection) { 131 if (indexOf(o, snapshot, from, to) == -1) { 132 return false; 133 } 134 } 135 return true; 136 } 137 138 /** 139 * Searches this list for {@code object} and returns the index of the first 140 * occurrence that is at or after {@code from}. 141 * 142 * @return the index or -1 if the object was not found. 143 */ 144 public int indexOf(E object, int from) { 145 Object[] snapshot = elements; 146 return indexOf(object, snapshot, from, snapshot.length); 147 } 148 149 public int indexOf(Object object) { 150 Object[] snapshot = elements; 151 return indexOf(object, snapshot, 0, snapshot.length); 152 } 153 154 /** 155 * Searches this list for {@code object} and returns the index of the last 156 * occurrence that is before {@code to}. 157 * 158 * @return the index or -1 if the object was not found. 159 */ 160 public int lastIndexOf(E object, int to) { 161 Object[] snapshot = elements; 162 return lastIndexOf(object, snapshot, 0, to); 163 } 164 165 public int lastIndexOf(Object object) { 166 Object[] snapshot = elements; 167 return lastIndexOf(object, snapshot, 0, snapshot.length); 168 } 169 170 public boolean isEmpty() { 171 return elements.length == 0; 172 } 173 174 /** 175 * Returns an {@link Iterator} that iterates over the elements of this list 176 * as they were at the time of this method call. Changes to the list made 177 * after this method call will not be reflected by the iterator, nor will 178 * they trigger a {@link ConcurrentModificationException}. 179 * 180 * <p>The returned iterator does not support {@link Iterator#remove()}. 181 */ 182 public Iterator<E> iterator() { 183 Object[] snapshot = elements; 184 return new CowIterator<E>(snapshot, 0, snapshot.length); 185 } 186 187 /** 188 * Returns a {@link ListIterator} that iterates over the elements of this 189 * list as they were at the time of this method call. Changes to the list 190 * made after this method call will not be reflected by the iterator, nor 191 * will they trigger a {@link ConcurrentModificationException}. 192 * 193 * <p>The returned iterator does not support {@link ListIterator#add}, 194 * {@link ListIterator#set} or {@link Iterator#remove()}, 195 */ 196 public ListIterator<E> listIterator(int index) { 197 Object[] snapshot = elements; 198 if (index < 0 || index > snapshot.length) { 199 throw new IndexOutOfBoundsException("index=" + index + ", length=" + snapshot.length); 200 } 201 CowIterator<E> result = new CowIterator<E>(snapshot, 0, snapshot.length); 202 result.index = index; 203 return result; 204 } 205 206 /** 207 * Equivalent to {@code listIterator(0)}. 208 */ 209 public ListIterator<E> listIterator() { 210 Object[] snapshot = elements; 211 return new CowIterator<E>(snapshot, 0, snapshot.length); 212 } 213 214 public List<E> subList(int from, int to) { 215 Object[] snapshot = elements; 216 if (from < 0 || from > to || to > snapshot.length) { 217 throw new IndexOutOfBoundsException("from=" + from + ", to=" + to + 218 ", list size=" + snapshot.length); 219 } 220 return new CowSubList(snapshot, from, to); 221 } 222 223 public Object[] toArray() { 224 return elements.clone(); 225 } 226 227 @SuppressWarnings({"unchecked","SuspiciousSystemArraycopy"}) 228 public <T> T[] toArray(T[] contents) { 229 Object[] snapshot = elements; 230 if (snapshot.length > contents.length) { 231 return (T[]) Arrays.copyOf(snapshot, snapshot.length, contents.getClass()); 232 } 233 System.arraycopy(snapshot, 0, contents, 0, snapshot.length); 234 if (snapshot.length < contents.length) { 235 contents[snapshot.length] = null; 236 } 237 return contents; 238 } 239 240 @Override public boolean equals(Object other) { 241 if (other instanceof CopyOnWriteArrayList) { 242 return this == other 243 || Arrays.equals(elements, ((CopyOnWriteArrayList<?>) other).elements); 244 } else if (other instanceof List) { 245 Object[] snapshot = elements; 246 Iterator<?> i = ((List<?>) other).iterator(); 247 for (Object o : snapshot) { 248 if (!i.hasNext() || !Objects.equal(o, i.next())) { 249 return false; 250 } 251 } 252 return !i.hasNext(); 253 } else { 254 return false; 255 } 256 } 257 258 @Override public int hashCode() { 259 return Arrays.hashCode(elements); 260 } 261 262 @Override public String toString() { 263 return Arrays.toString(elements); 264 } 265 266 public synchronized boolean add(E e) { 267 Object[] newElements = new Object[elements.length + 1]; 268 System.arraycopy(elements, 0, newElements, 0, elements.length); 269 newElements[elements.length] = e; 270 elements = newElements; 271 return true; 272 } 273 274 public synchronized void add(int index, E e) { 275 Object[] newElements = new Object[elements.length + 1]; 276 System.arraycopy(elements, 0, newElements, 0, index); 277 newElements[index] = e; 278 System.arraycopy(elements, index, newElements, index + 1, elements.length - index); 279 elements = newElements; 280 } 281 282 public synchronized boolean addAll(Collection<? extends E> collection) { 283 return addAll(elements.length, collection); 284 } 285 286 public synchronized boolean addAll(int index, Collection<? extends E> collection) { 287 Object[] toAdd = collection.toArray(); 288 Object[] newElements = new Object[elements.length + toAdd.length]; 289 System.arraycopy(elements, 0, newElements, 0, index); 290 System.arraycopy(toAdd, 0, newElements, index, toAdd.length); 291 System.arraycopy(elements, index, 292 newElements, index + toAdd.length, elements.length - index); 293 elements = newElements; 294 return toAdd.length > 0; 295 } 296 297 /** 298 * Adds the elements of {@code collection} that are not already present in 299 * this list. If {@code collection} includes a repeated value, at most one 300 * occurrence of that value will be added to this list. Elements are added 301 * at the end of this list. 302 * 303 * <p>Callers of this method may prefer {@link CopyOnWriteArraySet}, whose 304 * API is more appropriate for set operations. 305 */ 306 public synchronized int addAllAbsent(Collection<? extends E> collection) { 307 Object[] toAdd = collection.toArray(); 308 Object[] newElements = new Object[elements.length + toAdd.length]; 309 System.arraycopy(elements, 0, newElements, 0, elements.length); 310 int addedCount = 0; 311 for (Object o : toAdd) { 312 if (indexOf(o, newElements, 0, elements.length + addedCount) == -1) { 313 newElements[elements.length + addedCount++] = o; 314 } 315 } 316 if (addedCount < toAdd.length) { 317 newElements = Arrays.copyOfRange( 318 newElements, 0, elements.length + addedCount); // trim to size 319 } 320 elements = newElements; 321 return addedCount; 322 } 323 324 /** 325 * Adds {@code object} to the end of this list if it is not already present. 326 * 327 * <p>Callers of this method may prefer {@link CopyOnWriteArraySet}, whose 328 * API is more appropriate for set operations. 329 */ 330 public synchronized boolean addIfAbsent(E object) { 331 if (contains(object)) { 332 return false; 333 } 334 add(object); 335 return true; 336 } 337 338 @Override public synchronized void clear() { 339 elements = EmptyArray.OBJECT; 340 } 341 342 public synchronized E remove(int index) { 343 @SuppressWarnings("unchecked") 344 E removed = (E) elements[index]; 345 removeRange(index, index + 1); 346 return removed; 347 } 348 349 public synchronized boolean remove(Object o) { 350 int index = indexOf(o); 351 if (index == -1) { 352 return false; 353 } 354 remove(index); 355 return true; 356 } 357 358 public synchronized boolean removeAll(Collection<?> collection) { 359 return removeOrRetain(collection, false, 0, elements.length) != 0; 360 } 361 362 public synchronized boolean retainAll(Collection<?> collection) { 363 return removeOrRetain(collection, true, 0, elements.length) != 0; 364 } 365 366 /** 367 * Removes or retains the elements in {@code collection}. Returns the number 368 * of elements removed. 369 */ 370 private int removeOrRetain(Collection<?> collection, boolean retain, int from, int to) { 371 for (int i = from; i < to; i++) { 372 if (collection.contains(elements[i]) == retain) { 373 continue; 374 } 375 376 /* 377 * We've encountered an element that must be removed! Create a new 378 * array and copy in the surviving elements one by one. 379 */ 380 Object[] newElements = new Object[elements.length - 1]; 381 System.arraycopy(elements, 0, newElements, 0, i); 382 int newSize = i; 383 for (int j = i + 1; j < to; j++) { 384 if (collection.contains(elements[j]) == retain) { 385 newElements[newSize++] = elements[j]; 386 } 387 } 388 389 /* 390 * Copy the elements after 'to'. This is only useful for sub lists, 391 * where 'to' will be less than elements.length. 392 */ 393 System.arraycopy(elements, to, newElements, newSize, elements.length - to); 394 newSize += (elements.length - to); 395 396 if (newSize < newElements.length) { 397 newElements = Arrays.copyOfRange(newElements, 0, newSize); // trim to size 398 } 399 int removed = elements.length - newElements.length; 400 elements = newElements; 401 return removed; 402 } 403 404 // we made it all the way through the loop without making any changes 405 return 0; 406 } 407 408 public synchronized E set(int index, E e) { 409 Object[] newElements = elements.clone(); 410 @SuppressWarnings("unchecked") 411 E result = (E) newElements[index]; 412 newElements[index] = e; 413 elements = newElements; 414 return result; 415 } 416 417 private void removeRange(int from, int to) { 418 Object[] newElements = new Object[elements.length - (to - from)]; 419 System.arraycopy(elements, 0, newElements, 0, from); 420 System.arraycopy(elements, to, newElements, from, elements.length - to); 421 elements = newElements; 422 } 423 424 static int lastIndexOf(Object o, Object[] data, int from, int to) { 425 if (o == null) { 426 for (int i = to - 1; i >= from; i--) { 427 if (data[i] == null) { 428 return i; 429 } 430 } 431 } else { 432 for (int i = to - 1; i >= from; i--) { 433 if (o.equals(data[i])) { 434 return i; 435 } 436 } 437 } 438 return -1; 439 } 440 441 static int indexOf(Object o, Object[] data, int from, int to) { 442 if (o == null) { 443 for (int i = from; i < to; i++) { 444 if (data[i] == null) { 445 return i; 446 } 447 } 448 } else { 449 for (int i = from; i < to; i++) { 450 if (o.equals(data[i])) { 451 return i; 452 } 453 } 454 } 455 return -1; 456 } 457 458 final Object[] getArray() { 459 // CopyOnWriteArraySet needs this. 460 return elements; 461 } 462 463 /** 464 * The sub list is thread safe and supports non-blocking reads. Doing so is 465 * more difficult than in the full list, because each read needs to examine 466 * four fields worth of state: 467 * - the elements array of the full list 468 * - two integers for the bounds of this sub list 469 * - the expected elements array (to detect concurrent modification) 470 * 471 * This is accomplished by aggregating the sub list's three fields into a 472 * single snapshot object representing the current slice. This permits reads 473 * to be internally consistent without synchronization. This takes advantage 474 * of Java's concurrency semantics for final fields. 475 */ 476 class CowSubList extends AbstractList<E> { 477 478 /* 479 * An immutable snapshot of a sub list's state. By gathering all three 480 * of the sub list's fields in an immutable object, 481 */ 482 private volatile Slice slice; 483 484 public CowSubList(Object[] expectedElements, int from, int to) { 485 this.slice = new Slice(expectedElements, from, to); 486 } 487 488 @Override public int size() { 489 Slice slice = this.slice; 490 return slice.to - slice.from; 491 } 492 493 @Override public boolean isEmpty() { 494 Slice slice = this.slice; 495 return slice.from == slice.to; 496 } 497 498 @SuppressWarnings("unchecked") 499 @Override public E get(int index) { 500 Slice slice = this.slice; 501 Object[] snapshot = elements; 502 slice.checkElementIndex(index); 503 slice.checkConcurrentModification(snapshot); 504 return (E) snapshot[index + slice.from]; 505 } 506 507 @Override public Iterator<E> iterator() { 508 return listIterator(0); 509 } 510 511 @Override public ListIterator<E> listIterator() { 512 return listIterator(0); 513 } 514 515 @Override public ListIterator<E> listIterator(int index) { 516 Slice slice = this.slice; 517 Object[] snapshot = elements; 518 slice.checkPositionIndex(index); 519 slice.checkConcurrentModification(snapshot); 520 CowIterator<E> result = new CowIterator<E>(snapshot, slice.from, slice.to); 521 result.index = slice.from + index; 522 return result; 523 } 524 525 @Override public int indexOf(Object object) { 526 Slice slice = this.slice; 527 Object[] snapshot = elements; 528 slice.checkConcurrentModification(snapshot); 529 int result = CopyOnWriteArrayList.indexOf(object, snapshot, slice.from, slice.to); 530 return (result != -1) ? (result - slice.from) : -1; 531 } 532 533 @Override public int lastIndexOf(Object object) { 534 Slice slice = this.slice; 535 Object[] snapshot = elements; 536 slice.checkConcurrentModification(snapshot); 537 int result = CopyOnWriteArrayList.lastIndexOf(object, snapshot, slice.from, slice.to); 538 return (result != -1) ? (result - slice.from) : -1; 539 } 540 541 @Override public boolean contains(Object object) { 542 return indexOf(object) != -1; 543 } 544 545 @Override public boolean containsAll(Collection<?> collection) { 546 Slice slice = this.slice; 547 Object[] snapshot = elements; 548 slice.checkConcurrentModification(snapshot); 549 return CopyOnWriteArrayList.containsAll(collection, snapshot, slice.from, slice.to); 550 } 551 552 @Override public List<E> subList(int from, int to) { 553 Slice slice = this.slice; 554 if (from < 0 || from > to || to > size()) { 555 throw new IndexOutOfBoundsException("from=" + from + ", to=" + to + 556 ", list size=" + size()); 557 } 558 return new CowSubList(slice.expectedElements, slice.from + from, slice.from + to); 559 } 560 561 @Override public E remove(int index) { 562 synchronized (CopyOnWriteArrayList.this) { 563 slice.checkElementIndex(index); 564 slice.checkConcurrentModification(elements); 565 E removed = CopyOnWriteArrayList.this.remove(slice.from + index); 566 slice = new Slice(elements, slice.from, slice.to - 1); 567 return removed; 568 } 569 } 570 571 @Override public void clear() { 572 synchronized (CopyOnWriteArrayList.this) { 573 slice.checkConcurrentModification(elements); 574 CopyOnWriteArrayList.this.removeRange(slice.from, slice.to); 575 slice = new Slice(elements, slice.from, slice.from); 576 } 577 } 578 579 @Override public void add(int index, E object) { 580 synchronized (CopyOnWriteArrayList.this) { 581 slice.checkPositionIndex(index); 582 slice.checkConcurrentModification(elements); 583 CopyOnWriteArrayList.this.add(index + slice.from, object); 584 slice = new Slice(elements, slice.from, slice.to + 1); 585 } 586 } 587 588 @Override public boolean add(E object) { 589 synchronized (CopyOnWriteArrayList.this) { 590 add(slice.to - slice.from, object); 591 return true; 592 } 593 } 594 595 @Override public boolean addAll(int index, Collection<? extends E> collection) { 596 synchronized (CopyOnWriteArrayList.this) { 597 slice.checkPositionIndex(index); 598 slice.checkConcurrentModification(elements); 599 int oldSize = elements.length; 600 boolean result = CopyOnWriteArrayList.this.addAll(index + slice.from, collection); 601 slice = new Slice(elements, slice.from, slice.to + (elements.length - oldSize)); 602 return result; 603 } 604 } 605 606 @Override public boolean addAll(Collection<? extends E> collection) { 607 synchronized (CopyOnWriteArrayList.this) { 608 return addAll(size(), collection); 609 } 610 } 611 612 @Override public E set(int index, E object) { 613 synchronized (CopyOnWriteArrayList.this) { 614 slice.checkElementIndex(index); 615 slice.checkConcurrentModification(elements); 616 E result = CopyOnWriteArrayList.this.set(index + slice.from, object); 617 slice = new Slice(elements, slice.from, slice.to); 618 return result; 619 } 620 } 621 622 @Override public boolean remove(Object object) { 623 synchronized (CopyOnWriteArrayList.this) { 624 int index = indexOf(object); 625 if (index == -1) { 626 return false; 627 } 628 remove(index); 629 return true; 630 } 631 } 632 633 @Override public boolean removeAll(Collection<?> collection) { 634 synchronized (CopyOnWriteArrayList.this) { 635 slice.checkConcurrentModification(elements); 636 int removed = removeOrRetain(collection, false, slice.from, slice.to); 637 slice = new Slice(elements, slice.from, slice.to - removed); 638 return removed != 0; 639 } 640 } 641 642 @Override public boolean retainAll(Collection<?> collection) { 643 synchronized (CopyOnWriteArrayList.this) { 644 slice.checkConcurrentModification(elements); 645 int removed = removeOrRetain(collection, true, slice.from, slice.to); 646 slice = new Slice(elements, slice.from, slice.to - removed); 647 return removed != 0; 648 } 649 } 650 } 651 652 static class Slice { 653 private final Object[] expectedElements; 654 private final int from; 655 private final int to; 656 657 Slice(Object[] expectedElements, int from, int to) { 658 this.expectedElements = expectedElements; 659 this.from = from; 660 this.to = to; 661 } 662 663 /** 664 * Throws if {@code index} doesn't identify an element in the array. 665 */ 666 void checkElementIndex(int index) { 667 if (index < 0 || index >= to - from) { 668 throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from)); 669 } 670 } 671 672 /** 673 * Throws if {@code index} doesn't identify an insertion point in the 674 * array. Unlike element index, it's okay to add or iterate at size(). 675 */ 676 void checkPositionIndex(int index) { 677 if (index < 0 || index > to - from) { 678 throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from)); 679 } 680 } 681 682 void checkConcurrentModification(Object[] snapshot) { 683 if (expectedElements != snapshot) { 684 throw new ConcurrentModificationException(); 685 } 686 } 687 } 688 689 /** 690 * Iterates an immutable snapshot of the list. 691 */ 692 static class CowIterator<E> implements ListIterator<E> { 693 private final Object[] snapshot; 694 private final int from; 695 private final int to; 696 private int index = 0; 697 698 CowIterator(Object[] snapshot, int from, int to) { 699 this.snapshot = snapshot; 700 this.from = from; 701 this.to = to; 702 this.index = from; 703 } 704 705 public void add(E object) { 706 throw new UnsupportedOperationException(); 707 } 708 709 public boolean hasNext() { 710 return index < to; 711 } 712 713 public boolean hasPrevious() { 714 return index > from; 715 } 716 717 @SuppressWarnings("unchecked") 718 public E next() { 719 if (index < to) { 720 return (E) snapshot[index++]; 721 } else { 722 throw new NoSuchElementException(); 723 } 724 } 725 726 public int nextIndex() { 727 return index; 728 } 729 730 @SuppressWarnings("unchecked") 731 public E previous() { 732 if (index > from) { 733 return (E) snapshot[--index]; 734 } else { 735 throw new NoSuchElementException(); 736 } 737 } 738 739 public int previousIndex() { 740 return index - 1; 741 } 742 743 public void remove() { 744 throw new UnsupportedOperationException(); 745 } 746 747 public void set(E object) { 748 throw new UnsupportedOperationException(); 749 } 750 } 751 752 private void writeObject(ObjectOutputStream out) throws IOException { 753 Object[] snapshot = elements; 754 out.defaultWriteObject(); 755 out.writeInt(snapshot.length); 756 for (Object o : snapshot) { 757 out.writeObject(o); 758 } 759 } 760 761 private synchronized void readObject(ObjectInputStream in) 762 throws IOException, ClassNotFoundException { 763 in.defaultReadObject(); 764 Object[] snapshot = new Object[in.readInt()]; 765 for (int i = 0; i < snapshot.length; i++) { 766 snapshot[i] = in.readObject(); 767 } 768 elements = snapshot; 769 } 770} 771