1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package java.util.concurrent;
18
19import java.io.IOException;
20import java.io.ObjectInputStream;
21import java.io.ObjectOutputStream;
22import java.io.Serializable;
23import java.util.AbstractList;
24import java.util.Arrays;
25import java.util.Collection;
26import java.util.Comparator;
27import java.util.ConcurrentModificationException;
28import java.util.Iterator;
29import java.util.List;
30import java.util.ListIterator;
31import java.util.NoSuchElementException;
32import java.util.RandomAccess;
33import java.util.function.Consumer;
34import java.util.function.UnaryOperator;
35
36import libcore.util.EmptyArray;
37import libcore.util.Objects;
38
39/**
40 * A thread-safe random-access list.
41 *
42 * <p>Read operations (including {@link #get}) do not block and may overlap with
43 * update operations. Reads reflect the results of the most recently completed
44 * operations. Aggregate operations like {@link #addAll} and {@link #clear} are
45 * atomic; they never expose an intermediate state.
46 *
47 * <p>Iterators of this list never throw {@link
48 * ConcurrentModificationException}. When an iterator is created, it keeps a
49 * copy of the list's contents. It is always safe to iterate this list, but
50 * iterations may not reflect the latest state of the list.
51 *
52 * <p>Iterators returned by this list and its sub lists cannot modify the
53 * underlying list. In particular, {@link Iterator#remove}, {@link
54 * ListIterator#add} and {@link ListIterator#set} all throw {@link
55 * UnsupportedOperationException}.
56 *
57 * <p>This class offers extended API beyond the {@link List} interface. It
58 * includes additional overloads for indexed search ({@link #indexOf} and {@link
59 * #lastIndexOf}) and methods for conditional adds ({@link #addIfAbsent} and
60 * {@link #addAllAbsent}).
61 */
62public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
63
64    private static final long serialVersionUID = 8673264195747942595L;
65
66    /**
67     * Holds the latest snapshot of the list's data. This field is volatile so
68     * that data can be read without synchronization. As a consequence, all
69     * writes to this field must be atomic; it is an error to modify the
70     * contents of an array after it has been assigned to this field.
71     *
72     * Synchronization is required by all update operations. This defends
73     * against one update clobbering the result of another operation. For
74     * example, 100 threads simultaneously calling add() will grow the list's
75     * size by 100 when they have completed. No update operations are lost!
76     *
77     * Maintainers should be careful to read this field only once in
78     * non-blocking read methods. Write methods must be synchronized to avoid
79     * clobbering concurrent writes.
80     */
81    private transient volatile Object[] elements;
82
83    /**
84     * Creates a new empty instance.
85     */
86    public CopyOnWriteArrayList() {
87        elements = EmptyArray.OBJECT;
88    }
89
90    /**
91     * Creates a new instance containing the elements of {@code collection}.
92     */
93    @SuppressWarnings("unchecked")
94    public CopyOnWriteArrayList(Collection<? extends E> collection) {
95        this((E[]) collection.toArray());
96    }
97
98    /**
99     * Creates a new instance containing the elements of {@code array}.
100     */
101    public CopyOnWriteArrayList(E[] array) {
102        this.elements = Arrays.copyOf(array, array.length, Object[].class);
103    }
104
105    @Override public Object clone() {
106        try {
107            CopyOnWriteArrayList result = (CopyOnWriteArrayList) super.clone();
108            result.elements = result.elements.clone();
109            return result;
110        } catch (CloneNotSupportedException e) {
111            throw new AssertionError(e);
112        }
113    }
114
115    public int size() {
116        return elements.length;
117    }
118
119    @SuppressWarnings("unchecked")
120    public E get(int index) {
121        return (E) elements[index];
122    }
123
124    public boolean contains(Object o) {
125        return indexOf(o) != -1;
126    }
127
128    public boolean containsAll(Collection<?> collection) {
129        Object[] snapshot = elements;
130        return containsAll(collection, snapshot, 0, snapshot.length);
131    }
132
133    static boolean containsAll(Collection<?> collection, Object[] snapshot, int from, int to) {
134        for (Object o : collection) {
135            if (indexOf(o, snapshot, from, to) == -1) {
136                return false;
137            }
138        }
139        return true;
140    }
141
142    /**
143     * Searches this list for {@code object} and returns the index of the first
144     * occurrence that is at or after {@code from}.
145     *
146     * @return the index or -1 if the object was not found.
147     */
148    public int indexOf(E object, int from) {
149        Object[] snapshot = elements;
150        return indexOf(object, snapshot, from, snapshot.length);
151    }
152
153    public int indexOf(Object object) {
154        Object[] snapshot = elements;
155        return indexOf(object, snapshot, 0, snapshot.length);
156    }
157
158    /**
159     * Searches this list for {@code object} and returns the index of the last
160     * occurrence that is before {@code to}.
161     *
162     * @return the index or -1 if the object was not found.
163     */
164    public int lastIndexOf(E object, int to) {
165        Object[] snapshot = elements;
166        return lastIndexOf(object, snapshot, 0, to);
167    }
168
169    public int lastIndexOf(Object object) {
170        Object[] snapshot = elements;
171        return lastIndexOf(object, snapshot, 0, snapshot.length);
172    }
173
174    public boolean isEmpty() {
175        return elements.length == 0;
176    }
177
178    /**
179     * Returns an {@link Iterator} that iterates over the elements of this list
180     * as they were at the time of this method call. Changes to the list made
181     * after this method call will not be reflected by the iterator, nor will
182     * they trigger a {@link ConcurrentModificationException}.
183     *
184     * <p>The returned iterator does not support {@link Iterator#remove()}.
185     */
186    public Iterator<E> iterator() {
187        Object[] snapshot = elements;
188        return new CowIterator<E>(snapshot, 0, snapshot.length);
189    }
190
191    /**
192     * Returns a {@link ListIterator} that iterates over the elements of this
193     * list as they were at the time of this method call. Changes to the list
194     * made after this method call will not be reflected by the iterator, nor
195     * will they trigger a {@link ConcurrentModificationException}.
196     *
197     * <p>The returned iterator does not support {@link ListIterator#add},
198     * {@link ListIterator#set} or {@link Iterator#remove()},
199     */
200    public ListIterator<E> listIterator(int index) {
201        Object[] snapshot = elements;
202        if (index < 0 || index > snapshot.length) {
203            throw new IndexOutOfBoundsException("index=" + index + ", length=" + snapshot.length);
204        }
205        CowIterator<E> result = new CowIterator<E>(snapshot, 0, snapshot.length);
206        result.index = index;
207        return result;
208    }
209
210    /**
211     * Equivalent to {@code listIterator(0)}.
212     */
213    public ListIterator<E> listIterator() {
214        Object[] snapshot = elements;
215        return new CowIterator<E>(snapshot, 0, snapshot.length);
216    }
217
218    public List<E> subList(int from, int to) {
219        Object[] snapshot = elements;
220        if (from < 0 || from > to || to > snapshot.length) {
221            throw new IndexOutOfBoundsException("from=" + from + ", to=" + to +
222                    ", list size=" + snapshot.length);
223        }
224        return new CowSubList(snapshot, from, to);
225    }
226
227    public Object[] toArray() {
228        return elements.clone();
229    }
230
231    @SuppressWarnings({"unchecked","SuspiciousSystemArraycopy"})
232    public <T> T[] toArray(T[] contents) {
233        Object[] snapshot = elements;
234        if (snapshot.length > contents.length) {
235            return (T[]) Arrays.copyOf(snapshot, snapshot.length, contents.getClass());
236        }
237        System.arraycopy(snapshot, 0, contents, 0, snapshot.length);
238        if (snapshot.length < contents.length) {
239            contents[snapshot.length] = null;
240        }
241        return contents;
242    }
243
244    @Override public boolean equals(Object other) {
245        if (other instanceof CopyOnWriteArrayList) {
246            return this == other
247                    || Arrays.equals(elements, ((CopyOnWriteArrayList<?>) other).elements);
248        } else if (other instanceof List) {
249            Object[] snapshot = elements;
250            Iterator<?> i = ((List<?>) other).iterator();
251            for (Object o : snapshot) {
252                if (!i.hasNext() || !Objects.equal(o, i.next())) {
253                    return false;
254                }
255            }
256            return !i.hasNext();
257        } else {
258            return false;
259        }
260    }
261
262    @Override public int hashCode() {
263        return Arrays.hashCode(elements);
264    }
265
266    @Override public String toString() {
267        return Arrays.toString(elements);
268    }
269
270    public synchronized boolean add(E e) {
271        Object[] newElements = new Object[elements.length + 1];
272        System.arraycopy(elements, 0, newElements, 0, elements.length);
273        newElements[elements.length] = e;
274        elements = newElements;
275        return true;
276    }
277
278    public synchronized void add(int index, E e) {
279        Object[] newElements = new Object[elements.length + 1];
280        System.arraycopy(elements, 0, newElements, 0, index);
281        newElements[index] = e;
282        System.arraycopy(elements, index, newElements, index + 1, elements.length - index);
283        elements = newElements;
284    }
285
286    public synchronized boolean addAll(Collection<? extends E> collection) {
287        return addAll(elements.length, collection);
288    }
289
290    public synchronized boolean addAll(int index, Collection<? extends E> collection) {
291        Object[] toAdd = collection.toArray();
292        Object[] newElements = new Object[elements.length + toAdd.length];
293        System.arraycopy(elements, 0, newElements, 0, index);
294        System.arraycopy(toAdd, 0, newElements, index, toAdd.length);
295        System.arraycopy(elements, index,
296                newElements, index + toAdd.length, elements.length - index);
297        elements = newElements;
298        return toAdd.length > 0;
299    }
300
301    /**
302     * Adds the elements of {@code collection} that are not already present in
303     * this list. If {@code collection} includes a repeated value, at most one
304     * occurrence of that value will be added to this list. Elements are added
305     * at the end of this list.
306     *
307     * <p>Callers of this method may prefer {@link CopyOnWriteArraySet}, whose
308     * API is more appropriate for set operations.
309     */
310    public synchronized int addAllAbsent(Collection<? extends E> collection) {
311        Object[] toAdd = collection.toArray();
312        Object[] newElements = new Object[elements.length + toAdd.length];
313        System.arraycopy(elements, 0, newElements, 0, elements.length);
314        int addedCount = 0;
315        for (Object o : toAdd) {
316            if (indexOf(o, newElements, 0, elements.length + addedCount) == -1) {
317                newElements[elements.length + addedCount++] = o;
318            }
319        }
320        if (addedCount < toAdd.length) {
321            newElements = Arrays.copyOfRange(
322                    newElements, 0, elements.length + addedCount); // trim to size
323        }
324        elements = newElements;
325        return addedCount;
326    }
327
328    /**
329     * Adds {@code object} to the end of this list if it is not already present.
330     *
331     * <p>Callers of this method may prefer {@link CopyOnWriteArraySet}, whose
332     * API is more appropriate for set operations.
333     */
334    public synchronized boolean addIfAbsent(E object) {
335        if (contains(object)) {
336            return false;
337        }
338        add(object);
339        return true;
340    }
341
342    @Override public synchronized void clear() {
343        elements = EmptyArray.OBJECT;
344    }
345
346    public synchronized E remove(int index) {
347        @SuppressWarnings("unchecked")
348        E removed = (E) elements[index];
349        removeRange(index, index + 1);
350        return removed;
351    }
352
353    public synchronized boolean remove(Object o) {
354        int index = indexOf(o);
355        if (index == -1) {
356            return false;
357        }
358        remove(index);
359        return true;
360    }
361
362    public synchronized boolean removeAll(Collection<?> collection) {
363        return removeOrRetain(collection, false, 0, elements.length) != 0;
364    }
365
366    public synchronized boolean retainAll(Collection<?> collection) {
367        return removeOrRetain(collection, true, 0, elements.length) != 0;
368    }
369
370    @Override
371    public synchronized void replaceAll(UnaryOperator<E> operator) {
372        replaceInRange(0, elements.length,operator);
373    }
374
375    private void replaceInRange(int from, int to, UnaryOperator<E> operator) {
376        java.util.Objects.requireNonNull(operator);
377        Object[] newElements = new Object[elements.length];
378        System.arraycopy(elements, 0, newElements, 0, newElements.length);
379        for (int i = from; i < to; i++) {
380            @SuppressWarnings("unchecked") E e = (E) elements[i];
381            newElements[i] = operator.apply(e);
382        }
383        elements = newElements;
384    }
385
386    @Override
387    public synchronized void sort(Comparator<? super E> c) {
388        sortInRange(0, elements.length, c);
389    }
390
391    private synchronized void sortInRange(int from, int to, Comparator<? super E> c) {
392        java.util.Objects.requireNonNull(c);
393        Object[] newElements = new Object[elements.length];
394        System.arraycopy(elements, 0, newElements, 0, newElements.length);
395        Arrays.sort((E[])newElements, from, to, c);
396        elements = newElements;
397    }
398
399    @Override
400    public void forEach(Consumer<? super E> action) {
401        forInRange(0, elements.length, action);
402    }
403
404    private void forInRange(int from, int to, Consumer<? super E> action) {
405        java.util.Objects.requireNonNull(action);
406        Object[] newElements = new Object[elements.length];
407        System.arraycopy(elements, 0, newElements, 0, newElements.length);
408        for (int i = from; i < to; i++) {
409            action.accept((E)newElements[i]);
410        }
411    }
412
413    /**
414     * Removes or retains the elements in {@code collection}. Returns the number
415     * of elements removed.
416     */
417    private int removeOrRetain(Collection<?> collection, boolean retain, int from, int to) {
418        for (int i = from; i < to; i++) {
419            if (collection.contains(elements[i]) == retain) {
420                continue;
421            }
422
423            /*
424             * We've encountered an element that must be removed! Create a new
425             * array and copy in the surviving elements one by one.
426             */
427            Object[] newElements = new Object[elements.length - 1];
428            System.arraycopy(elements, 0, newElements, 0, i);
429            int newSize = i;
430            for (int j = i + 1; j < to; j++) {
431                if (collection.contains(elements[j]) == retain) {
432                    newElements[newSize++] = elements[j];
433                }
434            }
435
436            /*
437             * Copy the elements after 'to'. This is only useful for sub lists,
438             * where 'to' will be less than elements.length.
439             */
440            System.arraycopy(elements, to, newElements, newSize, elements.length - to);
441            newSize += (elements.length - to);
442
443            if (newSize < newElements.length) {
444                newElements = Arrays.copyOfRange(newElements, 0, newSize); // trim to size
445            }
446            int removed = elements.length - newElements.length;
447            elements = newElements;
448            return removed;
449        }
450
451        // we made it all the way through the loop without making any changes
452        return 0;
453    }
454
455    public synchronized E set(int index, E e) {
456        Object[] newElements = elements.clone();
457        @SuppressWarnings("unchecked")
458        E result = (E) newElements[index];
459        newElements[index] = e;
460        elements = newElements;
461        return result;
462    }
463
464    private void removeRange(int from, int to) {
465        Object[] newElements = new Object[elements.length - (to - from)];
466        System.arraycopy(elements, 0, newElements, 0, from);
467        System.arraycopy(elements, to, newElements, from, elements.length - to);
468        elements = newElements;
469    }
470
471    static int lastIndexOf(Object o, Object[] data, int from, int to) {
472        if (o == null) {
473            for (int i = to - 1; i >= from; i--) {
474                if (data[i] == null) {
475                    return i;
476                }
477            }
478        } else {
479            for (int i = to - 1; i >= from; i--) {
480                if (o.equals(data[i])) {
481                    return i;
482                }
483            }
484        }
485        return -1;
486    }
487
488    static int indexOf(Object o, Object[] data, int from, int to) {
489        if (o == null) {
490            for (int i = from; i < to; i++) {
491                if (data[i] == null) {
492                    return i;
493                }
494            }
495        } else {
496            for (int i = from; i < to; i++) {
497                if (o.equals(data[i])) {
498                    return i;
499                }
500            }
501        }
502        return -1;
503    }
504
505    final Object[] getArray() {
506        // CopyOnWriteArraySet needs this.
507        return elements;
508    }
509
510    /**
511     * The sub list is thread safe and supports non-blocking reads. Doing so is
512     * more difficult than in the full list, because each read needs to examine
513     * four fields worth of state:
514     *  - the elements array of the full list
515     *  - two integers for the bounds of this sub list
516     *  - the expected elements array (to detect concurrent modification)
517     *
518     * This is accomplished by aggregating the sub list's three fields into a
519     * single snapshot object representing the current slice. This permits reads
520     * to be internally consistent without synchronization. This takes advantage
521     * of Java's concurrency semantics for final fields.
522     */
523    class CowSubList extends AbstractList<E> {
524
525        /*
526         * An immutable snapshot of a sub list's state. By gathering all three
527         * of the sub list's fields in an immutable object,
528         */
529        private volatile Slice slice;
530
531        public CowSubList(Object[] expectedElements, int from, int to) {
532            this.slice = new Slice(expectedElements, from, to);
533        }
534
535        @Override public int size() {
536            Slice slice = this.slice;
537            return slice.to - slice.from;
538        }
539
540        @Override public boolean isEmpty() {
541            Slice slice = this.slice;
542            return slice.from == slice.to;
543        }
544
545        @SuppressWarnings("unchecked")
546        @Override public E get(int index) {
547            Slice slice = this.slice;
548            Object[] snapshot = elements;
549            slice.checkElementIndex(index);
550            slice.checkConcurrentModification(snapshot);
551            return (E) snapshot[index + slice.from];
552        }
553
554        @Override public Iterator<E> iterator() {
555            return listIterator(0);
556        }
557
558        @Override public ListIterator<E> listIterator() {
559            return listIterator(0);
560        }
561
562        @Override public ListIterator<E> listIterator(int index) {
563            Slice slice = this.slice;
564            Object[] snapshot = elements;
565            slice.checkPositionIndex(index);
566            slice.checkConcurrentModification(snapshot);
567            CowIterator<E> result = new CowIterator<E>(snapshot, slice.from, slice.to);
568            result.index = slice.from + index;
569            return result;
570        }
571
572        @Override public int indexOf(Object object) {
573            Slice slice = this.slice;
574            Object[] snapshot = elements;
575            slice.checkConcurrentModification(snapshot);
576            int result = CopyOnWriteArrayList.indexOf(object, snapshot, slice.from, slice.to);
577            return (result != -1) ? (result - slice.from) : -1;
578        }
579
580        @Override public int lastIndexOf(Object object) {
581            Slice slice = this.slice;
582            Object[] snapshot = elements;
583            slice.checkConcurrentModification(snapshot);
584            int result = CopyOnWriteArrayList.lastIndexOf(object, snapshot, slice.from, slice.to);
585            return (result != -1) ? (result - slice.from) : -1;
586        }
587
588        @Override public boolean contains(Object object) {
589            return indexOf(object) != -1;
590        }
591
592        @Override public boolean containsAll(Collection<?> collection) {
593            Slice slice = this.slice;
594            Object[] snapshot = elements;
595            slice.checkConcurrentModification(snapshot);
596            return CopyOnWriteArrayList.containsAll(collection, snapshot, slice.from, slice.to);
597        }
598
599        @Override public List<E> subList(int from, int to) {
600            Slice slice = this.slice;
601            if (from < 0 || from > to || to > size()) {
602                throw new IndexOutOfBoundsException("from=" + from + ", to=" + to +
603                        ", list size=" + size());
604            }
605            return new CowSubList(slice.expectedElements, slice.from + from, slice.from + to);
606        }
607
608        @Override public E remove(int index) {
609            synchronized (CopyOnWriteArrayList.this) {
610                slice.checkElementIndex(index);
611                slice.checkConcurrentModification(elements);
612                E removed = CopyOnWriteArrayList.this.remove(slice.from + index);
613                slice = new Slice(elements, slice.from, slice.to - 1);
614                return removed;
615            }
616        }
617
618        @Override public void clear() {
619            synchronized (CopyOnWriteArrayList.this) {
620                slice.checkConcurrentModification(elements);
621                CopyOnWriteArrayList.this.removeRange(slice.from, slice.to);
622                slice = new Slice(elements, slice.from, slice.from);
623            }
624        }
625
626        @Override public void add(int index, E object) {
627            synchronized (CopyOnWriteArrayList.this) {
628                slice.checkPositionIndex(index);
629                slice.checkConcurrentModification(elements);
630                CopyOnWriteArrayList.this.add(index + slice.from, object);
631                slice = new Slice(elements, slice.from, slice.to + 1);
632            }
633        }
634
635        @Override public boolean add(E object) {
636            synchronized (CopyOnWriteArrayList.this) {
637                add(slice.to - slice.from, object);
638                return true;
639            }
640        }
641
642        @Override public boolean addAll(int index, Collection<? extends E> collection) {
643            synchronized (CopyOnWriteArrayList.this) {
644                slice.checkPositionIndex(index);
645                slice.checkConcurrentModification(elements);
646                int oldSize = elements.length;
647                boolean result = CopyOnWriteArrayList.this.addAll(index + slice.from, collection);
648                slice = new Slice(elements, slice.from, slice.to + (elements.length - oldSize));
649                return result;
650            }
651        }
652
653        @Override public boolean addAll(Collection<? extends E> collection) {
654            synchronized (CopyOnWriteArrayList.this) {
655                return addAll(size(), collection);
656            }
657        }
658
659        @Override public E set(int index, E object) {
660            synchronized (CopyOnWriteArrayList.this) {
661                slice.checkElementIndex(index);
662                slice.checkConcurrentModification(elements);
663                E result = CopyOnWriteArrayList.this.set(index + slice.from, object);
664                slice = new Slice(elements, slice.from, slice.to);
665                return result;
666            }
667        }
668
669        @Override public boolean remove(Object object) {
670            synchronized (CopyOnWriteArrayList.this) {
671                int index = indexOf(object);
672                if (index == -1) {
673                    return false;
674                }
675                remove(index);
676                return true;
677            }
678        }
679
680        @Override public boolean removeAll(Collection<?> collection) {
681            synchronized (CopyOnWriteArrayList.this) {
682                slice.checkConcurrentModification(elements);
683                int removed = removeOrRetain(collection, false, slice.from, slice.to);
684                slice = new Slice(elements, slice.from, slice.to - removed);
685                return removed != 0;
686            }
687        }
688
689        @Override public boolean retainAll(Collection<?> collection) {
690            synchronized (CopyOnWriteArrayList.this) {
691                slice.checkConcurrentModification(elements);
692                int removed = removeOrRetain(collection, true, slice.from, slice.to);
693                slice = new Slice(elements, slice.from, slice.to - removed);
694                return removed != 0;
695            }
696        }
697
698        @Override
699        public void forEach(Consumer<? super E> action) {
700            CopyOnWriteArrayList.this.forInRange(slice.from, slice.to, action);
701        }
702
703        @Override
704        public void replaceAll(UnaryOperator<E> operator) {
705            synchronized (CopyOnWriteArrayList.this) {
706                slice.checkConcurrentModification(elements);
707                CopyOnWriteArrayList.this.replaceInRange(slice.from, slice.to, operator);
708                slice = new Slice(elements, slice.from, slice.to);
709            }
710        }
711
712        @Override
713        public synchronized void sort(Comparator<? super E> c) {
714            synchronized (CopyOnWriteArrayList.this) {
715                slice.checkConcurrentModification(elements);
716                CopyOnWriteArrayList.this.sortInRange(slice.from, slice.to, c);
717                slice = new Slice(elements, slice.from, slice.to);
718            }
719        }
720    }
721
722    static class Slice {
723        private final Object[] expectedElements;
724        private final int from;
725        private final int to;
726
727        Slice(Object[] expectedElements, int from, int to) {
728            this.expectedElements = expectedElements;
729            this.from = from;
730            this.to = to;
731        }
732
733        /**
734         * Throws if {@code index} doesn't identify an element in the array.
735         */
736        void checkElementIndex(int index) {
737            if (index < 0 || index >= to - from) {
738                throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from));
739            }
740        }
741
742        /**
743         * Throws if {@code index} doesn't identify an insertion point in the
744         * array. Unlike element index, it's okay to add or iterate at size().
745         */
746        void checkPositionIndex(int index) {
747            if (index < 0 || index > to - from) {
748                throw new IndexOutOfBoundsException("index=" + index + ", size=" + (to - from));
749            }
750        }
751
752        void checkConcurrentModification(Object[] snapshot) {
753            if (expectedElements != snapshot) {
754                throw new ConcurrentModificationException();
755            }
756        }
757    }
758
759    /**
760     * Iterates an immutable snapshot of the list.
761     */
762    static class CowIterator<E> implements ListIterator<E> {
763        private final Object[] snapshot;
764        private final int from;
765        private final int to;
766        private int index = 0;
767
768        CowIterator(Object[] snapshot, int from, int to) {
769            this.snapshot = snapshot;
770            this.from = from;
771            this.to = to;
772            this.index = from;
773        }
774
775        public void add(E object) {
776            throw new UnsupportedOperationException();
777        }
778
779        public boolean hasNext() {
780            return index < to;
781        }
782
783        public boolean hasPrevious() {
784            return index > from;
785        }
786
787        @SuppressWarnings("unchecked")
788        public E next() {
789            if (index < to) {
790                return (E) snapshot[index++];
791            } else {
792                throw new NoSuchElementException();
793            }
794        }
795
796        public int nextIndex() {
797            return index;
798        }
799
800        @SuppressWarnings("unchecked")
801        public E previous() {
802            if (index > from) {
803                return (E) snapshot[--index];
804            } else {
805                throw new NoSuchElementException();
806            }
807        }
808
809        public int previousIndex() {
810            return index - 1;
811        }
812
813        public void remove() {
814            throw new UnsupportedOperationException();
815        }
816
817        public void set(E object) {
818            throw new UnsupportedOperationException();
819        }
820
821        @Override
822        public void forEachRemaining(Consumer<? super E> action) {
823            java.util.Objects.requireNonNull(action);
824            Object[] elements = snapshot;
825            for (int i = index; i < to; i++) {
826                @SuppressWarnings("unchecked") E e = (E) elements[i];
827                action.accept(e);
828            }
829            index = to;
830        }
831    }
832
833    private void writeObject(ObjectOutputStream out) throws IOException {
834        Object[] snapshot = elements;
835        out.defaultWriteObject();
836        out.writeInt(snapshot.length);
837        for (Object o : snapshot) {
838            out.writeObject(o);
839        }
840    }
841
842    private synchronized void readObject(ObjectInputStream in)
843            throws IOException, ClassNotFoundException {
844        in.defaultReadObject();
845        Object[] snapshot = new Object[in.readInt()];
846        for (int i = 0; i < snapshot.length; i++) {
847            snapshot[i] = in.readObject();
848        }
849        elements = snapshot;
850    }
851}
852