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