ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
Revision: 1.41
Committed: Tue May 31 17:39:18 2005 UTC (19 years ago) by dl
Branch: MAIN
Changes since 1.40: +110 -116 lines
Log Message:
Reduce generics warnings

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