1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */

24
25 /*
26  * This file is available under and governed by the GNU General Public
27  * License version 2 only, as published by the Free Software Foundation.
28  * However, the following notice accompanied the original version of this
29  * file:
30  *
31  * Written by Doug Lea with assistance from members of JCP JSR-166
32  * Expert Group and released to the public domain, as explained at
33  * http://creativecommons.org/publicdomain/zero/1.0/
34  */

35
36 package java.util.concurrent;
37
38 import java.lang.reflect.Field;
39 import java.util.AbstractSet;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.Comparator;
43 import java.util.Iterator;
44 import java.util.Map;
45 import java.util.NavigableSet;
46 import java.util.Set;
47 import java.util.SortedSet;
48 import java.util.Spliterator;
49
50 /**
51  * A scalable concurrent {@link NavigableSet} implementation based on
52  * a {@link ConcurrentSkipListMap}.  The elements of the set are kept
53  * sorted according to their {@linkplain Comparable natural ordering},
54  * or by a {@link Comparator} provided at set creation time, depending
55  * on which constructor is used.
56  *
57  * <p>This implementation provides expected average <i>log(n)</i> time
58  * cost for the {@code contains}, {@code add}, and {@code remove}
59  * operations and their variants.  Insertion, removal, and access
60  * operations safely execute concurrently by multiple threads.
61  *
62  * <p>Iterators and spliterators are
63  * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
64  *
65  * <p>Ascending ordered views and their iterators are faster than
66  * descending ones.
67  *
68  * <p>Beware that, unlike in most collections, the {@code size}
69  * method is <em>not</em> a constant-time operation. Because of the
70  * asynchronous nature of these sets, determining the current number
71  * of elements requires a traversal of the elements, and so may report
72  * inaccurate results if this collection is modified during traversal.
73  *
74  * <p>Bulk operations that add, remove, or examine multiple elements,
75  * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
76  * are <em>not</em> guaranteed to be performed atomically.
77  * For example, a {@code forEach} traversal concurrent with an {@code
78  * addAll} operation might observe only some of the added elements.
79  *
80  * <p>This class and its iterators implement all of the
81  * <em>optional</em> methods of the {@link Set} and {@link Iterator}
82  * interfaces. Like most other concurrent collection implementations,
83  * this class does not permit the use of {@code null} elements,
84  * because {@code null} arguments and return values cannot be reliably
85  * distinguished from the absence of elements.
86  *
87  * <p>This class is a member of the
88  * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
89  * Java Collections Framework</a>.
90  *
91  * @author Doug Lea
92  * @param <E> the type of elements maintained by this set
93  * @since 1.6
94  */

95 public class ConcurrentSkipListSet<E>
96     extends AbstractSet<E>
97     implements NavigableSet<E>, Cloneable, java.io.Serializable {
98
99     private static final long serialVersionUID = -2479143111061671589L;
100
101     /**
102      * The underlying map. Uses Boolean.TRUE as value for each
103      * element.  This field is declared final for the sake of thread
104      * safety, which entails some ugliness in clone().
105      */

106     private final ConcurrentNavigableMap<E,Object> m;
107
108     /**
109      * Constructs a new, empty set that orders its elements according to
110      * their {@linkplain Comparable natural ordering}.
111      */

112     public ConcurrentSkipListSet() {
113         m = new ConcurrentSkipListMap<E,Object>();
114     }
115
116     /**
117      * Constructs a new, empty set that orders its elements according to
118      * the specified comparator.
119      *
120      * @param comparator the comparator that will be used to order this set.
121      *        If {@code null}, the {@linkplain Comparable natural
122      *        ordering} of the elements will be used.
123      */

124     public ConcurrentSkipListSet(Comparator<? super E> comparator) {
125         m = new ConcurrentSkipListMap<E,Object>(comparator);
126     }
127
128     /**
129      * Constructs a new set containing the elements in the specified
130      * collection, that orders its elements according to their
131      * {@linkplain Comparable natural ordering}.
132      *
133      * @param c The elements that will comprise the new set
134      * @throws ClassCastException if the elements in {@code c} are
135      *         not {@link Comparable}, or are not mutually comparable
136      * @throws NullPointerException if the specified collection or any
137      *         of its elements are null
138      */

139     public ConcurrentSkipListSet(Collection<? extends E> c) {
140         m = new ConcurrentSkipListMap<E,Object>();
141         addAll(c);
142     }
143
144     /**
145      * Constructs a new set containing the same elements and using the
146      * same ordering as the specified sorted set.
147      *
148      * @param s sorted set whose elements will comprise the new set
149      * @throws NullPointerException if the specified sorted set or any
150      *         of its elements are null
151      */

152     public ConcurrentSkipListSet(SortedSet<E> s) {
153         m = new ConcurrentSkipListMap<E,Object>(s.comparator());
154         addAll(s);
155     }
156
157     /**
158      * For use by submaps
159      */

160     ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
161         this.m = m;
162     }
163
164     /**
165      * Returns a shallow copy of this {@code ConcurrentSkipListSet}
166      * instance. (The elements themselves are not cloned.)
167      *
168      * @return a shallow copy of this set
169      */

