ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
Revision: 1.42
Committed: Sun Jun 5 13:53:25 2005 UTC (19 years ago) by dl
Branch: MAIN
Changes since 1.41: +368 -225 lines
Log Message:
Use ReentrantLock

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group. Adapted and released, under explicit permission,
4 * from JDK ArrayList.java which carries the following copyright:
5 *
6 * Copyright 1997 by Sun Microsystems, Inc.,
7 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
8 * All rights reserved.
9 *
10 * This software is the confidential and proprietary information
11 * of Sun Microsystems, Inc. ("Confidential Information"). You
12 * shall not disclose such Confidential Information and shall use
13 * it only in accordance with the terms of the license agreement
14 * you entered into with Sun.
15 */
16
17 package java.util.concurrent;
18 import java.util.*;
19 import java.util.concurrent.locks.*;
20 import sun.misc.*;
21
22 /**
23 * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
24 * operations (<tt>add</tt>, <tt>set</tt>, and so on) are implemented by
25 * making a fresh copy of the underlying array.
26 *
27 * <p> This is ordinarily too costly, but may be <em>more</em> efficient
28 * than alternatives when traversal operations vastly outnumber
29 * mutations, and is useful when you cannot or don't want to
30 * synchronize traversals, yet need to preclude interference among
31 * concurrent threads. The "snapshot" style iterator method uses a
32 * reference to the state of the array at the point that the iterator
33 * was created. This array never changes during the lifetime of the
34 * iterator, so interference is impossible and the iterator is
35 * guaranteed not to throw <tt>ConcurrentModificationException</tt>.
36 * The iterator will not reflect additions, removals, or changes to
37 * the list since the iterator was created. Element-changing
38 * operations on iterators themselves (<tt>remove</tt>, <tt>set</tt>, and
39 * <tt>add</tt>) are not supported. These methods throw
40 * <tt>UnsupportedOperationException</tt>.
41 *
42 * <p>All elements are permitted, including <tt>null</tt>.
43 *
44 * <p>This class is a member of the
45 * <a href="{@docRoot}/../guide/collections/index.html">
46 * Java Collections Framework</a>.
47 *
48 * @since 1.5
49 * @author Doug Lea
50 * @param <E> the type of elements held in this collection
51 */
52 public class CopyOnWriteArrayList<E>
53 implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
54 private static final long serialVersionUID = 8673264195747942595L;
55
56 /** The lock protecting all mutators */
57 transient final ReentrantLock lock = new ReentrantLock();
58
59 /** The array, accessed only via getArray/setArray. */
60 private volatile transient Object[] array;
61
62 Object[] getArray() { return array; }
63 void setArray(Object[] a) { array = a; }
64
65 /**
66 * Creates an empty list.
67 */
68 public CopyOnWriteArrayList() {
69 setArray(new Object[0]);
70 }
71
72 /**
73 * Creates a list containing the elements of the specified
74 * collection, in the order they are returned by the collection's
75 * iterator.
76 *
77 * @param c the collection of initially held elements
78 * @throws NullPointerException if the specified collection is null
79 */
80 public CopyOnWriteArrayList(Collection<? extends E> c) {
81 Object[] elements = new Object[c.size()];
82 int size = 0;
83 for (E e : c)
84 elements[size++] = e;
85 setArray(elements);
86 }
87
88 /**
89 * Creates a list holding a copy of the given array.
90 *
91 * @param toCopyIn the array (a copy of this array is used as the
92 * internal array)
93 * @throws NullPointerException if the specified array is null
94 */
95 public CopyOnWriteArrayList(E[] toCopyIn) {
96 copyIn(toCopyIn, 0, toCopyIn.length);
97 }
98
99 /**
100 * Replaces the held array with a copy of the <tt>n</tt> elements
101 * of the provided array, starting at position <tt>first</tt>. To
102 * copy an entire array, call with arguments (array, 0,
103 * array.length).
104 * @param toCopyIn the array. A copy of the indicated elements of
105 * this array is used as the internal array.
106 * @param first The index of first position of the array to
107 * start copying from.
108 * @param n the number of elements to copy. This will be the new size of
109 * the list.
110 */
111 private void copyIn(E[] toCopyIn, int first, int n) {
112 int limit = first + n;
113 if (limit > toCopyIn.length)
114 throw new IndexOutOfBoundsException();
115 Object[] newElements = copyOfRange(toCopyIn, first, limit,
116 Object[].class);
117 final ReentrantLock lock = this.lock;
118 lock.lock();
119 try { setArray(newElements); }
120 finally { lock.unlock(); }
121 }
122
123 /**
124 * Returns the number of elements in this list.
125 *
126 * @return the number of elements in this list
127 */
128 public int size() {
129 return getArray().length;
130 }
131
132 /**
133 * Returns <tt>true</tt> if this list contains no elements.
134 *
135 * @return <tt>true</tt> if this list contains no elements
136 */
137 public boolean isEmpty() {
138 return size() == 0;
139 }
140
141 /**
142 * static version of indexOf, to allow repeated calls without
143 * needing to re-acquire array each time.
144 * @param o element to search for
145 * @param elements the array
146 * @param index first index to search
147 * @param fence one past last index to search
148 * @return index of element, or -1 if absent
149 */
150 private static int indexOf(Object o, Object[] elements,
151 int index, int fence) {
152 if (o == null) {
153 for (int i = index; i < fence; i++)
154 if (elements[i] == null)
155 return i;
156 } else {
157 for (int i = index; i < fence; i++)
158 if (o.equals(elements[i]))
159 return i;
160 }
161 return -1;
162 }
163
164 /**
165 * static version of lastIndexOf.
166 * @param o element to search for
167 * @param elements the array
168 * @param index first index to search
169 * @return index of element, or -1 if absent
170 */
171 private static int lastIndexOf(Object o, Object[] elements, int index) {
172 if (o == null) {
173 for (int i = index; i >= 0; i--)
174 if (elements[i] == null)
175 return i;
176 } else {
177 for (int i = index; i >= 0; i--)
178 if (o.equals(elements[i]))
179 return i;
180 }
181 return -1;
182 }
183
184 /**
185 * Returns <tt>true</tt> if this list contains the specified element.
186 * More formally, returns <tt>true</tt> if and only if this list contains
187 * at least one element <tt>e</tt> such that
188 * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
189 *
190 * @param o element whose presence in this list is to be tested
191 * @return <tt>true</tt> if this list contains the specified element
192 */
193 public boolean contains(Object o) {
194 Object[] elements = getArray();
195 return indexOf(o, elements, 0, elements.length) >= 0;
196 }
197
198 /**
199 * {@inheritDoc}
200 */
201 public int indexOf(Object o) {
202 Object[] elements = getArray();
203 return indexOf(o, elements, 0, elements.length);
204 }
205
206
207 /**
208 * Returns the index of the first occurrence of the specified element in
209 * this list, searching forwards from <tt>index</tt>, or returns -1 if
210 * the element is not found.
211 * More formally, returns the lowest index <tt>i</tt> such that
212 * <tt>(i&nbsp;&gt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(e==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;e.equals(get(i))))</tt>,
213 * or -1 if there is no such index.
214 *
215 * @param e element to search for
216 * @param index index to start searching from
217 * @return the index of the first occurrence of the element in
218 * this list at position <tt>index</tt> or later in the list;
219 * <tt>-1</tt> if the element is not found.
220 * @throws IndexOutOfBoundsException if the specified index is negative
221 */
222 public int indexOf(E e, int index) {
223 Object[] elements = getArray();
224 return indexOf(e, elements, index, elements.length);
225 }
226
227 /**
228 * {@inheritDoc}
229 */
230 public int lastIndexOf(Object o) {
231 Object[] elements = getArray();
232 return lastIndexOf(o, elements, elements.length - 1);
233 }
234
235 /**
236 * Returns the index of the last occurrence of the specified element in
237 * this list, searching backwards from <tt>index</tt>, or returns -1 if
238 * the element is not found.
239 * More formally, returns the highest index <tt>i</tt> such that
240 * <tt>(i&nbsp;&lt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(e==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;e.equals(get(i))))</tt>,
241 * or -1 if there is no such index.
242 *
243 * @param e element to search for
244 * @param index index to start searching backwards from
245 * @return the index of the last occurrence of the element at position
246 * less than or equal to <tt>index</tt> in this list;
247 * -1 if the element is not found.
248 * @throws IndexOutOfBoundsException if the specified index is greater
249 * than or equal to the current size of this list
250 */
251 public int lastIndexOf(E e, int index) {
252 Object[] elements = getArray();
253 return lastIndexOf(e, elements, index);
254 }
255
256 /**
257 * Returns a shallow copy of this list. (The elements themselves
258 * are not copied.)
259 *
260 * @return a clone of this list
261 */
262 public Object clone() {
263 try {
264 return super.clone();
265 } catch (CloneNotSupportedException e) {
266 // this shouldn't happen, since we are Cloneable
267 throw new InternalError();
268 }
269 }
270
271 /**
272 * Returns an array containing all of the elements in this list
273 * in proper sequence (from first to last element).
274 *
275 * <p>The returned array will be "safe" in that no references to it are
276 * maintained by this list. (In other words, this method must allocate
277 * a new array). The caller is thus free to modify the returned array.
278 *
279 * <p>This method acts as bridge between array-based and collection-based
280 * APIs.
281 *
282 * @return an array containing all the elements in this list
283 */
284 public Object[] toArray() {
285 Object[] elements = getArray();
286 return copyOf(elements, elements.length);
287 }
288
289 /**
290 * Returns an array containing all of the elements in this list in
291 * proper sequence (from first to last element); the runtime type of
292 * the returned array is that of the specified array. If the list fits
293 * in the specified array, it is returned therein. Otherwise, a new
294 * array is allocated with the runtime type of the specified array and
295 * the size of this list.
296 *
297 * <p>If this list fits in the specified array with room to spare
298 * (i.e., the array has more elements than this list), the element in
299 * the array immediately following the end of the list is set to
300 * <tt>null</tt>. (This is useful in determining the length of this
301 * list <i>only</i> if the caller knows that this list does not contain
302 * any null elements.)
303 *
304 * <p>Like the {@link #toArray()} method, this method acts as bridge between
305 * array-based and collection-based APIs. Further, this method allows
306 * precise control over the runtime type of the output array, and may,
307 * under certain circumstances, be used to save allocation costs.
308 *
309 * <p>Suppose <tt>x</tt> is a list known to contain only strings.
310 * The following code can be used to dump the list into a newly
311 * allocated array of <tt>String</tt>:
312 *
313 * <pre>
314 * String[] y = x.toArray(new String[0]);</pre>
315 *
316 * Note that <tt>toArray(new Object[0])</tt> is identical in function to
317 * <tt>toArray()</tt>.
318 *
319 * @param a the array into which the elements of the list are to
320 * be stored, if it is big enough; otherwise, a new array of the
321 * same runtime type is allocated for this purpose.
322 * @return an array containing all the elements in this list
323 * @throws ArrayStoreException if the runtime type of the specified array
324 * is not a supertype of the runtime type of every element in
325 * this list
326 * @throws NullPointerException if the specified array is null
327 */
328 public <T> T[] toArray(T a[]) {
329 Object[] elements = getArray();
330 int len = elements.length;
331 if (a.length < len)
332 return (T[]) copyOf(elements, len, a.getClass());
333 else {
334 System.arraycopy(elements, 0, a, 0, len);
335 if (a.length > len)
336 a[len] = null;
337 return a;
338 }
339 }
340
341 // Positional Access Operations
342
343 /**
344 * {@inheritDoc}
345 *
346 * @throws IndexOutOfBoundsException {@inheritDoc}
347 */
348 public E get(int index) {
349 return (E)(getArray()[index]);
350 }
351
352 /**
353 * Replaces the element at the specified position in this list with the
354 * specified element.
355 *
356 * @throws IndexOutOfBoundsException {@inheritDoc}
357 */
358 public E set(int index, E element) {
359 final ReentrantLock lock = this.lock;
360 lock.lock();
361 try {
362 Object[] elements = getArray();
363 int len = elements.length;
364 Object oldValue = elements[index];
365
366 if (oldValue != element &&
367 (element == null || !element.equals(oldValue))) {
368 Object[] newElements = copyOf(elements, len);
369 newElements[index] = element;
370 setArray(newElements);
371 }
372 return (E)oldValue;
373 } finally {
374 lock.unlock();
375 }
376 }
377
378 /**
379 * Appends the specified element to the end of this list.
380 *
381 * @param e element to be appended to this list
382 * @return <tt>true</tt> (as per the spec for {@link Collection#add})
383 */
384 public boolean add(E e) {
385 final ReentrantLock lock = this.lock;
386 lock.lock();
387 try {
388 Object[] elements = getArray();
389 int len = elements.length;
390 Object[] newElements = copyOf(elements, len + 1);
391 newElements[len] = e;
392 setArray(newElements);
393 } finally {
394 lock.unlock();
395 }
396 return true;
397 }
398
399 /**
400 * Inserts the specified element at the specified position in this
401 * list. Shifts the element currently at that position (if any) and
402 * any subsequent elements to the right (adds one to their indices).
403 *
404 * @throws IndexOutOfBoundsException {@inheritDoc}
405 */
406 public void add(int index, E element) {
407 final ReentrantLock lock = this.lock;
408 lock.lock();
409 try {
410 Object[] elements = getArray();
411 int len = elements.length;
412 if (index > len || index < 0)
413 throw new IndexOutOfBoundsException("Index: " + index+
414 ", Size: " + len);
415 Object[] newElements;
416 int numMoved = len - index;
417 if (numMoved == 0)
418 newElements = copyOf(elements, len + 1);
419 else {
420 newElements = new Object[len + 1];
421 System.arraycopy(elements, 0, newElements, 0, index);
422 System.arraycopy(elements, index, newElements, index + 1,
423 numMoved);
424 }
425 newElements[index] = element;
426 setArray(newElements);
427 } finally {
428 lock.unlock();
429 }
430 }
431
432 /**
433 * Removes the element at the specified position in this list.
434 * Shifts any subsequent elements to the left (subtracts one from their
435 * indices). Returns the element that was removed from the list.
436 *
437 * @throws IndexOutOfBoundsException {@inheritDoc}
438 */
439 public E remove(int index) {
440 Object oldValue;
441 final ReentrantLock lock = this.lock;
442 lock.lock();
443 try {
444 Object[] elements = getArray();
445 int len = elements.length;
446 oldValue = elements[index];
447 int numMoved = len - index - 1;
448 if (numMoved == 0)
449 setArray(copyOf(elements, len - 1));
450 else {
451 Object[] newElements = new Object[len - 1];
452 System.arraycopy(elements, 0, newElements, 0, index);
453 System.arraycopy(elements, index + 1, newElements, index,
454 numMoved);
455 setArray(newElements);
456 }
457 } finally {
458 lock.unlock();
459 }
460 return (E)oldValue;
461 }
462
463 /**
464 * Removes the first occurrence of the specified element from this list,
465 * if it is present. If this list does not contain the element, it is
466 * unchanged. More formally, removes the element with the lowest index
467 * <tt>i</tt> such that
468 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
469 * (if such an element exists). Returns <tt>true</tt> if this list
470 * contained the specified element (or equivalently, if this list
471 * changed as a result of the call).
472 *
473 * @param o element to be removed from this list, if present
474 * @return <tt>true</tt> if this list contained the specified element
475 */
476 public boolean remove(Object o) {
477 final ReentrantLock lock = this.lock;
478 lock.lock();
479 try {
480 Object[] elements = getArray();
481 int len = elements.length;
482 if (len != 0) {
483 // Copy while searching for element to remove
484 // This wins in the normal case of element being present
485 int newlen = len - 1;
486 Object[] newElements = new Object[newlen];
487
488 for (int i = 0; i < newlen; ++i) {
489 if (o == elements[i] ||
490 (o != null && o.equals(elements[i]))) {
491 // found one; copy remaining and exit
492 for (int k = i + 1; k < len; ++k)
493 newElements[k - 1] = elements[k];
494 setArray(newElements);
495 return true;
496 } else
497 newElements[i] = elements[i];
498 }
499
500 // special handling for last cell
501 if (o == elements[newlen] ||
502 (o != null && o.equals(elements[newlen]))) {
503 setArray(newElements);
504 return true;
505 }
506 }
507 return false;
508 } finally {
509 lock.unlock();
510 }
511 }
512
513 /**
514 * Removes from this list all of the elements whose index is between
515 * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
516 * Shifts any succeeding elements to the left (reduces their index).
517 * This call shortens the list by <tt>(toIndex - fromIndex)</tt> elements.
518 * (If <tt>toIndex==fromIndex</tt>, this operation has no effect.)
519 *
520 * @param fromIndex index of first element to be removed
521 * @param toIndex index after last element to be removed
522 * @throws IndexOutOfBoundsException if fromIndex or toIndex out of
523 * range (fromIndex &lt; 0 || fromIndex &gt;= size() || toIndex
524 * &gt; size() || toIndex &lt; fromIndex)
525 */
526 private void removeRange(int fromIndex, int toIndex) {
527 final ReentrantLock lock = this.lock;
528 lock.lock();
529 try {
530 Object[] elements = getArray();
531 int len = elements.length;
532
533 if (fromIndex < 0 || fromIndex >= len ||
534 toIndex > len || toIndex < fromIndex)
535 throw new IndexOutOfBoundsException();
536 int newlen = len - (toIndex - fromIndex);
537 int numMoved = len - toIndex;
538 if (numMoved == 0)
539 setArray(copyOf(elements, newlen));
540 else {
541 Object[] newElements = new Object[newlen];
542 System.arraycopy(elements, 0, newElements, 0, fromIndex);
543 System.arraycopy(elements, toIndex, newElements,
544 fromIndex, numMoved);
545 setArray(newElements);
546 }
547 } finally {
548 lock.unlock();
549 }
550 }
551
552 /**
553 * Append the element if not present.
554 *
555 * @param e element to be added to this list, if absent
556 * @return <tt>true</tt> if the element was added
557 */
558 public boolean addIfAbsent(E e) {
559 final ReentrantLock lock = this.lock;
560 lock.lock();
561 try {
562 // Copy while checking if already present.
563 // This wins in the most common case where it is not present
564 Object[] elements = getArray();
565 int len = elements.length;
566 Object[] newElements = new Object[len + 1];
567 for (int i = 0; i < len; ++i) {
568 if (e == elements[i] || (e != null && e.equals(elements[i])))
569 return false; // exit, throwing away copy
570 else
571 newElements[i] = elements[i];
572 }
573 newElements[len] = e;
574 setArray(newElements);
575 return true;
576 } finally {
577 lock.unlock();
578 }
579 }
580
581 /**
582 * Returns <tt>true</tt> if this list contains all of the elements of the
583 * specified collection.
584 *
585 * @param c collection to be checked for containment in this list
586 * @return <tt>true</tt> if this list contains all of the elements of the
587 * specified collection
588 * @throws NullPointerException if the specified collection is null
589 * @see #contains(Object)
590 */
591 public boolean containsAll(Collection<?> c) {
592 Object[] elements = getArray();
593 int len = elements.length;
594 for (Object e : c) {
595 if (indexOf(e, elements, 0, len) < 0)
596 return false;
597 }
598 return true;
599 }
600
601 /**
602 * Removes from this list all of its elements that are contained in
603 * the specified collection. This is a particularly expensive operation
604 * in this class because of the need for an internal temporary array.
605 *
606 * @param c collection containing elements to be removed from this list
607 * @return <tt>true</tt> if this list changed as a result of the call
608 * @throws ClassCastException if the class of an element of this list
609 * is incompatible with the specified collection (optional)
610 * @throws NullPointerException if this list contains a null element and the
611 * specified collection does not permit null elements (optional),
612 * or if the specified collection is null
613 * @see #remove(Object)
614 */
615 public boolean removeAll(Collection<?> c) {
616 final ReentrantLock lock = this.lock;
617 lock.lock();
618 try {
619 Object[] elements = getArray();
620 int len = elements.length;
621 if (len != 0) {
622 // temp array holds those elements we know we want to keep
623 int newlen = 0;
624 Object[] temp = new Object[len];
625 for (int i = 0; i < len; ++i) {
626 Object element = elements[i];
627 if (!c.contains(element))
628 temp[newlen++] = element;
629 }
630 if (newlen != len) {
631 setArray(copyOfRange(temp, 0, newlen, Object[].class));
632 return true;
633 }
634 }
635 return false;
636 } finally {
637 lock.unlock();
638 }
639 }
640
641 /**
642 * Retains only the elements in this list that are contained in the
643 * specified collection. In other words, removes from this list all of
644 * its elements that are not contained in the specified collection.
645 *
646 * @param c collection containing elements to be retained in this list
647 * @return <tt>true</tt> if this list changed as a result of the call
648 * @throws ClassCastException if the class of an element of this list
649 * is incompatible with the specified collection (optional)
650 * @throws NullPointerException if this list contains a null element and the
651 * specified collection does not permit null elements (optional),
652 * or if the specified collection is null
653 * @see #remove(Object)
654 */
655 public boolean retainAll(Collection<?> c) {
656 final ReentrantLock lock = this.lock;
657 lock.lock();
658 try {
659 Object[] elements = getArray();
660 int len = elements.length;
661 if (len != 0) {
662 int newlen = 0;
663 Object[] temp = new Object[len];
664 for (int i = 0; i < len; ++i) {
665 Object element = elements[i];
666 if (c.contains(element))
667 temp[newlen++] = element;
668 }
669 if (newlen != len) {
670 setArray(copyOfRange(temp, 0, newlen, Object[].class));
671 return true;
672 }
673 }
674 return false;
675 } finally {
676 lock.unlock();
677 }
678 }
679
680 /**
681 * Appends all of the elements in the specified collection that
682 * are not already contained in this list, to the end of
683 * this list, in the order that they are returned by the
684 * specified collection's iterator.
685 *
686 * @param c collection containing elements to be added to this list
687 * @return the number of elements added
688 * @throws NullPointerException if the specified collection is null
689 * @see #addIfAbsent(Object)
690 */
691 public int addAllAbsent(Collection<? extends E> c) {
692 int added = 0;
693 final ReentrantLock lock = this.lock;
694 lock.lock();
695 try {
696 int numNew = c.size();
697 if (numNew != 0) {
698 Object[] elements = getArray();
699 int len = elements.length;
700
701 Object[] temp = new Object[numNew];
702 for (E e : c) {
703 if (indexOf(e, elements, 0, len) < 0 &&
704 indexOf(e, temp, 0, added) < 0)
705 temp[added++] = e;
706 }
707 if (added != 0) {
708 Object[] newElements = new Object[len + added];
709 System.arraycopy(elements, 0, newElements, 0, len);
710 System.arraycopy(temp, 0, newElements, len, added);
711 setArray(newElements);
712 }
713 }
714 } finally {
715 lock.unlock();
716 }
717 return added;
718 }
719
720 /**
721 * Removes all of the elements from this list.
722 * The list will be empty after this call returns.
723 */
724 public void clear() {
725 final ReentrantLock lock = this.lock;
726 lock.lock();
727 try { setArray(new Object[0]); }
728 finally { lock.unlock(); }
729 }
730
731 /**
732 * Appends all of the elements in the specified collection to the end
733 * of this list, in the order that they are returned by the specified
734 * collection's iterator.
735 *
736 * @param c collection containing elements to be added to this list
737 * @return <tt>true</tt> if this list changed as a result of the call
738 * @throws NullPointerException if the specified collection is null
739 * @see #add(Object)
740 */
741 public boolean addAll(Collection<? extends E> c) {
742 int numNew = c.size();
743 if (numNew == 0)
744 return false;
745 final ReentrantLock lock = this.lock;
746 lock.lock();
747 try {
748 Object[] elements = getArray();
749 int len = elements.length;
750 Object[] newElements = new Object[len + numNew];
751 System.arraycopy(elements, 0, newElements, 0, len);
752 for (E e : c)
753 newElements[len++] = e;
754 setArray(newElements);
755 } finally {
756 lock.unlock();
757 }
758 return true;
759 }
760
761 /**
762 * Inserts all of the elements in the specified collection into this
763 * list, starting at the specified position. Shifts the element
764 * currently at that position (if any) and any subsequent elements to
765 * the right (increases their indices). The new elements will appear
766 * in this list in the order that they are returned by the
767 * specified collection's iterator.
768 *
769 * @param index index at which to insert the first element
770 * from the specified collection
771 * @param c collection containing elements to be added to this list
772 * @return <tt>true</tt> if this list changed as a result of the call
773 * @throws IndexOutOfBoundsException {@inheritDoc}
774 * @throws NullPointerException if the specified collection is null
775 * @see #add(int,Object)
776 */
777 public boolean addAll(int index, Collection<? extends E> c) {
778 int numNew = c.size();
779 final ReentrantLock lock = this.lock;
780 lock.lock();
781 try {
782 Object[] elements = getArray();
783 int len = elements.length;
784 if (index > len || index < 0)
785 throw new IndexOutOfBoundsException("Index: " + index +
786 ", Size: "+ len);
787 if (numNew != 0) {
788 int numMoved = len - index;
789 Object[] newElements;
790 if (numMoved == 0)
791 newElements = copyOf(elements, len + numNew);
792 else {
793 newElements = new Object[len + numNew];
794 System.arraycopy(elements, index, newElements,
795 index + numNew, numMoved);
796 System.arraycopy(elements, index, newElements,
797 index + numNew, numMoved);
798 }
799 for (E e : c)
800 newElements[index++] = e;
801 setArray(newElements);
802 }
803 } finally {
804 lock.unlock();
805 }
806 return numNew != 0;
807 }
808
809 /**
810 * Save the state of the list to a stream (i.e., serialize it).
811 *
812 * @serialData The length of the array backing the list is emitted
813 * (int), followed by all of its elements (each an Object)
814 * in the proper order.
815 * @param s the stream
816 */
817 private void writeObject(java.io.ObjectOutputStream s)
818 throws java.io.IOException{
819
820 // Write out element count, and any hidden stuff
821 s.defaultWriteObject();
822
823 Object[] elements = getArray();
824 int len = elements.length;
825 // Write out array length
826 s.writeInt(len);
827
828 // Write out all elements in the proper order.
829 for (int i = 0; i < len; i++)
830 s.writeObject(elements[i]);
831 }
832
833 /**
834 * Reconstitute the list from a stream (i.e., deserialize it).
835 * @param s the stream
836 */
837 private void readObject(java.io.ObjectInputStream s)
838 throws java.io.IOException, ClassNotFoundException {
839
840 // Read in size, and any hidden stuff
841 s.defaultReadObject();
842
843 // bind to new lock
844 resetLock();
845
846 // Read in array length and allocate array
847 int len = s.readInt();
848 Object[] elements = new Object[len];
849
850 // Read in all elements in the proper order.
851 for (int i = 0; i < len; i++)
852 elements[i] = s.readObject();
853 setArray(elements);
854
855 }
856
857 /**
858 * Returns a string representation of this list, containing
859 * the String representation of each element.
860 */
861 public String toString() {
862 Object[] elements = getArray();
863 int maxIndex = elements.length - 1;
864 StringBuffer buf = new StringBuffer();
865 buf.append("[");
866 for (int i = 0; i <= maxIndex; i++) {
867 buf.append(String.valueOf(elements[i]));
868 if (i < maxIndex)
869 buf.append(", ");
870 }
871 buf.append("]");
872 return buf.toString();
873 }
874
875 /**
876 * Compares the specified object with this list for equality.
877 * Returns true if and only if the specified object is also a {@link
878 * List}, both lists have the same size, and all corresponding pairs
879 * of elements in the two lists are <em>equal</em>. (Two elements
880 * <tt>e1</tt> and <tt>e2</tt> are <em>equal</em> if <tt>(e1==null ?
881 * e2==null : e1.equals(e2))</tt>.) In other words, two lists are
882 * defined to be equal if they contain the same elements in the same
883 * order.
884 *
885 * @param o the object to be compared for equality with this list
886 * @return <tt>true</tt> if the specified object is equal to this list
887 */
888 public boolean equals(Object o) {
889 if (o == this)
890 return true;
891 if (!(o instanceof List))
892 return false;
893
894 List<E> l2 = (List<E>)(o);
895 if (size() != l2.size())
896 return false;
897
898 ListIterator<?> e1 = listIterator();
899 ListIterator<?> e2 = l2.listIterator();
900 while (e1.hasNext()) {
901 Object o1 = e1.next();
902 Object o2 = e2.next();
903 if (!(o1 == null ? o2 == null : o1.equals(o2)))
904 return false;
905 }
906 return true;
907 }
908
909 /**
910 * Returns the hash code value for this list.
911 *
912 * <p> This implementation uses the definition in {@link
913 * List#hashCode}.
914 * @return the hash code
915 */
916 public int hashCode() {
917 int hashCode = 1;
918 Object[] elements = getArray();
919 int len = elements.length;
920 for (int i = 0; i < len; ++i) {
921 Object obj = elements[i];
922 hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
923 }
924 return hashCode;
925 }
926
927 /**
928 * Returns an iterator over the elements in this list in proper sequence.
929 *
930 * <p>The returned iterator provides a snapshot of the state of the list
931 * when the iterator was constructed. No synchronization is needed while
932 * traversing the iterator. The iterator does <em>NOT</em> support the
933 * <tt>remove</tt> method.
934 *
935 * @return an iterator over the elements in this list in proper sequence
936 */
937 public Iterator<E> iterator() {
938 return new COWIterator<E>(getArray(), 0);
939 }
940
941 /**
942 * {@inheritDoc}
943 *
944 * <p>The returned iterator provides a snapshot of the state of the list
945 * when the iterator was constructed. No synchronization is needed while
946 * traversing the iterator. The iterator does <em>NOT</em> support the
947 * <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.
948 */
949 public ListIterator<E> listIterator() {
950 return new COWIterator<E>(getArray(), 0);
951 }
952
953 /**
954 * {@inheritDoc}
955 *
956 * <p>The list iterator returned by this implementation will throw an
957 * <tt>UnsupportedOperationException</tt> in its <tt>remove</tt>,
958 * <tt>set</tt> and <tt>add</tt> methods.
959 *
960 * @throws IndexOutOfBoundsException {@inheritDoc}
961 */
962 public ListIterator<E> listIterator(final int index) {
963 Object[] elements = getArray();
964 int len = elements.length;
965 if (index < 0 || index > len)
966 throw new IndexOutOfBoundsException("Index: " + index);
967
968 return new COWIterator<E>(getArray(), index);
969 }
970
971 private static class COWIterator<E> implements ListIterator<E> {
972 /** Snapshot of the array **/
973 private final Object[] snapshot;
974 /** Index of element to be returned by subsequent call to next. */
975 private int cursor;
976
977 private COWIterator(Object[] elements, int initialCursor) {
978 cursor = initialCursor;
979 snapshot = elements;
980 }
981
982 public boolean hasNext() {
983 return cursor < snapshot.length;
984 }
985
986 public boolean hasPrevious() {
987 return cursor > 0;
988 }
989
990 public E next() {
991 try {
992 return (E)(snapshot[cursor++]);
993 } catch (IndexOutOfBoundsException ex) {
994 throw new NoSuchElementException();
995 }
996 }
997
998 public E previous() {
999 try {
1000 return (E)(snapshot[--cursor]);
1001 } catch (IndexOutOfBoundsException e) {
1002 throw new NoSuchElementException();
1003 }
1004 }
1005
1006 public int nextIndex() {
1007 return cursor;
1008 }
1009
1010 public int previousIndex() {
1011 return cursor - 1;
1012 }
1013
1014 /**
1015 * Not supported. Always throws UnsupportedOperationException.
1016 * @throws UnsupportedOperationException always; <tt>remove</tt>
1017 * is not supported by this iterator.
1018 */
1019 public void remove() {
1020 throw new UnsupportedOperationException();
1021 }
1022
1023 /**
1024 * Not supported. Always throws UnsupportedOperationException.
1025 * @throws UnsupportedOperationException always; <tt>set</tt>
1026 * is not supported by this iterator.
1027 */
1028 public void set(E e) {
1029 throw new UnsupportedOperationException();
1030 }
1031
1032 /**
1033 * Not supported. Always throws UnsupportedOperationException.
1034 * @throws UnsupportedOperationException always; <tt>add</tt>
1035 * is not supported by this iterator.
1036 */
1037 public void add(E e) {
1038 throw new UnsupportedOperationException();
1039 }
1040 }
1041
1042 /**
1043 * Returns a view of the portion of this list between
1044 * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
1045 * The returned list is backed by this list, so changes in the
1046 * returned list are reflected in this list, and vice-versa.
1047 * While mutative operations are supported, they are probably not
1048 * very useful for CopyOnWriteArrayLists.
1049 *
1050 * <p>The semantics of the list returned by this method become
1051 * undefined if the backing list (i.e., this list) is
1052 * <i>structurally modified</i> in any way other than via the
1053 * returned list. (Structural modifications are those that change
1054 * the size of the list, or otherwise perturb it in such a fashion
1055 * that iterations in progress may yield incorrect results.)
1056 *
1057 * @param fromIndex low endpoint (inclusive) of the subList
1058 * @param toIndex high endpoint (exclusive) of the subList
1059 * @return a view of the specified range within this list
1060 * @throws IndexOutOfBoundsException {@inheritDoc}
1061 */
1062 public List<E> subList(int fromIndex, int toIndex) {
1063 final ReentrantLock lock = this.lock;
1064 lock.lock();
1065 try {
1066 Object[] elements = getArray();
1067 int len = elements.length;
1068 if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
1069 throw new IndexOutOfBoundsException();
1070 return new COWSubList<E>(this, fromIndex, toIndex);
1071 } finally {
1072 lock.unlock();
1073 }
1074 }
1075
1076
1077 /**
1078 * Sublist for CopyOnWriteArrayList.
1079 * This class extends AbstractList merely for convenience, to
1080 * avoid having to define addAll, etc. This doesn't hurt, but
1081 * is wasteful. This class does not need or use modCount
1082 * mechanics in AbstractList, but does need to check for
1083 * concurrent modification using similar mechanics. On each
1084 * operation, the array that we expect the backing list to use
1085 * is checked and updated. Since we do this for all of the
1086 * base operations invoked by those defined in AbstractList,
1087 * all is well. While inefficient, this is not worth
1088 * improving. The kinds of list operations inherited from
1089 * AbstractList are already so slow on COW sublists that
1090 * adding a bit more space/time doesn't seem even noticeable.
1091 */
1092 private static class COWSubList<E> extends AbstractList<E> {
1093 private final CopyOnWriteArrayList<E> l;
1094 private final int offset;
1095 private int size;
1096 private Object[] expectedArray;
1097
1098 private COWSubList(CopyOnWriteArrayList<E> list,
1099 int fromIndex, int toIndex) {
1100 l = list;
1101 expectedArray = l.getArray();
1102 offset = fromIndex;
1103 size = toIndex - fromIndex;
1104 }
1105
1106 // only call this holding l's lock
1107 private void checkForComodification() {
1108 if (l.getArray() != expectedArray)
1109 throw new ConcurrentModificationException();
1110 }
1111
1112 // only call this holding l's lock
1113 private void rangeCheck(int index) {
1114 if (index < 0 || index >= size)
1115 throw new IndexOutOfBoundsException("Index: " + index +
1116 ",Size: " + size);
1117 }
1118
1119 public E set(int index, E element) {
1120 ReentrantLock lock = l.lock;
1121 lock.lock();
1122 try {
1123 rangeCheck(index);
1124 checkForComodification();
1125 E x = l.set(index + offset, element);
1126 expectedArray = l.getArray();
1127 return x;
1128 } finally {
1129 lock.unlock();
1130 }
1131 }
1132
1133 public E get(int index) {
1134 ReentrantLock lock = l.lock;
1135 lock.lock();
1136 try {
1137 rangeCheck(index);
1138 checkForComodification();
1139 return l.get(index + offset);
1140 } finally {
1141 lock.unlock();
1142 }
1143 }
1144
1145 public int size() {
1146 ReentrantLock lock = l.lock;
1147 lock.lock();
1148 try {
1149 checkForComodification();
1150 return size;
1151 } finally {
1152 lock.unlock();
1153 }
1154 }
1155
1156 public void add(int index, E element) {
1157 ReentrantLock lock = l.lock;
1158 lock.lock();
1159 try {
1160 checkForComodification();
1161 if (index<0 || index>size)
1162 throw new IndexOutOfBoundsException();
1163 l.add(index + offset, element);
1164 expectedArray = l.getArray();
1165 size++;
1166 } finally {
1167 lock.unlock();
1168 }
1169 }
1170
1171 public void clear() {
1172 ReentrantLock lock = l.lock;
1173 lock.lock();
1174 try {
1175 checkForComodification();
1176 l.removeRange(offset, offset+size);
1177 expectedArray = l.getArray();
1178 size = 0;
1179 } finally {
1180 lock.unlock();
1181 }
1182 }
1183
1184 public E remove(int index) {
1185 ReentrantLock lock = l.lock;
1186 lock.lock();
1187 try {
1188 rangeCheck(index);
1189 checkForComodification();
1190 E result = l.remove(index + offset);
1191 expectedArray = l.getArray();
1192 size--;
1193 return result;
1194 } finally {
1195 lock.unlock();
1196 }
1197 }
1198
1199 public Iterator<E> iterator() {
1200 ReentrantLock lock = l.lock;
1201 lock.lock();
1202 try {
1203 checkForComodification();
1204 return new COWSubListIterator<E>(l, 0, offset, size);
1205 } finally {
1206 lock.unlock();
1207 }
1208 }
1209
1210 public ListIterator<E> listIterator(final int index) {
1211 ReentrantLock lock = l.lock;
1212 lock.lock();
1213 try {
1214 checkForComodification();
1215 if (index<0 || index>size)
1216 throw new IndexOutOfBoundsException("Index: "+index+
1217 ", Size: "+size);
1218 return new COWSubListIterator<E>(l, index, offset, size);
1219 } finally {
1220 lock.unlock();
1221 }
1222 }
1223
1224 public List<E> subList(int fromIndex, int toIndex) {
1225 ReentrantLock lock = l.lock;
1226 lock.lock();
1227 try {
1228 checkForComodification();
1229 if (fromIndex<0 || toIndex>size)
1230 throw new IndexOutOfBoundsException();
1231 return new COWSubList<E>(l, fromIndex + offset,
1232 toIndex + offset);
1233 } finally {
1234 lock.unlock();
1235 }
1236 }
1237
1238 }
1239
1240
1241 private static class COWSubListIterator<E> implements ListIterator<E> {
1242 private final ListIterator<E> i;
1243 private final int index;
1244 private final int offset;
1245 private final int size;
1246 private COWSubListIterator(List<E> l, int index, int offset,
1247 int size) {
1248 this.index = index;
1249 this.offset = offset;
1250 this.size = size;
1251 i = l.listIterator(index + offset);
1252 }
1253
1254 public boolean hasNext() {
1255 return nextIndex() < size;
1256 }
1257
1258 public E next() {
1259 if (hasNext())
1260 return i.next();
1261 else
1262 throw new NoSuchElementException();
1263 }
1264
1265 public boolean hasPrevious() {
1266 return previousIndex() >= 0;
1267 }
1268
1269 public E previous() {
1270 if (hasPrevious())
1271 return i.previous();
1272 else
1273 throw new NoSuchElementException();
1274 }
1275
1276 public int nextIndex() {
1277 return i.nextIndex() - offset;
1278 }
1279
1280 public int previousIndex() {
1281 return i.previousIndex() - offset;
1282 }
1283
1284 public void remove() {
1285 throw new UnsupportedOperationException();
1286 }
1287
1288 public void set(E e) {
1289 throw new UnsupportedOperationException();
1290 }
1291
1292 public void add(E e) {
1293 throw new UnsupportedOperationException();
1294 }
1295 }
1296
1297 // Support for resetting lock while deserializing
1298 private static final Unsafe unsafe = Unsafe.getUnsafe();
1299 private static final long lockOffset;
1300 static {
1301 try {
1302 lockOffset = unsafe.objectFieldOffset
1303 (CopyOnWriteArrayList.class.getDeclaredField("lock"));
1304 } catch (Exception ex) { throw new Error(ex); }
1305 }
1306 private void resetLock() {
1307 unsafe.putObjectVolatile(this, lockOffset, new ReentrantLock());
1308 }
1309
1310
1311 // Temporary emulations of anticipated new j.u.Arrays functions
1312
1313 private static <T,U> T[] copyOfRange(U[] original, int from, int to,
1314 Class<? extends T[]> newType) {
1315 int newLength = to - from;
1316 if (newLength < 0)
1317 throw new IllegalArgumentException(from + " > " + to);
1318 T[] copy = (T[]) java.lang.reflect.Array.newInstance
1319 (newType.getComponentType(), newLength);
1320 System.arraycopy(original, from, copy, 0,
1321 Math.min(original.length - from, newLength));
1322 return copy;
1323 }
1324
1325 private static <T,U> T[] copyOf(U[] original, int newLength,
1326 Class<? extends T[]> newType) {
1327 T[] copy = (T[]) java.lang.reflect.Array.newInstance
1328 (newType.getComponentType(), newLength);
1329 System.arraycopy(original, 0, copy, 0,
1330 Math.min(original.length, newLength));
1331 return copy;
1332 }
1333
1334 private static <T> T[] copyOf(T[] original, int newLength) {
1335 return (T[]) copyOf(original, newLength, original.getClass());
1336 }
1337 }