ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
Revision: 1.15
Committed: Sat Sep 13 18:51:11 2003 UTC (20 years, 9 months ago) by dl
Branch: MAIN
Changes since 1.14: +57 -54 lines
Log Message:
Proofreading pass -- many minor adjustments

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