@@ -14,6 +14,9 @@ use std::ops::RangeBounds;
14
14
use std:: panic:: { catch_unwind, AssertUnwindSafe } ;
15
15
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
16
16
17
+ mod ord_chaos;
18
+ use ord_chaos:: { Cyclic3 , Governed , Governor } ;
19
+
17
20
// Capacity of a tree with a single level,
18
21
// i.e., a tree who's root is a leaf node at height 0.
19
22
const NODE_CAPACITY : usize = node:: CAPACITY ;
@@ -28,7 +31,7 @@ const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1;
28
31
// It's not the minimum size: removing an element from such a tree does not always reduce height.
29
32
const MIN_INSERTS_HEIGHT_2 : usize = 89 ;
30
33
31
- // Gather all references from a mutable iterator and make sure Miri notices if
34
+ // Gathers all references from a mutable iterator and makes sure Miri notices if
32
35
// using them is dangerous.
33
36
fn test_all_refs < ' a , T : ' a > ( dummy : & mut T , iter : impl Iterator < Item = & ' a mut T > ) {
34
37
// Gather all those references.
@@ -43,28 +46,43 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>
43
46
}
44
47
45
48
impl < K , V > BTreeMap < K , V > {
46
- /// Panics if the map (or the code navigating it) is corrupted.
47
- fn check ( & self )
48
- where
49
- K : Copy + Debug + Ord ,
50
- {
49
+ // Panics if the map (or the code navigating it) is corrupted.
50
+ fn check_invariants ( & self ) {
51
51
if let Some ( root) = & self . root {
52
52
let root_node = root. node_as_ref ( ) ;
53
53
54
+ // Check the back pointers top-down, before we attempt to rely on
55
+ // more serious navigation code.
54
56
assert ! ( root_node. ascend( ) . is_err( ) ) ;
55
57
root_node. assert_back_pointers ( ) ;
56
58
59
+ // Check consistenty of `length` and some of the navigation.
57
60
assert_eq ! ( self . length, root_node. calc_length( ) ) ;
61
+ assert_eq ! ( self . length, self . keys( ) . count( ) ) ;
58
62
63
+ // Lastly, check the invariant causing the least harm.
59
64
root_node. assert_min_len ( if root_node. height ( ) > 0 { 1 } else { 0 } ) ;
60
65
} else {
66
+ // Check consistenty of `length` and some of the navigation.
61
67
assert_eq ! ( self . length, 0 ) ;
68
+ assert_eq ! ( self . length, self . keys( ) . count( ) ) ;
62
69
}
70
+ }
63
71
64
- self . assert_ascending ( ) ;
72
+ // Panics if the map is corrupted or if the keys are not in strictly
73
+ // ascending order, in the current opinion of the `Ord` implementation.
74
+ // If the `Ord` implementation does not honor transitivity, this method
75
+ // does not guarantee that all the keys are unique, just that adjacent
76
+ // keys are unique.
77
+ fn check ( & self )
78
+ where
79
+ K : Debug + Ord ,
80
+ {
81
+ self . check_invariants ( ) ;
82
+ self . assert_strictly_ascending ( ) ;
65
83
}
66
84
67
- /// Returns the height of the root, if any.
85
+ // Returns the height of the root, if any.
68
86
fn height ( & self ) -> Option < usize > {
69
87
self . root . as_ref ( ) . map ( node:: Root :: height)
70
88
}
@@ -80,22 +98,18 @@ impl<K, V> BTreeMap<K, V> {
80
98
}
81
99
}
82
100
83
- /// Asserts that the keys are in strictly ascending order.
84
- fn assert_ascending ( & self )
101
+ // Panics if the keys are not in strictly ascending order.
102
+ fn assert_strictly_ascending ( & self )
85
103
where
86
- K : Copy + Debug + Ord ,
104
+ K : Debug + Ord ,
87
105
{
88
- let mut num_seen = 0 ;
89
106
let mut keys = self . keys ( ) ;
90
107
if let Some ( mut previous) = keys. next ( ) {
91
- num_seen = 1 ;
92
108
for next in keys {
93
109
assert ! ( previous < next, "{:?} >= {:?}" , previous, next) ;
94
110
previous = next;
95
- num_seen += 1 ;
96
111
}
97
112
}
98
- assert_eq ! ( num_seen, self . len( ) ) ;
99
113
}
100
114
}
101
115
@@ -111,7 +125,7 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
111
125
}
112
126
}
113
127
114
- // Test our value of MIN_INSERTS_HEIGHT_2. It may change according to the
128
+ // Tests our value of MIN_INSERTS_HEIGHT_2. It may change according to the
115
129
// implementation of insertion, but it's best to be aware of when it does.
116
130
#[ test]
117
131
fn test_levels ( ) {
@@ -149,6 +163,25 @@ fn test_levels() {
149
163
assert_eq ! ( map. len( ) , MIN_INSERTS_HEIGHT_2 , "{}" , map. dump_keys( ) ) ;
150
164
}
151
165
166
+ // Ensures the testing infrastructure usually notices order violations.
167
+ #[ test]
168
+ #[ should_panic]
169
+ fn test_check_ord_chaos ( ) {
170
+ let gov = Governor :: new ( ) ;
171
+ let map: BTreeMap < _ , _ > = ( 0 ..2 ) . map ( |i| ( Governed ( i, & gov) , ( ) ) ) . collect ( ) ;
172
+ gov. flip ( ) ;
173
+ map. check ( ) ;
174
+ }
175
+
176
+ // Ensures the testing infrastructure doesn't always mind order violations.
177
+ #[ test]
178
+ fn test_check_invariants_ord_chaos ( ) {
179
+ let gov = Governor :: new ( ) ;
180
+ let map: BTreeMap < _ , _ > = ( 0 ..2 ) . map ( |i| ( Governed ( i, & gov) , ( ) ) ) . collect ( ) ;
181
+ gov. flip ( ) ;
182
+ map. check_invariants ( ) ;
183
+ }
184
+
152
185
#[ test]
153
186
fn test_basic_large ( ) {
154
187
let mut map = BTreeMap :: new ( ) ;
@@ -334,7 +367,7 @@ fn test_iter_rev() {
334
367
test ( size, map. into_iter ( ) . rev ( ) ) ;
335
368
}
336
369
337
- /// Specifically tests iter_mut's ability to mutate the value of pairs in-line
370
+ // Specifically tests iter_mut's ability to mutate the value of pairs in-line.
338
371
fn do_test_iter_mut_mutation < T > ( size : usize )
339
372
where
340
373
T : Copy + Debug + Ord + TryFrom < usize > ,
@@ -439,6 +472,8 @@ fn test_iter_entering_root_twice() {
439
472
* back. 1 = 42 ;
440
473
assert_eq ! ( front, ( & 0 , & mut 24 ) ) ;
441
474
assert_eq ! ( back, ( & 1 , & mut 42 ) ) ;
475
+ assert_eq ! ( it. next( ) , None ) ;
476
+ assert_eq ! ( it. next_back( ) , None ) ;
442
477
map. check ( ) ;
443
478
}
444
479
@@ -591,11 +626,12 @@ fn test_range_small() {
591
626
592
627
#[ test]
593
628
fn test_range_height_1 ( ) {
594
- // Tests tree with a root and 2 leaves. Depending on details we don't want or need
595
- // to rely upon, the single key at the root will be 6 or 7 .
629
+ // Tests tree with a root and 2 leaves. The single key in the root node is
630
+ // close to the middle among the keys .
596
631
597
- let map: BTreeMap < _ , _ > = ( 1 ..=MIN_INSERTS_HEIGHT_1 as i32 ) . map ( |i| ( i, i) ) . collect ( ) ;
598
- for & root in & [ 6 , 7 ] {
632
+ let map: BTreeMap < _ , _ > = ( 0 ..MIN_INSERTS_HEIGHT_1 as i32 ) . map ( |i| ( i, i) ) . collect ( ) ;
633
+ let middle = MIN_INSERTS_HEIGHT_1 as i32 / 2 ;
634
+ for root in middle - 2 ..=middle + 2 {
599
635
assert_eq ! ( range_keys( & map, ( Excluded ( root) , Excluded ( root + 1 ) ) ) , vec![ ] ) ;
600
636
assert_eq ! ( range_keys( & map, ( Excluded ( root) , Included ( root + 1 ) ) ) , vec![ root + 1 ] ) ;
601
637
assert_eq ! ( range_keys( & map, ( Included ( root) , Excluded ( root + 1 ) ) ) , vec![ root] ) ;
@@ -727,6 +763,19 @@ fn test_range_backwards_4() {
727
763
map. range ( ( Excluded ( 3 ) , Excluded ( 2 ) ) ) ;
728
764
}
729
765
766
+ #[ test]
767
+ #[ should_panic]
768
+ fn test_range_backwards_5 ( ) {
769
+ let mut map = BTreeMap :: new ( ) ;
770
+ map. insert ( Cyclic3 :: B , ( ) ) ;
771
+ // Lacking static_assert, call `range` conditionally, to emphasise that
772
+ // we cause a different panic than `test_range_backwards_1` does.
773
+ // A more refined `should_panic` would be welcome.
774
+ if Cyclic3 :: C < Cyclic3 :: A {
775
+ map. range ( Cyclic3 :: C ..=Cyclic3 :: A ) ;
776
+ }
777
+ }
778
+
730
779
#[ test]
731
780
fn test_range_1000 ( ) {
732
781
// Miri is too slow
@@ -831,18 +880,28 @@ mod test_drain_filter {
831
880
}
832
881
833
882
#[ test]
834
- fn consuming_nothing ( ) {
883
+ fn consumed_keeping_all ( ) {
835
884
let pairs = ( 0 ..3 ) . map ( |i| ( i, i) ) ;
836
885
let mut map: BTreeMap < _ , _ > = pairs. collect ( ) ;
837
886
assert ! ( map. drain_filter( |_, _| false ) . eq( iter:: empty( ) ) ) ;
838
887
map. check ( ) ;
839
888
}
840
889
841
890
#[ test]
842
- fn consuming_all ( ) {
891
+ fn consumed_removing_all ( ) {
843
892
let pairs = ( 0 ..3 ) . map ( |i| ( i, i) ) ;
844
893
let mut map: BTreeMap < _ , _ > = pairs. clone ( ) . collect ( ) ;
845
894
assert ! ( map. drain_filter( |_, _| true ) . eq( pairs) ) ;
895
+ assert ! ( map. is_empty( ) ) ;
896
+ map. check ( ) ;
897
+ }
898
+
899
+ #[ test]
900
+ fn dropped_removing_all ( ) {
901
+ let pairs = ( 0 ..3 ) . map ( |i| ( i, i) ) ;
902
+ let mut map: BTreeMap < _ , _ > = pairs. collect ( ) ;
903
+ map. drain_filter ( |_, _| true ) ;
904
+ assert ! ( map. is_empty( ) ) ;
846
905
map. check ( ) ;
847
906
}
848
907
@@ -1723,6 +1782,27 @@ fn test_append_drop_leak() {
1723
1782
assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 4 ) ; // Rust issue #47949 ate one little piggy
1724
1783
}
1725
1784
1785
+ #[ test]
1786
+ fn test_append_ord_chaos ( ) {
1787
+ let mut map1 = BTreeMap :: new ( ) ;
1788
+ map1. insert ( Cyclic3 :: A , ( ) ) ;
1789
+ map1. insert ( Cyclic3 :: B , ( ) ) ;
1790
+ let mut map2 = BTreeMap :: new ( ) ;
1791
+ map2. insert ( Cyclic3 :: A , ( ) ) ;
1792
+ map2. insert ( Cyclic3 :: B , ( ) ) ;
1793
+ map2. insert ( Cyclic3 :: C , ( ) ) ; // lands first, before A
1794
+ map2. insert ( Cyclic3 :: B , ( ) ) ; // lands first, before C
1795
+ map1. check ( ) ;
1796
+ map2. check ( ) ; // keys are not unique but still strictly ascending
1797
+ assert_eq ! ( map1. len( ) , 2 ) ;
1798
+ assert_eq ! ( map2. len( ) , 4 ) ;
1799
+ map1. append ( & mut map2) ;
1800
+ assert_eq ! ( map1. len( ) , 5 ) ;
1801
+ assert_eq ! ( map2. len( ) , 0 ) ;
1802
+ map1. check ( ) ;
1803
+ map2. check ( ) ;
1804
+ }
1805
+
1726
1806
fn rand_data ( len : usize ) -> Vec < ( u32 , u32 ) > {
1727
1807
assert ! ( len * 2 <= 70029 ) ; // from that point on numbers repeat
1728
1808
let mut rng = DeterministicRng :: new ( ) ;
@@ -1885,11 +1965,27 @@ fn test_insert_remove_intertwined() {
1885
1965
let loops = if cfg ! ( miri) { 100 } else { 1_000_000 } ;
1886
1966
let mut map = BTreeMap :: new ( ) ;
1887
1967
let mut i = 1 ;
1968
+ let offset = 165 ; // somewhat arbitrarily chosen to cover some code paths
1888
1969
for _ in 0 ..loops {
1889
- i = ( i + 421 ) & 0xFF ;
1970
+ i = ( i + offset ) & 0xFF ;
1890
1971
map. insert ( i, i) ;
1891
1972
map. remove ( & ( 0xFF - i) ) ;
1892
1973
}
1893
-
1894
1974
map. check ( ) ;
1895
1975
}
1976
+
1977
+ #[ test]
1978
+ fn test_insert_remove_intertwined_ord_chaos ( ) {
1979
+ let loops = if cfg ! ( miri) { 100 } else { 1_000_000 } ;
1980
+ let gov = Governor :: new ( ) ;
1981
+ let mut map = BTreeMap :: new ( ) ;
1982
+ let mut i = 1 ;
1983
+ let offset = 165 ; // more arbitrarily copied from above
1984
+ for _ in 0 ..loops {
1985
+ i = ( i + offset) & 0xFF ;
1986
+ map. insert ( Governed ( i, & gov) , ( ) ) ;
1987
+ map. remove ( & Governed ( 0xFF - i, & gov) ) ;
1988
+ gov. flip ( ) ;
1989
+ }
1990
+ map. check_invariants ( ) ;
1991
+ }
0 commit comments