--- jsr166/src/jsr166x/ConcurrentSkipListMap.java 2004/10/16 14:49:45 1.4
+++ jsr166/src/jsr166x/ConcurrentSkipListMap.java 2011/04/27 14:06:30 1.14
@@ -1,10 +1,10 @@
/*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
- * http://creativecommons.org/licenses/publicdomain
+ * http://creativecommons.org/publicdomain/zero/1.0/
*/
-package jsr166x;
+package jsr166x;
import java.util.*;
import java.util.concurrent.*;
@@ -27,7 +27,8 @@ import java.util.concurrent.atomic.*;
* elements reflecting the state of the map at some point at or since
* the creation of the iterator. They do not throw {@link
* ConcurrentModificationException}, and may proceed concurrently with
- * other operations.
+ * other operations. Ascending key ordered views and their iterators
+ * are faster than descending ones.
*
*
All Map.Entry pairs returned by methods in this class
* and its views represent snapshots of mappings at the time they were
@@ -55,11 +56,11 @@ import java.util.concurrent.atomic.*;
*
* @author Doug Lea
* @param the type of keys maintained by this map
- * @param the type of mapped values
+ * @param the type of mapped values
*/
-public class ConcurrentSkipListMap extends AbstractMap
+public class ConcurrentSkipListMap extends AbstractMap
implements ConcurrentNavigableMap,
- Cloneable,
+ Cloneable,
java.io.Serializable {
/*
* This class implements a tree-like two-dimensionally linked skip
@@ -73,19 +74,19 @@ public class ConcurrentSkipListMap
* possible list with 2 levels of index:
*
* Head nodes Index nodes
- * +-+ right +-+ +-+
+ * +-+ right +-+ +-+
* |2|---------------->| |--------------------->| |->null
- * +-+ +-+ +-+
+ * +-+ +-+ +-+
* | down | |
* v v v
- * +-+ +-+ +-+ +-+ +-+ +-+
+ * +-+ +-+ +-+ +-+ +-+ +-+
* |1|----------->| |->| |------>| |----------->| |------>| |->null
- * +-+ +-+ +-+ +-+ +-+ +-+
+ * +-+ +-+ +-+ +-+ +-+ +-+
* v | | | | |
* Nodes next v v v v v
- * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
+ * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
* | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null
- * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
+ * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
*
* The base lists use a variant of the HM linked ordered set
* algorithm. See Tim Harris, "A pragmatic implementation of
@@ -144,9 +145,9 @@ public class ConcurrentSkipListMap
* Here's the sequence of events for a deletion of node n with
* predecessor b and successor f, initially:
*
- * +------+ +------+ +------+
+ * +------+ +------+ +------+
* ... | b |------>| n |----->| f | ...
- * +------+ +------+ +------+
+ * +------+ +------+ +------+
*
* 1. CAS n's value field from non-null to null.
* From this point on, no public operations encountering
@@ -160,15 +161,15 @@ public class ConcurrentSkipListMap
*
* +------+ +------+ +------+ +------+
* ... | b |------>| n |----->|marker|------>| f | ...
- * +------+ +------+ +------+ +------+
+ * +------+ +------+ +------+ +------+
*
* 3. CAS b's next pointer over both n and its marker.
* From this point on, no new traversals will encounter n,
* and it can eventually be GCed.
* +------+ +------+
* ... | b |----------------------------------->| f | ...
- * +------+ +------+
- *
+ * +------+ +------+
+ *
* A failure at step 1 leads to simple retry due to a lost race
* with another operation. Steps 2-3 can fail because some other
* thread noticed during a traversal a node with null value and
@@ -187,7 +188,7 @@ public class ConcurrentSkipListMap
* nodes. This doesn't change the basic algorithm except for the
* need to make sure base traversals start at predecessors (here,
* b) that are not (structurally) deleted, otherwise retrying
- * after processing the deletion.
+ * after processing the deletion.
*
* Index levels are maintained as lists with volatile next fields,
* using CAS to link and unlink. Races are allowed in index-list
@@ -265,8 +266,8 @@ public class ConcurrentSkipListMap
* For explanation of algorithms sharing at least a couple of
* features with this one, see Mikhail Fomitchev's thesis
* (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
- * (http://www.cl.cam.ac.uk/users/kaf24/), and papers by
- * Håkan Sundell (http://www.cs.chalmers.se/~phs/).
+ * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
+ * thesis (http://www.cs.chalmers.se/~phs/).
*
* Given the use of tree-like index nodes, you might wonder why
* this doesn't use some kind of search tree instead, which would
@@ -291,11 +292,11 @@ public class ConcurrentSkipListMap
/**
* Special value used to identify base-level header
- */
+ */
private static final Object BASE_HEADER = new Object();
/**
- * The topmost head index of the skiplist.
+ * The topmost head index of the skiplist.
*/
private transient volatile HeadIndex head;
@@ -318,6 +319,10 @@ public class ConcurrentSkipListMap
private transient EntrySet entrySet;
/** Lazily initialized values collection */
private transient Values values;
+ /** Lazily initialized descending key set */
+ private transient DescendingKeySet descendingKeySet;
+ /** Lazily initialized descending entry set */
+ private transient DescendingEntrySet descendingEntrySet;
/**
* Initialize or reset state. Needed by constructors, clone,
@@ -326,16 +331,18 @@ public class ConcurrentSkipListMap
*/
final void initialize() {
keySet = null;
- entrySet = null;
+ entrySet = null;
values = null;
+ descendingEntrySet = null;
+ descendingKeySet = null;
randomSeed = (int) System.nanoTime();
head = new HeadIndex(new Node(null, BASE_HEADER, null),
null, null, 1);
}
/** Updater for casHead */
- private static final
- AtomicReferenceFieldUpdater
+ private static final
+ AtomicReferenceFieldUpdater
headUpdater = AtomicReferenceFieldUpdater.newUpdater
(ConcurrentSkipListMap.class, HeadIndex.class, "head");
@@ -383,16 +390,15 @@ public class ConcurrentSkipListMap
}
/** Updater for casNext */
- static final AtomicReferenceFieldUpdater
+ static final AtomicReferenceFieldUpdater
nextUpdater = AtomicReferenceFieldUpdater.newUpdater
(Node.class, Node.class, "next");
/** Updater for casValue */
- static final AtomicReferenceFieldUpdater
+ static final AtomicReferenceFieldUpdater
valueUpdater = AtomicReferenceFieldUpdater.newUpdater
(Node.class, Object.class, "value");
-
/**
* compareAndSet value field
*/
@@ -460,7 +466,7 @@ public class ConcurrentSkipListMap
/**
* Return value if this node contains a valid key-value pair,
- * else null.
+ * else null.
* @return this node's value if it isn't a marker or header or
* is deleted, else null.
*/
@@ -502,7 +508,7 @@ public class ConcurrentSkipListMap
/**
* Creates index node with given values
- */
+ */
Index(Node node, Index down, Index right) {
this.node = node;
this.key = node.key;
@@ -511,7 +517,7 @@ public class ConcurrentSkipListMap
}
/** Updater for casRight */
- static final AtomicReferenceFieldUpdater
+ static final AtomicReferenceFieldUpdater
rightUpdater = AtomicReferenceFieldUpdater.newUpdater
(Index.class, Index.class, "right");
@@ -540,7 +546,7 @@ public class ConcurrentSkipListMap
*/
final boolean link(Index succ, Index newSucc) {
Node n = node;
- newSucc.right = succ;
+ newSucc.right = succ;
return n.value != null && casRight(succ, newSucc);
}
@@ -567,7 +573,7 @@ public class ConcurrentSkipListMap
super(node, down, right);
this.level = level;
}
- }
+ }
/* ---------------- Map.Entry support -------------- */
@@ -575,10 +581,10 @@ public class ConcurrentSkipListMap
* An immutable representation of a key-value mapping as it
* existed at some point in time. This class does not
* support the Map.Entry.setValue method.
- */
+ */
static class SnapshotEntry implements Map.Entry {
- private final K key;
- private final V value;
+ private final K key;
+ private final V value;
/**
* Creates a new entry representing the given key and value.
@@ -586,31 +592,31 @@ public class ConcurrentSkipListMap
* @param value the value
*/
SnapshotEntry(K key, V value) {
- this.key = key;
- this.value = value;
- }
-
- /**
- * Returns the key corresponding to this entry.
- *
- * @return the key corresponding to this entry.
- */
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Returns the key corresponding to this entry.
+ *
+ * @return the key corresponding to this entry.
+ */
public K getKey() {
return key;
}
- /**
- * Returns the value corresponding to this entry.
- *
- * @return the value corresponding to this entry.
- */
+ /**
+ * Returns the value corresponding to this entry.
+ *
+ * @return the value corresponding to this entry.
+ */
public V getValue() {
- return value;
+ return value;
}
- /**
- * Always fails, throwing UnsupportedOperationException.
- * @throws UnsupportedOperationException always.
+ /**
+ * Always fails, throwing UnsupportedOperationException.
+ * @throws UnsupportedOperationException always.
*/
public V setValue(V value) {
throw new UnsupportedOperationException();
@@ -643,7 +649,7 @@ public class ConcurrentSkipListMap
* @return a String representation of this entry.
*/
public String toString() {
- return getKey() + "=" + getValue();
+ return getKey() + "=" + getValue();
}
}
@@ -682,10 +688,10 @@ public class ConcurrentSkipListMap
* which is propagated back to caller.
*/
private Comparable comparable(Object key) throws ClassCastException {
- if (key == null)
+ if (key == null)
throw new NullPointerException();
- return (comparator != null)
- ? new ComparableUsingComparator(key, comparator)
+ return (comparator != null)
+ ? new ComparableUsingComparator(key, comparator)
: (Comparable)key;
}
@@ -707,7 +713,7 @@ public class ConcurrentSkipListMap
* fence oare null. Needed mainly in submap operations.
*/
boolean inHalfOpenRange(K key, K least, K fence) {
- if (key == null)
+ if (key == null)
throw new NullPointerException();
return ((least == null || compare(key, least) >= 0) &&
(fence == null || compare(key, fence) < 0));
@@ -718,7 +724,7 @@ public class ConcurrentSkipListMap
* or equal to fence. Needed mainly in submap operations.
*/
boolean inOpenRange(K key, K least, K fence) {
- if (key == null)
+ if (key == null)
throw new NullPointerException();
return ((least == null || compare(key, least) >= 0) &&
(fence == null || compare(key, fence) <= 0));
@@ -732,7 +738,7 @@ public class ConcurrentSkipListMap
* unlinks indexes to deleted nodes found along the way. Callers
* rely on this side-effect of clearing indices to deleted nodes.
* @param key the key
- * @return a predecessor of key
+ * @return a predecessor of key
*/
private Node findPredecessor(Comparable key) {
for (;;) {
@@ -751,7 +757,7 @@ public class ConcurrentSkipListMap
continue;
}
}
- if ((d = q.down) != null)
+ if ((d = q.down) != null)
q = d;
else
return q.node;
@@ -781,7 +787,7 @@ public class ConcurrentSkipListMap
* here because doing so would not usually outweigh cost of
* restarting.
*
- * (3) n is a marker or n's predecessor's value field is null,
+ * (3) n is a marker or n's predecessor's value field is null,
* indicating (among other possibilities) that
* findPredecessor returned a deleted node. We can't unlink
* the node because we don't know its predecessor, so rely
@@ -799,7 +805,7 @@ public class ConcurrentSkipListMap
* findLast. They can't easily share code because each uses the
* reads of fields held in locals occurring in the orders they
* were performed.
- *
+ *
* @param key the key
* @return node holding key, or null if no such.
*/
@@ -808,7 +814,7 @@ public class ConcurrentSkipListMap
Node b = findPredecessor(key);
Node n = b.next;
for (;;) {
- if (n == null)
+ if (n == null)
return null;
Node f = n.next;
if (n != b.next) // inconsistent read
@@ -823,7 +829,7 @@ public class ConcurrentSkipListMap
int c = key.compareTo(n.key);
if (c < 0)
return null;
- if (c == 0)
+ if (c == 0)
return n;
b = n;
n = f;
@@ -831,8 +837,8 @@ public class ConcurrentSkipListMap
}
}
- /**
- * Specialized variant of findNode to perform map.get. Does a weak
+ /**
+ * Specialized variant of findNode to perform Map.get. Does a weak
* traversal, not bothering to fix any deleted index nodes,
* returning early if it happens to see key in index, and passing
* over any deleted base nodes, falling back to getUsingFindNode
@@ -850,7 +856,7 @@ public class ConcurrentSkipListMap
for (;;) {
K rk;
Index d, r;
- if ((r = q.right) != null &&
+ if ((r = q.right) != null &&
(rk = r.key) != null && rk != bound) {
int c = key.compareTo(rk);
if (c > 0) {
@@ -859,11 +865,11 @@ public class ConcurrentSkipListMap
}
if (c == 0) {
Object v = r.node.value;
- return (v != null)? (V)v : getUsingFindNode(key);
+ return (v != null) ? (V)v : getUsingFindNode(key);
}
bound = rk;
}
- if ((d = q.down) != null)
+ if ((d = q.down) != null)
q = d;
else {
for (Node n = q.node.next; n != null; n = n.next) {
@@ -872,7 +878,7 @@ public class ConcurrentSkipListMap
int c = key.compareTo(nk);
if (c == 0) {
Object v = n.value;
- return (v != null)? (V)v : getUsingFindNode(key);
+ return (v != null) ? (V)v : getUsingFindNode(key);
}
if (c < 0)
return null;
@@ -910,7 +916,7 @@ public class ConcurrentSkipListMap
/**
* Main insertion method. Adds element if not present, or
* replaces value if present and onlyIfAbsent is false.
- * @param kkey the key
+ * @param kkey the key
* @param value the value that must be associated with key
* @param onlyIfAbsent if should not insert if already present
* @return the old value, or null if newly inserted
@@ -924,7 +930,7 @@ public class ConcurrentSkipListMap
if (n != null) {
Node f = n.next;
if (n != b.next) // inconsistent read
- break;;
+ break;
Object v = n.value;
if (v == null) { // n is deleted
n.helpDelete(b, f);
@@ -946,12 +952,12 @@ public class ConcurrentSkipListMap
}
// else c < 0; fall through
}
-
+
Node z = new Node(kkey, value, n);
- if (!b.casNext(n, z))
+ if (!b.casNext(n, z))
break; // restart if lost race to append to b
- int level = randomLevel();
- if (level > 0)
+ int level = randomLevel();
+ if (level > 0)
insertIndex(z, level);
return null;
}
@@ -973,8 +979,8 @@ public class ConcurrentSkipListMap
int level = 0;
int r = randomSeed;
randomSeed = r * 134775813 + 1;
- if (r < 0) {
- while ((r <<= 1) > 0)
+ if (r < 0) {
+ while ((r <<= 1) > 0)
++level;
}
return level;
@@ -1007,7 +1013,7 @@ public class ConcurrentSkipListMap
level = max + 1;
Index[] idxs = (Index[])new Index[level+1];
Index idx = null;
- for (int i = 1; i <= level; ++i)
+ for (int i = 1; i <= level; ++i)
idxs[i] = idx = new Index(z, idx, null);
HeadIndex oldh;
@@ -1021,7 +1027,7 @@ public class ConcurrentSkipListMap
}
HeadIndex newh = oldh;
Node oldbase = oldh.node;
- for (int j = oldLevel+1; j <= level; ++j)
+ for (int j = oldLevel+1; j <= level; ++j)
newh = new HeadIndex(oldbase, newh, idxs[j], j);
if (casHead(oldh, newh)) {
k = oldLevel;
@@ -1059,7 +1065,7 @@ public class ConcurrentSkipListMap
if (q.unlink(r))
continue;
else
- break;
+ break;
}
if (c > 0) {
q = r;
@@ -1073,17 +1079,17 @@ public class ConcurrentSkipListMap
findNode(key); // cleans up
return;
}
- if (!q.link(r, t))
+ if (!q.link(r, t))
break; // restart
if (--insertionLevel == 0) {
// need final deletion check before return
- if (t.indexesDeletedNode())
- findNode(key);
+ if (t.indexesDeletedNode())
+ findNode(key);
return;
}
}
- if (j > insertionLevel && j <= indexLevel)
+ if (j > insertionLevel && j <= indexLevel)
t = t.down;
q = q.down;
--j;
@@ -1098,14 +1104,14 @@ public class ConcurrentSkipListMap
* deletion marker, unlinks predecessor, removes associated index
* nodes, and possibly reduces head index level.
*
- * Index node are cleared out simply by calling findPredecessor.
+ * Index nodes are cleared out simply by calling findPredecessor.
* which unlinks indexes to deleted nodes found along path to key,
* which will include the indexes to this node. This is done
* unconditionally. We can't check beforehand whether there are
* index nodes because it might be the case that some or all
* indexes hadn't been inserted yet for this node during initial
* search for it, and we'd like to ensure lack of garbage
- * retention, so must call to be sure.
+ * retention, so must call to be sure.
*
* @param okey the key
* @param value if non-null, the value that must be
@@ -1114,11 +1120,11 @@ public class ConcurrentSkipListMap
*/
private V doRemove(Object okey, Object value) {
Comparable key = comparable(okey);
- for (;;) {
+ for (;;) {
Node b = findPredecessor(key);
Node n = b.next;
for (;;) {
- if (n == null)
+ if (n == null)
return null;
Node f = n.next;
if (n != b.next) // inconsistent read
@@ -1138,15 +1144,15 @@ public class ConcurrentSkipListMap
n = f;
continue;
}
- if (value != null && !value.equals(v))
- return null;
- if (!n.casValue(v, null))
+ if (value != null && !value.equals(v))
+ return null;
+ if (!n.casValue(v, null))
break;
- if (!n.appendMarker(f) || !b.casNext(n, f))
+ if (!n.appendMarker(f) || !b.casNext(n, f))
findNode(key); // Retry via findNode
else {
findPredecessor(key); // Clean index
- if (head.right == null)
+ if (head.right == null)
tryReduceLevel();
}
return (V)v;
@@ -1179,16 +1185,22 @@ public class ConcurrentSkipListMap
HeadIndex d;
HeadIndex e;
if (h.level > 3 &&
- (d = (HeadIndex)h.down) != null &&
- (e = (HeadIndex)d.down) != null &&
- e.right == null &&
- d.right == null &&
+ (d = (HeadIndex)h.down) != null &&
+ (e = (HeadIndex)d.down) != null &&
+ e.right == null &&
+ d.right == null &&
h.right == null &&
casHead(h, d) && // try to set
h.right != null) // recheck
casHead(d, h); // try to backout
}
+ /**
+ * Version of remove with boolean return. Needed by view classes
+ */
+ boolean removep(Object key) {
+ return doRemove(key, null) != null;
+ }
/* ---------------- Finding and removing first element -------------- */
@@ -1202,23 +1214,23 @@ public class ConcurrentSkipListMap
Node n = b.next;
if (n == null)
return null;
- if (n.value != null)
+ if (n.value != null)
return n;
n.helpDelete(b, n.next);
}
}
/**
- * Remove first entry; return either its key or a snapshot.
+ * Remove first entry; return either its key or a snapshot.
* @param keyOnly if true return key, else return SnapshotEntry
* (This is a little ugly, but avoids code duplication.)
* @return null if empty, first key if keyOnly true, else key,value entry
*/
Object doRemoveFirst(boolean keyOnly) {
- for (;;) {
+ for (;;) {
Node b = head.node;
Node n = b.next;
- if (n == null)
+ if (n == null)
return null;
Node f = n.next;
if (n != b.next)
@@ -1234,7 +1246,7 @@ public class ConcurrentSkipListMap
findFirst(); // retry
clearIndexToFirst();
K key = n.key;
- return (keyOnly)? key : new SnapshotEntry(key, (V)v);
+ return keyOnly ? key : new SnapshotEntry(key, (V)v);
}
}
@@ -1248,9 +1260,9 @@ public class ConcurrentSkipListMap
for (;;) {
Index r = q.right;
if (r != null && r.indexesDeletedNode() && !q.unlink(r))
- break;
+ break;
if ((q = q.down) == null) {
- if (head.right == null)
+ if (head.right == null)
tryReduceLevel();
return;
}
@@ -1258,6 +1270,13 @@ public class ConcurrentSkipListMap
}
}
+ /**
+ * Remove first entry; return key or null if empty.
+ */
+ K pollFirstKey() {
+ return (K)doRemoveFirst(true);
+ }
+
/* ---------------- Finding and removing last element -------------- */
/**
@@ -1277,7 +1296,7 @@ public class ConcurrentSkipListMap
if (r.indexesDeletedNode()) {
q.unlink(r);
q = head; // restart
- }
+ }
else
q = r;
} else if ((d = q.down) != null) {
@@ -1286,8 +1305,8 @@ public class ConcurrentSkipListMap
Node b = q.node;
Node n = b.next;
for (;;) {
- if (n == null)
- return (b.isBaseHeader())? null : b;
+ if (n == null)
+ return b.isBaseHeader() ? null : b;
Node f = n.next; // inconsistent read
if (n != b.next)
break;
@@ -1313,13 +1332,13 @@ public class ConcurrentSkipListMap
* @return null if empty, last key if keyOnly true, else key,value entry
*/
Object doRemoveLast(boolean keyOnly) {
- for (;;) {
+ for (;;) {
Node b = findPredecessorOfLast();
Node n = b.next;
if (n == null) {
if (b.isBaseHeader()) // empty
return null;
- else
+ else
continue; // all b's successors are deleted; retry
}
for (;;) {
@@ -1338,18 +1357,18 @@ public class ConcurrentSkipListMap
n = f;
continue;
}
- if (!n.casValue(v, null))
+ if (!n.casValue(v, null))
break;
K key = n.key;
Comparable ck = comparable(key);
- if (!n.appendMarker(f) || !b.casNext(n, f))
+ if (!n.appendMarker(f) || !b.casNext(n, f))
findNode(ck); // Retry via findNode
else {
findPredecessor(ck); // Clean index
- if (head.right == null)
+ if (head.right == null)
tryReduceLevel();
}
- return (keyOnly)? key : new SnapshotEntry(key, (V)v);
+ return keyOnly ? key : new SnapshotEntry(key, (V)v);
}
}
}
@@ -1359,7 +1378,7 @@ public class ConcurrentSkipListMap
* last valid node. Needed by doRemoveLast. It is possible that
* all successors of returned node will have been deleted upon
* return, in which case this method can be retried.
- * @return likely predecessor of last node.
+ * @return likely predecessor of last node.
*/
private Node findPredecessorOfLast() {
for (;;) {
@@ -1377,21 +1396,28 @@ public class ConcurrentSkipListMap
continue;
}
}
- if ((d = q.down) != null)
+ if ((d = q.down) != null)
q = d;
- else
+ else
return q.node;
}
}
}
-
+
+ /**
+ * Remove last entry; return key or null if empty.
+ */
+ K pollLastKey() {
+ return (K)doRemoveLast(true);
+ }
+
/* ---------------- Relational operations -------------- */
// Control values OR'ed as arguments to findNear
private static final int EQ = 1;
private static final int LT = 2;
- private static final int GT = 0;
+ private static final int GT = 0; // Actually checked as !LT
/**
* Utility for ceiling, floor, lower, higher methods.
@@ -1405,8 +1431,8 @@ public class ConcurrentSkipListMap
Node b = findPredecessor(key);
Node n = b.next;
for (;;) {
- if (n == null)
- return ((rel & LT) == 0 || b.isBaseHeader())? null : b;
+ if (n == null)
+ return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
Node f = n.next;
if (n != b.next) // inconsistent read
break;
@@ -1422,7 +1448,7 @@ public class ConcurrentSkipListMap
(c < 0 && (rel & LT) == 0))
return n;
if ( c <= 0 && (rel & LT) != 0)
- return (b.isBaseHeader())? null : b;
+ return b.isBaseHeader() ? null : b;
b = n;
n = f;
}
@@ -1446,11 +1472,98 @@ public class ConcurrentSkipListMap
}
}
+ /**
+ * Return ceiling, or first node if key is null
+ */
+ Node findCeiling(K key) {
+ return (key == null) ? findFirst() : findNear(key, GT|EQ);
+ }
+
+ /**
+ * Return lower node, or last node if key is null
+ */
+ Node findLower(K key) {
+ return (key == null) ? findLast() : findNear(key, LT);
+ }
+
+ /**
+ * Return SnapshotEntry or key for results of findNear ofter screening
+ * to ensure result is in given range. Needed by submaps.
+ * @param kkey the key
+ * @param rel the relation -- OR'ed combination of EQ, LT, GT
+ * @param least minimum allowed key value
+ * @param fence key greater than maximum allowed key value
+ * @param keyOnly if true return key, else return SnapshotEntry
+ * @return Key or Entry fitting relation, or null if no such
+ */
+ Object getNear(K kkey, int rel, K least, K fence, boolean keyOnly) {
+ K key = kkey;
+ // Don't return keys less than least
+ if ((rel & LT) == 0) {
+ if (compare(key, least) < 0) {
+ key = least;
+ rel = rel | EQ;
+ }
+ }
+
+ for (;;) {
+ Node n = findNear(key, rel);
+ if (n == null || !inHalfOpenRange(n.key, least, fence))
+ return null;
+ K k = n.key;
+ V v = n.getValidValue();
+ if (v != null)
+ return keyOnly ? k : new SnapshotEntry(k, v);
+ }
+ }
+
+ /**
+ * Find and remove least element of subrange.
+ * @param least minimum allowed key value
+ * @param fence key greater than maximum allowed key value
+ * @param keyOnly if true return key, else return SnapshotEntry
+ * @return least Key or Entry, or null if no such
+ */
+ Object removeFirstEntryOfSubrange(K least, K fence, boolean keyOnly) {
+ for (;;) {
+ Node n = findCeiling(least);
+ if (n == null)
+ return null;
+ K k = n.key;
+ if (fence != null && compare(k, fence) >= 0)
+ return null;
+ V v = doRemove(k, null);
+ if (v != null)
+ return keyOnly ? k : new SnapshotEntry(k, v);
+ }
+ }
+
+ /**
+ * Find and remove greatest element of subrange.
+ * @param least minimum allowed key value
+ * @param fence key greater than maximum allowed key value
+ * @param keyOnly if true return key, else return SnapshotEntry
+ * @return least Key or Entry, or null if no such
+ */
+ Object removeLastEntryOfSubrange(K least, K fence, boolean keyOnly) {
+ for (;;) {
+ Node n = findLower(fence);
+ if (n == null)
+ return null;
+ K k = n.key;
+ if (least != null && compare(k, least) < 0)
+ return null;
+ V v = doRemove(k, null);
+ if (v != null)
+ return keyOnly ? k : new SnapshotEntry(k, v);
+ }
+ }
+
/* ---------------- Constructors -------------- */
/**
* Constructs a new empty map, sorted according to the keys' natural
- * order.
+ * order.
*/
public ConcurrentSkipListMap() {
this.comparator = null;
@@ -1471,7 +1584,7 @@ public class ConcurrentSkipListMap
/**
* Constructs a new map containing the same mappings as the given map,
- * sorted according to the keys' natural order.
+ * sorted according to the keys' natural order.
*
* @param m the map whose mappings are to be placed in this map.
* @throws ClassCastException if the keys in m are not Comparable, or
@@ -1486,7 +1599,7 @@ public class ConcurrentSkipListMap
/**
* Constructs a new map containing the same mappings as the given
- * SortedMap, sorted according to the same ordering.
+ * SortedMap, sorted according to the same ordering.
* @param m the sorted map whose mappings are to be placed in this
* map, and whose comparator is to be used to sort this map.
* @throws NullPointerException if the specified sorted map is
@@ -1534,7 +1647,7 @@ public class ConcurrentSkipListMap
ArrayList> preds = new ArrayList>();
// initialize
- for (int i = 0; i <= h.level; ++i)
+ for (int i = 0; i <= h.level; ++i)
preds.add(null);
Index q = h;
for (int i = h.level; i > 0; --i) {
@@ -1542,7 +1655,7 @@ public class ConcurrentSkipListMap
q = q.down;
}
- Iterator extends Map.Entry extends K, ? extends V>> it =
+ Iterator extends Map.Entry extends K, ? extends V>> it =
map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry extends K, ? extends V> e = it.next();
@@ -1559,7 +1672,7 @@ public class ConcurrentSkipListMap
Index idx = null;
for (int i = 1; i <= j; ++i) {
idx = new Index(z, idx, null);
- if (i > h.level)
+ if (i > h.level)
h = new HeadIndex(h.node, h, idx, i);
if (i < preds.size()) {
@@ -1579,7 +1692,7 @@ public class ConcurrentSkipListMap
* Save the state of the Map instance to a stream.
*
* @serialData The key (Object) and value (Object) for each
- * key-value mapping represented by the Map, followed by
+ * key-value mapping represented by the Map, followed by
* null. The key-value mappings are emitted in key-order
* (as determined by the Comparator, or by the keys' natural
* ordering if no Comparator).
@@ -1610,7 +1723,7 @@ public class ConcurrentSkipListMap
// Reset transients
initialize();
- /*
+ /*
* This is nearly identical to buildFromSorted, but is
* distinct because readObject calls can't be nicely adapted
* as the kind of iterator needed by buildFromSorted. (They
@@ -1621,7 +1734,7 @@ public class ConcurrentSkipListMap
HeadIndex h = head;
Node basepred = h.node;
ArrayList> preds = new ArrayList>();
- for (int i = 0; i <= h.level; ++i)
+ for (int i = 0; i <= h.level; ++i)
preds.add(null);
Index q = h;
for (int i = h.level; i > 0; --i) {
@@ -1634,7 +1747,7 @@ public class ConcurrentSkipListMap
if (k == null)
break;
Object v = s.readObject();
- if (v == null)
+ if (v == null)
throw new NullPointerException();
K key = (K) k;
V val = (V) v;
@@ -1647,7 +1760,7 @@ public class ConcurrentSkipListMap
Index idx = null;
for (int i = 1; i <= j; ++i) {
idx = new Index(z, idx, null);
- if (i > h.level)
+ if (i > h.level)
h = new HeadIndex(h.node, h, idx, i);
if (i < preds.size()) {
@@ -1679,7 +1792,7 @@ public class ConcurrentSkipListMap
/**
* Returns the value to which this map maps the specified key. Returns
- * null if the map contains no mapping for this key.
+ * null if the map contains no mapping for this key.
*
* @param key key whose associated value is to be returned.
* @return the value to which this map maps the specified key, or
@@ -1701,13 +1814,13 @@ public class ConcurrentSkipListMap
* @param value value to be associated with the specified key.
*
* @return previous value associated with specified key, or null
- * if there was no mapping for key.
+ * if there was no mapping for key.
* @throws ClassCastException if the key cannot be compared with the keys
* currently in the map.
* @throws NullPointerException if the key or value are null.
*/
public V put(K key, V value) {
- if (value == null)
+ if (value == null)
throw new NullPointerException();
return doPut(key, value, false);
}
@@ -1717,7 +1830,7 @@ public class ConcurrentSkipListMap
*
* @param key key for which mapping should be removed
* @return previous value associated with specified key, or null
- * if there was no mapping for key.
+ * if there was no mapping for key.
*
* @throws ClassCastException if the key cannot be compared with the keys
* currently in the map.
@@ -1734,11 +1847,11 @@ public class ConcurrentSkipListMap
*
* @param value value whose presence in this Map is to be tested.
* @return true if a mapping to value exists;
- * false otherwise.
+ * false otherwise.
* @throws NullPointerException if the value is null.
- */
+ */
public boolean containsValue(Object value) {
- if (value == null)
+ if (value == null)
throw new NullPointerException();
for (Node n = findFirst(); n != null; n = n.next) {
V v = n.getValidValue();
@@ -1770,7 +1883,7 @@ public class ConcurrentSkipListMap
if (n.getValidValue() != null)
++count;
}
- return (count >= Integer.MAX_VALUE)? Integer.MAX_VALUE : (int)count;
+ return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)count;
}
/**
@@ -1819,6 +1932,37 @@ public class ConcurrentSkipListMap
}
/**
+ * Returns a set view of the keys contained in this map in
+ * descending order. The set is backed by the map, so changes to
+ * the map are reflected in the set, and vice-versa. The set
+ * supports element removal, which removes the corresponding
+ * mapping from this map, via the Iterator.remove,
+ * Set.remove, removeAll, retainAll,
+ * and clear operations. It does not support the
+ * add or addAll operations. The view's
+ * iterator is a "weakly consistent" iterator that will
+ * never throw {@link java.util.ConcurrentModificationException},
+ * and guarantees to traverse elements as they existed upon
+ * construction of the iterator, and may (but is not guaranteed
+ * to) reflect any modifications subsequent to construction.
+ *
+ * @return a set view of the keys contained in this map.
+ */
+ public Set descendingKeySet() {
+ /*
+ * Note: Lazy intialization works here and for other views
+ * because view classes are stateless/immutable so it doesn't
+ * matter wrt correctness if more than one is created (which
+ * will only rarely happen). Even so, the following idiom
+ * conservatively ensures that the method returns the one it
+ * created if it does so, not one created by another racing
+ * thread.
+ */
+ DescendingKeySet ks = descendingKeySet;
+ return (ks != null) ? ks : (descendingKeySet = new DescendingKeySet());
+ }
+
+ /**
* Returns a collection view of the values contained in this map.
* The collection is backed by the map, so changes to the map are
* reflected in the collection, and vice-versa. The collection
@@ -1868,6 +2012,33 @@ public class ConcurrentSkipListMap
return (es != null) ? es : (entrySet = new EntrySet());
}
+ /**
+ * Returns a collection view of the mappings contained in this
+ * map, in descending order. Each element in the returned
+ * collection is a Map.Entry. The collection is backed
+ * by the map, so changes to the map are reflected in the
+ * collection, and vice-versa. The collection supports element
+ * removal, which removes the corresponding mapping from the map,
+ * via the Iterator.remove, Collection.remove,
+ * removeAll, retainAll, and clear
+ * operations. It does not support the add or
+ * addAll operations. The view's iterator is a
+ * "weakly consistent" iterator that will never throw {@link
+ * java.util.ConcurrentModificationException}, and guarantees to
+ * traverse elements as they existed upon construction of the
+ * iterator, and may (but is not guaranteed to) reflect any
+ * modifications subsequent to construction. The
+ * Map.Entry elements returned by
+ * iterator.next() do not support the
+ * setValue operation.
+ *
+ * @return a collection view of the mappings contained in this map.
+ */
+ public Set> descendingEntrySet() {
+ DescendingEntrySet es = descendingEntrySet;
+ return (es != null) ? es : (descendingEntrySet = new DescendingEntrySet());
+ }
+
/* ---------------- AbstractMap Overrides -------------- */
/**
@@ -1885,17 +2056,17 @@ public class ConcurrentSkipListMap
* @return true if the specified object is equal to this map.
*/
public boolean equals(Object o) {
- if (o == this)
- return true;
- if (!(o instanceof Map))
- return false;
- Map t = (Map) o;
+ if (o == this)
+ return true;
+ if (!(o instanceof Map))
+ return false;
+ Map t = (Map) o;
try {
- return (containsAllMappings(this, t) &&
+ return (containsAllMappings(this, t) &&
containsAllMappings(t, this));
- } catch(ClassCastException unused) {
+ } catch (ClassCastException unused) {
return false;
- } catch(NullPointerException unused) {
+ } catch (NullPointerException unused) {
return false;
}
}
@@ -1909,7 +2080,7 @@ public class ConcurrentSkipListMap
Entry e = it.next();
Object k = e.getKey();
Object v = e.getValue();
- if (k == null || v == null || !v.equals(a.get(k)))
+ if (k == null || v == null || !v.equals(a.get(k)))
return false;
}
return true;
@@ -1922,7 +2093,7 @@ public class ConcurrentSkipListMap
* with a value, associate it with the given value.
* This is equivalent to
*
- * if (!map.containsKey(key))
+ * if (!map.containsKey(key))
* return map.put(key, value);
* else
* return map.get(key);
@@ -1931,14 +2102,14 @@ public class ConcurrentSkipListMap
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @return previous value associated with specified key, or null
- * if there was no mapping for key.
+ * if there was no mapping for key.
*
* @throws ClassCastException if the key cannot be compared with the keys
* currently in the map.
* @throws NullPointerException if the key or value are null.
*/
public V putIfAbsent(K key, V value) {
- if (value == null)
+ if (value == null)
throw new NullPointerException();
return doPut(key, value, true);
}
@@ -1946,7 +2117,7 @@ public class ConcurrentSkipListMap
/**
* Remove entry for key only if currently mapped to given value.
* Acts as
- *
+ *
* if ((map.containsKey(key) && map.get(key).equals(value)) {
* map.remove(key);
* return true;
@@ -1961,7 +2132,7 @@ public class ConcurrentSkipListMap
* @throws NullPointerException if the key or value are null.
*/
public boolean remove(Object key, Object value) {
- if (value == null)
+ if (value == null)
throw new NullPointerException();
return doRemove(key, value) != null;
}
@@ -1969,7 +2140,7 @@ public class ConcurrentSkipListMap
/**
* Replace entry for key only if currently mapped to given value.
* Acts as
- *
+ *
* if ((map.containsKey(key) && map.get(key).equals(oldValue)) {
* map.put(key, newValue);
* return true;
@@ -1986,7 +2157,7 @@ public class ConcurrentSkipListMap
* null.
*/
public boolean replace(K key, V oldValue, V newValue) {
- if (oldValue == null || newValue == null)
+ if (oldValue == null || newValue == null)
throw new NullPointerException();
Comparable k = comparable(key);
for (;;) {
@@ -2006,7 +2177,7 @@ public class ConcurrentSkipListMap
/**
* Replace entry for key only if currently mapped to some value.
* Acts as
- *
+ *
* if ((map.containsKey(key)) {
* return map.put(key, value);
* } else return null;
@@ -2015,13 +2186,13 @@ public class ConcurrentSkipListMap
* @param key key with which the specified value is associated.
* @param value value to be associated with the specified key.
* @return previous value associated with specified key, or null
- * if there was no mapping for key.
+ * if there was no mapping for key.
* @throws ClassCastException if the key cannot be compared with the keys
* currently in the map.
* @throws NullPointerException if the key or value are null.
*/
public V replace(K key, V value) {
- if (value == null)
+ if (value == null)
throw new NullPointerException();
Comparable k = comparable(key);
for (;;) {
@@ -2053,7 +2224,7 @@ public class ConcurrentSkipListMap
* @return the first (lowest) key currently in this map.
* @throws NoSuchElementException Map is empty.
*/
- public K firstKey() {
+ public K firstKey() {
Node n = findFirst();
if (n == null)
throw new NoSuchElementException();
@@ -2079,7 +2250,7 @@ public class ConcurrentSkipListMap
* fromKey and toKey are equal, the returned sorted map
* is empty.) The returned sorted map is backed by this map, so changes
* in the returned sorted map are reflected in this map, and vice-versa.
-
+ *
* @param fromKey low endpoint (inclusive) of the subMap.
* @param toKey high endpoint (exclusive) of the subMap.
*
@@ -2147,7 +2318,7 @@ public class ConcurrentSkipListMap
* greater than or equal to the given key, or null if
* there is no such entry. The returned entry does not
* support the Entry.setValue method.
- *
+ *
* @param key the key.
* @return an Entry associated with ceiling of given key, or
* null if there is no such Entry.
@@ -2160,11 +2331,27 @@ public class ConcurrentSkipListMap
}
/**
+ * Returns least key greater than or equal to the given key, or
+ * null if there is no such key.
+ *
+ * @param key the key.
+ * @return the ceiling key, or null
+ * if there is no such key.
+ * @throws ClassCastException if key cannot be compared with the keys
+ * currently in the map.
+ * @throws NullPointerException if key is null.
+ */
+ public K ceilingKey(K key) {
+ Node n = findNear(key, GT|EQ);
+ return (n == null) ? null : n.key;
+ }
+
+ /**
* Returns a key-value mapping associated with the greatest
* key strictly less than the given key, or null if there is no
* such entry. The returned entry does not support
* the Entry.setValue method.
- *
+ *
* @param key the key.
* @return an Entry with greatest key less than the given
* key, or null if there is no such Entry.
@@ -2177,11 +2364,27 @@ public class ConcurrentSkipListMap
}
/**
+ * Returns the greatest key strictly less than the given key, or
+ * null if there is no such key.
+ *
+ * @param key the key.
+ * @return the greatest key less than the given
+ * key, or null if there is no such key.
+ * @throws ClassCastException if key cannot be compared with the keys
+ * currently in the map.
+ * @throws NullPointerException if key is null.
+ */
+ public K lowerKey(K key) {
+ Node n = findNear(key, LT);
+ return (n == null) ? null : n.key;
+ }
+
+ /**
* Returns a key-value mapping associated with the greatest key
* less than or equal to the given key, or null if there
* is no such entry. The returned entry does not support
* the Entry.setValue method.
- *
+ *
* @param key the key.
* @return an Entry associated with floor of given key, or null
* if there is no such Entry.
@@ -2194,11 +2397,28 @@ public class ConcurrentSkipListMap
}
/**
+ * Returns the greatest key
+ * less than or equal to the given key, or null if there
+ * is no such key.
+ *
+ * @param key the key.
+ * @return the floor of given key, or null if there is no
+ * such key.
+ * @throws ClassCastException if key cannot be compared with the keys
+ * currently in the map.
+ * @throws NullPointerException if key is null.
+ */
+ public K floorKey(K key) {
+ Node n = findNear(key, LT|EQ);
+ return (n == null) ? null : n.key;
+ }
+
+ /**
* Returns a key-value mapping associated with the least key
* strictly greater than the given key, or null if there
* is no such entry. The returned entry does not support
* the Entry.setValue method.
- *
+ *
* @param key the key.
* @return an Entry with least key greater than the given key, or
* null if there is no such Entry.
@@ -2211,18 +2431,34 @@ public class ConcurrentSkipListMap
}
/**
+ * Returns the least key strictly greater than the given key, or
+ * null if there is no such key.
+ *
+ * @param key the key.
+ * @return the least key greater than the given key, or
+ * null if there is no such key.
+ * @throws ClassCastException if key cannot be compared with the keys
+ * currently in the map.
+ * @throws NullPointerException if key is null.
+ */
+ public K higherKey(K key) {
+ Node n = findNear(key, GT);
+ return (n == null) ? null : n.key;
+ }
+
+ /**
* Returns a key-value mapping associated with the least
* key in this map, or null if the map is empty.
* The returned entry does not support
* the Entry.setValue method.
- *
- * @return an Entry with least key, or null
+ *
+ * @return an Entry with least key, or null
* if the map is empty.
*/
public Map.Entry firstEntry() {
for (;;) {
Node n = findFirst();
- if (n == null)
+ if (n == null)
return null;
SnapshotEntry e = n.createSnapshot();
if (e != null)
@@ -2235,14 +2471,14 @@ public class ConcurrentSkipListMap
* key in this map, or null if the map is empty.
* The returned entry does not support
* the Entry.setValue method.
- *
+ *
* @return an Entry with greatest key, or null
* if the map is empty.
*/
public Map.Entry lastEntry() {
for (;;) {
Node n = findLast();
- if (n == null)
+ if (n == null)
return null;
SnapshotEntry e = n.createSnapshot();
if (e != null)
@@ -2255,7 +2491,7 @@ public class ConcurrentSkipListMap
* the least key in this map, or null if the map is empty.
* The returned entry does not support
* the Entry.setValue method.
- *
+ *
* @return the removed first entry of this map, or null
* if the map is empty.
*/
@@ -2268,7 +2504,7 @@ public class ConcurrentSkipListMap
* the greatest key in this map, or null if the map is empty.
* The returned entry does not support
* the Entry.setValue method.
- *
+ *
* @return the removed last entry of this map, or null
* if the map is empty.
*/
@@ -2276,24 +2512,32 @@ public class ConcurrentSkipListMap
return (SnapshotEntry)doRemoveLast(false);
}
+
/* ---------------- Iterators -------------- */
/**
- * Base of iterator classes.
- * (Six kinds: {key, value, entry} X {map, submap})
+ * Base of ten kinds of iterator classes:
+ * ascending: {map, submap} X {key, value, entry}
+ * descending: {map, submap} X {key, entry}
*/
- abstract class ConcurrentSkipListMapIterator {
+ abstract class Iter {
/** the last node returned by next() */
Node last;
/** the next node to return from next(); */
Node next;
- /** Cache of next value field to maintain weak consistency */
- Object nextValue;
+ /** Cache of next value field to maintain weak consistency */
+ Object nextValue;
+
+ Iter() {}
+
+ public final boolean hasNext() {
+ return next != null;
+ }
- /** Create normal iterator for entire range */
- ConcurrentSkipListMapIterator() {
+ /** initialize ascending iterator for entire range */
+ final void initAscending() {
for (;;) {
- next = findFirst();
+ next = findFirst();
if (next == null)
break;
nextValue = next.value;
@@ -2302,14 +2546,14 @@ public class ConcurrentSkipListMap
}
}
- /**
- * Create a submap iterator starting at given least key, or
- * first node if least is null, but not greater or equal to
- * fence, or end if fence is null.
+ /**
+ * initialize ascending iterator starting at given least key,
+ * or first node if least is null, but not greater or
+ * equal to fence, or end if fence is null.
*/
- ConcurrentSkipListMapIterator(K least, K fence) {
+ final void initAscending(K least, K fence) {
for (;;) {
- next = findCeiling(least);
+ next = findCeiling(least);
if (next == null)
break;
nextValue = next.value;
@@ -2322,16 +2566,82 @@ public class ConcurrentSkipListMap
}
}
}
+ /** advance next to higher entry */
+ final void ascend() {
+ if ((last = next) == null)
+ throw new NoSuchElementException();
+ for (;;) {
+ next = next.next;
+ if (next == null)
+ break;
+ nextValue = next.value;
+ if (nextValue != null && nextValue != next)
+ break;
+ }
+ }
+
+ /**
+ * Version of ascend for submaps to stop at fence
+ */
+ final void ascend(K fence) {
+ if ((last = next) == null)
+ throw new NoSuchElementException();
+ for (;;) {
+ next = next.next;
+ if (next == null)
+ break;
+ nextValue = next.value;
+ if (nextValue != null && nextValue != next) {
+ if (fence != null && compare(fence, next.key) <= 0) {
+ next = null;
+ nextValue = null;
+ }
+ break;
+ }
+ }
+ }
+
+ /** initialize descending iterator for entire range */
+ final void initDescending() {
+ for (;;) {
+ next = findLast();
+ if (next == null)
+ break;
+ nextValue = next.value;
+ if (nextValue != null && nextValue != next)
+ break;
+ }
+ }
- public final boolean hasNext() {
- return next != null;
+ /**
+ * initialize descending iterator starting at key less
+ * than or equal to given fence key, or
+ * last node if fence is null, but not less than
+ * least, or beginning if lest is null.
+ */
+ final void initDescending(K least, K fence) {
+ for (;;) {
+ next = findLower(fence);
+ if (next == null)
+ break;
+ nextValue = next.value;
+ if (nextValue != null && nextValue != next) {
+ if (least != null && compare(least, next.key) > 0) {
+ next = null;
+ nextValue = null;
+ }
+ break;
+ }
+ }
}
- final void advance() {
+ /** advance next to lower entry */
+ final void descend() {
if ((last = next) == null)
throw new NoSuchElementException();
+ K k = last.key;
for (;;) {
- next = next.next;
+ next = findNear(k, LT);
if (next == null)
break;
nextValue = next.value;
@@ -2341,18 +2651,19 @@ public class ConcurrentSkipListMap
}
/**
- * Version of advance for submaps to stop at fence
+ * Version of descend for submaps to stop at least
*/
- final void advance(K fence) {
+ final void descend(K least) {
if ((last = next) == null)
throw new NoSuchElementException();
+ K k = last.key;
for (;;) {
- next = next.next;
+ next = findNear(k, LT);
if (next == null)
break;
nextValue = next.value;
if (nextValue != null && nextValue != next) {
- if (fence != null && compare(fence, next.key) <= 0) {
+ if (least != null && compare(least, next.key) > 0) {
next = null;
nextValue = null;
}
@@ -2369,22 +2680,80 @@ public class ConcurrentSkipListMap
// unlink from here. Using remove is fast enough.
ConcurrentSkipListMap.this.remove(l.key);
}
+
}
- final class ValueIterator extends ConcurrentSkipListMapIterator
- implements Iterator {
- public V next() {
+ final class ValueIterator extends Iter implements Iterator {
+ ValueIterator() {
+ initAscending();
+ }
+ public V next() {
Object v = nextValue;
- advance();
+ ascend();
return (V)v;
}
}
- final class KeyIterator extends ConcurrentSkipListMapIterator
- implements Iterator {
- public K next() {
+ final class KeyIterator extends Iter implements Iterator {
+ KeyIterator() {
+ initAscending();
+ }
+ public K next() {
Node n = next;
- advance();
+ ascend();
+ return n.key;
+ }
+ }
+
+ class SubMapValueIterator extends Iter implements Iterator {
+ final K fence;
+ SubMapValueIterator(K least, K fence) {
+ initAscending(least, fence);
+ this.fence = fence;
+ }
+
+ public V next() {
+ Object v = nextValue;
+ ascend(fence);
+ return (V)v;
+ }
+ }
+
+ final class SubMapKeyIterator extends Iter implements Iterator {
+ final K fence;
+ SubMapKeyIterator(K least, K fence) {
+ initAscending(least, fence);
+ this.fence = fence;
+ }
+
+ public K next() {
+ Node n = next;
+ ascend(fence);
+ return n.key;
+ }
+ }
+
+ final class DescendingKeyIterator extends Iter implements Iterator {
+ DescendingKeyIterator() {
+ initDescending();
+ }
+ public K next() {
+ Node n = next;
+ descend();
+ return n.key;
+ }
+ }
+
+ final class DescendingSubMapKeyIterator extends Iter implements Iterator {
+ final K least;
+ DescendingSubMapKeyIterator(K least, K fence) {
+ initDescending(least, fence);
+ this.least = least;
+ }
+
+ public K next() {
+ Node n = next;
+ descend(least);
return n.key;
}
}
@@ -2394,23 +2763,11 @@ public class ConcurrentSkipListMap
* elsewhere of using the iterator itself to represent entries,
* thus avoiding having to create entry objects in next().
*/
- class EntryIterator extends ConcurrentSkipListMapIterator
- implements Map.Entry, Iterator> {
+ abstract class EntryIter extends Iter implements Map.Entry {
/** Cache of last value returned */
Object lastValue;
- EntryIterator() {
- super();
- }
-
- EntryIterator(K least, K fence) {
- super(least, fence);
- }
-
- public Map.Entry next() {
- lastValue = nextValue;
- advance();
- return this;
+ EntryIter() {
}
public K getKey() {
@@ -2424,7 +2781,7 @@ public class ConcurrentSkipListMap
Object v = lastValue;
if (last == null || v == null)
throw new IllegalStateException();
- return (V)v;
+ return (V)v;
}
public V setValue(V value) {
@@ -2453,60 +2810,64 @@ public class ConcurrentSkipListMap
// If not acting as entry, just use default.
if (last == null)
return super.toString();
- return getKey() + "=" + getValue();
+ return getKey() + "=" + getValue();
}
}
- /**
- * Submap iterators start at given starting point at beginning of
- * submap range, and advance until they are at end of range.
- */
- class SubMapEntryIterator extends EntryIterator {
+ final class EntryIterator extends EntryIter
+ implements Iterator> {
+ EntryIterator() {
+ initAscending();
+ }
+ public Map.Entry next() {
+ lastValue = nextValue;
+ ascend();
+ return this;
+ }
+ }
+
+ final class SubMapEntryIterator extends EntryIter
+ implements Iterator> {
final K fence;
SubMapEntryIterator(K least, K fence) {
- super(least, fence);
+ initAscending(least, fence);
this.fence = fence;
}
- public Map.Entry next() {
+ public Map.Entry next() {
lastValue = nextValue;
- advance(fence);
+ ascend(fence);
return this;
}
}
- class SubMapValueIterator extends ConcurrentSkipListMapIterator
- implements Iterator {
- final K fence;
- SubMapValueIterator(K least, K fence) {
- super(least, fence);
- this.fence = fence;
+ final class DescendingEntryIterator extends EntryIter
+ implements Iterator> {
+ DescendingEntryIterator() {
+ initDescending();
}
-
- public V next() {
- Object v = nextValue;
- advance(fence);
- return (V)v;
+ public Map.Entry