int j = randomLevel(); if (j > h.level) j = h.level + 1; Node<K,V> z = new Node<K,V>(key, val, null); basepred.next = z; basepred = z;
if (!oldValue.equals(v)) return false; if (n.casValue(v, newValue)) return true;
/** * Save the state of the <tt>Map</tt> instance to a stream. * * @serialData The key (Object) and value (Object) for each * key-value mapping represented by the Map, followed by * <tt>null</tt>. The key-value mappings are emitted in key-order * (as determined by the Comparator, or by the keys' natural * ordering if no Comparator). */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out the Comparator and any hidden stuff s.defaultWriteObject(); // Write out keys and values (alternating) for (Node<K,V> n = findFirst(); n != null; n = n.next) { V v = n.getValidValue(); if (v != null) { s.writeObject(n.key); s.writeObject(v); } } s.writeObject(null); }
Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); break;
Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); break; if (!n.casValue(v, null)) break; if (!n.appendMarker(f) || !b.casNext(n, f))
if (k == null || v == null) throw new NullPointerException(); Node<K,V> z = new Node<K,V>(k, v, null); basepred.next = z; basepred = z;
for (;;) { if (n == null) return (b.isBaseHeader())? null : b; Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); break;
Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); break; if (onlyIfAbsent || n.casValue(v, value)) return (V)v; else Node<K,V> z = new Node<K,V>(kkey, value, n); if (!b.casNext(n, z)) break; // restart if lost race to append to b int level = randomLevel();
Node<K,V> n = b.next; if (n == null) { if (b.isBaseHeader()) // empty return null; else Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); break; continue; if (!n.casValue(v, null)) break; K key = n.key; Comparable<K> ck = comparable(key); if (!n.appendMarker(f) || !b.casNext(n, f))
for (;;) { if (n == null) return ((rel & LT) == 0 || b.isBaseHeader())? null : b; Node<K,V> f = n.next; if (n != b.next) // inconsistent read Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); break; return n; if ( c <= 0 && (rel & LT) != 0) return (b.isBaseHeader())? null : b; b = n; n = f;
/** * Replace entry for key only if currently mapped to some value. * Acts as * <pre> * if ((map.containsKey(key)) { * return map.put(key, value); * } else return null; * </pre> * except that the action is performed atomically. * @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 <tt>null</tt> * 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 <tt>null</tt>. */ public V replace(K key, V value) { if (value == null) throw new NullPointerException(); Comparable<K> k = comparable(key); for (;;) { Node<K,V> n = findNode(k); if (n == null) return null; Object v = n.value; if (v != null && n.casValue(v, value)) return (V)v; } }
/** * 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 <tt>null</tt> 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<K,V> 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>(k, v); } }
/** * 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 (;;) { Node<K,V> b = head.node; Node<K,V> n = b.next; if (n == null) return null; Node<K,V> f = n.next; if (n != b.next) continue; Object v = n.value; if (v == null) { n.helpDelete(b, f); continue; } if (!n.casValue(v, null)) continue; if (!n.appendMarker(f) || !b.casNext(n, f)) findFirst(); // retry clearIndexToFirst(); K key = n.key; return (keyOnly)? key : new SnapshotEntry<K,V>(key, (V)v); } }
/** * Returns the number of elements in this map. If this map * contains more than <tt>Integer.MAX_VALUE</tt> elements, it * returns <tt>Integer.MAX_VALUE</tt>. * * <p>Beware that, unlike in most collections, this method is * <em>NOT</em> a constant-time operation. Because of the * asynchronous nature of these maps, 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 map. */ public int size() { long count = 0; for (Node<K,V> n = findFirst(); n != null; n = n.next) { if (n.getValidValue() != null) ++count; } return (count >= Integer.MAX_VALUE)? Integer.MAX_VALUE : (int)count; }
/** * Returns <tt>true</tt> if this map maps one or more keys to the * specified value. This operation requires time linear in the * Map size. * * @param value value whose presence in this Map is to be tested. * @return <tt>true</tt> if a mapping to <tt>value</tt> exists; * <tt>false</tt> otherwise. * @throws NullPointerException if the value is <tt>null</tt>. */ public boolean containsValue(Object value) { if (value == null) throw new NullPointerException(); for (Node<K,V> n = findFirst(); n != null; n = n.next) { V v = n.getValidValue(); if (v != null && value.equals(v)) return true; } return false; }
/** * Helps out a deletion by appending marker or unlinking from * predecessor. This is called during traversals when value * field seen to be null. * @param b predecessor * @param f successor */ void helpDelete(Node<K,V> b, Node<K,V> f) { /* * Rechecking links and then doing only one of the * help-out stages per call tends to minimize CAS * interference among helping threads. */ if (f == next && this == b.next) { if (f == null || f.value != f) // not already marked appendMarker(f); else b.casNext(this, f.next); } }
/** * Returns a key-value mapping associated with the least * key in this map, or <tt>null</tt> if the map is empty. * The returned entry does <em>not</em> support * the <tt>Entry.setValue</tt> method. * * @return an Entry with least key, or <tt>null</tt> * if the map is empty. */ public Map.Entry<K,V> firstEntry() { for (;;) { Node<K,V> n = findFirst(); if (n == null) return null; SnapshotEntry<K,V> e = n.createSnapshot(); if (e != null) return e; } }
/** * Returns a key-value mapping associated with the greatest * key in this map, or <tt>null</tt> if the map is empty. * The returned entry does <em>not</em> support * the <tt>Entry.setValue</tt> method. * * @return an Entry with greatest key, or <tt>null</tt> * if the map is empty. */ public Map.Entry<K,V> lastEntry() { for (;;) { Node<K,V> n = findLast(); if (n == null) return null; SnapshotEntry<K,V> e = n.createSnapshot(); if (e != null) return e; } }
/** * Return SnapshotEntry for results of findNear. * @param kkey the key * @param rel the relation -- OR'ed combination of EQ, LT, GT * @return Entry fitting relation, or null if no such */ SnapshotEntry<K,V> getNear(K kkey, int rel) { for (;;) { Node<K,V> n = findNear(kkey, rel); if (n == null) return null; SnapshotEntry<K,V> e = n.createSnapshot(); if (e != null) return e; } }
/** * Specialized variant of findNode to get first valid node * @return first node or null if empty */ Node<K,V> findFirst() { for (;;) { Node<K,V> b = head.node; Node<K,V> n = b.next; if (n == null) return null; if (n.value != null) return n; n.helpDelete(b, n.next); } }