ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/CopyOnWriteArrayList.java
Revision: 1.18
Committed: Sat Oct 18 12:29:33 2003 UTC (20 years, 7 months ago) by dl
Branch: MAIN
Changes since 1.17: +1 -0 lines
Log Message:
Added docs for type params

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