ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
Revision: 1.38
Committed: Sat May 21 17:32:20 2005 UTC (19 years ago) by jsr166
Branch: MAIN
Changes since 1.37: +23 -9 lines
Log Message:
doc fixes

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 E[] elementData = array();
363 rangeCheck(index, elementData.length);
364 return elementData[index];
365 }
366
367 /**
368 * Replaces the element at the specified position in this list with the
369 * specified element.
370 *
371 * @throws IndexOutOfBoundsException {@inheritDoc}
372 */
373 public synchronized E set(int index, E element) {
374 int len = array.length;
375 rangeCheck(index, len);
376 E oldValue = array[index];
377
378 boolean same = (oldValue == element ||
379 (element != null && element.equals(oldValue)));
380 if (!same) {
381 E[] newArray = (E[]) new Object[len];
382 System.arraycopy(array, 0, newArray, 0, len);
383 newArray[index] = element;
384 array = newArray;
385 }
386 return oldValue;
387 }
388
389 /**
390 * Appends the specified element to the end of this list.
391 *
392 * @param element element to be appended to this list
393 * @return <tt>true</tt> (as per the spec for {@link Collection#add})
394 */
395 public synchronized boolean add(E element) {
396 int len = array.length;
397 E[] newArray = (E[]) new Object[len+1];
398 System.arraycopy(array, 0, newArray, 0, len);
399 newArray[len] = element;
400 array = newArray;
401 return true;
402 }
403
404 /**
405 * Inserts the specified element at the specified position in this
406 * list. Shifts the element currently at that position (if any) and
407 * any subsequent elements to the right (adds one to their indices).
408 *
409 * @throws IndexOutOfBoundsException {@inheritDoc}
410 */
411 public synchronized void add(int index, E element) {
412 int len = array.length;
413 if (index > len || index < 0)
414 throw new IndexOutOfBoundsException("Index: "+index+", Size: "+len);
415
416 E[] newArray = (E[]) new Object[len+1];
417 System.arraycopy(array, 0, newArray, 0, index);
418 newArray[index] = element;
419 System.arraycopy(array, index, newArray, index+1, len - index);
420 array = newArray;
421 }
422
423 /**
424 * Removes the element at the specified position in this list.
425 * Shifts any subsequent elements to the left (subtracts one from their
426 * indices). Returns the element that was removed from the list.
427 *
428 * @throws IndexOutOfBoundsException {@inheritDoc}
429 */
430 public synchronized E remove(int index) {
431 int len = array.length;
432 rangeCheck(index, len);
433 E oldValue = array[index];
434 E[] newArray = (E[]) new Object[len-1];
435 System.arraycopy(array, 0, newArray, 0, index);
436 int numMoved = len - index - 1;
437 if (numMoved > 0)
438 System.arraycopy(array, index+1, newArray, index, numMoved);
439 array = newArray;
440 return oldValue;
441 }
442
443 /**
444 * Removes the first occurrence of the specified element from this list,
445 * if it is present. If this list does not contain the element, it is
446 * unchanged. More formally, removes the element with the lowest index
447 * <tt>i</tt> such that
448 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
449 * (if such an element exists). Returns <tt>true</tt> if this list
450 * contained the specified element (or equivalently, if this list
451 * changed as a result of the call).
452 *
453 * @param o element to be removed from this list, if present
454 * @return <tt>true</tt> if this list contained the specified element
455 */
456 public synchronized boolean remove(Object o) {
457 int len = array.length;
458 if (len == 0) return false;
459
460 // Copy while searching for element to remove
461 // This wins in the normal case of element being present
462
463 int newlen = len-1;
464 E[] newArray = (E[]) new Object[newlen];
465
466 for (int i = 0; i < newlen; ++i) {
467 if (o == array[i] ||
468 (o != null && o.equals(array[i]))) {
469 // found one; copy remaining and exit
470 for (int k = i + 1; k < len; ++k) newArray[k-1] = array[k];
471 array = newArray;
472 return true;
473 } else
474 newArray[i] = array[i];
475 }
476 // special handling for last cell
477
478 if (o == array[newlen] ||
479 (o != null && o.equals(array[newlen]))) {
480 array = newArray;
481 return true;
482 } else
483 return false; // throw away copy
484 }
485
486 /**
487 * Removes from this list all of the elements whose index is between
488 * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.
489 * Shifts any succeeding elements to the left (reduces their index).
490 * This call shortens the list by <tt>(toIndex - fromIndex)</tt> elements.
491 * (If <tt>toIndex==fromIndex</tt>, this operation has no effect.)
492 *
493 * @param fromIndex index of first element to be removed
494 * @param toIndex index after last element to be removed
495 * @throws IndexOutOfBoundsException if fromIndex or toIndex out of
496 * range (fromIndex &lt; 0 || fromIndex &gt;= size() || toIndex
497 * &gt; size() || toIndex &lt; fromIndex)
498 */
499 private synchronized void removeRange(int fromIndex, int toIndex) {
500 int len = array.length;
501
502 if (fromIndex < 0 || fromIndex >= len ||
503 toIndex > len || toIndex < fromIndex)
504 throw new IndexOutOfBoundsException();
505
506 int numMoved = len - toIndex;
507 int newlen = len - (toIndex-fromIndex);
508 E[] newArray = (E[]) new Object[newlen];
509 System.arraycopy(array, 0, newArray, 0, fromIndex);
510 System.arraycopy(array, toIndex, newArray, fromIndex, numMoved);
511 array = newArray;
512 }
513
514 /**
515 * Append the element if not present.
516 *
517 * @param element element to be added to this list, if absent
518 * @return <tt>true</tt> if the element was added
519 */
520 public synchronized boolean addIfAbsent(E element) {
521 // Copy while checking if already present.
522 // This wins in the most common case where it is not present
523 int len = array.length;
524 E[] newArray = (E[]) new Object[len + 1];
525 for (int i = 0; i < len; ++i) {
526 if (element == array[i] ||
527 (element != null && element.equals(array[i])))
528 return false; // exit, throwing away copy
529 else
530 newArray[i] = array[i];
531 }
532 newArray[len] = element;
533 array = newArray;
534 return true;
535 }
536
537 /**
538 * Returns <tt>true</tt> if this list contains all of the elements of the
539 * specified collection.
540 *
541 * @param c collection to be checked for containment in this list
542 * @return <tt>true</tt> if this list contains all of the elements of the
543 * specified collection
544 * @throws NullPointerException if the specified collection is null
545 * @see #contains(Object)
546 */
547 public boolean containsAll(Collection<?> c) {
548 E[] elementData = array();
549 int len = elementData.length;
550 Iterator e = c.iterator();
551 while (e.hasNext())
552 if (indexOf(e.next(), elementData, len) < 0)
553 return false;
554
555 return true;
556 }
557
558 /**
559 * Removes from this list all of its elements that are contained in
560 * the specified collection. This is a particularly expensive operation
561 * in this class because of the need for an internal temporary array.
562 *
563 * @param c collection containing elements to be removed from this list
564 * @return <tt>true</tt> if this list changed as a result of the call
565 * @throws ClassCastException if the class of an element of this list
566 * is incompatible with the specified collection (optional)
567 * @throws NullPointerException if this list contains a null element and the
568 * specified collection does not permit null elements (optional),
569 * or if the specified collection is null
570 * @see #remove(Object)
571 */
572 public synchronized boolean removeAll(Collection<?> c) {
573 E[] elementData = array;
574 int len = elementData.length;
575 if (len == 0) return false;
576
577 // temp array holds those elements we know we want to keep
578 E[] temp = (E[]) new Object[len];
579 int newlen = 0;
580 for (int i = 0; i < len; ++i) {
581 E element = elementData[i];
582 if (!c.contains(element)) {
583 temp[newlen++] = element;
584 }
585 }
586
587 if (newlen == len) return false;
588
589 // copy temp as new array
590 E[] newArray = (E[]) new Object[newlen];
591 System.arraycopy(temp, 0, newArray, 0, newlen);
592 array = newArray;
593 return true;
594 }
595
596 /**
597 * Retains only the elements in this list that are contained in the
598 * specified collection. In other words, removes from this list all of
599 * its elements that are not contained in the specified collection.
600 *
601 * @param c collection containing elements to be retained in this list
602 * @return <tt>true</tt> if this list changed as a result of the call
603 * @throws ClassCastException if the class of an element of this list
604 * is incompatible with the specified collection (optional)
605 * @throws NullPointerException if this list contains a null element and the
606 * specified collection does not permit null elements (optional),
607 * or if the specified collection is null
608 * @see #remove(Object)
609 */
610 public synchronized boolean retainAll(Collection<?> c) {
611 E[] elementData = array;
612 int len = elementData.length;
613 if (len == 0) return false;
614
615 E[] temp = (E[]) new Object[len];
616 int newlen = 0;
617 for (int i = 0; i < len; ++i) {
618 E element = elementData[i];
619 if (c.contains(element)) {
620 temp[newlen++] = element;
621 }
622 }
623
624 if (newlen == len) return false;
625
626 E[] newArray = (E[]) new Object[newlen];
627 System.arraycopy(temp, 0, newArray, 0, newlen);
628 array = newArray;
629 return true;
630 }
631
632 /**
633 * Appends all of the elements in the specified collection that
634 * are not already contained in this list, to the end of
635 * this list, in the order that they are returned by the
636 * specified collection's iterator.
637 *
638 * @param c collection containing elements to be added to this list
639 * @return the number of elements added
640 * @throws NullPointerException if the specified collection is null
641 * @see #addIfAbsent(Object)
642 */
643 public synchronized int addAllAbsent(Collection<? extends E> c) {
644 int numNew = c.size();
645 if (numNew == 0) return 0;
646
647 E[] elementData = array;
648 int len = elementData.length;
649
650 E[] temp = (E[]) new Object[numNew];
651 int added = 0;
652 Iterator<? extends E> e = c.iterator();
653 while (e.hasNext()) {
654 E element = e.next();
655 if (indexOf(element, elementData, len) < 0) {
656 if (indexOf(element, temp, added) < 0) {
657 temp[added++] = element;
658 }
659 }
660 }
661
662 if (added == 0) return 0;
663
664 E[] newArray = (E[]) new Object[len+added];
665 System.arraycopy(elementData, 0, newArray, 0, len);
666 System.arraycopy(temp, 0, newArray, len, added);
667 array = newArray;
668 return added;
669 }
670
671 /**
672 * Removes all of the elements from this list.
673 * The list will be empty after this call returns.
674 */
675 public synchronized void clear() {
676 array = (E[]) new Object[0];
677 }
678
679 /**
680 * Appends all of the elements in the specified collection to the end
681 * of this list, in the order that they are returned by the specified
682 * collection's iterator.
683 *
684 * @param c collection containing elements to be added to this list
685 * @return <tt>true</tt> if this list changed as a result of the call
686 * @throws NullPointerException if the specified collection is null
687 * @see #add(Object)
688 */
689 public synchronized boolean addAll(Collection<? extends E> c) {
690 int numNew = c.size();
691 if (numNew == 0) return false;
692
693 int len = array.length;
694 E[] newArray = (E[]) new Object[len+numNew];
695 System.arraycopy(array, 0, newArray, 0, len);
696 Iterator<? extends E> e = c.iterator();
697 for (int i=0; i<numNew; i++)
698 newArray[len++] = e.next();
699 array = newArray;
700
701 return true;
702 }
703
704 /**
705 * Inserts all of the elements in the specified collection into this
706 * list, starting at the specified position. Shifts the element
707 * currently at that position (if any) and any subsequent elements to
708 * the right (increases their indices). The new elements will appear
709 * in this list in the order that they are returned by the
710 * specified collection's iterator.
711 *
712 * @param index index at which to insert the first element
713 * from the specified collection
714 * @param c collection containing elements to be added to this list
715 * @return <tt>true</tt> if this list changed as a result of the call
716 * @throws IndexOutOfBoundsException {@inheritDoc}
717 * @throws NullPointerException if the specified collection is null
718 * @see #add(int,Object)
719 */
720 public synchronized boolean addAll(int index, Collection<? extends E> c) {
721 int len = array.length;
722 if (index > len || index < 0)
723 throw new IndexOutOfBoundsException("Index: "+index+", Size: "+len);
724
725 int numNew = c.size();
726 if (numNew == 0) return false;
727
728 E[] newArray = (E[]) new Object[len+numNew];
729 System.arraycopy(array, 0, newArray, 0, len);
730 int numMoved = len - index;
731 if (numMoved > 0)
732 System.arraycopy(array, index, newArray, index + numNew, numMoved);
733 Iterator<? extends E> e = c.iterator();
734 for (int i=0; i<numNew; i++)
735 newArray[index++] = e.next();
736 array = newArray;
737
738 return true;
739 }
740
741 /**
742 * Checks if the given index is in range. If not, throws an appropriate
743 * runtime exception.
744 */
745 private void rangeCheck(int index, int length) {
746 if (index >= length || index < 0)
747 throw new IndexOutOfBoundsException("Index: "+index+", Size: "+ length);
748 }
749
750 /**
751 * Save the state of the list to a stream (i.e., serialize it).
752 *
753 * @serialData The length of the array backing the list is emitted
754 * (int), followed by all of its elements (each an Object)
755 * in the proper order.
756 * @param s the stream
757 */
758 private void writeObject(java.io.ObjectOutputStream s)
759 throws java.io.IOException{
760
761 // Write out element count, and any hidden stuff
762 s.defaultWriteObject();
763
764 E[] elementData = array();
765 // Write out array length
766 s.writeInt(elementData.length);
767
768 // Write out all elements in the proper order.
769 for (int i=0; i<elementData.length; i++)
770 s.writeObject(elementData[i]);
771 }
772
773 /**
774 * Reconstitute the list from a stream (i.e., deserialize it).
775 * @param s the stream
776 */
777 private void readObject(java.io.ObjectInputStream s)
778 throws java.io.IOException, ClassNotFoundException {
779
780 // Read in size, and any hidden stuff
781 s.defaultReadObject();
782
783 // Read in array length and allocate array
784 int arrayLength = s.readInt();
785 E[] elementData = (E[]) new Object[arrayLength];
786
787 // Read in all elements in the proper order.
788 for (int i=0; i<elementData.length; i++)
789 elementData[i] = (E) s.readObject();
790 array = elementData;
791 }
792
793 /**
794 * Returns a string representation of this list, containing
795 * the String representation of each element.
796 */
797 public String toString() {
798 StringBuffer buf = new StringBuffer();
799 Iterator e = iterator();
800 buf.append("[");
801 int maxIndex = size() - 1;
802 for (int i = 0; i <= maxIndex; i++) {
803 buf.append(String.valueOf(e.next()));
804 if (i < maxIndex)
805 buf.append(", ");
806 }
807 buf.append("]");
808 return buf.toString();
809 }
810
811 /**
812 * Compares the specified object with this list for equality.
813 * Returns true if and only if the specified object is also a {@link
814 * List}, both lists have the same size, and all corresponding pairs
815 * of elements in the two lists are <em>equal</em>. (Two elements
816 * <tt>e1</tt> and <tt>e2</tt> are <em>equal</em> if <tt>(e1==null ?
817 * e2==null : e1.equals(e2))</tt>.) In other words, two lists are
818 * defined to be equal if they contain the same elements in the same
819 * order.
820 *
821 * @param o the object to be compared for equality with this list
822 * @return <tt>true</tt> if the specified object is equal to this list
823 */
824 public boolean equals(Object o) {
825 if (o == this)
826 return true;
827 if (!(o instanceof List))
828 return false;
829
830 List<E> l2 = (List<E>)(o);
831 if (size() != l2.size())
832 return false;
833
834 ListIterator<E> e1 = listIterator();
835 ListIterator<E> e2 = l2.listIterator();
836 while (e1.hasNext()) {
837 E o1 = e1.next();
838 E o2 = e2.next();
839 if (!(o1==null ? o2==null : o1.equals(o2)))
840 return false;
841 }
842 return true;
843 }
844
845 /**
846 * Returns the hash code value for this list.
847 *
848 * <p> This implementation uses the definition in {@link
849 * List#hashCode}.
850 * @return the hash code
851 */
852 public int hashCode() {
853 int hashCode = 1;
854 Iterator<E> i = iterator();
855 while (i.hasNext()) {
856 E obj = i.next();
857 hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
858 }
859 return hashCode;
860 }
861
862 /**
863 * Returns an iterator over the elements in this list in proper sequence.
864 *
865 * <p>The returned iterator provides a snapshot of the state of the list
866 * when the iterator was constructed. No synchronization is needed while
867 * traversing the iterator. The iterator does <em>NOT</em> support the
868 * <tt>remove</tt> method.
869 *
870 * @return an iterator over the elements in this list in proper sequence
871 */
872 public Iterator<E> iterator() {
873 return new COWIterator<E>(array(), 0);
874 }
875
876 /**
877 * {@inheritDoc}
878 *
879 * <p>The returned iterator provides a snapshot of the state of the list
880 * when the iterator was constructed. No synchronization is needed while
881 * traversing the iterator. The iterator does <em>NOT</em> support the
882 * <tt>remove</tt>, <tt>set</tt> or <tt>add</tt> methods.
883 */
884 public ListIterator<E> listIterator() {
885 return new COWIterator<E>(array(), 0);
886 }
887
888 /**
889 * {@inheritDoc}
890 *
891 * <p>The list iterator returned by this implementation will throw an
892 * <tt>UnsupportedOperationException</tt> in its <tt>remove</tt>,
893 * <tt>set</tt> and <tt>add</tt> methods.
894 *
895 * @throws IndexOutOfBoundsException {@inheritDoc}
896 */
897 public ListIterator<E> listIterator(final int index) {
898 E[] elementData = array();
899 int len = elementData.length;
900 if (index<0 || index>len)
901 throw new IndexOutOfBoundsException("Index: "+index);
902
903 return new COWIterator<E>(array(), index);
904 }
905
906 private static class COWIterator<E> implements ListIterator<E> {
907
908 /** Snapshot of the array **/
909 private final E[] array;
910
911 /**
912 * Index of element to be returned by subsequent call to next.
913 */
914 private int cursor;
915
916 private COWIterator(E[] elementArray, int initialCursor) {
917 array = elementArray;
918 cursor = initialCursor;
919 }
920
921 public boolean hasNext() {
922 return cursor < array.length;
923 }
924
925 public boolean hasPrevious() {
926 return cursor > 0;
927 }
928
929 public E next() {
930 try {
931 return array[cursor++];
932 } catch (IndexOutOfBoundsException ex) {
933 throw new NoSuchElementException();
934 }
935 }
936
937 public E previous() {
938 try {
939 return array[--cursor];
940 } catch (IndexOutOfBoundsException e) {
941 throw new NoSuchElementException();
942 }
943 }
944
945 public int nextIndex() {
946 return cursor;
947 }
948
949 public int previousIndex() {
950 return cursor-1;
951 }
952
953 /**
954 * Not supported. Always throws UnsupportedOperationException.
955 * @throws UnsupportedOperationException always; <tt>remove</tt>
956 * is not supported by this iterator.
957 */
958 public void remove() {
959 throw new UnsupportedOperationException();
960 }
961
962 /**
963 * Not supported. Always throws UnsupportedOperationException.
964 * @throws UnsupportedOperationException always; <tt>set</tt>
965 * is not supported by this iterator.
966 */
967 public void set(E e) {
968 throw new UnsupportedOperationException();
969 }
970
971 /**
972 * Not supported. Always throws UnsupportedOperationException.
973 * @throws UnsupportedOperationException always; <tt>add</tt>
974 * is not supported by this iterator.
975 */
976 public void add(E e) {
977 throw new UnsupportedOperationException();
978 }
979 }
980
981 /**
982 * Returns a view of the portion of this list between <tt>fromIndex</tt>,
983 * inclusive, and <tt>toIndex</tt>, exclusive. The returned list is
984 * backed by this list, so changes in the returned list are reflected in
985 * this list, and vice-versa. While mutative operations are supported,
986 * they are probably not very useful for CopyOnWriteArrayLists.
987 *
988 * <p>The semantics of the list returned by this method become undefined if
989 * the backing list (i.e., this list) is <i>structurally modified</i> in
990 * any way other than via the returned list. (Structural modifications are
991 * those that change the size of the list, or otherwise perturb it in such
992 * a fashion that iterations in progress may yield incorrect results.)
993 *
994 * @param fromIndex low endpoint (inclusive) of the subList
995 * @param toIndex high endpoint (exclusive) of the subList
996 * @return a view of the specified range within this list
997 * @throws IndexOutOfBoundsException {@inheritDoc}
998 */
999 public synchronized List<E> subList(int fromIndex, int toIndex) {
1000 // synchronized since sublist constructor depends on it.
1001 int len = array.length;
1002 if (fromIndex<0 || toIndex>len || fromIndex>toIndex)
1003 throw new IndexOutOfBoundsException();
1004 return new COWSubList<E>(this, fromIndex, toIndex);
1005 }
1006
1007 private static class COWSubList<E> extends AbstractList<E> {
1008
1009 /*
1010 This class extends AbstractList merely for convenience, to
1011 avoid having to define addAll, etc. This doesn't hurt, but
1012 is wasteful. This class does not need or use modCount
1013 mechanics in AbstractList, but does need to check for
1014 concurrent modification using similar mechanics. On each
1015 operation, the array that we expect the backing list to use
1016 is checked and updated. Since we do this for all of the
1017 base operations invoked by those defined in AbstractList,
1018 all is well. While inefficient, this is not worth
1019 improving. The kinds of list operations inherited from
1020 AbstractList are already so slow on COW sublists that
1021 adding a bit more space/time doesn't seem even noticeable.
1022 */
1023
1024 private final CopyOnWriteArrayList<E> l;
1025 private final int offset;
1026 private int size;
1027 private E[] expectedArray;
1028
1029 private COWSubList(CopyOnWriteArrayList<E> list,
1030 int fromIndex, int toIndex) {
1031 l = list;
1032 expectedArray = l.array();
1033 offset = fromIndex;
1034 size = toIndex - fromIndex;
1035 }
1036
1037 // only call this holding l's lock
1038 private void checkForComodification() {
1039 if (l.array != expectedArray)
1040 throw new ConcurrentModificationException();
1041 }
1042
1043 // only call this holding l's lock
1044 private void rangeCheck(int index) {
1045 if (index<0 || index>=size)
1046 throw new IndexOutOfBoundsException("Index: "+index+ ",Size: "+size);
1047 }
1048
1049
1050 public E set(int index, E element) {
1051 synchronized(l) {
1052 rangeCheck(index);
1053 checkForComodification();
1054 E x = l.set(index+offset, element);
1055 expectedArray = l.array;
1056 return x;
1057 }
1058 }
1059
1060 public E get(int index) {
1061 synchronized(l) {
1062 rangeCheck(index);
1063 checkForComodification();
1064 return l.get(index+offset);
1065 }
1066 }
1067
1068 public int size() {
1069 synchronized(l) {
1070 checkForComodification();
1071 return size;
1072 }
1073 }
1074
1075 public void add(int index, E element) {
1076 synchronized(l) {
1077 checkForComodification();
1078 if (index<0 || index>size)
1079 throw new IndexOutOfBoundsException();
1080 l.add(index+offset, element);
1081 expectedArray = l.array;
1082 size++;
1083 }
1084 }
1085
1086 public void clear() {
1087 synchronized(l) {
1088 checkForComodification();
1089 l.removeRange(offset, offset+size);
1090 expectedArray = l.array;
1091 size = 0;
1092 }
1093 }
1094
1095 public E remove(int index) {
1096 synchronized(l) {
1097 rangeCheck(index);
1098 checkForComodification();
1099 E result = l.remove(index+offset);
1100 expectedArray = l.array;
1101 size--;
1102 return result;
1103 }
1104 }
1105
1106 public Iterator<E> iterator() {
1107 synchronized(l) {
1108 checkForComodification();
1109 return new COWSubListIterator<E>(l, 0, offset, size);
1110 }
1111 }
1112
1113 public ListIterator<E> listIterator(final int index) {
1114 synchronized(l) {
1115 checkForComodification();
1116 if (index<0 || index>size)
1117 throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
1118 return new COWSubListIterator<E>(l, index, offset, size);
1119 }
1120 }
1121
1122 public List<E> subList(int fromIndex, int toIndex) {
1123 synchronized(l) {
1124 checkForComodification();
1125 if (fromIndex<0 || toIndex>size)
1126 throw new IndexOutOfBoundsException();
1127 return new COWSubList<E>(l, fromIndex+offset, toIndex+offset);
1128 }
1129 }
1130
1131 }
1132
1133
1134 private static class COWSubListIterator<E> implements ListIterator<E> {
1135 private final ListIterator<E> i;
1136 private final int index;
1137 private final int offset;
1138 private final int size;
1139 private COWSubListIterator(List<E> l, int index, int offset, int size) {
1140 this.index = index;
1141 this.offset = offset;
1142 this.size = size;
1143 i = l.listIterator(index+offset);
1144 }
1145
1146 public boolean hasNext() {
1147 return nextIndex() < size;
1148 }
1149
1150 public E next() {
1151 if (hasNext())
1152 return i.next();
1153 else
1154 throw new NoSuchElementException();
1155 }
1156
1157 public boolean hasPrevious() {
1158 return previousIndex() >= 0;
1159 }
1160
1161 public E previous() {
1162 if (hasPrevious())
1163 return i.previous();
1164 else
1165 throw new NoSuchElementException();
1166 }
1167
1168 public int nextIndex() {
1169 return i.nextIndex() - offset;
1170 }
1171
1172 public int previousIndex() {
1173 return i.previousIndex() - offset;
1174 }
1175
1176 public void remove() {
1177 throw new UnsupportedOperationException();
1178 }
1179
1180 public void set(E e) {
1181 throw new UnsupportedOperationException();
1182 }
1183
1184 public void add(E e) {
1185 throw new UnsupportedOperationException();
1186 }
1187 }
1188
1189 }