ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
Revision: 1.14
Committed: Sun Aug 31 13:33:13 2003 UTC (20 years, 9 months ago) by dl
Branch: MAIN
Changes since 1.13: +17 -17 lines
Log Message:
Removed non-standard tags and misc javadoc cleanup

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