ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
Revision: 1.39
Committed: Sun May 29 14:02:53 2005 UTC (19 years ago) by dl
Branch: MAIN
Changes since 1.38: +1 -5 lines
Log Message:
Avoid redundant bounds checks

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