/** * Returns <tt>true</tt> if this map contains no key-value mappings. * @return <tt>true</tt> if this map contains no key-value mappings. */ public boolean isEmpty() { return findFirst() == null; }
/** * Returns the first (lowest) key currently in this map. * * @return the first (lowest) key currently in this map. * @throws NoSuchElementException Map is empty. */ public K firstKey() { Node<K,V> n = findFirst(); if (n == null) throw new NoSuchElementException(); return n.key; }
/** * Return ceiling, or first node if key is <tt>null</tt> */ Node<K,V> findCeiling(K key) { return (key == null)? findFirst() : findNear(key, GT|EQ); }
/** * 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 <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; }
/** * 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; }
/** * 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); }
/** * 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); } }