1 /*
2  * Written by Doug Lea with assistance from members of JCP JSR-166
3  * Expert Group and released to the public domain, as explained at
4  * http://creativecommons.org/publicdomain/zero/1.0/
5  */
6 
7 package java.util.concurrent;
8 
9 import java.util.AbstractSet;
10 import java.util.Collection;
11 import java.util.Iterator;
12 import java.util.Objects;
13 import java.util.Set;
14 import java.util.Spliterator;
15 import java.util.Spliterators;
16 import java.util.function.Consumer;
17 import java.util.function.Predicate;
18 
19 // BEGIN android-note
20 // removed link to collections framework docs
21 // fixed framework docs link to "Collection#optional"
22 // END android-note
23 
24 /**
25  * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
26  * for all of its operations.  Thus, it shares the same basic properties:
27  * <ul>
28  *  <li>It is best suited for applications in which set sizes generally
29  *       stay small, read-only operations
30  *       vastly outnumber mutative operations, and you need
31  *       to prevent interference among threads during traversal.
32  *  <li>It is thread-safe.
33  *  <li>Mutative operations ({@code add}, {@code set}, {@code remove}, etc.)
34  *      are expensive since they usually entail copying the entire underlying
35  *      array.
36  *  <li>Iterators do not support the mutative {@code remove} operation.
37  *  <li>Traversal via iterators is fast and cannot encounter
38  *      interference from other threads. Iterators rely on
39  *      unchanging snapshots of the array at the time the iterators were
40  *      constructed.
41  * </ul>
42  *
43  * <p><b>Sample Usage.</b> The following code sketch uses a
44  * copy-on-write set to maintain a set of Handler objects that
45  * perform some action upon state updates.
46  *
47  * <pre> {@code
48  * class Handler { void handle(); ... }
49  *
50  * class X {
51  *   private final CopyOnWriteArraySet<Handler> handlers
52  *     = new CopyOnWriteArraySet<>();
53  *   public void addHandler(Handler h) { handlers.add(h); }
54  *
55  *   private long internalState;
56  *   private synchronized void changeState() { internalState = ...; }
57  *
58  *   public void update() {
59  *     changeState();
60  *     for (Handler handler : handlers)
61  *       handler.handle();
62  *   }
63  * }}</pre>
64  *
65  * @see CopyOnWriteArrayList
66  * @since 1.5
67  * @author Doug Lea
68  * @param <E> the type of elements held in this set
69  */
70 public class CopyOnWriteArraySet<E> extends AbstractSet<E>
71         implements java.io.Serializable {
72     private static final long serialVersionUID = 5457747651344034263L;
73 
74     private final CopyOnWriteArrayList<E> al;
75 
76     /**
77      * Creates an empty set.
78      */
CopyOnWriteArraySet()79     public CopyOnWriteArraySet() {
80         al = new CopyOnWriteArrayList<E>();
81     }
82 
83     /**
84      * Creates a set containing all of the elements of the specified
85      * collection.
86      *
87      * @param c the collection of elements to initially contain
88      * @throws NullPointerException if the specified collection is null
89      */
CopyOnWriteArraySet(Collection<? extends E> c)90     public CopyOnWriteArraySet(Collection<? extends E> c) {
91         if (c.getClass() == CopyOnWriteArraySet.class) {
92             @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
93                 (CopyOnWriteArraySet<E>)c;
94             al = new CopyOnWriteArrayList<E>(cc.al);
95         }
96         else {
97             al = new CopyOnWriteArrayList<E>();
98             al.addAllAbsent(c);
99         }
100     }
101 
102     /**
103      * Returns the number of elements in this set.
104      *
105      * @return the number of elements in this set
106      */
size()107     public int size() {
108         return al.size();
109     }
110 
111     /**
112      * Returns {@code true} if this set contains no elements.
113      *
114      * @return {@code true} if this set contains no elements
115      */
isEmpty()116     public boolean isEmpty() {
117         return al.isEmpty();
118     }
119 
120     /**
121      * Returns {@code true} if this set contains the specified element.
122      * More formally, returns {@code true} if and only if this set
123      * contains an element {@code e} such that {@code Objects.equals(o, e)}.
124      *
125      * @param o element whose presence in this set is to be tested
126      * @return {@code true} if this set contains the specified element
127      */
contains(Object o)128     public boolean contains(Object o) {
129         return al.contains(o);
130     }
131 
132     /**
133      * Returns an array containing all of the elements in this set.
134      * If this set makes any guarantees as to what order its elements
135      * are returned by its iterator, this method must return the
136      * elements in the same order.
137      *
138      * <p>The returned array will be "safe" in that no references to it
139      * are maintained by this set.  (In other words, this method must
140      * allocate a new array even if this set is backed by an array).
141      * The caller is thus free to modify the returned array.
142      *
143      * <p>This method acts as bridge between array-based and collection-based
144      * APIs.
145      *
146      * @return an array containing all the elements in this set
147      */
toArray()148     public Object[] toArray() {
149         return al.toArray();
150     }
151 
152     /**
153      * Returns an array containing all of the elements in this set; the
154      * runtime type of the returned array is that of the specified array.
155      * If the set fits in the specified array, it is returned therein.
156      * Otherwise, a new array is allocated with the runtime type of the
157      * specified array and the size of this set.
158      *
159      * <p>If this set fits in the specified array with room to spare
160      * (i.e., the array has more elements than this set), the element in
161      * the array immediately following the end of the set is set to
162      * {@code null}.  (This is useful in determining the length of this
163      * set <i>only</i> if the caller knows that this set does not contain
164      * any null elements.)
165      *
166      * <p>If this set makes any guarantees as to what order its elements
167      * are returned by its iterator, this method must return the elements
168      * in the same order.
169      *
170      * <p>Like the {@link #toArray()} method, this method acts as bridge between
171      * array-based and collection-based APIs.  Further, this method allows
172      * precise control over the runtime type of the output array, and may,
173      * under certain circumstances, be used to save allocation costs.
174      *
175      * <p>Suppose {@code x} is a set known to contain only strings.
176      * The following code can be used to dump the set into a newly allocated
177      * array of {@code String}:
178      *
179      * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
180      *
181      * Note that {@code toArray(new Object[0])} is identical in function to
182      * {@code toArray()}.
183      *
184      * @param a the array into which the elements of this set are to be
185      *        stored, if it is big enough; otherwise, a new array of the same
186      *        runtime type is allocated for this purpose.
187      * @return an array containing all the elements in this set
188      * @throws ArrayStoreException if the runtime type of the specified array
189      *         is not a supertype of the runtime type of every element in this
190      *         set
191      * @throws NullPointerException if the specified array is null
192      */
toArray(T[] a)193     public <T> T[] toArray(T[] a) {
194         return al.toArray(a);
195     }
196 
197     /**
198      * Removes all of the elements from this set.
199      * The set will be empty after this call returns.
200      */
clear()201     public void clear() {
202         al.clear();
203     }
204 
205     /**
206      * Removes the specified element from this set if it is present.
207      * More formally, removes an element {@code e} such that
208      * {@code Objects.equals(o, e)}, if this set contains such an element.
209      * Returns {@code true} if this set contained the element (or
210      * equivalently, if this set changed as a result of the call).
211      * (This set will not contain the element once the call returns.)
212      *
213      * @param o object to be removed from this set, if present
214      * @return {@code true} if this set contained the specified element
215      */
remove(Object o)216     public boolean remove(Object o) {
217         return al.remove(o);
218     }
219 
220     /**
221      * Adds the specified element to this set if it is not already present.
222      * More formally, adds the specified element {@code e} to this set if
223      * the set contains no element {@code e2} such that
224      * {@code Objects.equals(e, e2)}.
225      * If this set already contains the element, the call leaves the set
226      * unchanged and returns {@code false}.
227      *
228      * @param e element to be added to this set
229      * @return {@code true} if this set did not already contain the specified
230      *         element
231      */
add(E e)232     public boolean add(E e) {
233         return al.addIfAbsent(e);
234     }
235 
236     /**
237      * Returns {@code true} if this set contains all of the elements of the
238      * specified collection.  If the specified collection is also a set, this
239      * method returns {@code true} if it is a <i>subset</i> of this set.
240      *
241      * @param  c collection to be checked for containment in this set
242      * @return {@code true} if this set contains all of the elements of the
243      *         specified collection
244      * @throws NullPointerException if the specified collection is null
245      * @see #contains(Object)
246      */
containsAll(Collection<?> c)247     public boolean containsAll(Collection<?> c) {
248         return (c instanceof Set)
249             ? compareSets(al.getArray(), (Set<?>) c) >= 0
250             : al.containsAll(c);
251     }
252 
253     /**
254      * Tells whether the objects in snapshot (regarded as a set) are a
255      * superset of the given set.
256      *
257      * @return -1 if snapshot is not a superset, 0 if the two sets
258      * contain precisely the same elements, and 1 if snapshot is a
259      * proper superset of the given set
260      */
compareSets(Object[] snapshot, Set<?> set)261     private static int compareSets(Object[] snapshot, Set<?> set) {
262         // Uses O(n^2) algorithm, that is only appropriate for small
263         // sets, which CopyOnWriteArraySets should be.
264         //
265         // Optimize up to O(n) if the two sets share a long common prefix,
266         // as might happen if one set was created as a copy of the other set.
267 
268         final int len = snapshot.length;
269         // Mark matched elements to avoid re-checking
270         final boolean[] matched = new boolean[len];
271 
272         // j is the largest int with matched[i] true for { i | 0 <= i < j }
273         int j = 0;
274         outer: for (Object x : set) {
275             for (int i = j; i < len; i++) {
276                 if (!matched[i] && Objects.equals(x, snapshot[i])) {
277                     matched[i] = true;
278                     if (i == j)
279                         do { j++; } while (j < len && matched[j]);
280                     continue outer;
281                 }
282             }
283             return -1;
284         }
285         return (j == len) ? 0 : 1;
286     }
287 
288     /**
289      * Adds all of the elements in the specified collection to this set if
290      * they're not already present.  If the specified collection is also a
291      * set, the {@code addAll} operation effectively modifies this set so
292      * that its value is the <i>union</i> of the two sets.  The behavior of
293      * this operation is undefined if the specified collection is modified
294      * while the operation is in progress.
295      *
296      * @param  c collection containing elements to be added to this set
297      * @return {@code true} if this set changed as a result of the call
298      * @throws NullPointerException if the specified collection is null
299      * @see #add(Object)
300      */
addAll(Collection<? extends E> c)301     public boolean addAll(Collection<? extends E> c) {
302         return al.addAllAbsent(c) > 0;
303     }
304 
305     /**
306      * Removes from this set all of its elements that are contained in the
307      * specified collection.  If the specified collection is also a set,
308      * this operation effectively modifies this set so that its value is the
309      * <i>asymmetric set difference</i> of the two sets.
310      *
311      * @param  c collection containing elements to be removed from this set
312      * @return {@code true} if this set changed as a result of the call
313      * @throws ClassCastException if the class of an element of this set
314      *         is incompatible with the specified collection
315      * (<a href="../Collection.html#optional-restrictions">optional</a>)
316      * @throws NullPointerException if this set contains a null element and the
317      *         specified collection does not permit null elements
318      * (<a href="../Collection.html#optional-restrictions">optional</a>),
319      *         or if the specified collection is null
320      * @see #remove(Object)
321      */
removeAll(Collection<?> c)322     public boolean removeAll(Collection<?> c) {
323         return al.removeAll(c);
324     }
325 
326     /**
327      * Retains only the elements in this set that are contained in the
328      * specified collection.  In other words, removes from this set all of
329      * its elements that are not contained in the specified collection.  If
330      * the specified collection is also a set, this operation effectively
331      * modifies this set so that its value is the <i>intersection</i> of the
332      * two sets.
333      *
334      * @param  c collection containing elements to be retained in this set
335      * @return {@code true} if this set changed as a result of the call
336      * @throws ClassCastException if the class of an element of this set
337      *         is incompatible with the specified collection
338      * (<a href="../Collection.html#optional-restrictions">optional</a>)
339      * @throws NullPointerException if this set contains a null element and the
340      *         specified collection does not permit null elements
341      * (<a href="../Collection.html#optional-restrictions">optional</a>),
342      *         or if the specified collection is null
343      * @see #remove(Object)
344      */
retainAll(Collection<?> c)345     public boolean retainAll(Collection<?> c) {
346         return al.retainAll(c);
347     }
348 
349     /**
350      * Returns an iterator over the elements contained in this set
351      * in the order in which these elements were added.
352      *
353      * <p>The returned iterator provides a snapshot of the state of the set
354      * when the iterator was constructed. No synchronization is needed while
355      * traversing the iterator. The iterator does <em>NOT</em> support the
356      * {@code remove} method.
357      *
358      * @return an iterator over the elements in this set
359      */
iterator()360     public Iterator<E> iterator() {
361         return al.iterator();
362     }
363 
364     /**
365      * Compares the specified object with this set for equality.
366      * Returns {@code true} if the specified object is the same object
367      * as this object, or if it is also a {@link Set} and the elements
368      * returned by an {@linkplain Set#iterator() iterator} over the
369      * specified set are the same as the elements returned by an
370      * iterator over this set.  More formally, the two iterators are
371      * considered to return the same elements if they return the same
372      * number of elements and for every element {@code e1} returned by
373      * the iterator over the specified set, there is an element
374      * {@code e2} returned by the iterator over this set such that
375      * {@code Objects.equals(e1, e2)}.
376      *
377      * @param o object to be compared for equality with this set
378      * @return {@code true} if the specified object is equal to this set
379      */
equals(Object o)380     public boolean equals(Object o) {
381         return (o == this)
382             || ((o instanceof Set)
383                 && compareSets(al.getArray(), (Set<?>) o) == 0);
384     }
385 
removeIf(Predicate<? super E> filter)386     public boolean removeIf(Predicate<? super E> filter) {
387         return al.removeIf(filter);
388     }
389 
forEach(Consumer<? super E> action)390     public void forEach(Consumer<? super E> action) {
391         al.forEach(action);
392     }
393 
394     /**
395      * Returns a {@link Spliterator} over the elements in this set in the order
396      * in which these elements were added.
397      *
398      * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
399      * {@link Spliterator#DISTINCT}, {@link Spliterator#SIZED}, and
400      * {@link Spliterator#SUBSIZED}.
401      *
402      * <p>The spliterator provides a snapshot of the state of the set
403      * when the spliterator was constructed. No synchronization is needed while
404      * operating on the spliterator.
405      *
406      * @return a {@code Spliterator} over the elements in this set
407      * @since 1.8
408      */
spliterator()409     public Spliterator<E> spliterator() {
410         return Spliterators.spliterator
411             (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
412     }
413 }
414