170     public ConcurrentSkipListSet<E> clone() {
171         try {
172             @SuppressWarnings("unchecked")
173             ConcurrentSkipListSet<E> clone =
174                 (ConcurrentSkipListSet<E>) super.clone();
175             clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
176             return clone;
177         } catch (CloneNotSupportedException e) {
178             throw new InternalError();
179         }
180     }
181
182     /* ---------------- Set operations -------------- */
183
184     /**
185      * Returns the number of elements in this set.  If this set
186      * contains more than {@code Integer.MAX_VALUE} elements, it
187      * returns {@code Integer.MAX_VALUE}.
188      *
189      * <p>Beware that, unlike in most collections, this method is
190      * <em>NOT</em> a constant-time operation. Because of the
191      * asynchronous nature of these sets, determining the current
192      * number of elements requires traversing them all to count them.
193      * Additionally, it is possible for the size to change during
194      * execution of this method, in which case the returned result
195      * will be inaccurate. Thus, this method is typically not very
196      * useful in concurrent applications.
197      *
198      * @return the number of elements in this set
199      */

200     public int size() {
201         return m.size();
202     }
203
204     /**
205      * Returns {@code trueif this set contains no elements.
206      * @return {@code trueif this set contains no elements
207      */

208     public boolean isEmpty() {
209         return m.isEmpty();
210     }
211
212     /**
213      * Returns {@code trueif this set contains the specified element.
214      * More formally, returns {@code trueif and only if this set
215      * contains an element {@code e} such that {@code o.equals(e)}.
216      *
217      * @param o object to be checked for containment in this set
218      * @return {@code trueif this set contains the specified element
219      * @throws ClassCastException if the specified element cannot be
220      *         compared with the elements currently in this set
221      * @throws NullPointerException if the specified element is null
222      */

223     public boolean contains(Object o) {
224         return m.containsKey(o);
225     }
226
227     /**
228      * Adds the specified element to this set if it is not already present.
229      * More formally, adds the specified element {@code e} to this set if
230      * the set contains no element {@code e2} such that {@code e.equals(e2)}.
231      * If this set already contains the element, the call leaves the set
232      * unchanged and returns {@code false}.
233      *
234      * @param e element to be added to this set
235      * @return {@code trueif this set did not already contain the
236      *         specified element
237      * @throws ClassCastException if {@code e} cannot be compared
238      *         with the elements currently in this set
239      * @throws NullPointerException if the specified element is null
240      */

241     public boolean add(E e) {
242         return m.putIfAbsent(e, Boolean.TRUE) == null;
243     }
244
245     /**
246      * Removes the specified element from this set if it is present.
247      * More formally, removes an element {@code e} such that
248      * {@code o.equals(e)}, if this set contains such an element.
249      * Returns {@code trueif this set contained the element (or
250      * equivalently, if this set changed as a result of the call).
251      * (This set will not contain the element once the call returns.)
252      *
253      * @param o object to be removed from this set, if present
254      * @return {@code trueif this set contained the specified element
255      * @throws ClassCastException if {@code o} cannot be compared
256      *         with the elements currently in this set
257      * @throws NullPointerException if the specified element is null
258      */

259     public boolean remove(Object o) {
260         return m.remove(o, Boolean.TRUE);
261     }
262
263     /**
264      * Removes all of the elements from this set.
265      */

266     public void clear() {
267         m.clear();
268     }
269
270     /**
271      * Returns an iterator over the elements in this set in ascending order.
272      *
273      * @return an iterator over the elements in this set in ascending order
274      */

275     public Iterator<E> iterator() {
276         return m.navigableKeySet().iterator();
277     }
278
279     /**
280      * Returns an iterator over the elements in this set in descending order.
281      *
282      * @return an iterator over the elements in this set in descending order
283      */

284     public Iterator<E> descendingIterator() {
285         return m.descendingKeySet().iterator();
286     }
287
288
289     /* ---------------- AbstractSet Overrides -------------- */
290
291     /**
292      * Compares the specified object with this set for equality.  Returns
293      * {@code trueif the specified object is also a set, the two sets
294      * have the same size, and every member of the specified set is
295      * contained in this set (or equivalently, every member of this set is
296      * contained in the specified set).  This definition ensures that the
297      * equals method works properly across different implementations of the
298      * set interface.
299      *
300      * @param o the object to be compared for equality with this set
301      * @return {@code trueif the specified object is equal to this set
302      */

303     public boolean equals(Object o) {
304         // Override AbstractSet version to avoid calling size()
305         if (o == this)
306             return true;
307         if (!(o instanceof Set))
308             return false;
309         Collection<?> c = (Collection<?>) o;
310         try {
311             return containsAll(c) && c.containsAll(this);
312         } catch (ClassCastException | NullPointerException unused) {
313             return false;
314         }
315     }
316
317     /**
318      * Removes from this set all of its elements that are contained in
319      * the specified collection.  If the specified collection is also
320      * a set, this operation effectively modifies this set so that its
321      * value is the <i>asymmetric set difference</i> of the two sets.
322      *
323      * @param  c collection containing elements to be removed from this set
324      * @return {@code trueif this set changed as a result of the call
325      * @throws ClassCastException if the class of an element of this set
326      *         is incompatible with the specified collection
327      * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
328      * @throws NullPointerException if the specified collection or any
329      *         of its elements are null
330      */

331     public boolean removeAll(Collection<?> c) {
332         // Override AbstractSet version to avoid unnecessary call to size()
333         boolean modified = false;
334         for (Object e : c)
335             if (remove(e))
336                 modified = true;
337         return modified;
338     }
339
340     /* ---------------- Relational operations -------------- */
341
342     /**
343      * @throws ClassCastException {@inheritDoc}
344      * @throws NullPointerException if the specified element is null
345      */

346     public E lower(E e) {
347         return m.lowerKey(e);
348     }
349
350     /**
351      * @throws ClassCastException {@inheritDoc}
352      * @throws NullPointerException if the specified element is null
353      */

354     public E floor(E e) {
355         return m.floorKey(e);
356     }
357
358     /**
359      * @throws ClassCastException {@inheritDoc}
360      * @throws NullPointerException if the specified element is null
361      */

362     public E ceiling(E e) {
363         return m.ceilingKey(e);
364     }
365
366     /**
367      * @throws ClassCastException {@inheritDoc}
368      * @throws NullPointerException if the specified element is null
369      */

370     public E higher(E e) {
371         return m.higherKey(e);
372     }
373
374     public E pollFirst() {
375         Map.Entry<E,Object> e = m.pollFirstEntry();
376         return (e == null) ? null : e.getKey();
377     }
378
379     public E pollLast() {
380         Map.Entry<E,Object> e = m.pollLastEntry();
381         return (e == null) ? null : e.getKey();
382     }
383
384
385     /* ---------------- SortedSet operations -------------- */
386
387     public Comparator<? super E> comparator() {
388         return m.comparator();
389     }
390
391     /**
392      * @throws java.util.NoSuchElementException {@inheritDoc}
393      */

394     public E first() {
395         return m.firstKey();
396     }
397
398     /**
399      * @throws java.util.NoSuchElementException {@inheritDoc}
400      */

