ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166x/ConcurrentSkipListSet.java
(Generate patch)

Comparing jsr166/src/jsr166x/ConcurrentSkipListSet.java (file contents):
Revision 1.1 by dl, Wed Aug 11 10:58:15 2004 UTC vs.
Revision 1.11 by jsr166, Mon Nov 29 20:58:06 2010 UTC

# Line 4 | Line 4
4   * http://creativecommons.org/licenses/publicdomain
5   */
6  
7 < package jsr166x;
7 > package jsr166x;
8  
9   import java.util.*;
10   import java.util.concurrent.*;
11  
12   /**
13 < * A scalable concurrent {@link SortedSet} and (priority) {@link
14 < * Queue} implementation based on a {@link ConcurrentSkipListMap}.
15 < * This class maintains a set in ascending order, sorted according to
16 < * the <i>natural order</i> for the element's class (see {@link
17 < * Comparable}), or by the comparator provided at creation time,
18 < * depending on which constructor is used.<p>
13 > * A scalable concurrent {@link NavigableSet} implementation based on
14 > * a {@link ConcurrentSkipListMap}.  This class maintains a set in
15 > * ascending order, sorted according to the <i>natural order</i> for
16 > * the element's class (see {@link Comparable}), or by the comparator
17 > * provided at creation time, depending on which constructor is
18 > * used.<p>
19   *
20   * This implementation provides expected average <i>log(n)</i> time
21   * cost for the <tt>contains</tt>, <tt>add</tt>, and <tt>remove</tt>
# Line 24 | Line 24 | import java.util.concurrent.*;
24   * threads. Iterators are <i>weakly consistent</i>, returning elements
25   * reflecting the state of the set at some point at or since the
26   * creation of the iterator.  They do <em>not</em> throw {@link
27 < * ConcurrentModificationException}, and may procede concurrently with
27 > * ConcurrentModificationException}, and may proceed concurrently with
28   * other operations.
29   *
30 * <p>This class provides extended <tt>SortedSet</tt> methods
31 * searching for closest matches. Methods <tt>lower</tt>,
32 * <tt>floor</tt>, <tt>ceiling</tt>, and <tt>higher</tt> return
33 * elements respectively less, less than or equal, greater than or
34 * equal, and greater than a given value, returning null if there is
35 * no such element.  These methods are designed for locating, not
36 * traversing entries. To traverse, use iterators and/or
37 * <tt>subset</tt>.
38 *
39 * <p>The class additionally supports {@link Queue} methods such as
40 * <tt>poll</tt> that atomically returns and removes the first
41 * element, if one exists. Thus, this class can serve as a priority
42 * queue in which there are no duplicate elements.
43 *
44 * <p>The {@link ConcurrentSkipListSubSet} objects returned by methods
45 * <tt>subset</tt>, <tt>headSet</tt>, and <tt>tailSet</tt> support the
46 * same extended set of operations as this class, but operate on their
47 * designated subrange of elements.
48 *
30   * <p>Beware that, unlike in most collections, the <tt>size</tt>
31 < * method is <em>NOT</em> a constant-time operation. Because of the
31 > * method is <em>not</em> a constant-time operation. Because of the
32   * asynchronous nature of these sets, determining the current number
33 < * of elements requires a traversal of the elements.
33 > * of elements requires a traversal of the elements. Additionally, the
34 > * bulk operations <tt>addAll</tt>, <tt>removeAll</tt>,
35 > * <<tt>retainAll</tt>, and tt>containsAll</tt> are <em>not</em>
36 > * guaranteed to be performed atomically. For example, an iterator
37 > * operating concurrently with an <tt>addAll</tt> operation might view
38 > * only some of the added elements.
39   *
40   * <p>This class and its iterators implement all of the
41   * <em>optional</em> methods of the {@link Set} and {@link Iterator}
42   * interfaces. Like most other concurrent collection implementations,
43   * this class does not permit the use of <tt>null</tt> elements.
44 < * because null arguments and return values cannot be reliably
44 > * because <tt>null</tt> arguments and return values cannot be reliably
45   * distinguished from the absence of elements.
46   *
47   * @author Doug Lea
# Line 63 | Line 49 | import java.util.concurrent.*;
49   */
50   public class ConcurrentSkipListSet<E>
51      extends AbstractSet<E>
52 <    implements SortedSet<E>, Queue<E>, Cloneable, java.io.Serializable {
52 >    implements NavigableSet<E>, Cloneable, java.io.Serializable {
53  
54      private static final long serialVersionUID = -2479143111061671589L;
55  
# Line 74 | Line 60 | public class ConcurrentSkipListSet<E>
60       * fields of underlying map, but enables this field to be declared
61       * final, which is necessary for thread safety.
62       */
63 <    private final ConcurrentSkipListMap<E,Object> m;
63 >    private final ConcurrentSkipListMap<E,Object> m;
64  
65      /**
66       * Constructs a new, empty set, sorted according to the elements' natural
67 <     * order.
67 >     * order.
68       */
69      public ConcurrentSkipListSet() {
70          m = new ConcurrentSkipListMap<E,Object>();
# Line 86 | Line 72 | public class ConcurrentSkipListSet<E>
72  
73      /**
74       * Constructs a new, empty set, sorted according to the specified
75 <     * comparator.  
75 >     * comparator.
76       *
77       * @param c the comparator that will be used to sort this set.  A
78       *        <tt>null</tt> value indicates that the elements' <i>natural
# Line 104 | Line 90 | public class ConcurrentSkipListSet<E>
90       *
91       * @throws ClassCastException if the elements in the specified
92       * collection are not comparable, or are not mutually comparable.
93 <     * @throws NullPointerException if the specified collection is null.
93 >     * @throws NullPointerException if the specified collection is
94 >     * <tt>null</tt>.
95       */
96      public ConcurrentSkipListSet(Collection<? extends E> c) {
97          m = new ConcurrentSkipListMap<E,Object>();
# Line 116 | Line 103 | public class ConcurrentSkipListSet<E>
103       * sorted set, sorted according to the same ordering.
104       *
105       * @param s sorted set whose elements will comprise the new set.
106 <     * @throws NullPointerException if the specified sorted set is null.
106 >     * @throws NullPointerException if the specified sorted set is
107 >     * <tt>null</tt>.
108       */
109      public ConcurrentSkipListSet(SortedSet<E> s) {
110          m = new ConcurrentSkipListMap<E,Object>(s.comparator());
# Line 131 | Line 119 | public class ConcurrentSkipListSet<E>
119       */
120      public Object clone() {
121          ConcurrentSkipListSet<E> clone = null;
122 <        try {
123 <            clone = (ConcurrentSkipListSet<E>) super.clone();
124 <        } catch (CloneNotSupportedException e) {
125 <            throw new InternalError();
126 <        }
122 >        try {
123 >            clone = (ConcurrentSkipListSet<E>) super.clone();
124 >        } catch (CloneNotSupportedException e) {
125 >            throw new InternalError();
126 >        }
127  
128          clone.m.initialize();
129          clone.addAll(this);
# Line 161 | Line 149 | public class ConcurrentSkipListSet<E>
149       * @return  the number of elements in this set.
150       */
151      public int size() {
152 <        return m.size();
152 >        return m.size();
153      }
154  
155      /**
# Line 169 | Line 157 | public class ConcurrentSkipListSet<E>
157       * @return <tt>true</tt> if this set contains no elements.
158       */
159      public boolean isEmpty() {
160 <        return m.isEmpty();
160 >        return m.isEmpty();
161      }
162  
163      /**
# Line 179 | Line 167 | public class ConcurrentSkipListSet<E>
167       * @return <tt>true</tt> if this set contains the specified element.
168       *
169       * @throws ClassCastException if the specified object cannot be compared
170 <     *            with the elements currently in the set.
170 >     *            with the elements currently in the set.
171       * @throws NullPointerException if o is <tt>null</tt>.
172       */
173      public boolean contains(Object o) {
174 <        return m.containsKey(o);
174 >        return m.containsKey(o);
175      }
176  
177      /**
# Line 194 | Line 182 | public class ConcurrentSkipListSet<E>
182       *         element.
183       *
184       * @throws ClassCastException if the specified object cannot be compared
185 <     *            with the elements currently in the set.
185 >     *            with the elements currently in the set.
186       * @throws NullPointerException if o is <tt>null</tt>.
187       */
188      public boolean add(E o) {
189 <        return m.putIfAbsent(o, Boolean.TRUE) == null;
189 >        return m.putIfAbsent(o, Boolean.TRUE) == null;
190      }
191  
192      /**
# Line 208 | Line 196 | public class ConcurrentSkipListSet<E>
196       * @return <tt>true</tt> if the set contained the specified element.
197       *
198       * @throws ClassCastException if the specified object cannot be compared
199 <     *            with the elements currently in the set.
199 >     *            with the elements currently in the set.
200       * @throws NullPointerException if o is <tt>null</tt>.
201       */
202      public boolean remove(Object o) {
203 <        return m.removep(o);
203 >        return m.removep(o);
204      }
205  
206      /**
207       * Removes all of the elements from this set.
208       */
209      public void clear() {
210 <        m.clear();
210 >        m.clear();
211      }
212  
213      /**
# Line 229 | Line 217 | public class ConcurrentSkipListSet<E>
217       * @return an iterator over the elements in this set.
218       */
219      public Iterator<E> iterator() {
220 <        return m.keyIterator();
220 >        return m.keyIterator();
221      }
234    
235    /* ---------------- Queue operations -------------- */
222  
223      /**
224 <     * Adds the specified element, or fails if this element is already
225 <     * present.
240 <     * @param o the element to insert.
241 <     * @return <tt>true</tt> if it was possible to add the element,
242 <     * else <tt>false</tt>
243 <     */
244 <    public boolean offer(E o) {
245 <        return add(o);
246 <    }
247 <
248 <    /**
249 <     * Retrieves and removes the first (lowest) element.
224 >     * Returns an iterator over the elements in this set.  The elements
225 >     * are returned in descending order.
226       *
227 <     * @return the least element, or <tt>null</tt> if empty.
227 >     * @return an iterator over the elements in this set.
228       */
229 <    public E poll() {
230 <        return m.removeFirstKey();
229 >    public Iterator<E> descendingIterator() {
230 >        return m.descendingKeyIterator();
231      }
232  
233 <    /**
258 <     * Retrieves and removes the first (lowest) element.  This method
259 <     * differs from the <tt>poll</tt> method in that it throws an
260 <     * exception if empty.
261 <     *
262 <     * @return the first (lowest) element.
263 <     * @throws NoSuchElementException if empty.
264 <     */
265 <    public E remove() {
266 <        E x = m.removeFirstKey();
267 <        if (x == null)
268 <            throw new NoSuchElementException();
269 <        return x;
270 <    }
233 >    /* ---------------- AbstractSet Overrides -------------- */
234  
235      /**
236 <     * Retrieves, but does not remove, the first (lowest) element,
237 <     * returning <tt>null</tt> if empty.
238 <     *
239 <     * @return the first (lowest) element, or <tt>null</tt> if empty.
240 <     */
241 <    public E peek() {
242 <        return m.lowestKey();
236 >     * Compares the specified object with this set for equality.  Returns
237 >     * <tt>true</tt> if the specified object is also a set, the two sets
238 >     * have the same size, and every member of the specified set is
239 >     * contained in this set (or equivalently, every member of this set is
240 >     * contained in the specified set).  This definition ensures that the
241 >     * equals method works properly across different implementations of the
242 >     * set interface.
243 >     *
244 >     * @param o Object to be compared for equality with this set.
245 >     * @return <tt>true</tt> if the specified Object is equal to this set.
246 >     */
247 >    public boolean equals(Object o) {
248 >        // Override AbstractSet version to avoid calling size()
249 >        if (o == this)
250 >            return true;
251 >        if (!(o instanceof Set))
252 >            return false;
253 >        Collection c = (Collection) o;
254 >        try {
255 >            return containsAll(c) && c.containsAll(this);
256 >        } catch (ClassCastException unused)   {
257 >            return false;
258 >        } catch (NullPointerException unused) {
259 >            return false;
260 >        }
261      }
262  
263      /**
264 <     * Retrieves, but does not remove, the first (lowest) element.
265 <     * This method differs from the <tt>peek</tt> method only in that
266 <     * it throws an exception if empty.
267 <     *
268 <     * @return the first (lowest) element.
269 <     * @throws NoSuchElementException if empty.
270 <     */
271 <    public E element() {
272 <        return m.firstKey();
273 <    }        
264 >     * Removes from this set all of its elements that are contained in
265 >     * the specified collection.  If the specified collection is also
266 >     * a set, this operation effectively modifies this set so that its
267 >     * value is the <i>asymmetric set difference</i> of the two sets.
268 >     *
269 >     * @param  c collection that defines which elements will be removed from
270 >     *           this set.
271 >     * @return <tt>true</tt> if this set changed as a result of the call.
272 >     *
273 >     * @throws ClassCastException if the types of one or more elements in this
274 >     *            set are incompatible with the specified collection
275 >     * @throws NullPointerException if the specified collection, or any
276 >     * of its elements are <tt>null</tt>.
277 >     */
278 >    public boolean removeAll(Collection<?> c) {
279 >        // Override AbstractSet version to avoid unnecessary call to size()
280 >        boolean modified = false;
281 >        for (Iterator<?> i = c.iterator(); i.hasNext(); )
282 >            if (remove(i.next()))
283 >                modified = true;
284 >        return modified;
285 >    }
286  
287      /* ---------------- Relational operations -------------- */
288  
289      /**
290       * Returns an element greater than or equal to the given element, or
291 <     * null if there is no such element.
292 <     *
291 >     * <tt>null</tt> if there is no such element.
292 >     *
293       * @param o the value to match
294 <     * @return an element greater than or equal to given element, or null
295 <     * if there is no such element.
294 >     * @return an element greater than or equal to given element, or
295 >     * <tt>null</tt> if there is no such element.
296       * @throws ClassCastException if o cannot be compared with the elements
297       *            currently in the set.
298       * @throws NullPointerException if o is <tt>null</tt>
# Line 309 | Line 302 | public class ConcurrentSkipListSet<E>
302      }
303  
304      /**
305 <     * Returns an element strictly less than the given element, or null if
306 <     * there is no such element.
307 <     *
305 >     * Returns an element strictly less than the given element, or
306 >     * <tt>null</tt> if there is no such element.
307 >     *
308       * @param o the value to match
309       * @return the greatest element less than the given element, or
310 <     * null if there is no such element.
310 >     * <tt>null</tt> if there is no such element.
311       * @throws ClassCastException if o cannot be compared with the elements
312       *            currently in the set.
313       * @throws NullPointerException if o is <tt>null</tt>.
# Line 324 | Line 317 | public class ConcurrentSkipListSet<E>
317      }
318  
319      /**
320 <     * Returns an element less than or equal to the given element, or null
321 <     * if there is no such element.
322 <     *
320 >     * Returns an element less than or equal to the given element, or
321 >     * <tt>null</tt> if there is no such element.
322 >     *
323       * @param o the value to match
324       * @return the greatest element less than or equal to given
325 <     * element, or null if there is no such element.
325 >     * element, or <tt>null</tt> if there is no such element.
326       * @throws ClassCastException if o cannot be compared with the elements
327       *            currently in the set.
328       * @throws NullPointerException if o is <tt>null</tt>.
# Line 339 | Line 332 | public class ConcurrentSkipListSet<E>
332      }
333  
334      /**
335 <     * Returns an element strictly greater than the given element, or null
336 <     * if there is no such element.
337 <     *
335 >     * Returns an element strictly greater than the given element, or
336 >     * <tt>null</tt> if there is no such element.
337 >     *
338       * @param o the value to match
339       * @return the least element greater than the given element, or
340 <     * null if there is no such element.
340 >     * <tt>null</tt> if there is no such element.
341       * @throws ClassCastException if o cannot be compared with the elements
342       *            currently in the set.
343       * @throws NullPointerException if o is <tt>null</tt>.
# Line 353 | Line 346 | public class ConcurrentSkipListSet<E>
346          return m.higherKey(o);
347      }
348  
349 +    /**
350 +     * Retrieves and removes the first (lowest) element.
351 +     *
352 +     * @return the least element, or <tt>null</tt> if empty.
353 +     */
354 +    public E pollFirst() {
355 +        return m.pollFirstKey();
356 +    }
357 +
358 +    /**
359 +     * Retrieves and removes the last (highest) element.
360 +     *
361 +     * @return the last element, or <tt>null</tt> if empty.
362 +     */
363 +    public E pollLast() {
364 +        return m.pollLastKey();
365 +    }
366 +
367 +
368      /* ---------------- SortedSet operations -------------- */
369  
370  
# Line 387 | Line 399 | public class ConcurrentSkipListSet<E>
399          return m.lastKey();
400      }
401  
402 +
403 +
404      /**
405       * Returns a view of the portion of this set whose elements range from
406       * <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>, exclusive.  (If
407       * <tt>fromElement</tt> and <tt>toElement</tt> are equal, the returned
408       * sorted set is empty.)  The returned sorted set is backed by this set,
409       * so changes in the returned sorted set are reflected in this set, and
410 <     * vice-versa.
410 >     * vice-versa.
411       * @param fromElement low endpoint (inclusive) of the subSet.
412       * @param toElement high endpoint (exclusive) of the subSet.
413       * @return a view of the portion of this set whose elements range from
414 <     *         <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>,
415 <     *         exclusive.
414 >     *         <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>,
415 >     *         exclusive.
416       * @throws ClassCastException if <tt>fromElement</tt> and
417       *         <tt>toElement</tt> cannot be compared to one another using
418       *         this set's comparator (or, if the set has no comparator,
# Line 406 | Line 420 | public class ConcurrentSkipListSet<E>
420       * @throws IllegalArgumentException if <tt>fromElement</tt> is
421       * greater than <tt>toElement</tt>.
422       * @throws NullPointerException if <tt>fromElement</tt> or
423 <     *         <tt>toElement</tt> is <tt>null</tt>.
423 >     *         <tt>toElement</tt> is <tt>null</tt>.
424       */
425 <    public ConcurrentSkipListSubSet<E> subSet(E fromElement, E toElement) {
426 <        return new ConcurrentSkipListSubSet<E>(m, fromElement, toElement);
425 >    public NavigableSet<E> subSet(E fromElement, E toElement) {
426 >        return new ConcurrentSkipListSubSet<E>(m, fromElement, toElement);
427      }
428  
429      /**
430       * Returns a view of the portion of this set whose elements are strictly
431       * less than <tt>toElement</tt>.  The returned sorted set is backed by
432       * this set, so changes in the returned sorted set are reflected in this
433 <     * set, and vice-versa.  
433 >     * set, and vice-versa.
434       * @param toElement high endpoint (exclusive) of the headSet.
435       * @return a view of the portion of this set whose elements are strictly
436 <     *         less than toElement.
436 >     *         less than toElement.
437       * @throws ClassCastException if <tt>toElement</tt> is not compatible
438       *         with this set's comparator (or, if the set has no comparator,
439       *         if <tt>toElement</tt> does not implement <tt>Comparable</tt>).
440       * @throws NullPointerException if <tt>toElement</tt> is <tt>null</tt>.
441       */
442 <    public ConcurrentSkipListSubSet<E> headSet(E toElement) {
443 <        return new ConcurrentSkipListSubSet<E>(m, null, toElement);
442 >    public NavigableSet<E> headSet(E toElement) {
443 >        return new ConcurrentSkipListSubSet<E>(m, null, toElement);
444      }
445  
446  
# Line 444 | Line 458 | public class ConcurrentSkipListSet<E>
458       * <tt>Comparable</tt>).
459       * @throws NullPointerException if <tt>fromElement</tt> is <tt>null</tt>.
460       */
461 <    public ConcurrentSkipListSubSet<E> tailSet(E fromElement) {
462 <        return new ConcurrentSkipListSubSet<E>(m, fromElement, null);
461 >    public NavigableSet<E> tailSet(E fromElement) {
462 >        return new ConcurrentSkipListSubSet<E>(m, fromElement, null);
463 >    }
464 >
465 >    /**
466 >     * Subsets returned by {@link ConcurrentSkipListSet} subset operations
467 >     * represent a subrange of elements of their underlying
468 >     * sets. Instances of this class support all methods of their
469 >     * underlying sets, differing in that elements outside their range are
470 >     * ignored, and attempts to add elements outside their ranges result
471 >     * in {@link IllegalArgumentException}.  Instances of this class are
472 >     * constructed only using the <tt>subSet</tt>, <tt>headSet</tt>, and
473 >     * <tt>tailSet</tt> methods of their underlying sets.
474 >     *
475 >     */
476 >    static class ConcurrentSkipListSubSet<E>
477 >        extends AbstractSet<E>
478 >        implements NavigableSet<E>, java.io.Serializable {
479 >
480 >        private static final long serialVersionUID = -7647078645896651609L;
481 >
482 >        /** The underlying submap  */
483 >        private final ConcurrentSkipListMap.ConcurrentSkipListSubMap<E,Object> s;
484 >
485 >        /**
486 >         * Creates a new submap.
487 >         * @param fromElement inclusive least value, or <tt>null</tt> if from start
488 >         * @param toElement exclusive upper bound or <tt>null</tt> if to end
489 >         * @throws IllegalArgumentException if fromElement and toElement
490 >         * non-null and fromElement greater than toElement
491 >         */
492 >        ConcurrentSkipListSubSet(ConcurrentSkipListMap<E,Object> map,
493 >                                 E fromElement, E toElement) {
494 >            s = new ConcurrentSkipListMap.ConcurrentSkipListSubMap<E,Object>
495 >                (map, fromElement, toElement);
496 >        }
497 >
498 >        // subsubset construction
499 >
500 >        public NavigableSet<E> subSet(E fromElement, E toElement) {
501 >            if (!s.inOpenRange(fromElement) || !s.inOpenRange(toElement))
502 >                throw new IllegalArgumentException("element out of range");
503 >            return new ConcurrentSkipListSubSet<E>(s.getMap(),
504 >                                                   fromElement, toElement);
505 >        }
506 >
507 >        public NavigableSet<E> headSet(E toElement) {
508 >            E least = s.getLeast();
509 >            if (!s.inOpenRange(toElement))
510 >                throw new IllegalArgumentException("element out of range");
511 >            return new ConcurrentSkipListSubSet<E>(s.getMap(),
512 >                                                   least, toElement);
513 >        }
514 >
515 >        public NavigableSet<E> tailSet(E fromElement) {
516 >            E fence = s.getFence();
517 >            if (!s.inOpenRange(fromElement))
518 >                throw new IllegalArgumentException("element out of range");
519 >            return new ConcurrentSkipListSubSet<E>(s.getMap(),
520 >                                                   fromElement, fence);
521 >        }
522 >
523 >        // relays to submap methods
524 >
525 >        public int size()                 { return s.size(); }
526 >        public boolean isEmpty()          { return s.isEmpty(); }
527 >        public boolean contains(Object o) { return s.containsKey(o); }
528 >        public void clear()               { s.clear(); }
529 >        public E first()                  { return s.firstKey(); }
530 >        public E last()                   { return s.lastKey(); }
531 >        public E ceiling(E o)             { return s.ceilingKey(o); }
532 >        public E lower(E o)               { return s.lowerKey(o); }
533 >        public E floor(E o)               { return s.floorKey(o); }
534 >        public E higher(E o)              { return s.higherKey(o); }
535 >        public boolean remove(Object o) { return s.remove(o)==Boolean.TRUE; }
536 >        public boolean add(E o)       { return s.put(o, Boolean.TRUE)==null; }
537 >        public Comparator<? super E> comparator() { return s.comparator(); }
538 >        public Iterator<E> iterator()     { return s.keySet().iterator(); }
539 >        public Iterator<E> descendingIterator() {
540 >            return s.descendingKeySet().iterator();
541 >        }
542 >        public E pollFirst() {
543 >            Map.Entry<E,?> e = s.pollFirstEntry();
544 >            return (e == null) ? null : e.getKey();
545 >        }
546 >        public E pollLast() {
547 >            Map.Entry<E,?> e = s.pollLastEntry();
548 >            return (e == null) ? null : e.getKey();
549 >        }
550 >
551      }
552 < }    
552 > }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines