5 |
|
*/ |
6 |
|
|
7 |
|
package java.util.concurrent; |
8 |
< |
import java.util.*; |
9 |
< |
import java.util.stream.Stream; |
8 |
> |
import java.util.AbstractCollection; |
9 |
> |
import java.util.AbstractMap; |
10 |
> |
import java.util.AbstractSet; |
11 |
> |
import java.util.ArrayList; |
12 |
> |
import java.util.Collection; |
13 |
> |
import java.util.Collections; |
14 |
> |
import java.util.Comparator; |
15 |
> |
import java.util.Comparators; |
16 |
> |
import java.util.Iterator; |
17 |
> |
import java.util.List; |
18 |
> |
import java.util.Map; |
19 |
> |
import java.util.NavigableMap; |
20 |
> |
import java.util.NavigableSet; |
21 |
> |
import java.util.NoSuchElementException; |
22 |
> |
import java.util.Set; |
23 |
> |
import java.util.SortedMap; |
24 |
> |
import java.util.SortedSet; |
25 |
|
import java.util.Spliterator; |
26 |
< |
import java.util.stream.Streams; |
26 |
> |
import java.util.concurrent.ConcurrentMap; |
27 |
> |
import java.util.concurrent.ConcurrentNavigableMap; |
28 |
> |
import java.util.function.BiFunction; |
29 |
|
import java.util.function.Consumer; |
30 |
|
import java.util.function.Function; |
14 |
– |
import java.util.function.BiFunction; |
31 |
|
|
32 |
|
/** |
33 |
|
* A scalable concurrent {@link ConcurrentNavigableMap} implementation. |
249 |
|
* |
250 |
|
* Indexing uses skip list parameters that maintain good search |
251 |
|
* performance while using sparser-than-usual indices: The |
252 |
< |
* hardwired parameters k=1, p=0.5 (see method addIndex) mean |
252 |
> |
* hardwired parameters k=1, p=0.5 (see method doPut) mean |
253 |
|
* that about one-quarter of the nodes have indices. Of those that |
254 |
|
* do, half have one level, a quarter have two, and so on (see |
255 |
|
* Pugh's Skip List Cookbook, sec 3.4). The expected total space |
294 |
|
* |
295 |
|
* A previous version of this class wrapped non-comparable keys |
296 |
|
* with their comparators to emulate Comparables when using |
297 |
< |
* comparators vs Comparables. This saved the need to choose |
298 |
< |
* among the unpleasant options of either possibly re-reading a |
299 |
< |
* comparator on each comparison (which suffers when among all of |
300 |
< |
* the volatile read snapshots) versus code duplication, at the |
301 |
< |
* cost of usually requiring an object construction per operation |
302 |
< |
* when not naturally ordered. However, as usage evolves, use of |
287 |
< |
* comparators has become more common, so we have to settle for |
288 |
< |
* code duplication as the lesser evil. Thus, there are "xxxCmp" |
289 |
< |
* versions of many of the xxx methods, all bundled later in this |
290 |
< |
* file. |
297 |
> |
* comparators vs Comparables. However, JVMs now appear to better |
298 |
> |
* handle infusing comparator-vs-comparable choice into search |
299 |
> |
* loops. Static method cpr(comparator, x, y) is used for all |
300 |
> |
* comparisons, which works well as long as the comparator |
301 |
> |
* argument is set up outside of loops (thus sometimes passed as |
302 |
> |
* an argument to internal methods) to avoid field re-reads. |
303 |
|
* |
304 |
|
* For explanation of algorithms sharing at least a couple of |
305 |
|
* features with this one, see Mikhail Fomitchev's thesis |
339 |
|
private transient volatile HeadIndex<K,V> head; |
340 |
|
|
341 |
|
/** |
342 |
< |
* The comparator used to maintain order in this map, or null |
343 |
< |
* if using natural ordering. |
342 |
> |
* The comparator used to maintain order in this map, or null if |
343 |
> |
* using natural ordering. (Non-private to simplify access in |
344 |
> |
* nested clases.) |
345 |
|
* @serial |
346 |
|
*/ |
347 |
< |
private final Comparator<? super K> comparator; |
347 |
> |
final Comparator<? super K> comparator; |
348 |
|
|
349 |
|
/** Lazily initialized key set */ |
350 |
< |
private transient KeySetView<K,V> keySet; |
350 |
> |
private transient KeySet<K> keySet; |
351 |
|
/** Lazily initialized entry set */ |
352 |
|
private transient EntrySet<K,V> entrySet; |
353 |
|
/** Lazily initialized values collection */ |
360 |
|
* clear, readObject. and ConcurrentSkipListSet.clone. |
361 |
|
* (Note that comparator must be separately initialized.) |
362 |
|
*/ |
363 |
< |
final void initialize() { |
363 |
> |
private void initialize() { |
364 |
|
keySet = null; |
365 |
|
entrySet = null; |
366 |
|
values = null; |
471 |
|
*/ |
472 |
|
if (f == next && this == b.next) { |
473 |
|
if (f == null || f.value != f) // not already marked |
474 |
< |
appendMarker(f); |
474 |
> |
casNext(f, new Node<K,V>(f)); |
475 |
|
else |
476 |
|
b.casNext(this, f.next); |
477 |
|
} |
483 |
|
* @return this node's value if it isn't a marker or header or |
484 |
|
* is deleted, else null. |
485 |
|
*/ |
473 |
– |
@SuppressWarnings("unchecked") |
486 |
|
V getValidValue() { |
487 |
|
Object v = value; |
488 |
|
if (v == this || v == BASE_HEADER) |
489 |
|
return null; |
490 |
< |
return (V)v; |
490 |
> |
@SuppressWarnings("unchecked") V vv = (V)v; |
491 |
> |
return vv; |
492 |
|
} |
493 |
|
|
494 |
|
/** |
497 |
|
* @return new entry or null |
498 |
|
*/ |
499 |
|
AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() { |
500 |
< |
V v = getValidValue(); |
501 |
< |
if (v == null) |
500 |
> |
Object v = value; |
501 |
> |
if (v == null || v == this || v == BASE_HEADER) |
502 |
|
return null; |
503 |
< |
return new AbstractMap.SimpleImmutableEntry<K,V>(key, v); |
503 |
> |
@SuppressWarnings("unchecked") V vv = (V)v; |
504 |
> |
return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv); |
505 |
|
} |
506 |
|
|
507 |
|
// UNSAFE mechanics |
584 |
|
* @return true if successful |
585 |
|
*/ |
586 |
|
final boolean unlink(Index<K,V> succ) { |
587 |
< |
return !indexesDeletedNode() && casRight(succ, succ.right); |
587 |
> |
return node.value != null && casRight(succ, succ.right); |
588 |
|
} |
589 |
|
|
590 |
|
// Unsafe mechanics |
618 |
|
/* ---------------- Comparison utilities -------------- */ |
619 |
|
|
620 |
|
/** |
621 |
< |
* Compares using comparator or natural ordering. Used in cases |
622 |
< |
* where it isn't worthwhile to use multiple code paths. |
609 |
< |
*/ |
610 |
< |
@SuppressWarnings("unchecked") |
611 |
< |
int compare(K k1, K k2) throws ClassCastException { |
612 |
< |
Comparator<? super K> cmp = comparator; |
613 |
< |
if (cmp != null) |
614 |
< |
return cmp.compare(k1, k2); |
615 |
< |
else |
616 |
< |
return ((Comparable<? super K>)k1).compareTo(k2); |
617 |
< |
} |
618 |
< |
|
619 |
< |
/** |
620 |
< |
* Returns true if given key greater than or equal to least and |
621 |
< |
* strictly less than fence, bypassing either test if least or |
622 |
< |
* fence are null. Needed mainly in submap operations. |
623 |
< |
*/ |
624 |
< |
boolean inHalfOpenRange(K key, K least, K fence) { |
625 |
< |
if (key == null) |
626 |
< |
throw new NullPointerException(); |
627 |
< |
return ((least == null || compare(key, least) >= 0) && |
628 |
< |
(fence == null || compare(key, fence) < 0)); |
629 |
< |
} |
630 |
< |
|
631 |
< |
/** |
632 |
< |
* Returns true if given key greater than or equal to least and less |
633 |
< |
* or equal to fence. Needed mainly in submap operations. |
621 |
> |
* Compares using comparator or natural ordering if null. |
622 |
> |
* Called only by methods that have performed required type checks. |
623 |
|
*/ |
624 |
< |
boolean inOpenRange(K key, K least, K fence) { |
625 |
< |
if (key == null) |
626 |
< |
throw new NullPointerException(); |
638 |
< |
return ((least == null || compare(key, least) >= 0) && |
639 |
< |
(fence == null || compare(key, fence) <= 0)); |
624 |
> |
@SuppressWarnings({"unchecked", "rawtypes"}) |
625 |
> |
static final int cpr(Comparator c, Object x, Object y) { |
626 |
> |
return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y); |
627 |
|
} |
628 |
|
|
629 |
|
/* ---------------- Traversal -------------- */ |
636 |
|
* @param key the key |
637 |
|
* @return a predecessor of key |
638 |
|
*/ |
639 |
< |
private Node<K,V> findPredecessor(Comparable<? super K> key) { |
639 |
> |
private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) { |
640 |
|
if (key == null) |
641 |
|
throw new NullPointerException(); // don't postpone errors |
642 |
|
for (;;) { |
643 |
< |
Index<K,V> q = head; |
657 |
< |
Index<K,V> r = q.right; |
658 |
< |
for (;;) { |
643 |
> |
for (Index<K,V> q = head, r = q.right, d;;) { |
644 |
|
if (r != null) { |
645 |
|
Node<K,V> n = r.node; |
646 |
|
K k = n.key; |
650 |
|
r = q.right; // reread r |
651 |
|
continue; |
652 |
|
} |
653 |
< |
if (key.compareTo(k) > 0) { |
653 |
> |
if (cpr(cmp, key, k) > 0) { |
654 |
|
q = r; |
655 |
|
r = r.right; |
656 |
|
continue; |
657 |
|
} |
658 |
|
} |
659 |
< |
Index<K,V> d = q.down; |
675 |
< |
if (d != null) { |
676 |
< |
q = d; |
677 |
< |
r = d.right; |
678 |
< |
} else |
659 |
> |
if ((d = q.down) == null) |
660 |
|
return q.node; |
661 |
+ |
q = d; |
662 |
+ |
r = d.right; |
663 |
|
} |
664 |
|
} |
665 |
|
} |
708 |
|
* @param key the key |
709 |
|
* @return node holding key, or null if no such |
710 |
|
*/ |
711 |
< |
private Node<K,V> findNode(Comparable<? super K> key) { |
711 |
> |
private Node<K,V> findNode(Object key) { |
712 |
|
if (key == null) |
713 |
|
throw new NullPointerException(); // don't postpone errors |
714 |
< |
for (;;) { |
715 |
< |
Node<K,V> b = findPredecessor(key); |
716 |
< |
Node<K,V> n = b.next; |
717 |
< |
for (;;) { |
714 |
> |
Comparator<? super K> cmp = comparator; |
715 |
> |
outer: for (;;) { |
716 |
> |
for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) { |
717 |
> |
Object v; int c; |
718 |
|
if (n == null) |
719 |
< |
return null; |
719 |
> |
break outer; |
720 |
|
Node<K,V> f = n.next; |
721 |
|
if (n != b.next) // inconsistent read |
722 |
|
break; |
723 |
< |
Object v = n.value; |
741 |
< |
if (v == null) { // n is deleted |
723 |
> |
if ((v = n.value) == null) { // n is deleted |
724 |
|
n.helpDelete(b, f); |
725 |
|
break; |
726 |
|
} |
727 |
< |
if (v == n || b.value == null) // b is deleted |
727 |
> |
if (b.value == null || v == n) // b is deleted |
728 |
|
break; |
729 |
< |
int c = key.compareTo(n.key); |
748 |
< |
if (c == 0) |
729 |
> |
if ((c = cpr(cmp, key, n.key)) == 0) |
730 |
|
return n; |
731 |
|
if (c < 0) |
732 |
< |
return null; |
732 |
> |
break outer; |
733 |
|
b = n; |
734 |
|
n = f; |
735 |
|
} |
736 |
|
} |
737 |
+ |
return null; |
738 |
|
} |
739 |
|
|
740 |
|
/** |
741 |
|
* Gets value for key. Almost the same as findNode, but returns |
742 |
|
* the found value (to avoid retries during re-reads) |
743 |
|
* |
744 |
< |
* @param okey the key |
744 |
> |
* @param key the key |
745 |
|
* @return the value, or null if absent |
746 |
|
*/ |
747 |
< |
private V doGet(Object okey) { |
748 |
< |
if (okey == null) |
747 |
> |
private V doGet(Object key) { |
748 |
> |
if (key == null) |
749 |
|
throw new NullPointerException(); |
750 |
< |
@SuppressWarnings("unchecked") Comparable<? super K> key = |
751 |
< |
(Comparable<? super K>)okey; |
752 |
< |
for (;;) { |
753 |
< |
Node<K,V> b = findPredecessor(key); |
772 |
< |
Node<K,V> n = b.next; |
773 |
< |
for (;;) { |
750 |
> |
Comparator<? super K> cmp = comparator; |
751 |
> |
outer: for (;;) { |
752 |
> |
for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) { |
753 |
> |
Object v; int c; |
754 |
|
if (n == null) |
755 |
< |
return null; |
755 |
> |
break outer; |
756 |
|
Node<K,V> f = n.next; |
757 |
|
if (n != b.next) // inconsistent read |
758 |
|
break; |
759 |
< |
Object v = n.value; |
780 |
< |
if (v == null) { // n is deleted |
759 |
> |
if ((v = n.value) == null) { // n is deleted |
760 |
|
n.helpDelete(b, f); |
761 |
|
break; |
762 |
|
} |
763 |
< |
if (v == n || b.value == null) // b is deleted |
763 |
> |
if (b.value == null || v == n) // b is deleted |
764 |
|
break; |
765 |
< |
@SuppressWarnings("unchecked") V vv = (V)v; |
766 |
< |
int c = key.compareTo(n.key); |
788 |
< |
if (c == 0) |
765 |
> |
if ((c = cpr(cmp, key, n.key)) == 0) { |
766 |
> |
@SuppressWarnings("unchecked") V vv = (V)v; |
767 |
|
return vv; |
768 |
+ |
} |
769 |
|
if (c < 0) |
770 |
< |
return null; |
770 |
> |
break outer; |
771 |
|
b = n; |
772 |
|
n = f; |
773 |
|
} |
774 |
|
} |
775 |
+ |
return null; |
776 |
|
} |
777 |
|
|
798 |
– |
|
778 |
|
/* ---------------- Insertion -------------- */ |
779 |
|
|
780 |
|
/** |
781 |
|
* Main insertion method. Adds element if not present, or |
782 |
|
* replaces value if present and onlyIfAbsent is false. |
783 |
< |
* @param kkey the key |
783 |
> |
* @param key the key |
784 |
|
* @param value the value that must be associated with key |
785 |
|
* @param onlyIfAbsent if should not insert if already present |
786 |
|
* @return the old value, or null if newly inserted |
787 |
|
*/ |
788 |
< |
private V doPut(K kkey, V value, boolean onlyIfAbsent) { |
789 |
< |
if (kkey == null) |
788 |
> |
private V doPut(K key, V value, boolean onlyIfAbsent) { |
789 |
> |
Node<K,V> z; // added node |
790 |
> |
if (key == null) |
791 |
|
throw new NullPointerException(); |
792 |
< |
@SuppressWarnings("unchecked") Comparable<? super K> key = |
793 |
< |
(Comparable<? super K>)kkey; |
794 |
< |
for (;;) { |
815 |
< |
Node<K,V> b = findPredecessor(key); |
816 |
< |
Node<K,V> n = b.next; |
817 |
< |
for (;;) { |
792 |
> |
Comparator<? super K> cmp = comparator; |
793 |
> |
outer: for (;;) { |
794 |
> |
for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) { |
795 |
|
if (n != null) { |
796 |
+ |
Object v; int c; |
797 |
|
Node<K,V> f = n.next; |
798 |
|
if (n != b.next) // inconsistent read |
799 |
|
break; |
800 |
< |
Object v = n.value; |
823 |
< |
if (v == null) { // n is deleted |
800 |
> |
if ((v = n.value) == null) { // n is deleted |
801 |
|
n.helpDelete(b, f); |
802 |
|
break; |
803 |
|
} |
804 |
< |
if (v == n || b.value == null) // b is deleted |
804 |
> |
if (b.value == null || v == n) // b is deleted |
805 |
|
break; |
806 |
< |
int c = key.compareTo(n.key); |
830 |
< |
if (c > 0) { |
806 |
> |
if ((c = cpr(cmp, key, n.key)) > 0) { |
807 |
|
b = n; |
808 |
|
n = f; |
809 |
|
continue; |
810 |
|
} |
835 |
– |
|
811 |
|
if (c == 0) { |
812 |
< |
@SuppressWarnings("unchecked") V vv = (V)v; |
813 |
< |
if (onlyIfAbsent || n.casValue(vv, value)) |
812 |
> |
if (onlyIfAbsent || n.casValue(v, value)) { |
813 |
> |
@SuppressWarnings("unchecked") V vv = (V)v; |
814 |
|
return vv; |
815 |
< |
else |
816 |
< |
break; // restart if lost race to replace value |
815 |
> |
} |
816 |
> |
break; // restart if lost race to replace value |
817 |
|
} |
818 |
|
// else c < 0; fall through |
819 |
|
} |
820 |
|
|
821 |
< |
Node<K,V> z = new Node<K,V>(kkey, value, n); |
821 |
> |
z = new Node<K,V>(key, value, n); |
822 |
|
if (!b.casNext(n, z)) |
823 |
|
break; // restart if lost race to append to b |
824 |
< |
addIndex(kkey, z); |
850 |
< |
return null; |
824 |
> |
break outer; |
825 |
|
} |
826 |
|
} |
853 |
– |
} |
827 |
|
|
855 |
– |
/** |
856 |
– |
* Adds zero or more index nodes for the given key and node. |
857 |
– |
* Shared by plain and Cmp versions of put |
858 |
– |
*/ |
859 |
– |
@SuppressWarnings("unchecked") |
860 |
– |
private void addIndex(K key, Node<K,V> z) { |
861 |
– |
if (key == null || z == null) // don't postpone errors |
862 |
– |
throw new NullPointerException(); |
828 |
|
int rnd; // generate a random level |
829 |
|
Thread thread = Thread.currentThread(); |
830 |
|
if ((rnd = UNSAFE.getInt(thread, SECONDARY)) == 0) // initialize |
845 |
|
} |
846 |
|
else { // try to grow by one level |
847 |
|
level = max + 1; // hold in array and later pick the one to use |
848 |
< |
Index<K,V>[] idxs = (Index<K,V>[])new Index<?,?>[level+1]; |
848 |
> |
@SuppressWarnings("unchecked")Index<K,V>[] idxs = |
849 |
> |
(Index<K,V>[])new Index<?,?>[level+1]; |
850 |
|
for (int i = 1; i <= level; ++i) |
851 |
|
idxs[i] = idx = new Index<K,V>(z, idx, null); |
852 |
|
for (;;) { |
865 |
|
} |
866 |
|
} |
867 |
|
} |
868 |
< |
Comparator<? super K> cmp = comparator; |
869 |
< |
for (int insertionLevel = level;;) { // find insertion points; splice |
868 |
> |
// find insertion points and splice in |
869 |
> |
splice: for (int insertionLevel = level;;) { |
870 |
|
int j = h.level; |
871 |
< |
Index<K,V> q = h; |
906 |
< |
Index<K,V> r = q.right; |
907 |
< |
Index<K,V> t = idx; |
908 |
< |
for (;;) { |
871 |
> |
for (Index<K,V> q = h, r = q.right, t = idx;;) { |
872 |
|
if (q == null || t == null) |
873 |
< |
return; |
873 |
> |
break splice; |
874 |
|
if (r != null) { |
875 |
|
Node<K,V> n = r.node; |
876 |
|
// compare before deletion check avoids needing recheck |
877 |
< |
int c = (cmp == null) ? |
915 |
< |
((Comparable<? super K>)key).compareTo(n.key) : |
916 |
< |
cmp.compare(key, n.key); |
877 |
> |
int c = cpr(cmp, key, n.key); |
878 |
|
if (n.value == null) { |
879 |
|
if (!q.unlink(r)) |
880 |
|
break; |
892 |
|
if (!q.link(r, t)) |
893 |
|
break; // restart |
894 |
|
if (t.node.value == null) { |
895 |
< |
if (cmp == null) // node deleted; clean up |
896 |
< |
findNode((Comparable<? super K>)key); |
936 |
< |
else |
937 |
< |
findNodeCmp(cmp, key); |
938 |
< |
return; |
895 |
> |
findNode(key); |
896 |
> |
break splice; |
897 |
|
} |
898 |
|
if (--insertionLevel == 0) |
899 |
< |
return; |
899 |
> |
break splice; |
900 |
|
} |
901 |
|
|
902 |
|
if (--j >= insertionLevel && j < level) |
906 |
|
} |
907 |
|
} |
908 |
|
} |
909 |
+ |
return null; |
910 |
|
} |
911 |
|
|
912 |
|
/* ---------------- Deletion -------------- */ |
925 |
|
* search for it, and we'd like to ensure lack of garbage |
926 |
|
* retention, so must call to be sure. |
927 |
|
* |
928 |
< |
* @param okey the key |
928 |
> |
* @param key the key |
929 |
|
* @param value if non-null, the value that must be |
930 |
|
* associated with key |
931 |
|
* @return the node, or null if not found |
932 |
|
*/ |
933 |
< |
final V doRemove(Object okey, Object value) { |
934 |
< |
if (okey == null) |
933 |
> |
final V doRemove(Object key, Object value) { |
934 |
> |
if (key == null) |
935 |
|
throw new NullPointerException(); |
936 |
< |
@SuppressWarnings("unchecked") Comparable<? super K> key = |
937 |
< |
(Comparable<? super K>)okey; |
938 |
< |
for (;;) { |
939 |
< |
Node<K,V> b = findPredecessor(key); |
981 |
< |
Node<K,V> n = b.next; |
982 |
< |
for (;;) { |
936 |
> |
Comparator<? super K> cmp = comparator; |
937 |
> |
outer: for (;;) { |
938 |
> |
for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) { |
939 |
> |
Object v; int c; |
940 |
|
if (n == null) |
941 |
< |
return null; |
941 |
> |
break outer; |
942 |
|
Node<K,V> f = n.next; |
943 |
|
if (n != b.next) // inconsistent read |
944 |
|
break; |
945 |
< |
Object v = n.value; |
989 |
< |
if (v == null) { // n is deleted |
945 |
> |
if ((v = n.value) == null) { // n is deleted |
946 |
|
n.helpDelete(b, f); |
947 |
|
break; |
948 |
|
} |
949 |
< |
if (v == n || b.value == null) // b is deleted |
949 |
> |
if (b.value == null || v == n) // b is deleted |
950 |
|
break; |
951 |
< |
int c = key.compareTo(n.key); |
952 |
< |
if (c < 0) |
997 |
< |
return null; |
951 |
> |
if ((c = cpr(cmp, key, n.key)) < 0) |
952 |
> |
break outer; |
953 |
|
if (c > 0) { |
954 |
|
b = n; |
955 |
|
n = f; |
956 |
|
continue; |
957 |
|
} |
958 |
|
if (value != null && !value.equals(v)) |
959 |
< |
return null; |
959 |
> |
break outer; |
960 |
|
if (!n.casValue(v, null)) |
961 |
|
break; |
962 |
|
if (!n.appendMarker(f) || !b.casNext(n, f)) |
963 |
< |
findNode(key); // Retry via findNode |
963 |
> |
findNode(key); // retry via findNode |
964 |
|
else { |
965 |
< |
findPredecessor(key); // Clean index |
965 |
> |
findPredecessor(key, cmp); // clean index |
966 |
|
if (head.right == null) |
967 |
|
tryReduceLevel(); |
968 |
|
} |
970 |
|
return vv; |
971 |
|
} |
972 |
|
} |
973 |
+ |
return null; |
974 |
|
} |
975 |
|
|
976 |
|
/** |
1014 |
|
* Specialized variant of findNode to get first valid node. |
1015 |
|
* @return first node or null if empty |
1016 |
|
*/ |
1017 |
< |
Node<K,V> findFirst() { |
1018 |
< |
for (;;) { |
1019 |
< |
Node<K,V> b = head.node; |
1064 |
< |
Node<K,V> n = b.next; |
1065 |
< |
if (n == null) |
1017 |
> |
final Node<K,V> findFirst() { |
1018 |
> |
for (Node<K,V> b, n;;) { |
1019 |
> |
if ((n = (b = head.node).next) == null) |
1020 |
|
return null; |
1021 |
|
if (n.value != null) |
1022 |
|
return n; |
1028 |
|
* Removes first entry; returns its snapshot. |
1029 |
|
* @return null if empty, else snapshot of first entry |
1030 |
|
*/ |
1031 |
< |
Map.Entry<K,V> doRemoveFirstEntry() { |
1032 |
< |
for (;;) { |
1033 |
< |
Node<K,V> b = head.node; |
1080 |
< |
Node<K,V> n = b.next; |
1081 |
< |
if (n == null) |
1031 |
> |
private Map.Entry<K,V> doRemoveFirstEntry() { |
1032 |
> |
for (Node<K,V> b, n;;) { |
1033 |
> |
if ((n = (b = head.node).next) == null) |
1034 |
|
return null; |
1035 |
|
Node<K,V> f = n.next; |
1036 |
|
if (n != b.next) |
1055 |
|
*/ |
1056 |
|
private void clearIndexToFirst() { |
1057 |
|
for (;;) { |
1058 |
< |
Index<K,V> q = head; |
1107 |
< |
for (;;) { |
1058 |
> |
for (Index<K,V> q = head;;) { |
1059 |
|
Index<K,V> r = q.right; |
1060 |
|
if (r != null && r.indexesDeletedNode() && !q.unlink(r)) |
1061 |
|
break; |
1073 |
|
* Specialized variant of doRemove. |
1074 |
|
* @return null if empty, else snapshot of last entry |
1075 |
|
*/ |
1076 |
< |
@SuppressWarnings("unchecked") |
1126 |
< |
Map.Entry<K,V> doRemoveLastEntry() { |
1076 |
> |
private Map.Entry<K,V> doRemoveLastEntry() { |
1077 |
|
for (;;) { |
1078 |
|
Node<K,V> b = findPredecessorOfLast(); |
1079 |
|
Node<K,V> n = b.next; |
1092 |
|
n.helpDelete(b, f); |
1093 |
|
break; |
1094 |
|
} |
1095 |
< |
if (v == n || b.value == null) // b is deleted |
1095 |
> |
if (b.value == null || v == n) // b is deleted |
1096 |
|
break; |
1097 |
|
if (f != null) { |
1098 |
|
b = n; |
1102 |
|
if (!n.casValue(v, null)) |
1103 |
|
break; |
1104 |
|
K key = n.key; |
1105 |
< |
Comparator<? super K> cmp = comparator; |
1106 |
< |
if (!n.appendMarker(f) || !b.casNext(n, f)) { |
1107 |
< |
if (cmp == null) // Retry via findNode |
1108 |
< |
findNode((Comparable<? super K>)key); |
1159 |
< |
else |
1160 |
< |
findNodeCmp(cmp, key); |
1161 |
< |
} |
1162 |
< |
else { // Clean index |
1163 |
< |
if (cmp == null) |
1164 |
< |
findPredecessor((Comparable<? super K>)key); |
1165 |
< |
else |
1166 |
< |
findPredecessorCmp(cmp, key); |
1105 |
> |
if (!n.appendMarker(f) || !b.casNext(n, f)) |
1106 |
> |
findNode(key); // retry via findNode |
1107 |
> |
else { // clean index |
1108 |
> |
findPredecessor(key, comparator); |
1109 |
|
if (head.right == null) |
1110 |
|
tryReduceLevel(); |
1111 |
|
} |
1112 |
< |
return new AbstractMap.SimpleImmutableEntry<K,V>(key, (V)v); |
1112 |
> |
@SuppressWarnings("unchecked") V vv = (V)v; |
1113 |
> |
return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv); |
1114 |
|
} |
1115 |
|
} |
1116 |
|
} |
1121 |
|
* Specialized version of find to get last valid node. |
1122 |
|
* @return last node or null if empty |
1123 |
|
*/ |
1124 |
< |
Node<K,V> findLast() { |
1124 |
> |
final Node<K,V> findLast() { |
1125 |
|
/* |
1126 |
|
* findPredecessor can't be used to traverse index level |
1127 |
|
* because this doesn't use comparisons. So traversals of |
1140 |
|
} else if ((d = q.down) != null) { |
1141 |
|
q = d; |
1142 |
|
} else { |
1143 |
< |
Node<K,V> b = q.node; |
1201 |
< |
Node<K,V> n = b.next; |
1202 |
< |
for (;;) { |
1143 |
> |
for (Node<K,V> b = q.node, n = b.next;;) { |
1144 |
|
if (n == null) |
1145 |
|
return b.isBaseHeader() ? null : b; |
1146 |
|
Node<K,V> f = n.next; // inconsistent read |
1151 |
|
n.helpDelete(b, f); |
1152 |
|
break; |
1153 |
|
} |
1154 |
< |
if (v == n || b.value == null) // b is deleted |
1154 |
> |
if (b.value == null || v == n) // b is deleted |
1155 |
|
break; |
1156 |
|
b = n; |
1157 |
|
n = f; |
1170 |
|
*/ |
1171 |
|
private Node<K,V> findPredecessorOfLast() { |
1172 |
|
for (;;) { |
1173 |
< |
Index<K,V> q = head; |
1233 |
< |
for (;;) { |
1173 |
> |
for (Index<K,V> q = head;;) { |
1174 |
|
Index<K,V> d, r; |
1175 |
|
if ((r = q.right) != null) { |
1176 |
|
if (r.indexesDeletedNode()) { |
1201 |
|
|
1202 |
|
/** |
1203 |
|
* Utility for ceiling, floor, lower, higher methods. |
1204 |
< |
* @param kkey the key |
1204 |
> |
* @param key the key |
1205 |
|
* @param rel the relation -- OR'ed combination of EQ, LT, GT |
1206 |
|
* @return nearest node fitting relation, or null if no such |
1207 |
|
*/ |
1208 |
< |
Node<K,V> doFindNear(K kkey, int rel) { |
1209 |
< |
@SuppressWarnings("unchecked") Comparable<? super K> key = |
1210 |
< |
(Comparable<? super K>)kkey; |
1271 |
< |
for (;;) { |
1272 |
< |
Node<K,V> b = findPredecessor(key); |
1273 |
< |
Node<K,V> n = b.next; |
1274 |
< |
for (;;) { |
1275 |
< |
if (n == null) |
1276 |
< |
return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b; |
1277 |
< |
Node<K,V> f = n.next; |
1278 |
< |
if (n != b.next) // inconsistent read |
1279 |
< |
break; |
1280 |
< |
Object v = n.value; |
1281 |
< |
if (v == null) { // n is deleted |
1282 |
< |
n.helpDelete(b, f); |
1283 |
< |
break; |
1284 |
< |
} |
1285 |
< |
if (v == n || b.value == null) // b is deleted |
1286 |
< |
break; |
1287 |
< |
int c = key.compareTo(n.key); |
1288 |
< |
if ((c == 0 && (rel & EQ) != 0) || |
1289 |
< |
(c < 0 && (rel & LT) == 0)) |
1290 |
< |
return n; |
1291 |
< |
if ( c <= 0 && (rel & LT) != 0) |
1292 |
< |
return b.isBaseHeader() ? null : b; |
1293 |
< |
b = n; |
1294 |
< |
n = f; |
1295 |
< |
} |
1296 |
< |
} |
1297 |
< |
} |
1298 |
< |
|
1299 |
< |
/* ---------------- cmp versions -------------- */ |
1300 |
< |
|
1301 |
< |
// Boringly almost the same as natural-Comparable ones |
1302 |
< |
|
1303 |
< |
private Node<K,V> findPredecessorCmp(Comparator<? super K> cmp, Object okey) { |
1304 |
< |
if (cmp == null) |
1305 |
< |
throw new NullPointerException(); // don't postpone errors |
1306 |
< |
@SuppressWarnings("unchecked") K key = (K) okey; |
1307 |
< |
for (;;) { |
1308 |
< |
Index<K,V> q = head; |
1309 |
< |
Index<K,V> r = q.right; |
1310 |
< |
for (;;) { |
1311 |
< |
if (r != null) { |
1312 |
< |
Node<K,V> n = r.node; |
1313 |
< |
K k = n.key; |
1314 |
< |
if (n.value == null) { |
1315 |
< |
if (!q.unlink(r)) |
1316 |
< |
break; // restart |
1317 |
< |
r = q.right; // reread r |
1318 |
< |
continue; |
1319 |
< |
} |
1320 |
< |
if (cmp.compare(key, k) > 0) { |
1321 |
< |
q = r; |
1322 |
< |
r = r.right; |
1323 |
< |
continue; |
1324 |
< |
} |
1325 |
< |
} |
1326 |
< |
Index<K,V> d = q.down; |
1327 |
< |
if (d != null) { |
1328 |
< |
q = d; |
1329 |
< |
r = d.right; |
1330 |
< |
} else |
1331 |
< |
return q.node; |
1332 |
< |
} |
1333 |
< |
} |
1334 |
< |
} |
1335 |
< |
|
1336 |
< |
private Node<K,V> findNodeCmp(Comparator<? super K> cmp, Object okey) { |
1337 |
< |
if (cmp == null) |
1338 |
< |
throw new NullPointerException(); // don't postpone errors |
1339 |
< |
@SuppressWarnings("unchecked") K key = (K) okey; |
1340 |
< |
for (;;) { |
1341 |
< |
Node<K,V> b = findPredecessorCmp(cmp, key); |
1342 |
< |
Node<K,V> n = b.next; |
1343 |
< |
for (;;) { |
1344 |
< |
if (n == null) |
1345 |
< |
return null; |
1346 |
< |
Node<K,V> f = n.next; |
1347 |
< |
if (n != b.next) // inconsistent read |
1348 |
< |
break; |
1349 |
< |
Object v = n.value; |
1350 |
< |
if (v == null) { // n is deleted |
1351 |
< |
n.helpDelete(b, f); |
1352 |
< |
break; |
1353 |
< |
} |
1354 |
< |
if (v == n || b.value == null) // b is deleted |
1355 |
< |
break; |
1356 |
< |
int c = cmp.compare(key, n.key); |
1357 |
< |
if (c == 0) |
1358 |
< |
return n; |
1359 |
< |
if (c < 0) |
1360 |
< |
return null; |
1361 |
< |
b = n; |
1362 |
< |
n = f; |
1363 |
< |
} |
1364 |
< |
} |
1365 |
< |
} |
1366 |
< |
|
1367 |
< |
private V doGetCmp(Comparator<? super K> cmp, Object okey) { |
1368 |
< |
if (cmp == null) |
1369 |
< |
throw new NullPointerException(); // don't postpone errors |
1370 |
< |
@SuppressWarnings("unchecked") K key = (K) okey; |
1371 |
< |
for (;;) { |
1372 |
< |
Node<K,V> b = findPredecessorCmp(cmp, key); |
1373 |
< |
Node<K,V> n = b.next; |
1374 |
< |
for (;;) { |
1375 |
< |
if (n == null) |
1376 |
< |
return null; |
1377 |
< |
Node<K,V> f = n.next; |
1378 |
< |
if (n != b.next) // inconsistent read |
1379 |
< |
break; |
1380 |
< |
Object v = n.value; |
1381 |
< |
if (v == null) { // n is deleted |
1382 |
< |
n.helpDelete(b, f); |
1383 |
< |
break; |
1384 |
< |
} |
1385 |
< |
if (v == n || b.value == null) // b is deleted |
1386 |
< |
break; |
1387 |
< |
@SuppressWarnings("unchecked") V vv = (V)v; |
1388 |
< |
int c = cmp.compare(key, n.key); |
1389 |
< |
if (c == 0) |
1390 |
< |
return vv; |
1391 |
< |
if (c < 0) |
1392 |
< |
return null; |
1393 |
< |
b = n; |
1394 |
< |
n = f; |
1395 |
< |
} |
1396 |
< |
} |
1397 |
< |
} |
1398 |
< |
|
1399 |
< |
private V doPutCmp(Comparator<? super K> cmp, K key, V value, boolean onlyIfAbsent) { |
1400 |
< |
if (cmp == null) |
1401 |
< |
throw new NullPointerException(); // don't postpone errors |
1402 |
< |
for (;;) { |
1403 |
< |
Node<K,V> b = findPredecessorCmp(cmp, key); |
1404 |
< |
Node<K,V> n = b.next; |
1405 |
< |
for (;;) { |
1406 |
< |
if (n != null) { |
1407 |
< |
Node<K,V> f = n.next; |
1408 |
< |
if (n != b.next) // inconsistent read |
1409 |
< |
break; |
1410 |
< |
Object v = n.value; |
1411 |
< |
if (v == null) { // n is deleted |
1412 |
< |
n.helpDelete(b, f); |
1413 |
< |
break; |
1414 |
< |
} |
1415 |
< |
if (v == n || b.value == null) // b is deleted |
1416 |
< |
break; |
1417 |
< |
int c = cmp.compare(key, n.key); |
1418 |
< |
if (c > 0) { |
1419 |
< |
b = n; |
1420 |
< |
n = f; |
1421 |
< |
continue; |
1422 |
< |
} |
1423 |
< |
if (c == 0) { |
1424 |
< |
@SuppressWarnings("unchecked") V vv = (V)v; |
1425 |
< |
if (onlyIfAbsent || n.casValue(vv, value)) |
1426 |
< |
return vv; |
1427 |
< |
else |
1428 |
< |
break; // restart if lost race to replace value |
1429 |
< |
} |
1430 |
< |
// else c < 0; fall through |
1431 |
< |
} |
1432 |
< |
|
1433 |
< |
Node<K,V> z = new Node<K,V>(key, value, n); |
1434 |
< |
if (!b.casNext(n, z)) |
1435 |
< |
break; // restart if lost race to append to b |
1436 |
< |
addIndex(key, z); |
1437 |
< |
return null; |
1438 |
< |
} |
1439 |
< |
} |
1440 |
< |
} |
1441 |
< |
|
1442 |
< |
final V doRemoveCmp(Comparator<? super K> cmp, Object okey, Object value) { |
1443 |
< |
if (cmp == null) |
1444 |
< |
throw new NullPointerException(); // don't postpone errors |
1445 |
< |
@SuppressWarnings("unchecked") K key = (K) okey; |
1446 |
< |
for (;;) { |
1447 |
< |
Node<K,V> b = findPredecessorCmp(cmp, key); |
1448 |
< |
Node<K,V> n = b.next; |
1449 |
< |
for (;;) { |
1450 |
< |
if (n == null) |
1451 |
< |
return null; |
1452 |
< |
Node<K,V> f = n.next; |
1453 |
< |
if (n != b.next) // inconsistent read |
1454 |
< |
break; |
1455 |
< |
Object v = n.value; |
1456 |
< |
if (v == null) { // n is deleted |
1457 |
< |
n.helpDelete(b, f); |
1458 |
< |
break; |
1459 |
< |
} |
1460 |
< |
if (v == n || b.value == null) // b is deleted |
1461 |
< |
break; |
1462 |
< |
int c = cmp.compare(key, n.key); |
1463 |
< |
if (c < 0) |
1464 |
< |
return null; |
1465 |
< |
if (c > 0) { |
1466 |
< |
b = n; |
1467 |
< |
n = f; |
1468 |
< |
continue; |
1469 |
< |
} |
1470 |
< |
if (value != null && !value.equals(v)) |
1471 |
< |
return null; |
1472 |
< |
if (!n.casValue(v, null)) |
1473 |
< |
break; |
1474 |
< |
if (!n.appendMarker(f) || !b.casNext(n, f)) |
1475 |
< |
findNodeCmp(cmp, key); // Retry via findNode |
1476 |
< |
else { |
1477 |
< |
findPredecessorCmp(cmp, key); // Clean index |
1478 |
< |
if (head.right == null) |
1479 |
< |
tryReduceLevel(); |
1480 |
< |
} |
1481 |
< |
@SuppressWarnings("unchecked") V vv = (V)v; |
1482 |
< |
return vv; |
1483 |
< |
} |
1484 |
< |
} |
1485 |
< |
} |
1486 |
< |
|
1487 |
< |
Node<K,V> doFindNearCmp(Comparator<? super K> cmp, K key, int rel) { |
1488 |
< |
if (cmp == null) |
1489 |
< |
throw new NullPointerException(); // don't postpone errors |
1208 |
> |
final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) { |
1209 |
> |
if (key == null) |
1210 |
> |
throw new NullPointerException(); |
1211 |
|
for (;;) { |
1212 |
< |
Node<K,V> b = findPredecessorCmp(cmp, key); |
1213 |
< |
Node<K,V> n = b.next; |
1493 |
< |
for (;;) { |
1212 |
> |
for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) { |
1213 |
> |
Object v; |
1214 |
|
if (n == null) |
1215 |
|
return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b; |
1216 |
|
Node<K,V> f = n.next; |
1217 |
|
if (n != b.next) // inconsistent read |
1218 |
|
break; |
1219 |
< |
Object v = n.value; |
1500 |
< |
if (v == null) { // n is deleted |
1219 |
> |
if ((v = n.value) == null) { // n is deleted |
1220 |
|
n.helpDelete(b, f); |
1221 |
|
break; |
1222 |
|
} |
1223 |
< |
if (v == n || b.value == null) // b is deleted |
1223 |
> |
if (b.value == null || v == n) // b is deleted |
1224 |
|
break; |
1225 |
< |
int c = cmp.compare(key, n.key); |
1225 |
> |
int c = cpr(cmp, key, n.key); |
1226 |
|
if ((c == 0 && (rel & EQ) != 0) || |
1227 |
|
(c < 0 && (rel & LT) == 0)) |
1228 |
|
return n; |
1234 |
|
} |
1235 |
|
} |
1236 |
|
|
1518 |
– |
/* ---------------- Relays to natural vs cmp methods -------------- */ |
1519 |
– |
|
1520 |
– |
Node<K,V> findNear(K key, int rel) { |
1521 |
– |
Comparator<? super K> cmp; |
1522 |
– |
return (cmp = comparator) == null ? doFindNear(key, rel) : |
1523 |
– |
doFindNearCmp(cmp, key, rel); |
1524 |
– |
} |
1525 |
– |
|
1237 |
|
/** |
1238 |
|
* Returns SimpleImmutableEntry for results of findNear. |
1239 |
|
* @param key the key |
1240 |
|
* @param rel the relation -- OR'ed combination of EQ, LT, GT |
1241 |
|
* @return Entry fitting relation, or null if no such |
1242 |
|
*/ |
1243 |
< |
AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) { |
1243 |
> |
final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) { |
1244 |
> |
Comparator<? super K> cmp = comparator; |
1245 |
|
for (;;) { |
1246 |
< |
Node<K,V> n = findNear(key, rel); |
1246 |
> |
Node<K,V> n = findNear(key, rel, cmp); |
1247 |
|
if (n == null) |
1248 |
|
return null; |
1249 |
|
AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot(); |
1497 |
|
* @throws NullPointerException if the specified key is null |
1498 |
|
*/ |
1499 |
|
public boolean containsKey(Object key) { |
1500 |
< |
Comparator<? super K> cmp; |
1789 |
< |
Object v = ((cmp = comparator) == null ? doGet(key) : |
1790 |
< |
doGetCmp(cmp, key)); |
1791 |
< |
return v != null; |
1500 |
> |
return doGet(key) != null; |
1501 |
|
} |
1502 |
|
|
1503 |
|
/** |
1515 |
|
* @throws NullPointerException if the specified key is null |
1516 |
|
*/ |
1517 |
|
public V get(Object key) { |
1518 |
< |
Comparator<? super K> cmp; |
1810 |
< |
return ((cmp = comparator) == null) ? doGet(key) : doGetCmp(cmp, key); |
1518 |
> |
return doGet(key); |
1519 |
|
} |
1520 |
|
|
1521 |
|
/** |
1531 |
|
*/ |
1532 |
|
public V getOrDefault(Object key, V defaultValue) { |
1533 |
|
V v; |
1534 |
< |
return (v = get(key)) == null ? defaultValue : v; |
1534 |
> |
return (v = doGet(key)) == null ? defaultValue : v; |
1535 |
|
} |
1536 |
|
|
1537 |
|
/** |
1548 |
|
* @throws NullPointerException if the specified key or value is null |
1549 |
|
*/ |
1550 |
|
public V put(K key, V value) { |
1843 |
– |
Comparator<? super K> cmp; |
1551 |
|
if (value == null) |
1552 |
|
throw new NullPointerException(); |
1553 |
< |
return ((cmp = comparator) == null) ? |
1847 |
< |
doPut(key, value, false) : doPutCmp(cmp, key, value, false); |
1553 |
> |
return doPut(key, value, false); |
1554 |
|
} |
1555 |
|
|
1556 |
|
/** |
1564 |
|
* @throws NullPointerException if the specified key is null |
1565 |
|
*/ |
1566 |
|
public V remove(Object key) { |
1567 |
< |
Comparator<? super K> cmp; |
1862 |
< |
return ((cmp = comparator) == null) ? doRemove(key, null) : |
1863 |
< |
doRemoveCmp(cmp, key, null); |
1567 |
> |
return doRemove(key, null); |
1568 |
|
} |
1569 |
|
|
1570 |
|
/** |
1649 |
|
Function<? super K, ? extends V> mappingFunction) { |
1650 |
|
if (key == null || mappingFunction == null) |
1651 |
|
throw new NullPointerException(); |
1948 |
– |
Comparator<? super K> cmp; |
1652 |
|
V v, p, r; |
1653 |
< |
if ((cmp = comparator) == null) { |
1654 |
< |
if ((v = doGet(key)) == null && |
1655 |
< |
(r = mappingFunction.apply(key)) != null) |
1953 |
< |
v = (p = doPut(key, r, true)) == null ? r : p; |
1954 |
< |
} |
1955 |
< |
else { |
1956 |
< |
if ((v = doGetCmp(cmp, key)) == null && |
1957 |
< |
(r = mappingFunction.apply(key)) != null) |
1958 |
< |
v = (p = doPutCmp(cmp, key, r, true)) == null ? r : p; |
1959 |
< |
} |
1653 |
> |
if ((v = doGet(key)) == null && |
1654 |
> |
(r = mappingFunction.apply(key)) != null) |
1655 |
> |
v = (p = doPut(key, r, true)) == null ? r : p; |
1656 |
|
return v; |
1657 |
|
} |
1658 |
|
|
1673 |
|
BiFunction<? super K, ? super V, ? extends V> remappingFunction) { |
1674 |
|
if (key == null || remappingFunction == null) |
1675 |
|
throw new NullPointerException(); |
1676 |
< |
Comparator<? super K> cmp; |
1677 |
< |
if ((cmp = comparator) == null) { |
1678 |
< |
Node<K,V> n; Object v; |
1679 |
< |
@SuppressWarnings("unchecked") Comparable<? super K> k = |
1680 |
< |
(Comparable<? super K>) key; |
1681 |
< |
while ((n = findNode(k)) != null) { |
1682 |
< |
if ((v = n.value) != null) { |
1683 |
< |
@SuppressWarnings("unchecked") V vv = (V) v; |
1988 |
< |
V r = remappingFunction.apply(key, vv); |
1989 |
< |
if (r != null) { |
1990 |
< |
if (n.casValue(vv, r)) |
1991 |
< |
return r; |
1992 |
< |
} |
1993 |
< |
else if (doRemove(k, vv) != null) |
1994 |
< |
break; |
1995 |
< |
} |
1996 |
< |
} |
1997 |
< |
} |
1998 |
< |
else { |
1999 |
< |
Node<K,V> n; Object v; |
2000 |
< |
while ((n = findNodeCmp(cmp, key)) != null) { |
2001 |
< |
if ((v = n.value) != null) { |
2002 |
< |
@SuppressWarnings("unchecked") V vv = (V) v; |
2003 |
< |
V r = remappingFunction.apply(key, vv); |
2004 |
< |
if (r != null) { |
2005 |
< |
if (n.casValue(vv, r)) |
2006 |
< |
return r; |
2007 |
< |
} |
2008 |
< |
else if (doRemoveCmp(cmp, key, vv) != null) |
2009 |
< |
break; |
1676 |
> |
Node<K,V> n; Object v; |
1677 |
> |
while ((n = findNode(key)) != null) { |
1678 |
> |
if ((v = n.value) != null) { |
1679 |
> |
@SuppressWarnings("unchecked") V vv = (V) v; |
1680 |
> |
V r = remappingFunction.apply(key, vv); |
1681 |
> |
if (r != null) { |
1682 |
> |
if (n.casValue(vv, r)) |
1683 |
> |
return r; |
1684 |
|
} |
1685 |
+ |
else if (doRemove(key, vv) != null) |
1686 |
+ |
break; |
1687 |
|
} |
1688 |
|
} |
1689 |
|
return null; |
1706 |
|
BiFunction<? super K, ? super V, ? extends V> remappingFunction) { |
1707 |
|
if (key == null || remappingFunction == null) |
1708 |
|
throw new NullPointerException(); |
1709 |
< |
Comparator<? super K> cmp; |
1710 |
< |
if ((cmp = comparator) == null) { |
1711 |
< |
@SuppressWarnings("unchecked") Comparable<? super K> k = |
1712 |
< |
(Comparable<? super K>) key; |
1713 |
< |
for (;;) { |
1714 |
< |
Node<K,V> n; Object v; V r; |
1715 |
< |
if ((n = findNode(k)) == null) { |
1716 |
< |
if ((r = remappingFunction.apply(key, null)) == null) |
1717 |
< |
break; |
1718 |
< |
if (doPut(key, r, false) == null) |
1719 |
< |
return r; |
1720 |
< |
} |
2045 |
< |
else if ((v = n.value) != null) { |
2046 |
< |
@SuppressWarnings("unchecked") V vv = (V) v; |
2047 |
< |
if ((r = remappingFunction.apply(key, vv)) != null) { |
2048 |
< |
if (n.casValue(vv, r)) |
2049 |
< |
return r; |
2050 |
< |
} |
2051 |
< |
else if (doRemove(k, vv) != null) |
2052 |
< |
break; |
2053 |
< |
} |
2054 |
< |
} |
2055 |
< |
} |
2056 |
< |
else { |
2057 |
< |
for (;;) { |
2058 |
< |
Node<K,V> n; Object v; V r; |
2059 |
< |
if ((n = findNodeCmp(cmp, key)) == null) { |
2060 |
< |
if ((r = remappingFunction.apply(key, null)) == null) |
2061 |
< |
break; |
2062 |
< |
if (doPutCmp(cmp, key, r, false) == null) |
1709 |
> |
for (;;) { |
1710 |
> |
Node<K,V> n; Object v; V r; |
1711 |
> |
if ((n = findNode(key)) == null) { |
1712 |
> |
if ((r = remappingFunction.apply(key, null)) == null) |
1713 |
> |
break; |
1714 |
> |
if (doPut(key, r, false) == null) |
1715 |
> |
return r; |
1716 |
> |
} |
1717 |
> |
else if ((v = n.value) != null) { |
1718 |
> |
@SuppressWarnings("unchecked") V vv = (V) v; |
1719 |
> |
if ((r = remappingFunction.apply(key, vv)) != null) { |
1720 |
> |
if (n.casValue(vv, r)) |
1721 |
|
return r; |
1722 |
|
} |
1723 |
< |
else if ((v = n.value) != null) { |
1724 |
< |
@SuppressWarnings("unchecked") V vv = (V) v; |
2067 |
< |
if ((r = remappingFunction.apply(key, vv)) != null) { |
2068 |
< |
if (n.casValue(vv, r)) |
2069 |
< |
return r; |
2070 |
< |
} |
2071 |
< |
else if (doRemoveCmp(cmp, key, vv) != null) |
2072 |
< |
break; |
2073 |
< |
} |
1723 |
> |
else if (doRemove(key, vv) != null) |
1724 |
> |
break; |
1725 |
|
} |
1726 |
|
} |
1727 |
|
return null; |
1746 |
|
BiFunction<? super V, ? super V, ? extends V> remappingFunction) { |
1747 |
|
if (key == null || value == null || remappingFunction == null) |
1748 |
|
throw new NullPointerException(); |
1749 |
< |
Comparator<? super K> cmp; |
1750 |
< |
if ((cmp = comparator) == null) { |
1751 |
< |
@SuppressWarnings("unchecked") Comparable<? super K> k = |
1752 |
< |
(Comparable<? super K>) key; |
1753 |
< |
for (;;) { |
1754 |
< |
Node<K,V> n; Object v; V r; |
1755 |
< |
if ((n = findNode(k)) == null) { |
1756 |
< |
if (doPut(key, value, false) == null) |
1757 |
< |
return value; |
1758 |
< |
} |
1759 |
< |
else if ((v = n.value) != null) { |
2109 |
< |
@SuppressWarnings("unchecked") V vv = (V) v; |
2110 |
< |
if ((r = remappingFunction.apply(vv, value)) != null) { |
2111 |
< |
if (n.casValue(vv, r)) |
2112 |
< |
return r; |
2113 |
< |
} |
2114 |
< |
else if (doRemove(k, vv) != null) |
2115 |
< |
return null; |
2116 |
< |
} |
2117 |
< |
} |
2118 |
< |
} |
2119 |
< |
else { |
2120 |
< |
for (;;) { |
2121 |
< |
Node<K,V> n; Object v; V r; |
2122 |
< |
if ((n = findNodeCmp(cmp, key)) == null) { |
2123 |
< |
if (doPutCmp(cmp, key, value, false) == null) |
2124 |
< |
return value; |
2125 |
< |
} |
2126 |
< |
else if ((v = n.value) != null) { |
2127 |
< |
@SuppressWarnings("unchecked") V vv = (V) v; |
2128 |
< |
if ((r = remappingFunction.apply(vv, value)) != null) { |
2129 |
< |
if (n.casValue(vv, r)) |
2130 |
< |
return r; |
2131 |
< |
} |
2132 |
< |
else if (doRemoveCmp(cmp, key, vv) != null) |
2133 |
< |
return null; |
1749 |
> |
for (;;) { |
1750 |
> |
Node<K,V> n; Object v; V r; |
1751 |
> |
if ((n = findNode(key)) == null) { |
1752 |
> |
if (doPut(key, value, false) == null) |
1753 |
> |
return value; |
1754 |
> |
} |
1755 |
> |
else if ((v = n.value) != null) { |
1756 |
> |
@SuppressWarnings("unchecked") V vv = (V) v; |
1757 |
> |
if ((r = remappingFunction.apply(vv, value)) != null) { |
1758 |
> |
if (n.casValue(vv, r)) |
1759 |
> |
return r; |
1760 |
|
} |
1761 |
+ |
else if (doRemove(key, vv) != null) |
1762 |
+ |
return null; |
1763 |
|
} |
1764 |
|
} |
1765 |
|
} |
1797 |
|
* @return a navigable set view of the keys in this map |
1798 |
|
*/ |
1799 |
|
public NavigableSet<K> keySet() { |
1800 |
< |
KeySetView<K,V> ks = keySet; |
1801 |
< |
return (ks != null) ? ks : (keySet = new KeySetView<K,V>(this, null)); |
1800 |
> |
KeySet<K> ks = keySet; |
1801 |
> |
return (ks != null) ? ks : (keySet = new KeySet<K>(this)); |
1802 |
|
} |
1803 |
|
|
1804 |
|
public NavigableSet<K> navigableKeySet() { |
1805 |
< |
KeySetView<K,V> ks = keySet; |
1806 |
< |
return (ks != null) ? ks : (keySet = new KeySetView<K,V>(this, null)); |
1805 |
> |
KeySet<K> ks = keySet; |
1806 |
> |
return (ks != null) ? ks : (keySet = new KeySet<K>(this)); |
1807 |
|
} |
1808 |
|
|
1809 |
|
/** |
1918 |
|
* @throws NullPointerException if the specified key or value is null |
1919 |
|
*/ |
1920 |
|
public V putIfAbsent(K key, V value) { |
2293 |
– |
Comparator<? super K> cmp; |
1921 |
|
if (value == null) |
1922 |
|
throw new NullPointerException(); |
1923 |
< |
return ((cmp = comparator) == null) ? |
2297 |
< |
doPut(key, value, true) : doPutCmp(cmp, key, value, true); |
1923 |
> |
return doPut(key, value, true); |
1924 |
|
} |
1925 |
|
|
1926 |
|
/** |
1933 |
|
public boolean remove(Object key, Object value) { |
1934 |
|
if (key == null) |
1935 |
|
throw new NullPointerException(); |
1936 |
< |
if (value == null) |
2311 |
< |
return false; |
2312 |
< |
Comparator<? super K> cmp; |
2313 |
< |
Object v = ((cmp = comparator) == null) ? doRemove(key, value) : |
2314 |
< |
doRemoveCmp(cmp, key, value); |
2315 |
< |
return v != null; |
1936 |
> |
return value != null && doRemove(key, value) != null; |
1937 |
|
} |
1938 |
|
|
1939 |
|
/** |
1944 |
|
* @throws NullPointerException if any of the arguments are null |
1945 |
|
*/ |
1946 |
|
public boolean replace(K key, V oldValue, V newValue) { |
1947 |
< |
if (oldValue == null || newValue == null) |
1947 |
> |
if (key == null || oldValue == null || newValue == null) |
1948 |
|
throw new NullPointerException(); |
2328 |
– |
Comparator<? super K> cmp = comparator; |
1949 |
|
for (;;) { |
1950 |
< |
@SuppressWarnings("unchecked") |
1951 |
< |
Node<K,V> n = (cmp == null) ? |
2332 |
< |
findNode((Comparable<? super K>)key) : |
2333 |
< |
findNodeCmp(cmp, key); |
2334 |
< |
if (n == null) |
1950 |
> |
Node<K,V> n; Object v; |
1951 |
> |
if ((n = findNode(key)) == null) |
1952 |
|
return false; |
1953 |
< |
Object v = n.value; |
2337 |
< |
if (v != null) { |
1953 |
> |
if ((v = n.value) != null) { |
1954 |
|
if (!oldValue.equals(v)) |
1955 |
|
return false; |
1956 |
|
if (n.casValue(v, newValue)) |
1969 |
|
* @throws NullPointerException if the specified key or value is null |
1970 |
|
*/ |
1971 |
|
public V replace(K key, V value) { |
1972 |
< |
if (value == null) |
1972 |
> |
if (key == null || value == null) |
1973 |
|
throw new NullPointerException(); |
2358 |
– |
Comparator<? super K> cmp = comparator; |
1974 |
|
for (;;) { |
1975 |
< |
@SuppressWarnings("unchecked") |
1976 |
< |
Node<K,V> n = (cmp == null) ? |
2362 |
< |
findNode((Comparable<? super K>)key) : |
2363 |
< |
findNodeCmp(cmp, key); |
2364 |
< |
if (n == null) |
1975 |
> |
Node<K,V> n; Object v; |
1976 |
> |
if ((n = findNode(key)) == null) |
1977 |
|
return null; |
1978 |
< |
@SuppressWarnings("unchecked") V v = (V)n.value; |
1979 |
< |
if (v != null && n.casValue(v, value)) |
1980 |
< |
return v; |
1978 |
> |
if ((v = n.value) != null && n.casValue(v, value)) { |
1979 |
> |
@SuppressWarnings("unchecked") V vv = (V)v; |
1980 |
> |
return vv; |
1981 |
> |
} |
1982 |
|
} |
1983 |
|
} |
1984 |
|
|
2096 |
|
* @throws NullPointerException if the specified key is null |
2097 |
|
*/ |
2098 |
|
public K lowerKey(K key) { |
2099 |
< |
Comparator<? super K> cmp; |
2487 |
< |
Node<K,V> n = findNear(key, LT); |
2099 |
> |
Node<K,V> n = findNear(key, LT, comparator); |
2100 |
|
return (n == null) ? null : n.key; |
2101 |
|
} |
2102 |
|
|
2120 |
|
* @throws NullPointerException if the specified key is null |
2121 |
|
*/ |
2122 |
|
public K floorKey(K key) { |
2123 |
< |
Node<K,V> n = findNear(key, LT|EQ); |
2123 |
> |
Node<K,V> n = findNear(key, LT|EQ, comparator); |
2124 |
|
return (n == null) ? null : n.key; |
2125 |
|
} |
2126 |
|
|
2142 |
|
* @throws NullPointerException if the specified key is null |
2143 |
|
*/ |
2144 |
|
public K ceilingKey(K key) { |
2145 |
< |
Node<K,V> n = findNear(key, GT|EQ); |
2145 |
> |
Node<K,V> n = findNear(key, GT|EQ, comparator); |
2146 |
|
return (n == null) ? null : n.key; |
2147 |
|
} |
2148 |
|
|
2166 |
|
* @throws NullPointerException if the specified key is null |
2167 |
|
*/ |
2168 |
|
public K higherKey(K key) { |
2169 |
< |
Node<K,V> n = findNear(key, GT); |
2169 |
> |
Node<K,V> n = findNear(key, GT, comparator); |
2170 |
|
return (n == null) ? null : n.key; |
2171 |
|
} |
2172 |
|
|
2240 |
|
|
2241 |
|
/** Initializes ascending iterator for entire range. */ |
2242 |
|
Iter() { |
2243 |
< |
for (;;) { |
2632 |
< |
next = findFirst(); |
2633 |
< |
if (next == null) |
2634 |
< |
break; |
2243 |
> |
while ((next = findFirst()) != null) { |
2244 |
|
Object x = next.value; |
2245 |
|
if (x != null && x != next) { |
2246 |
|
@SuppressWarnings("unchecked") V vv = (V)x; |
2259 |
|
if (next == null) |
2260 |
|
throw new NoSuchElementException(); |
2261 |
|
lastReturned = next; |
2262 |
< |
for (;;) { |
2654 |
< |
next = next.next; |
2655 |
< |
if (next == null) |
2656 |
< |
break; |
2262 |
> |
while ((next = next.next) != null) { |
2263 |
|
Object x = next.value; |
2264 |
|
if (x != null && x != next) { |
2265 |
|
@SuppressWarnings("unchecked") V vv = (V)x; |
2338 |
|
|
2339 |
|
static final class KeySet<E> |
2340 |
|
extends AbstractSet<E> implements NavigableSet<E> { |
2341 |
< |
private final ConcurrentNavigableMap<E,?> m; |
2341 |
> |
final ConcurrentNavigableMap<E,?> m; |
2342 |
|
KeySet(ConcurrentNavigableMap<E,?> map) { m = map; } |
2343 |
|
public int size() { return m.size(); } |
2344 |
|
public boolean isEmpty() { return m.isEmpty(); } |
2421 |
|
} |
2422 |
|
|
2423 |
|
static final class Values<E> extends AbstractCollection<E> { |
2424 |
< |
private final ConcurrentNavigableMap<?, E> m; |
2424 |
> |
final ConcurrentNavigableMap<?, E> m; |
2425 |
|
Values(ConcurrentNavigableMap<?, E> map) { |
2426 |
|
m = map; |
2427 |
|
} |
2456 |
|
} |
2457 |
|
|
2458 |
|
static final class EntrySet<K1,V1> extends AbstractSet<Map.Entry<K1,V1>> { |
2459 |
< |
private final ConcurrentNavigableMap<K1, V1> m; |
2459 |
> |
final ConcurrentNavigableMap<K1, V1> m; |
2460 |
|
EntrySet(ConcurrentNavigableMap<K1, V1> map) { |
2461 |
|
m = map; |
2462 |
|
} |
2559 |
|
K fromKey, boolean fromInclusive, |
2560 |
|
K toKey, boolean toInclusive, |
2561 |
|
boolean isDescending) { |
2562 |
+ |
Comparator<? super K> cmp = map.comparator; |
2563 |
|
if (fromKey != null && toKey != null && |
2564 |
< |
map.compare(fromKey, toKey) > 0) |
2564 |
> |
cpr(cmp, fromKey, toKey) > 0) |
2565 |
|
throw new IllegalArgumentException("inconsistent range"); |
2566 |
|
this.m = map; |
2567 |
|
this.lo = fromKey; |
2573 |
|
|
2574 |
|
/* ---------------- Utilities -------------- */ |
2575 |
|
|
2576 |
< |
private boolean tooLow(K key) { |
2577 |
< |
if (lo != null) { |
2578 |
< |
int c = m.compare(key, lo); |
2579 |
< |
if (c < 0 || (c == 0 && !loInclusive)) |
2973 |
< |
return true; |
2974 |
< |
} |
2975 |
< |
return false; |
2576 |
> |
boolean tooLow(Object key, Comparator<? super K> cmp) { |
2577 |
> |
int c; |
2578 |
> |
return (lo != null && ((c = cpr(cmp, key, lo)) < 0 || |
2579 |
> |
(c == 0 && !loInclusive))); |
2580 |
|
} |
2581 |
|
|
2582 |
< |
private boolean tooHigh(K key) { |
2583 |
< |
if (hi != null) { |
2584 |
< |
int c = m.compare(key, hi); |
2585 |
< |
if (c > 0 || (c == 0 && !hiInclusive)) |
2982 |
< |
return true; |
2983 |
< |
} |
2984 |
< |
return false; |
2582 |
> |
boolean tooHigh(Object key, Comparator<? super K> cmp) { |
2583 |
> |
int c; |
2584 |
> |
return (hi != null && ((c = cpr(cmp, key, hi)) > 0 || |
2585 |
> |
(c == 0 && !hiInclusive))); |
2586 |
|
} |
2587 |
|
|
2588 |
< |
private boolean inBounds(K key) { |
2589 |
< |
return !tooLow(key) && !tooHigh(key); |
2588 |
> |
boolean inBounds(Object key, Comparator<? super K> cmp) { |
2589 |
> |
return !tooLow(key, cmp) && !tooHigh(key, cmp); |
2590 |
|
} |
2591 |
|
|
2592 |
< |
private void checkKeyBounds(K key) throws IllegalArgumentException { |
2592 |
> |
void checkKeyBounds(K key, Comparator<? super K> cmp) { |
2593 |
|
if (key == null) |
2594 |
|
throw new NullPointerException(); |
2595 |
< |
if (!inBounds(key)) |
2595 |
> |
if (!inBounds(key, cmp)) |
2596 |
|
throw new IllegalArgumentException("key out of range"); |
2597 |
|
} |
2598 |
|
|
2599 |
|
/** |
2600 |
|
* Returns true if node key is less than upper bound of range. |
2601 |
|
*/ |
2602 |
< |
private boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n) { |
2602 |
> |
boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n, |
2603 |
> |
Comparator<? super K> cmp) { |
2604 |
|
if (n == null) |
2605 |
|
return false; |
2606 |
|
if (hi == null) |
2608 |
|
K k = n.key; |
2609 |
|
if (k == null) // pass by markers and headers |
2610 |
|
return true; |
2611 |
< |
int c = m.compare(k, hi); |
2611 |
> |
int c = cpr(cmp, k, hi); |
2612 |
|
if (c > 0 || (c == 0 && !hiInclusive)) |
2613 |
|
return false; |
2614 |
|
return true; |
2618 |
|
* Returns lowest node. This node might not be in range, so |
2619 |
|
* most usages need to check bounds. |
2620 |
|
*/ |
2621 |
< |
private ConcurrentSkipListMap.Node<K,V> loNode() { |
2621 |
> |
ConcurrentSkipListMap.Node<K,V> loNode(Comparator<? super K> cmp) { |
2622 |
|
if (lo == null) |
2623 |
|
return m.findFirst(); |
2624 |
|
else if (loInclusive) |
2625 |
< |
return m.findNear(lo, GT|EQ); |
2625 |
> |
return m.findNear(lo, GT|EQ, cmp); |
2626 |
|
else |
2627 |
< |
return m.findNear(lo, GT); |
2627 |
> |
return m.findNear(lo, GT, cmp); |
2628 |
|
} |
2629 |
|
|
2630 |
|
/** |
2631 |
|
* Returns highest node. This node might not be in range, so |
2632 |
|
* most usages need to check bounds. |
2633 |
|
*/ |
2634 |
< |
private ConcurrentSkipListMap.Node<K,V> hiNode() { |
2634 |
> |
ConcurrentSkipListMap.Node<K,V> hiNode(Comparator<? super K> cmp) { |
2635 |
|
if (hi == null) |
2636 |
|
return m.findLast(); |
2637 |
|
else if (hiInclusive) |
2638 |
< |
return m.findNear(hi, LT|EQ); |
2638 |
> |
return m.findNear(hi, LT|EQ, cmp); |
2639 |
|
else |
2640 |
< |
return m.findNear(hi, LT); |
2640 |
> |
return m.findNear(hi, LT, cmp); |
2641 |
|
} |
2642 |
|
|
2643 |
|
/** |
2644 |
|
* Returns lowest absolute key (ignoring directonality). |
2645 |
|
*/ |
2646 |
< |
private K lowestKey() { |
2647 |
< |
ConcurrentSkipListMap.Node<K,V> n = loNode(); |
2648 |
< |
if (isBeforeEnd(n)) |
2646 |
> |
K lowestKey() { |
2647 |
> |
Comparator<? super K> cmp = m.comparator; |
2648 |
> |
ConcurrentSkipListMap.Node<K,V> n = loNode(cmp); |
2649 |
> |
if (isBeforeEnd(n, cmp)) |
2650 |
|
return n.key; |
2651 |
|
else |
2652 |
|
throw new NoSuchElementException(); |
2655 |
|
/** |
2656 |
|
* Returns highest absolute key (ignoring directonality). |
2657 |
|
*/ |
2658 |
< |
private K highestKey() { |
2659 |
< |
ConcurrentSkipListMap.Node<K,V> n = hiNode(); |
2658 |
> |
K highestKey() { |
2659 |
> |
Comparator<? super K> cmp = m.comparator; |
2660 |
> |
ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp); |
2661 |
|
if (n != null) { |
2662 |
|
K last = n.key; |
2663 |
< |
if (inBounds(last)) |
2663 |
> |
if (inBounds(last, cmp)) |
2664 |
|
return last; |
2665 |
|
} |
2666 |
|
throw new NoSuchElementException(); |
2667 |
|
} |
2668 |
|
|
2669 |
< |
private Map.Entry<K,V> lowestEntry() { |
2669 |
> |
Map.Entry<K,V> lowestEntry() { |
2670 |
> |
Comparator<? super K> cmp = m.comparator; |
2671 |
|
for (;;) { |
2672 |
< |
ConcurrentSkipListMap.Node<K,V> n = loNode(); |
2673 |
< |
if (!isBeforeEnd(n)) |
2672 |
> |
ConcurrentSkipListMap.Node<K,V> n = loNode(cmp); |
2673 |
> |
if (!isBeforeEnd(n, cmp)) |
2674 |
|
return null; |
2675 |
|
Map.Entry<K,V> e = n.createSnapshot(); |
2676 |
|
if (e != null) |
2678 |
|
} |
2679 |
|
} |
2680 |
|
|
2681 |
< |
private Map.Entry<K,V> highestEntry() { |
2681 |
> |
Map.Entry<K,V> highestEntry() { |
2682 |
> |
Comparator<? super K> cmp = m.comparator; |
2683 |
|
for (;;) { |
2684 |
< |
ConcurrentSkipListMap.Node<K,V> n = hiNode(); |
2685 |
< |
if (n == null || !inBounds(n.key)) |
2684 |
> |
ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp); |
2685 |
> |
if (n == null || !inBounds(n.key, cmp)) |
2686 |
|
return null; |
2687 |
|
Map.Entry<K,V> e = n.createSnapshot(); |
2688 |
|
if (e != null) |
2690 |
|
} |
2691 |
|
} |
2692 |
|
|
2693 |
< |
private Map.Entry<K,V> removeLowest() { |
2693 |
> |
Map.Entry<K,V> removeLowest() { |
2694 |
> |
Comparator<? super K> cmp = m.comparator; |
2695 |
|
for (;;) { |
2696 |
< |
Node<K,V> n = loNode(); |
2696 |
> |
Node<K,V> n = loNode(cmp); |
2697 |
|
if (n == null) |
2698 |
|
return null; |
2699 |
|
K k = n.key; |
2700 |
< |
if (!inBounds(k)) |
2700 |
> |
if (!inBounds(k, cmp)) |
2701 |
|
return null; |
2702 |
< |
V v = (m.comparator == null) ? m.doRemove(k, null) : |
3096 |
< |
m.doRemoveCmp(m.comparator, k, null); |
2702 |
> |
V v = m.doRemove(k, null); |
2703 |
|
if (v != null) |
2704 |
|
return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); |
2705 |
|
} |
2706 |
|
} |
2707 |
|
|
2708 |
< |
private Map.Entry<K,V> removeHighest() { |
2708 |
> |
Map.Entry<K,V> removeHighest() { |
2709 |
> |
Comparator<? super K> cmp = m.comparator; |
2710 |
|
for (;;) { |
2711 |
< |
Node<K,V> n = hiNode(); |
2711 |
> |
Node<K,V> n = hiNode(cmp); |
2712 |
|
if (n == null) |
2713 |
|
return null; |
2714 |
|
K k = n.key; |
2715 |
< |
if (!inBounds(k)) |
2715 |
> |
if (!inBounds(k, cmp)) |
2716 |
|
return null; |
2717 |
< |
V v = (m.comparator == null) ? m.doRemove(k, null) : |
3111 |
< |
m.doRemoveCmp(m.comparator, k, null); |
2717 |
> |
V v = m.doRemove(k, null); |
2718 |
|
if (v != null) |
2719 |
|
return new AbstractMap.SimpleImmutableEntry<K,V>(k, v); |
2720 |
|
} |
2723 |
|
/** |
2724 |
|
* Submap version of ConcurrentSkipListMap.getNearEntry |
2725 |
|
*/ |
2726 |
< |
private Map.Entry<K,V> getNearEntry(K key, int rel) { |
2726 |
> |
Map.Entry<K,V> getNearEntry(K key, int rel) { |
2727 |
> |
Comparator<? super K> cmp = m.comparator; |
2728 |
|
if (isDescending) { // adjust relation for direction |
2729 |
|
if ((rel & LT) == 0) |
2730 |
|
rel |= LT; |
2731 |
|
else |
2732 |
|
rel &= ~LT; |
2733 |
|
} |
2734 |
< |
if (tooLow(key)) |
2734 |
> |
if (tooLow(key, cmp)) |
2735 |
|
return ((rel & LT) != 0) ? null : lowestEntry(); |
2736 |
< |
if (tooHigh(key)) |
2736 |
> |
if (tooHigh(key, cmp)) |
2737 |
|
return ((rel & LT) != 0) ? highestEntry() : null; |
2738 |
|
for (;;) { |
2739 |
< |
Node<K,V> n = m.findNear(key, rel); |
2740 |
< |
if (n == null || !inBounds(n.key)) |
2739 |
> |
Node<K,V> n = m.findNear(key, rel, cmp); |
2740 |
> |
if (n == null || !inBounds(n.key, cmp)) |
2741 |
|
return null; |
2742 |
|
K k = n.key; |
2743 |
|
V v = n.getValidValue(); |
2747 |
|
} |
2748 |
|
|
2749 |
|
// Almost the same as getNearEntry, except for keys |
2750 |
< |
private K getNearKey(K key, int rel) { |
2750 |
> |
K getNearKey(K key, int rel) { |
2751 |
> |
Comparator<? super K> cmp = m.comparator; |
2752 |
|
if (isDescending) { // adjust relation for direction |
2753 |
|
if ((rel & LT) == 0) |
2754 |
|
rel |= LT; |
2755 |
|
else |
2756 |
|
rel &= ~LT; |
2757 |
|
} |
2758 |
< |
if (tooLow(key)) { |
2758 |
> |
if (tooLow(key, cmp)) { |
2759 |
|
if ((rel & LT) == 0) { |
2760 |
< |
ConcurrentSkipListMap.Node<K,V> n = loNode(); |
2761 |
< |
if (isBeforeEnd(n)) |
2760 |
> |
ConcurrentSkipListMap.Node<K,V> n = loNode(cmp); |
2761 |
> |
if (isBeforeEnd(n, cmp)) |
2762 |
|
return n.key; |
2763 |
|
} |
2764 |
|
return null; |
2765 |
|
} |
2766 |
< |
if (tooHigh(key)) { |
2766 |
> |
if (tooHigh(key, cmp)) { |
2767 |
|
if ((rel & LT) != 0) { |
2768 |
< |
ConcurrentSkipListMap.Node<K,V> n = hiNode(); |
2768 |
> |
ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp); |
2769 |
|
if (n != null) { |
2770 |
|
K last = n.key; |
2771 |
< |
if (inBounds(last)) |
2771 |
> |
if (inBounds(last, cmp)) |
2772 |
|
return last; |
2773 |
|
} |
2774 |
|
} |
2775 |
|
return null; |
2776 |
|
} |
2777 |
|
for (;;) { |
2778 |
< |
Node<K,V> n = m.findNear(key, rel); |
2779 |
< |
if (n == null || !inBounds(n.key)) |
2778 |
> |
Node<K,V> n = m.findNear(key, rel, cmp); |
2779 |
> |
if (n == null || !inBounds(n.key, cmp)) |
2780 |
|
return null; |
2781 |
|
K k = n.key; |
2782 |
|
V v = n.getValidValue(); |
2789 |
|
|
2790 |
|
public boolean containsKey(Object key) { |
2791 |
|
if (key == null) throw new NullPointerException(); |
2792 |
< |
@SuppressWarnings("unchecked") K k = (K)key; |
3185 |
< |
return inBounds(k) && m.containsKey(k); |
2792 |
> |
return inBounds(key, m.comparator) && m.containsKey(key); |
2793 |
|
} |
2794 |
|
|
2795 |
|
public V get(Object key) { |
2796 |
|
if (key == null) throw new NullPointerException(); |
2797 |
< |
@SuppressWarnings("unchecked") K k = (K)key; |
3191 |
< |
return (!inBounds(k)) ? null : m.get(k); |
2797 |
> |
return (!inBounds(key, m.comparator)) ? null : m.get(key); |
2798 |
|
} |
2799 |
|
|
2800 |
|
public V put(K key, V value) { |
2801 |
< |
checkKeyBounds(key); |
2801 |
> |
checkKeyBounds(key, m.comparator); |
2802 |
|
return m.put(key, value); |
2803 |
|
} |
2804 |
|
|
2805 |
|
public V remove(Object key) { |
2806 |
< |
@SuppressWarnings("unchecked") K k = (K)key; |
3201 |
< |
return (!inBounds(k)) ? null : m.remove(k); |
2806 |
> |
return (!inBounds(key, m.comparator)) ? null : m.remove(key); |
2807 |
|
} |
2808 |
|
|
2809 |
|
public int size() { |
2810 |
+ |
Comparator<? super K> cmp = m.comparator; |
2811 |
|
long count = 0; |
2812 |
< |
for (ConcurrentSkipListMap.Node<K,V> n = loNode(); |
2813 |
< |
isBeforeEnd(n); |
2812 |
> |
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp); |
2813 |
> |
isBeforeEnd(n, cmp); |
2814 |
|
n = n.next) { |
2815 |
|
if (n.getValidValue() != null) |
2816 |
|
++count; |
2819 |
|
} |
2820 |
|
|
2821 |
|
public boolean isEmpty() { |
2822 |
< |
return !isBeforeEnd(loNode()); |
2822 |
> |
Comparator<? super K> cmp = m.comparator; |
2823 |
> |
return !isBeforeEnd(loNode(cmp), cmp); |
2824 |
|
} |
2825 |
|
|
2826 |
|
public boolean containsValue(Object value) { |
2827 |
|
if (value == null) |
2828 |
|
throw new NullPointerException(); |
2829 |
< |
for (ConcurrentSkipListMap.Node<K,V> n = loNode(); |
2830 |
< |
isBeforeEnd(n); |
2829 |
> |
Comparator<? super K> cmp = m.comparator; |
2830 |
> |
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp); |
2831 |
> |
isBeforeEnd(n, cmp); |
2832 |
|
n = n.next) { |
2833 |
|
V v = n.getValidValue(); |
2834 |
|
if (v != null && value.equals(v)) |
2838 |
|
} |
2839 |
|
|
2840 |
|
public void clear() { |
2841 |
< |
for (ConcurrentSkipListMap.Node<K,V> n = loNode(); |
2842 |
< |
isBeforeEnd(n); |
2841 |
> |
Comparator<? super K> cmp = m.comparator; |
2842 |
> |
for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp); |
2843 |
> |
isBeforeEnd(n, cmp); |
2844 |
|
n = n.next) { |
2845 |
|
if (n.getValidValue() != null) |
2846 |
|
m.remove(n.key); |
2850 |
|
/* ---------------- ConcurrentMap API methods -------------- */ |
2851 |
|
|
2852 |
|
public V putIfAbsent(K key, V value) { |
2853 |
< |
checkKeyBounds(key); |
2853 |
> |
checkKeyBounds(key, m.comparator); |
2854 |
|
return m.putIfAbsent(key, value); |
2855 |
|
} |
2856 |
|
|
2857 |
|
public boolean remove(Object key, Object value) { |
2858 |
< |
@SuppressWarnings("unchecked") K k = (K)key; |
3250 |
< |
return inBounds(k) && m.remove(k, value); |
2858 |
> |
return inBounds(key, m.comparator) && m.remove(key, value); |
2859 |
|
} |
2860 |
|
|
2861 |
|
public boolean replace(K key, V oldValue, V newValue) { |
2862 |
< |
checkKeyBounds(key); |
2862 |
> |
checkKeyBounds(key, m.comparator); |
2863 |
|
return m.replace(key, oldValue, newValue); |
2864 |
|
} |
2865 |
|
|
2866 |
|
public V replace(K key, V value) { |
2867 |
< |
checkKeyBounds(key); |
2867 |
> |
checkKeyBounds(key, m.comparator); |
2868 |
|
return m.replace(key, value); |
2869 |
|
} |
2870 |
|
|
2882 |
|
* Utility to create submaps, where given bounds override |
2883 |
|
* unbounded(null) ones and/or are checked against bounded ones. |
2884 |
|
*/ |
2885 |
< |
private SubMap<K,V> newSubMap(K fromKey, |
2886 |
< |
boolean fromInclusive, |
2887 |
< |
K toKey, |
3280 |
< |
boolean toInclusive) { |
2885 |
> |
SubMap<K,V> newSubMap(K fromKey, boolean fromInclusive, |
2886 |
> |
K toKey, boolean toInclusive) { |
2887 |
> |
Comparator<? super K> cmp = m.comparator; |
2888 |
|
if (isDescending) { // flip senses |
2889 |
|
K tk = fromKey; |
2890 |
|
fromKey = toKey; |
2899 |
|
fromInclusive = loInclusive; |
2900 |
|
} |
2901 |
|
else { |
2902 |
< |
int c = m.compare(fromKey, lo); |
2902 |
> |
int c = cpr(cmp, fromKey, lo); |
2903 |
|
if (c < 0 || (c == 0 && !loInclusive && fromInclusive)) |
2904 |
|
throw new IllegalArgumentException("key out of range"); |
2905 |
|
} |
2910 |
|
toInclusive = hiInclusive; |
2911 |
|
} |
2912 |
|
else { |
2913 |
< |
int c = m.compare(toKey, hi); |
2913 |
> |
int c = cpr(cmp, toKey, hi); |
2914 |
|
if (c > 0 || (c == 0 && !hiInclusive && toInclusive)) |
2915 |
|
throw new IllegalArgumentException("key out of range"); |
2916 |
|
} |
2919 |
|
toKey, toInclusive, isDescending); |
2920 |
|
} |
2921 |
|
|
2922 |
< |
public SubMap<K,V> subMap(K fromKey, |
2923 |
< |
boolean fromInclusive, |
3317 |
< |
K toKey, |
3318 |
< |
boolean toInclusive) { |
2922 |
> |
public SubMap<K,V> subMap(K fromKey, boolean fromInclusive, |
2923 |
> |
K toKey, boolean toInclusive) { |
2924 |
|
if (fromKey == null || toKey == null) |
2925 |
|
throw new NullPointerException(); |
2926 |
|
return newSubMap(fromKey, fromInclusive, toKey, toInclusive); |
2927 |
|
} |
2928 |
|
|
2929 |
< |
public SubMap<K,V> headMap(K toKey, |
3325 |
< |
boolean inclusive) { |
2929 |
> |
public SubMap<K,V> headMap(K toKey, boolean inclusive) { |
2930 |
|
if (toKey == null) |
2931 |
|
throw new NullPointerException(); |
2932 |
|
return newSubMap(null, false, toKey, inclusive); |
2933 |
|
} |
2934 |
|
|
2935 |
< |
public SubMap<K,V> tailMap(K fromKey, |
3332 |
< |
boolean inclusive) { |
2935 |
> |
public SubMap<K,V> tailMap(K fromKey, boolean inclusive) { |
2936 |
|
if (fromKey == null) |
2937 |
|
throw new NullPointerException(); |
2938 |
|
return newSubMap(fromKey, inclusive, null, false); |
3064 |
|
V nextValue; |
3065 |
|
|
3066 |
|
SubMapIter() { |
3067 |
+ |
Comparator<? super K> cmp = m.comparator; |
3068 |
|
for (;;) { |
3069 |
< |
next = isDescending ? hiNode() : loNode(); |
3069 |
> |
next = isDescending ? hiNode(cmp) : loNode(cmp); |
3070 |
|
if (next == null) |
3071 |
|
break; |
3072 |
|
Object x = next.value; |
3073 |
|
if (x != null && x != next) { |
3074 |
< |
@SuppressWarnings("unchecked") V vv = (V)x; |
3471 |
< |
if (! inBounds(next.key)) |
3074 |
> |
if (! inBounds(next.key, cmp)) |
3075 |
|
next = null; |
3076 |
< |
else |
3076 |
> |
else { |
3077 |
> |
@SuppressWarnings("unchecked") V vv = (V)x; |
3078 |
|
nextValue = vv; |
3079 |
+ |
} |
3080 |
|
break; |
3081 |
|
} |
3082 |
|
} |
3097 |
|
} |
3098 |
|
|
3099 |
|
private void ascend() { |
3100 |
+ |
Comparator<? super K> cmp = m.comparator; |
3101 |
|
for (;;) { |
3102 |
|
next = next.next; |
3103 |
|
if (next == null) |
3104 |
|
break; |
3105 |
|
Object x = next.value; |
3106 |
|
if (x != null && x != next) { |
3107 |
< |
@SuppressWarnings("unchecked") V vv = (V)x; |
3502 |
< |
if (tooHigh(next.key)) |
3107 |
> |
if (tooHigh(next.key, cmp)) |
3108 |
|
next = null; |
3109 |
< |
else |
3109 |
> |
else { |
3110 |
> |
@SuppressWarnings("unchecked") V vv = (V)x; |
3111 |
|
nextValue = vv; |
3112 |
+ |
} |
3113 |
|
break; |
3114 |
|
} |
3115 |
|
} |
3118 |
|
private void descend() { |
3119 |
|
Comparator<? super K> cmp = m.comparator; |
3120 |
|
for (;;) { |
3121 |
< |
next = (cmp == null) ? m.doFindNear(lastReturned.key, LT) : |
3515 |
< |
m.doFindNearCmp(cmp, lastReturned.key, LT); |
3121 |
> |
next = m.findNear(lastReturned.key, LT, cmp); |
3122 |
|
if (next == null) |
3123 |
|
break; |
3124 |
|
Object x = next.value; |
3125 |
|
if (x != null && x != next) { |
3126 |
< |
@SuppressWarnings("unchecked") V vv = (V)x; |
3521 |
< |
if (tooLow(next.key)) |
3126 |
> |
if (tooLow(next.key, cmp)) |
3127 |
|
next = null; |
3128 |
< |
else |
3128 |
> |
else { |
3129 |
> |
@SuppressWarnings("unchecked") V vv = (V)x; |
3130 |
|
nextValue = vv; |
3131 |
+ |
} |
3132 |
|
break; |
3133 |
|
} |
3134 |
|
} |
3205 |
|
} |
3206 |
|
|
3207 |
|
/** |
3601 |
– |
* A view of a ConcurrentSkipListMap as a {@link Set} of keys, in |
3602 |
– |
* which additions may optionally be enabled by mapping to a |
3603 |
– |
* common value. |
3604 |
– |
*/ |
3605 |
– |
static class KeySetView<K,V> extends AbstractSet<K> |
3606 |
– |
implements NavigableSet<K>, java.io.Serializable { |
3607 |
– |
|
3608 |
– |
/* |
3609 |
– |
* This class overlaps in functionality with the |
3610 |
– |
* relative-scoped KeySet class, but must be distinct and |
3611 |
– |
* unrelated. So we repeat most of the boring delegation code. |
3612 |
– |
*/ |
3613 |
– |
|
3614 |
– |
private static final long serialVersionUID = 7249069246763182397L; |
3615 |
– |
private final ConcurrentSkipListMap<K,V> m; |
3616 |
– |
private final V value; |
3617 |
– |
|
3618 |
– |
KeySetView(ConcurrentSkipListMap<K,V> map, V value) { // non-public |
3619 |
– |
this.m = map; |
3620 |
– |
this.value = value; |
3621 |
– |
} |
3622 |
– |
|
3623 |
– |
/** |
3624 |
– |
* Returns the map backing this view. |
3625 |
– |
* |
3626 |
– |
* @return the map backing this view |
3627 |
– |
*/ |
3628 |
– |
public ConcurrentSkipListMap<K,V> getMap() { return m; } |
3629 |
– |
|
3630 |
– |
/** |
3631 |
– |
* Returns the default mapped value for additions, |
3632 |
– |
* or {@code null} if additions are not supported. |
3633 |
– |
* |
3634 |
– |
* @return the default mapped value for additions, or {@code null} |
3635 |
– |
* if not supported. |
3636 |
– |
*/ |
3637 |
– |
public V getMappedValue() { return value; } |
3638 |
– |
|
3639 |
– |
public boolean add(K e) { |
3640 |
– |
V v; |
3641 |
– |
if ((v = value) == null) |
3642 |
– |
throw new UnsupportedOperationException(); |
3643 |
– |
if (e == null) |
3644 |
– |
throw new NullPointerException(); |
3645 |
– |
return m.put(e, v) == null; |
3646 |
– |
} |
3647 |
– |
|
3648 |
– |
public boolean addAll(Collection<? extends K> c) { |
3649 |
– |
boolean added = false; |
3650 |
– |
V v; |
3651 |
– |
if ((v = value) == null) |
3652 |
– |
throw new UnsupportedOperationException(); |
3653 |
– |
for (K e : c) { |
3654 |
– |
if (e == null) |
3655 |
– |
throw new NullPointerException(); |
3656 |
– |
if (m.put(e, v) == null) |
3657 |
– |
added = true; |
3658 |
– |
} |
3659 |
– |
return added; |
3660 |
– |
} |
3661 |
– |
|
3662 |
– |
public int size() { return m.size(); } |
3663 |
– |
public boolean isEmpty() { return m.isEmpty(); } |
3664 |
– |
public boolean contains(Object o) { return m.containsKey(o); } |
3665 |
– |
public boolean remove(Object o) { return m.remove(o) != null; } |
3666 |
– |
public void clear() { m.clear(); } |
3667 |
– |
public K lower(K e) { return m.lowerKey(e); } |
3668 |
– |
public K floor(K e) { return m.floorKey(e); } |
3669 |
– |
public K ceiling(K e) { return m.ceilingKey(e); } |
3670 |
– |
public K higher(K e) { return m.higherKey(e); } |
3671 |
– |
public Comparator<? super K> comparator() { return m.comparator(); } |
3672 |
– |
public K first() { return m.firstKey(); } |
3673 |
– |
public K last() { return m.lastKey(); } |
3674 |
– |
public Iterator<K> iterator() { return m.keyIterator(); } |
3675 |
– |
public K pollFirst() { |
3676 |
– |
Map.Entry<K,?> e = m.pollFirstEntry(); |
3677 |
– |
return (e == null) ? null : e.getKey(); |
3678 |
– |
} |
3679 |
– |
public K pollLast() { |
3680 |
– |
Map.Entry<K,?> e = m.pollLastEntry(); |
3681 |
– |
return (e == null) ? null : e.getKey(); |
3682 |
– |
} |
3683 |
– |
public boolean equals(Object o) { |
3684 |
– |
if (o == this) |
3685 |
– |
return true; |
3686 |
– |
if (!(o instanceof Set)) |
3687 |
– |
return false; |
3688 |
– |
Collection<?> c = (Collection<?>) o; |
3689 |
– |
try { |
3690 |
– |
return containsAll(c) && c.containsAll(this); |
3691 |
– |
} catch (ClassCastException unused) { |
3692 |
– |
return false; |
3693 |
– |
} catch (NullPointerException unused) { |
3694 |
– |
return false; |
3695 |
– |
} |
3696 |
– |
} |
3697 |
– |
public Object[] toArray() { return toList(this).toArray(); } |
3698 |
– |
public <T> T[] toArray(T[] a) { return toList(this).toArray(a); } |
3699 |
– |
public Iterator<K> descendingIterator() { |
3700 |
– |
return descendingSet().iterator(); |
3701 |
– |
} |
3702 |
– |
public NavigableSet<K> subSet(K fromElement, |
3703 |
– |
boolean fromInclusive, |
3704 |
– |
K toElement, |
3705 |
– |
boolean toInclusive) { |
3706 |
– |
return new KeySet<K>(m.subMap(fromElement, fromInclusive, |
3707 |
– |
toElement, toInclusive)); |
3708 |
– |
} |
3709 |
– |
public NavigableSet<K> headSet(K toElement, boolean inclusive) { |
3710 |
– |
return new KeySet<K>(m.headMap(toElement, inclusive)); |
3711 |
– |
} |
3712 |
– |
public NavigableSet<K> tailSet(K fromElement, boolean inclusive) { |
3713 |
– |
return new KeySet<K>(m.tailMap(fromElement, inclusive)); |
3714 |
– |
} |
3715 |
– |
public NavigableSet<K> subSet(K fromElement, K toElement) { |
3716 |
– |
return subSet(fromElement, true, toElement, false); |
3717 |
– |
} |
3718 |
– |
public NavigableSet<K> headSet(K toElement) { |
3719 |
– |
return headSet(toElement, false); |
3720 |
– |
} |
3721 |
– |
public NavigableSet<K> tailSet(K fromElement) { |
3722 |
– |
return tailSet(fromElement, true); |
3723 |
– |
} |
3724 |
– |
public NavigableSet<K> descendingSet() { |
3725 |
– |
return new KeySet<K>(m.descendingMap()); |
3726 |
– |
} |
3727 |
– |
public Spliterator<K> spliterator() { |
3728 |
– |
return m.keySpliterator(); |
3729 |
– |
} |
3730 |
– |
} |
3731 |
– |
|
3732 |
– |
/** |
3208 |
|
* Base class providing common structure for Spliterators. |
3209 |
|
* (Although not all that much common functionality; as usual for |
3210 |
|
* view classes, details annoyingly vary in key, value, and entry |
3221 |
|
* don't. But we can just use Integer.MAX_VALUE so that we |
3222 |
|
* don't prematurely zero out while splitting. |
3223 |
|
*/ |
3224 |
< |
static class CSLMSpliterator<K,V> { |
3224 |
> |
static abstract class CSLMSpliterator<K,V> { |
3225 |
|
final Comparator<? super K> comparator; |
3226 |
|
final K fence; // exclusive upper bound for keys, or null if to end |
3227 |
|
Index<K,V> row; // the level to split out |
3228 |
|
Node<K,V> current; // current traversal node; initialize at origin |
3229 |
|
int est; // pseudo-size estimate |
3755 |
– |
|
3756 |
– |
CSLMSpliterator(ConcurrentSkipListMap<K,V> m) { |
3757 |
– |
this.comparator = m.comparator; |
3758 |
– |
this.fence = null; |
3759 |
– |
for (;;) { // ensure h corresponds to origin p |
3760 |
– |
HeadIndex<K,V> h; Node<K,V> p; |
3761 |
– |
Node<K,V> b = (h = m.head).node; |
3762 |
– |
if ((p = b.next) == null || p.value != null) { |
3763 |
– |
this.est = (p == null) ? 0 : Integer.MAX_VALUE; |
3764 |
– |
this.current = p; |
3765 |
– |
this.row = h; |
3766 |
– |
break; |
3767 |
– |
} |
3768 |
– |
p.helpDelete(b, p.next); |
3769 |
– |
} |
3770 |
– |
} |
3771 |
– |
|
3230 |
|
CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row, |
3231 |
|
Node<K,V> origin, K fence, int est) { |
3232 |
|
this.comparator = comparator; this.row = row; |
3233 |
|
this.current = origin; this.fence = fence; this.est = est; |
3234 |
|
} |
3235 |
|
|
3778 |
– |
/** Return >= 0 if key is too large (out of bounds) */ |
3779 |
– |
@SuppressWarnings("unchecked") |
3780 |
– |
final int compareBounds(K k) { |
3781 |
– |
Comparator<? super K> cmp; K f; |
3782 |
– |
if (k == null || (f = fence) == null) |
3783 |
– |
return -1; |
3784 |
– |
else if ((cmp = comparator) != null) |
3785 |
– |
return cmp.compare(k, f); |
3786 |
– |
else |
3787 |
– |
return ((Comparable<? super K>)k).compareTo(f); |
3788 |
– |
} |
3789 |
– |
|
3236 |
|
public final long estimateSize() { return (long)est; } |
3791 |
– |
|
3792 |
– |
} |
3793 |
– |
|
3794 |
– |
// factory methods |
3795 |
– |
final KeySpliterator<K,V> keySpliterator() { |
3796 |
– |
return new KeySpliterator<K,V>(this); |
3797 |
– |
} |
3798 |
– |
|
3799 |
– |
final ValueSpliterator<K,V> valueSpliterator() { |
3800 |
– |
return new ValueSpliterator<K,V>(this); |
3801 |
– |
} |
3802 |
– |
|
3803 |
– |
final EntrySpliterator<K,V> entrySpliterator() { |
3804 |
– |
return new EntrySpliterator<K,V>(this); |
3237 |
|
} |
3238 |
|
|
3239 |
|
static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V> |
3240 |
|
implements Spliterator<K> { |
3809 |
– |
KeySpliterator(ConcurrentSkipListMap<K,V> m) { super(m); } |
3241 |
|
KeySpliterator(Comparator<? super K> comparator, Index<K,V> row, |
3242 |
|
Node<K,V> origin, K fence, int est) { |
3243 |
|
super(comparator, row, origin, fence, est); |
3244 |
|
} |
3245 |
|
|
3815 |
– |
@SuppressWarnings("unchecked") |
3246 |
|
public Spliterator<K> trySplit() { |
3247 |
|
Node<K,V> e; K ek; |
3248 |
|
Comparator<? super K> cmp = comparator; |
3249 |
|
K f = fence; |
3250 |
|
if ((e = current) != null && (ek = e.key) != null) { |
3251 |
|
for (Index<K,V> q = row; q != null; q = row = q.down) { |
3252 |
< |
Index<K,V> s; Node<K,V> n; K sk; |
3253 |
< |
if ((s = q.right) != null) { |
3254 |
< |
for (;;) { |
3255 |
< |
Node<K,V> b = s.node; |
3256 |
< |
if ((n = b.next) == null || n.value != null) |
3257 |
< |
break; |
3258 |
< |
n.helpDelete(b, n.next); |
3259 |
< |
} |
3260 |
< |
if (n != null && (sk = n.key) != null && |
3261 |
< |
(cmp != null ? |
3832 |
< |
(cmp.compare(sk, ek) > 0) : |
3833 |
< |
((Comparable<? super K>)sk).compareTo(ek) > 0) && |
3834 |
< |
(f == null || |
3835 |
< |
(cmp != null ? |
3836 |
< |
(cmp.compare(sk, f) < 0) : |
3837 |
< |
((Comparable<? super K>)sk).compareTo(f) < 0))) { |
3838 |
< |
current = n; |
3839 |
< |
Index<K,V> r = q.down; |
3840 |
< |
row = (s.right != null) ? s : s.down; |
3841 |
< |
est -= est >>> 2; |
3842 |
< |
return new KeySpliterator<K,V>(cmp, r, e, sk, est); |
3843 |
< |
} |
3252 |
> |
Index<K,V> s; Node<K,V> b, n; K sk; |
3253 |
> |
if ((s = q.right) != null && (b = s.node) != null && |
3254 |
> |
(n = b.next) != null && n.value != null && |
3255 |
> |
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 && |
3256 |
> |
(f == null || cpr(cmp, sk, f) < 0)) { |
3257 |
> |
current = n; |
3258 |
> |
Index<K,V> r = q.down; |
3259 |
> |
row = (s.right != null) ? s : s.down; |
3260 |
> |
est -= est >>> 2; |
3261 |
> |
return new KeySpliterator<K,V>(cmp, r, e, sk, est); |
3262 |
|
} |
3263 |
|
} |
3264 |
|
} |
3267 |
|
|
3268 |
|
public void forEachRemaining(Consumer<? super K> action) { |
3269 |
|
if (action == null) throw new NullPointerException(); |
3852 |
– |
K f = fence; |
3270 |
|
Comparator<? super K> cmp = comparator; |
3271 |
< |
@SuppressWarnings("unchecked") |
3855 |
< |
Comparable<? super K> cf = (f != null && cmp == null) ? |
3856 |
< |
(Comparable<? super K>)f : null; |
3271 |
> |
K f = fence; |
3272 |
|
Node<K,V> e = current; |
3273 |
|
current = null; |
3274 |
|
for (; e != null; e = e.next) { |
3275 |
|
K k; Object v; |
3276 |
< |
if ((k = e.key) != null && |
3862 |
< |
(cf != null ? (cf.compareTo(k) <= 0) : |
3863 |
< |
(f != null && cmp.compare(f, k) <= 0))) |
3276 |
> |
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) |
3277 |
|
break; |
3278 |
|
if ((v = e.value) != null && v != e) |
3279 |
|
action.accept(k); |
3282 |
|
|
3283 |
|
public boolean tryAdvance(Consumer<? super K> action) { |
3284 |
|
if (action == null) throw new NullPointerException(); |
3285 |
< |
Node<K,V> e; |
3286 |
< |
for (e = current; e != null; e = e.next) { |
3285 |
> |
Comparator<? super K> cmp = comparator; |
3286 |
> |
K f = fence; |
3287 |
> |
Node<K,V> e = current; |
3288 |
> |
for (; e != null; e = e.next) { |
3289 |
|
K k; Object v; |
3290 |
< |
if (compareBounds(k = e.key) >= 0) { |
3290 |
> |
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) { |
3291 |
|
e = null; |
3292 |
|
break; |
3293 |
|
} |
3311 |
|
return comparator; |
3312 |
|
} |
3313 |
|
} |
3314 |
+ |
// factory method for Keyspliterator |
3315 |
+ |
final KeySpliterator<K,V> keySpliterator() { |
3316 |
+ |
Comparator<? super K> cmp = comparator; |
3317 |
+ |
for (;;) { // ensure h corresponds to origin p |
3318 |
+ |
HeadIndex<K,V> h; Node<K,V> p; |
3319 |
+ |
Node<K,V> b = (h = head).node; |
3320 |
+ |
if ((p = b.next) == null || p.value != null) |
3321 |
+ |
return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ? |
3322 |
+ |
0 : Integer.MAX_VALUE); |
3323 |
+ |
p.helpDelete(b, p.next); |
3324 |
+ |
} |
3325 |
+ |
} |
3326 |
|
|
3327 |
|
static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V> |
3328 |
|
implements Spliterator<V> { |
3902 |
– |
ValueSpliterator(ConcurrentSkipListMap<K,V> m) { super(m); } |
3329 |
|
ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row, |
3330 |
|
Node<K,V> origin, K fence, int est) { |
3331 |
|
super(comparator, row, origin, fence, est); |
3332 |
|
} |
3333 |
|
|
3908 |
– |
@SuppressWarnings("unchecked") |
3334 |
|
public Spliterator<V> trySplit() { |
3335 |
|
Node<K,V> e; K ek; |
3336 |
|
Comparator<? super K> cmp = comparator; |
3337 |
|
K f = fence; |
3338 |
|
if ((e = current) != null && (ek = e.key) != null) { |
3339 |
|
for (Index<K,V> q = row; q != null; q = row = q.down) { |
3340 |
< |
Index<K,V> s; Node<K,V> n; K sk; |
3341 |
< |
if ((s = q.right) != null) { |
3342 |
< |
for (;;) { |
3343 |
< |
Node<K,V> b = s.node; |
3344 |
< |
if ((n = b.next) == null || n.value != null) |
3345 |
< |
break; |
3346 |
< |
n.helpDelete(b, n.next); |
3347 |
< |
} |
3348 |
< |
if (n != null && (sk = n.key) != null && |
3349 |
< |
(cmp != null ? |
3925 |
< |
(cmp.compare(sk, ek) > 0) : |
3926 |
< |
((Comparable<? super K>)sk).compareTo(ek) > 0) && |
3927 |
< |
(f == null || |
3928 |
< |
(cmp != null ? |
3929 |
< |
(cmp.compare(sk, f) < 0) : |
3930 |
< |
((Comparable<? super K>)sk).compareTo(f) < 0))) { |
3931 |
< |
current = n; |
3932 |
< |
Index<K,V> r = q.down; |
3933 |
< |
row = (s.right != null) ? s : s.down; |
3934 |
< |
est -= est >>> 2; |
3935 |
< |
return new ValueSpliterator<K,V>(cmp, r, e, sk, est); |
3936 |
< |
} |
3340 |
> |
Index<K,V> s; Node<K,V> b, n; K sk; |
3341 |
> |
if ((s = q.right) != null && (b = s.node) != null && |
3342 |
> |
(n = b.next) != null && n.value != null && |
3343 |
> |
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 && |
3344 |
> |
(f == null || cpr(cmp, sk, f) < 0)) { |
3345 |
> |
current = n; |
3346 |
> |
Index<K,V> r = q.down; |
3347 |
> |
row = (s.right != null) ? s : s.down; |
3348 |
> |
est -= est >>> 2; |
3349 |
> |
return new ValueSpliterator<K,V>(cmp, r, e, sk, est); |
3350 |
|
} |
3351 |
|
} |
3352 |
|
} |
3355 |
|
|
3356 |
|
public void forEachRemaining(Consumer<? super V> action) { |
3357 |
|
if (action == null) throw new NullPointerException(); |
3945 |
– |
K f = fence; |
3358 |
|
Comparator<? super K> cmp = comparator; |
3359 |
< |
@SuppressWarnings("unchecked") |
3948 |
< |
Comparable<? super K> cf = (f != null && cmp == null) ? |
3949 |
< |
(Comparable<? super K>)f : null; |
3359 |
> |
K f = fence; |
3360 |
|
Node<K,V> e = current; |
3361 |
|
current = null; |
3362 |
|
for (; e != null; e = e.next) { |
3363 |
|
K k; Object v; |
3364 |
< |
if ((k = e.key) != null && |
3955 |
< |
(cf != null ? (cf.compareTo(k) <= 0) : |
3956 |
< |
(f != null && cmp.compare(f, k) <= 0))) |
3364 |
> |
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) |
3365 |
|
break; |
3366 |
|
if ((v = e.value) != null && v != e) { |
3367 |
|
@SuppressWarnings("unchecked") V vv = (V)v; |
3372 |
|
|
3373 |
|
public boolean tryAdvance(Consumer<? super V> action) { |
3374 |
|
if (action == null) throw new NullPointerException(); |
3375 |
< |
boolean advanced = false; |
3376 |
< |
Node<K,V> e; |
3377 |
< |
for (e = current; e != null; e = e.next) { |
3375 |
> |
Comparator<? super K> cmp = comparator; |
3376 |
> |
K f = fence; |
3377 |
> |
Node<K,V> e = current; |
3378 |
> |
for (; e != null; e = e.next) { |
3379 |
|
K k; Object v; |
3380 |
< |
if (compareBounds(k = e.key) >= 0) { |
3380 |
> |
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) { |
3381 |
|
e = null; |
3382 |
|
break; |
3383 |
|
} |
3397 |
|
} |
3398 |
|
} |
3399 |
|
|
3400 |
+ |
// Almost the same as keySpliterator() |
3401 |
+ |
final ValueSpliterator<K,V> valueSpliterator() { |
3402 |
+ |
Comparator<? super K> cmp = comparator; |
3403 |
+ |
for (;;) { |
3404 |
+ |
HeadIndex<K,V> h; Node<K,V> p; |
3405 |
+ |
Node<K,V> b = (h = head).node; |
3406 |
+ |
if ((p = b.next) == null || p.value != null) |
3407 |
+ |
return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ? |
3408 |
+ |
0 : Integer.MAX_VALUE); |
3409 |
+ |
p.helpDelete(b, p.next); |
3410 |
+ |
} |
3411 |
+ |
} |
3412 |
+ |
|
3413 |
|
static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V> |
3414 |
|
implements Spliterator<Map.Entry<K,V>> { |
3993 |
– |
EntrySpliterator(ConcurrentSkipListMap<K,V> m) { super(m); } |
3415 |
|
EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row, |
3416 |
|
Node<K,V> origin, K fence, int est) { |
3417 |
|
super(comparator, row, origin, fence, est); |
3418 |
|
} |
3419 |
|
|
3999 |
– |
@SuppressWarnings("unchecked") |
3420 |
|
public Spliterator<Map.Entry<K,V>> trySplit() { |
3421 |
|
Node<K,V> e; K ek; |
3422 |
|
Comparator<? super K> cmp = comparator; |
3423 |
|
K f = fence; |
3424 |
|
if ((e = current) != null && (ek = e.key) != null) { |
3425 |
|
for (Index<K,V> q = row; q != null; q = row = q.down) { |
3426 |
< |
Index<K,V> s; Node<K,V> n; K sk; |
3427 |
< |
if ((s = q.right) != null) { |
3428 |
< |
for (;;) { |
3429 |
< |
Node<K,V> b = s.node; |
3430 |
< |
if ((n = b.next) == null || n.value != null) |
3431 |
< |
break; |
3432 |
< |
n.helpDelete(b, n.next); |
3433 |
< |
} |
3434 |
< |
if (n != null && (sk = n.key) != null && |
3435 |
< |
(cmp != null ? |
4016 |
< |
(cmp.compare(sk, ek) > 0) : |
4017 |
< |
((Comparable<? super K>)sk).compareTo(ek) > 0) && |
4018 |
< |
(f == null || |
4019 |
< |
(cmp != null ? |
4020 |
< |
(cmp.compare(sk, f) < 0) : |
4021 |
< |
((Comparable<? super K>)sk).compareTo(f) < 0))) { |
4022 |
< |
current = n; |
4023 |
< |
Index<K,V> r = q.down; |
4024 |
< |
row = (s.right != null) ? s : s.down; |
4025 |
< |
est -= est >>> 2; |
4026 |
< |
return new EntrySpliterator<K,V>(cmp, r, e, sk, est); |
4027 |
< |
} |
3426 |
> |
Index<K,V> s; Node<K,V> b, n; K sk; |
3427 |
> |
if ((s = q.right) != null && (b = s.node) != null && |
3428 |
> |
(n = b.next) != null && n.value != null && |
3429 |
> |
(sk = n.key) != null && cpr(cmp, sk, ek) > 0 && |
3430 |
> |
(f == null || cpr(cmp, sk, f) < 0)) { |
3431 |
> |
current = n; |
3432 |
> |
Index<K,V> r = q.down; |
3433 |
> |
row = (s.right != null) ? s : s.down; |
3434 |
> |
est -= est >>> 2; |
3435 |
> |
return new EntrySpliterator<K,V>(cmp, r, e, sk, est); |
3436 |
|
} |
3437 |
|
} |
3438 |
|
} |
3441 |
|
|
3442 |
|
public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) { |
3443 |
|
if (action == null) throw new NullPointerException(); |
4036 |
– |
K f = fence; |
3444 |
|
Comparator<? super K> cmp = comparator; |
3445 |
< |
@SuppressWarnings("unchecked") |
4039 |
< |
Comparable<? super K> cf = (f != null && cmp == null) ? |
4040 |
< |
(Comparable<? super K>)f : null; |
3445 |
> |
K f = fence; |
3446 |
|
Node<K,V> e = current; |
3447 |
|
current = null; |
3448 |
|
for (; e != null; e = e.next) { |
3449 |
|
K k; Object v; |
3450 |
< |
if ((k = e.key) != null && |
4046 |
< |
(cf != null ? |
4047 |
< |
(cf.compareTo(k) <= 0) : |
4048 |
< |
(f != null && cmp.compare(f, k) <= 0))) |
3450 |
> |
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) |
3451 |
|
break; |
3452 |
|
if ((v = e.value) != null && v != e) { |
3453 |
|
@SuppressWarnings("unchecked") V vv = (V)v; |
3459 |
|
|
3460 |
|
public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) { |
3461 |
|
if (action == null) throw new NullPointerException(); |
3462 |
< |
Node<K,V> e; |
3463 |
< |
for (e = current; e != null; e = e.next) { |
3462 |
> |
Comparator<? super K> cmp = comparator; |
3463 |
> |
K f = fence; |
3464 |
> |
Node<K,V> e = current; |
3465 |
> |
for (; e != null; e = e.next) { |
3466 |
|
K k; Object v; |
3467 |
< |
if (compareBounds(k = e.key) >= 0) { |
3467 |
> |
if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) { |
3468 |
|
e = null; |
3469 |
|
break; |
3470 |
|
} |
3490 |
|
return comparator == null ? null : |
3491 |
|
Comparators.byKey(comparator); |
3492 |
|
} |
3493 |
+ |
} |
3494 |
|
|
3495 |
+ |
// Almost the same as keySpliterator() |
3496 |
+ |
final EntrySpliterator<K,V> entrySpliterator() { |
3497 |
+ |
Comparator<? super K> cmp = comparator; |
3498 |
+ |
for (;;) { // almost same as key version |
3499 |
+ |
HeadIndex<K,V> h; Node<K,V> p; |
3500 |
+ |
Node<K,V> b = (h = head).node; |
3501 |
+ |
if ((p = b.next) == null || p.value != null) |
3502 |
+ |
return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ? |
3503 |
+ |
0 : Integer.MAX_VALUE); |
3504 |
+ |
p.helpDelete(b, p.next); |
3505 |
+ |
} |
3506 |
|
} |
3507 |
|
|
3508 |
|
// Unsafe mechanics |