401     public E last() {
402         return m.lastKey();
403     }
404
405     /**
406      * @throws ClassCastException {@inheritDoc}
407      * @throws NullPointerException if {@code fromElement} or
408      *         {@code toElement} is null
409      * @throws IllegalArgumentException {@inheritDoc}
410      */

411     public NavigableSet<E> subSet(E fromElement,
412                                   boolean fromInclusive,
413                                   E toElement,
414                                   boolean toInclusive) {
415         return new ConcurrentSkipListSet<E>
416             (m.subMap(fromElement, fromInclusive,
417                       toElement,   toInclusive));
418     }
419
420     /**
421      * @throws ClassCastException {@inheritDoc}
422      * @throws NullPointerException if {@code toElement} is null
423      * @throws IllegalArgumentException {@inheritDoc}
424      */

425     public NavigableSet<E> headSet(E toElement, boolean inclusive) {
426         return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
427     }
428
429     /**
430      * @throws ClassCastException {@inheritDoc}
431      * @throws NullPointerException if {@code fromElement} is null
432      * @throws IllegalArgumentException {@inheritDoc}
433      */

434     public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
435         return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
436     }
437
438     /**
439      * @throws ClassCastException {@inheritDoc}
440      * @throws NullPointerException if {@code fromElement} or
441      *         {@code toElement} is null
442      * @throws IllegalArgumentException {@inheritDoc}
443      */

444     public NavigableSet<E> subSet(E fromElement, E toElement) {
445         return subSet(fromElement, true, toElement, false);
446     }
447
448     /**
449      * @throws ClassCastException {@inheritDoc}
450      * @throws NullPointerException if {@code toElement} is null
451      * @throws IllegalArgumentException {@inheritDoc}
452      */

453     public NavigableSet<E> headSet(E toElement) {
454         return headSet(toElement, false);
455     }
456
457     /**
458      * @throws ClassCastException {@inheritDoc}
459      * @throws NullPointerException if {@code fromElement} is null
460      * @throws IllegalArgumentException {@inheritDoc}
461      */

462     public NavigableSet<E> tailSet(E fromElement) {
463         return tailSet(fromElement, true);
464     }
465
466     /**
467      * Returns a reverse order view of the elements contained in this set.
468      * The descending set is backed by this set, so changes to the set are
469      * reflected in the descending set, and vice-versa.
470      *
471      * <p>The returned set has an ordering equivalent to
472      * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
473      * The expression {@code s.descendingSet().descendingSet()} returns a
474      * view of {@code s} essentially equivalent to {@code s}.
475      *
476      * @return a reverse order view of this set
477      */

478     public NavigableSet<E> descendingSet() {
479         return new ConcurrentSkipListSet<E>(m.descendingMap());
480     }
481
482     /**
483      * Returns a {@link Spliterator} over the elements in this set.
484      *
485      * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
486      * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
487      * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
488      * encounter order that is ascending order.  Overriding implementations
489      * should document the reporting of additional characteristic values.
490      *
491      * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
492      * is {@code nullif the {@linkplain #comparator() set's comparator}
493      * is {@code null}.
494      * Otherwise, the spliterator's comparator is the same as or imposes the
495      * same total ordering as the set's comparator.
496      *
497      * @return a {@code Spliterator} over the elements in this set
498      * @since 1.8
499      */

500     public Spliterator<E> spliterator() {
501         return (m instanceof ConcurrentSkipListMap)
502             ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
503             : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
504     }
505
506     /** Initializes map field; for use in clone. */
507     private void setMap(ConcurrentNavigableMap<E,Object> map) {
508         Field mapField = java.security.AccessController.doPrivileged(
509             (java.security.PrivilegedAction<Field>) () -> {
510                 try {
511                     Field f = ConcurrentSkipListSet.class
512                         .getDeclaredField("m");
513                     f.setAccessible(true);
514                     return f;
515                 } catch (ReflectiveOperationException e) {
516                     throw new Error(e);
517                 }});
518         try {
519             mapField.set(this, map);
520         } catch (IllegalAccessException e) {
521             throw new Error(e);
522         }
523     }
524 }
525