--- jsr166/src/jsr166x/ConcurrentSkipListSet.java 2004/08/11 10:58:15 1.1
+++ jsr166/src/jsr166x/ConcurrentSkipListSet.java 2004/09/06 17:01:54 1.2
@@ -10,12 +10,12 @@ import java.util.*;
import java.util.concurrent.*;
/**
- * A scalable concurrent {@link SortedSet} and (priority) {@link
- * Queue} implementation based on a {@link ConcurrentSkipListMap}.
- * This class maintains a set in ascending order, sorted according to
- * the natural order for the element's class (see {@link
- * Comparable}), or by the comparator provided at creation time,
- * depending on which constructor is used.
+ * A scalable concurrent {@link NavigableSet} implementation based on
+ * a {@link ConcurrentSkipListMap}. This class maintains a set in
+ * ascending order, sorted according to the natural order for
+ * the element's class (see {@link Comparable}), or by the comparator
+ * provided at creation time, depending on which constructor is
+ * used.
*
* This implementation provides expected average log(n) time
* cost for the contains, add, and remove
@@ -27,25 +27,6 @@ import java.util.concurrent.*;
* ConcurrentModificationException}, and may procede concurrently with
* other operations.
*
- *
This class provides extended SortedSet methods
- * searching for closest matches. Methods lower,
- * floor, ceiling, and higher return
- * elements respectively less, less than or equal, greater than or
- * equal, and greater than a given value, returning null if there is
- * no such element. These methods are designed for locating, not
- * traversing entries. To traverse, use iterators and/or
- * subset.
- *
- *
The class additionally supports {@link Queue} methods such as
- * poll that atomically returns and removes the first
- * element, if one exists. Thus, this class can serve as a priority
- * queue in which there are no duplicate elements.
- *
- *
The {@link ConcurrentSkipListSubSet} objects returned by methods
- * subset, headSet, and tailSet support the
- * same extended set of operations as this class, but operate on their
- * designated subrange of elements.
- *
*
Beware that, unlike in most collections, the size
* method is NOT a constant-time operation. Because of the
* asynchronous nature of these sets, determining the current number
@@ -63,7 +44,7 @@ import java.util.concurrent.*;
*/
public class ConcurrentSkipListSet
extends AbstractSet
- implements SortedSet, Queue, Cloneable, java.io.Serializable {
+ implements NavigableSet, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -2479143111061671589L;
@@ -232,65 +213,6 @@ public class ConcurrentSkipListSet
return m.keyIterator();
}
- /* ---------------- Queue operations -------------- */
-
- /**
- * Adds the specified element, or fails if this element is already
- * present.
- * @param o the element to insert.
- * @return true if it was possible to add the element,
- * else false
- */
- public boolean offer(E o) {
- return add(o);
- }
-
- /**
- * Retrieves and removes the first (lowest) element.
- *
- * @return the least element, or null if empty.
- */
- public E poll() {
- return m.removeFirstKey();
- }
-
- /**
- * Retrieves and removes the first (lowest) element. This method
- * differs from the poll method in that it throws an
- * exception if empty.
- *
- * @return the first (lowest) element.
- * @throws NoSuchElementException if empty.
- */
- public E remove() {
- E x = m.removeFirstKey();
- if (x == null)
- throw new NoSuchElementException();
- return x;
- }
-
- /**
- * Retrieves, but does not remove, the first (lowest) element,
- * returning null if empty.
- *
- * @return the first (lowest) element, or null if empty.
- */
- public E peek() {
- return m.lowestKey();
- }
-
- /**
- * Retrieves, but does not remove, the first (lowest) element.
- * This method differs from the peek method only in that
- * it throws an exception if empty.
- *
- * @return the first (lowest) element.
- * @throws NoSuchElementException if empty.
- */
- public E element() {
- return m.firstKey();
- }
-
/* ---------------- Relational operations -------------- */
/**
@@ -353,6 +275,25 @@ public class ConcurrentSkipListSet
return m.higherKey(o);
}
+ /**
+ * Retrieves and removes the first (lowest) element.
+ *
+ * @return the least element, or null if empty.
+ */
+ public E pollFirst() {
+ return m.removeFirstKey();
+ }
+
+ /**
+ * Retrieves and removes the last (highest) element.
+ *
+ * @return the last element, or null if empty.
+ */
+ public E pollLast() {
+ return m.removeLastKey();
+ }
+
+
/* ---------------- SortedSet operations -------------- */
@@ -408,7 +349,7 @@ public class ConcurrentSkipListSet
* @throws NullPointerException if fromElement or
* toElement is null.
*/
- public ConcurrentSkipListSubSet subSet(E fromElement, E toElement) {
+ public NavigableSet subSet(E fromElement, E toElement) {
return new ConcurrentSkipListSubSet(m, fromElement, toElement);
}
@@ -425,7 +366,7 @@ public class ConcurrentSkipListSet
* if toElement does not implement Comparable).
* @throws NullPointerException if toElement is null.
*/
- public ConcurrentSkipListSubSet headSet(E toElement) {
+ public NavigableSet headSet(E toElement) {
return new ConcurrentSkipListSubSet(m, null, toElement);
}
@@ -444,7 +385,355 @@ public class ConcurrentSkipListSet
* Comparable).
* @throws NullPointerException if fromElement is null.
*/
- public ConcurrentSkipListSubSet tailSet(E fromElement) {
+ public NavigableSet tailSet(E fromElement) {
return new ConcurrentSkipListSubSet(m, fromElement, null);
}
+
+ /**
+ * Subsets returned by {@link ConcurrentSkipListSet} subset operations
+ * represent a subrange of elements of their underlying
+ * sets. Instances of this class support all methods of their
+ * underlying sets, differing in that elements outside their range are
+ * ignored, and attempts to add elements outside their ranges result
+ * in {@link IllegalArgumentException}. Instances of this class are
+ * constructed only using the subSet, headSet, and
+ * tailSet methods of their underlying sets.
+ *
+ */
+ static class ConcurrentSkipListSubSet
+ extends AbstractSet
+ implements NavigableSet, java.io.Serializable {
+
+ private static final long serialVersionUID = -7647078645896651609L;
+
+ /** The underlying submap */
+ private final ConcurrentSkipListMap.ConcurrentSkipListSubMap s;
+
+ /**
+ * Creates a new submap.
+ * @param fromElement inclusive least value, or null if from start
+ * @param toElement exclusive upper bound or null if to end
+ * @throws IllegalArgumentException if fromElement and toElement
+ * nonnull and fromElement greater than toElement
+ */
+ ConcurrentSkipListSubSet(ConcurrentSkipListMap map,
+ E fromElement, E toElement) {
+ s = new ConcurrentSkipListMap.ConcurrentSkipListSubMap(map, fromElement,
+ toElement);
+ }
+
+ /**
+ * Returns the number of elements in this set. If this set
+ * contains more than Integer.MAX_VALUE elements, it
+ * returns Integer.MAX_VALUE.
+ *
+ * Beware that, unlike in most collections, this method is
+ * NOT a constant-time operation. Because of the
+ * asynchronous nature of these sets, determining the current
+ * number of elements requires traversing them all to count them.
+ * Additionally, it is possible for the size to change during
+ * execution of this method, in which case the returned result
+ * will be inaccurate. Thus, this method is typically not very
+ * useful in concurrent applications.
+ *
+ * @return the number of elements in this set.
+ */
+ public int size() {
+ return s.size();
+ }
+
+ /**
+ * Returns true if this set contains no elements.
+ * @return true if this set contains no elements.
+ */
+ public boolean isEmpty() {
+ return s.isEmpty();
+ }
+
+ /**
+ * Returns true if this set contains the specified
+ * element.
+ *
+ * @param o the object to be checked for containment in this
+ * set.
+ * @return true if this set contains the specified
+ * element.
+ *
+ * @throws ClassCastException if the specified object cannot
+ * be compared with the elements currently in the set.
+ * @throws NullPointerException if o is null.
+ */
+ public boolean contains(Object o) {
+ return s.containsKey(o);
+ }
+
+
+ /**
+ * Adds the specified element to this set if it is not already
+ * present.
+ *
+ * @param o element to be added to this set.
+ * @return true if the set did not already contain
+ * the specified element.
+ *
+ * @throws ClassCastException if the specified object cannot
+ * be compared with the elements currently in the set.
+ * @throws IllegalArgumentException if o is outside the range
+ * of this subset.
+ * @throws NullPointerException if o is null.
+ */
+ public boolean add(E o) {
+ return s.put(o, Boolean.TRUE) == null;
+ }
+
+ /**
+ * Removes the specified element from this set if it is
+ * present.
+ *
+ * @param o object to be removed from this set, if present.
+ * @return true if the set contained the specified element.
+ *
+ * @throws ClassCastException if the specified object cannot
+ * be compared with the elements currently in the set.
+ * @throws NullPointerException if o is null.
+ */
+ public boolean remove(Object o) {
+ return s.remove(o) != null;
+ }
+
+ /**
+ * Removes all of the elements from this set.
+ */
+ public void clear() {
+ s.clear();
+ }
+
+ /**
+ * Returns an iterator over the elements in this set. The elements
+ * are returned in ascending order.
+ *
+ * @return an iterator over the elements in this set.
+ */
+ public Iterator iterator() {
+ return s.keySet().iterator();
+ }
+
+ /**
+ * Returns an element greater than or equal to the given
+ * element, or null if there is no such element.
+ *
+ * @param o the value to match
+ * @return an element greater than or equal to given element, or null
+ * if there is no such element.
+ * @throws ClassCastException if o cannot be compared with the
+ * elements currently in the set.
+ * @throws NullPointerException if o is null
+ */
+ public E ceiling(E o) {
+ E key = o;
+ E least = s.getLeast();
+ if (least != null && s.getMap().compare(o, least) < 0)
+ key = least;
+ E k = s.getMap().ceilingKey(key);
+ return (k != null && s.inHalfOpenRange(k))? k : null;
+ }
+
+ /**
+ * Returns an element strictly less than the given element, or null if
+ * there is no such element.
+ *
+ * @param o the value to match
+ * @return the greatest element less than the given element, or
+ * null if there is no such element.
+ * @throws ClassCastException if o cannot be compared with the
+ * elements currently in the set.
+ * @throws NullPointerException if o is null.
+ */
+ public E lower(E o) {
+ E k = s.getMap().lowerKey(o);
+ return (k != null && s.inHalfOpenRange(k))? k : null;
+ }
+
+ /**
+ * Returns an element less than or equal to the given element, or null
+ * if there is no such element.
+ *
+ * @param o the value to match
+ * @return the greatest element less than or equal to given
+ * element, or null if there is no such element.
+ * @throws ClassCastException if o cannot be compared with the
+ * elements currently in the set.
+ * @throws NullPointerException if o is null.
+ */
+ public E floor(E o) {
+ E k = s.getMap().floorKey(o);
+ return (k != null && s.inHalfOpenRange(k))? k : null;
+ }
+
+ /**
+ * Returns an element strictly greater than the given element, or null
+ * if there is no such element.
+ *
+ * @param o the value to match
+ * @return the least element greater than the given element, or
+ * null if there is no such element.
+ * @throws ClassCastException if o cannot be compared with the
+ * elements currently in the set.
+ * @throws NullPointerException if o is null.
+ */
+ public E higher(E o) {
+ E k;
+ E least = s.getLeast();
+ if (least != null && s.getMap().compare(o, least) < 0)
+ k = s.getMap().ceilingKey(least);
+ else
+ k = s.getMap().higherKey(o);
+ return (k != null && s.inHalfOpenRange(k))? k : null;
+ }
+
+ /**
+ * Retrieves and removes the first (lowest) element.
+ *
+ * @return the first element, or null if empty.
+ */
+ public E pollFirst() {
+ for (;;) {
+ E k = s.lowestKey();
+ if (k == null)
+ return null;
+ if (remove(k))
+ return k;
+ }
+ }
+
+ /**
+ * Retrieves and removes the last (highest) element.
+ *
+ * @return the last element, or null if empty.
+ */
+ public E pollLast() {
+ for (;;) {
+ E k = s.highestKey();
+ if (k == null)
+ return null;
+ if (remove(k))
+ return k;
+ }
+ }
+
+ /**
+ * Returns the comparator used to order this set, or null
+ * if this set uses its elements natural ordering.
+ *
+ * @return the comparator used to order this set, or null
+ * if this set uses its elements natural ordering.
+ */
+ public Comparator super E> comparator() {
+ return s.comparator();
+ }
+
+ /**
+ * Returns the first (lowest) element currently in this set.
+ *
+ * @return the first (lowest) element currently in this set.
+ * @throws NoSuchElementException sorted set is empty.
+ */
+ public E first() {
+ return s.firstKey();
+ }
+
+ /**
+ * Returns the last (highest) element currently in this set.
+ *
+ * @return the last (highest) element currently in this set.
+ * @throws NoSuchElementException sorted set is empty.
+ */
+ public E last() {
+ return s.lastKey();
+ }
+
+ /**
+ * Returns a view of the portion of this set whose elements
+ * range from fromElement, inclusive, to
+ * toElement, exclusive. (If fromElement
+ * and toElement are equal, the returned sorted set
+ * is empty.) The returned sorted set is backed by this set,
+ * so changes in the returned sorted set are reflected in this
+ * set, and vice-versa.
+ * @param fromElement low endpoint (inclusive) of the subSet.
+ * @param toElement high endpoint (exclusive) of the subSet.
+ * @return a view of the portion of this set whose elements
+ * range from fromElement, inclusive, to
+ * toElement, exclusive.
+ * @throws ClassCastException if fromElement and
+ * toElement cannot be compared to one another using
+ * this set's comparator (or, if the set has no comparator,
+ * using natural ordering).
+ * @throws IllegalArgumentException if fromElement is
+ * greater than toElement or either key is outside
+ * the range of this set.
+ * @throws NullPointerException if fromElement or
+ * toElement is null.
+ */
+ public NavigableSet subSet(E fromElement,
+ E toElement) {
+ if (!s.inOpenRange(fromElement) || !s.inOpenRange(toElement))
+ throw new IllegalArgumentException("element out of range");
+ return new ConcurrentSkipListSubSet(s.getMap(),
+ fromElement, toElement);
+ }
+
+ /**
+ * Returns a view of the portion of this set whose elements are
+ * strictly less than toElement. The returned sorted set
+ * is backed by this set, so changes in the returned sorted set
+ * are reflected in this set, and vice-versa.
+ * @param toElement high endpoint (exclusive) of the headSet.
+ * @return a view of the portion of this set whose elements
+ * are strictly less than toElement.
+ * @throws ClassCastException if toElement is not
+ * compatible with this set's comparator (or, if the set has
+ * no comparator, if toElement does not implement
+ * Comparable).
+ * @throws IllegalArgumentException if toElement is
+ * outside the range of this set.
+ * @throws NullPointerException if toElement is
+ * null.
+ */
+ public NavigableSet headSet(E toElement) {
+ E least = s.getLeast();
+ if (!s.inOpenRange(toElement))
+ throw new IllegalArgumentException("element out of range");
+ return new ConcurrentSkipListSubSet(s.getMap(),
+ least, toElement);
+ }
+
+ /**
+ * Returns a view of the portion of this set whose elements
+ * are greater than or equal to fromElement. The
+ * returned sorted set is backed by this set, so changes in
+ * the returned sorted set are reflected in this set, and
+ * vice-versa.
+ * @param fromElement low endpoint (inclusive) of the tailSet.
+ * @return a view of the portion of this set whose elements
+ * are greater than or equal to fromElement.
+ * @throws ClassCastException if fromElement is not
+ * compatible with this set's comparator (or, if the set has
+ * no comparator, if fromElement does not implement
+ * Comparable).
+ * @throws IllegalArgumentException if fromElement is
+ * outside the range of this set.
+ * @throws NullPointerException if fromElement is
+ * null.
+ */
+ public NavigableSet tailSet(E fromElement) {
+ E fence = s.getFence();
+ if (!s.inOpenRange(fromElement))
+ throw new IllegalArgumentException("element out of range");
+ return new ConcurrentSkipListSubSet(s.getMap(),
+ fromElement, fence);
+ }
+ }
+
+
}