@@ -3,6 +3,7 @@ use std::collections::BTreeMap;
3
3
use std:: convert:: TryFrom ;
4
4
use std:: fmt:: Debug ;
5
5
use std:: iter:: FromIterator ;
6
+ use std:: mem;
6
7
use std:: ops:: Bound :: { self , Excluded , Included , Unbounded } ;
7
8
use std:: ops:: RangeBounds ;
8
9
use std:: panic:: { catch_unwind, AssertUnwindSafe } ;
@@ -25,6 +26,20 @@ const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1;
25
26
// It's not the minimum size: removing an element from such a tree does not always reduce height.
26
27
const MIN_INSERTS_HEIGHT_2 : usize = NODE_CAPACITY + ( NODE_CAPACITY + 1 ) * NODE_CAPACITY + 1 ;
27
28
29
+ // Gather all references from a mutable iterator and make sure Miri notices if
30
+ // using them is dangerous.
31
+ fn test_all_refs < ' a , T : ' a > ( dummy : & mut T , iter : impl Iterator < Item = & ' a mut T > ) {
32
+ // Gather all those references.
33
+ let mut refs: Vec < & mut T > = iter. collect ( ) ;
34
+ // Use them all. Twice, to be sure we got all interleavings.
35
+ for r in refs. iter_mut ( ) {
36
+ mem:: swap ( dummy, r) ;
37
+ }
38
+ for r in refs {
39
+ mem:: swap ( dummy, r) ;
40
+ }
41
+ }
42
+
28
43
#[ test]
29
44
fn test_basic_large ( ) {
30
45
let mut map = BTreeMap :: new ( ) ;
@@ -268,7 +283,14 @@ fn test_iter_mut_mutation() {
268
283
}
269
284
270
285
#[ test]
286
+ #[ cfg_attr( miri, ignore) ] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
271
287
fn test_values_mut ( ) {
288
+ let mut a: BTreeMap < _ , _ > = ( 0 ..MIN_INSERTS_HEIGHT_2 ) . map ( |i| ( i, i) ) . collect ( ) ;
289
+ test_all_refs ( & mut 13 , a. values_mut ( ) ) ;
290
+ }
291
+
292
+ #[ test]
293
+ fn test_values_mut_mutation ( ) {
272
294
let mut a = BTreeMap :: new ( ) ;
273
295
a. insert ( 1 , String :: from ( "hello" ) ) ;
274
296
a. insert ( 2 , String :: from ( "goodbye" ) ) ;
@@ -281,6 +303,36 @@ fn test_values_mut() {
281
303
assert_eq ! ( values, [ String :: from( "hello!" ) , String :: from( "goodbye!" ) ] ) ;
282
304
}
283
305
306
+ #[ test]
307
+ #[ cfg_attr( miri, ignore) ] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
308
+ fn test_iter_entering_root_twice ( ) {
309
+ let mut map: BTreeMap < _ , _ > = ( 0 ..2 ) . map ( |i| ( i, i) ) . collect ( ) ;
310
+ let mut it = map. iter_mut ( ) ;
311
+ let front = it. next ( ) . unwrap ( ) ;
312
+ let back = it. next_back ( ) . unwrap ( ) ;
313
+ assert_eq ! ( front, ( & 0 , & mut 0 ) ) ;
314
+ assert_eq ! ( back, ( & 1 , & mut 1 ) ) ;
315
+ * front. 1 = 24 ;
316
+ * back. 1 = 42 ;
317
+ assert_eq ! ( front, ( & 0 , & mut 24 ) ) ;
318
+ assert_eq ! ( back, ( & 1 , & mut 42 ) ) ;
319
+ }
320
+
321
+ #[ test]
322
+ #[ cfg_attr( miri, ignore) ] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
323
+ fn test_iter_descending_to_same_node_twice ( ) {
324
+ let mut map: BTreeMap < _ , _ > = ( 0 ..MIN_INSERTS_HEIGHT_1 ) . map ( |i| ( i, i) ) . collect ( ) ;
325
+ let mut it = map. iter_mut ( ) ;
326
+ // Descend into first child.
327
+ let front = it. next ( ) . unwrap ( ) ;
328
+ // Descend into first child again, after running through second child.
329
+ while it. next_back ( ) . is_some ( ) { }
330
+ // Check immutable access.
331
+ assert_eq ! ( front, ( & 0 , & mut 0 ) ) ;
332
+ // Perform mutable access.
333
+ * front. 1 = 42 ;
334
+ }
335
+
284
336
#[ test]
285
337
fn test_iter_mixed ( ) {
286
338
// Miri is too slow
@@ -835,18 +887,16 @@ mod test_drain_filter {
835
887
}
836
888
}
837
889
838
- let mut map = BTreeMap :: new ( ) ;
839
- map. insert ( 0 , D ) ;
840
- map. insert ( 4 , D ) ;
841
- map. insert ( 8 , D ) ;
890
+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
891
+ let mut map = ( 0 ..3 ) . map ( |i| ( i * 4 , D ) ) . collect :: < BTreeMap < _ , _ > > ( ) ;
842
892
843
893
catch_unwind ( move || {
844
894
drop ( map. drain_filter ( |i, _| {
845
895
PREDS . fetch_add ( 1usize << i, Ordering :: SeqCst ) ;
846
896
true
847
897
} ) )
848
898
} )
849
- . ok ( ) ;
899
+ . unwrap_err ( ) ;
850
900
851
901
assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 0x011 ) ;
852
902
assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 3 ) ;
@@ -864,10 +914,8 @@ mod test_drain_filter {
864
914
}
865
915
}
866
916
867
- let mut map = BTreeMap :: new ( ) ;
868
- map. insert ( 0 , D ) ;
869
- map. insert ( 4 , D ) ;
870
- map. insert ( 8 , D ) ;
917
+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
918
+ let mut map = ( 0 ..3 ) . map ( |i| ( i * 4 , D ) ) . collect :: < BTreeMap < _ , _ > > ( ) ;
871
919
872
920
catch_unwind ( AssertUnwindSafe ( || {
873
921
drop ( map. drain_filter ( |i, _| {
@@ -878,7 +926,45 @@ mod test_drain_filter {
878
926
}
879
927
} ) )
880
928
} ) )
881
- . ok ( ) ;
929
+ . unwrap_err ( ) ;
930
+
931
+ assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 0x011 ) ;
932
+ assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 1 ) ;
933
+ assert_eq ! ( map. len( ) , 2 ) ;
934
+ assert_eq ! ( map. first_entry( ) . unwrap( ) . key( ) , & 4 ) ;
935
+ assert_eq ! ( map. last_entry( ) . unwrap( ) . key( ) , & 8 ) ;
936
+ }
937
+
938
+ // Same as above, but attempt to use the iterator again after the panic in the predicate
939
+ #[ test]
940
+ fn pred_panic_reuse ( ) {
941
+ static PREDS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
942
+ static DROPS : AtomicUsize = AtomicUsize :: new ( 0 ) ;
943
+
944
+ struct D ;
945
+ impl Drop for D {
946
+ fn drop ( & mut self ) {
947
+ DROPS . fetch_add ( 1 , Ordering :: SeqCst ) ;
948
+ }
949
+ }
950
+
951
+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
952
+ let mut map = ( 0 ..3 ) . map ( |i| ( i * 4 , D ) ) . collect :: < BTreeMap < _ , _ > > ( ) ;
953
+
954
+ {
955
+ let mut it = map. drain_filter ( |i, _| {
956
+ PREDS . fetch_add ( 1usize << i, Ordering :: SeqCst ) ;
957
+ match i {
958
+ 0 => true ,
959
+ _ => panic ! ( ) ,
960
+ }
961
+ } ) ;
962
+ catch_unwind ( AssertUnwindSafe ( || while it. next ( ) . is_some ( ) { } ) ) . unwrap_err ( ) ;
963
+ // Iterator behaviour after a panic is explicitly unspecified,
964
+ // so this is just the current implementation:
965
+ let result = catch_unwind ( AssertUnwindSafe ( || it. next ( ) ) ) ;
966
+ assert ! ( matches!( result, Ok ( None ) ) ) ;
967
+ }
882
968
883
969
assert_eq ! ( PREDS . load( Ordering :: SeqCst ) , 0x011 ) ;
884
970
assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 1 ) ;
@@ -1283,6 +1369,34 @@ fn test_split_off_empty_left() {
1283
1369
assert ! ( right. into_iter( ) . eq( data) ) ;
1284
1370
}
1285
1371
1372
+ // In a tree with 3 levels, if all but a part of the first leaf node is split off,
1373
+ // make sure fix_top eliminates both top levels.
1374
+ #[ test]
1375
+ fn test_split_off_tiny_left_height_2 ( ) {
1376
+ let pairs = ( 0 ..MIN_INSERTS_HEIGHT_2 ) . map ( |i| ( i, i) ) ;
1377
+ let mut left: BTreeMap < _ , _ > = pairs. clone ( ) . collect ( ) ;
1378
+ let right = left. split_off ( & 1 ) ;
1379
+ assert_eq ! ( left. len( ) , 1 ) ;
1380
+ assert_eq ! ( right. len( ) , MIN_INSERTS_HEIGHT_2 - 1 ) ;
1381
+ assert_eq ! ( * left. first_key_value( ) . unwrap( ) . 0 , 0 ) ;
1382
+ assert_eq ! ( * right. first_key_value( ) . unwrap( ) . 0 , 1 ) ;
1383
+ }
1384
+
1385
+ // In a tree with 3 levels, if only part of the last leaf node is split off,
1386
+ // make sure fix_top eliminates both top levels.
1387
+ #[ test]
1388
+ fn test_split_off_tiny_right_height_2 ( ) {
1389
+ let pairs = ( 0 ..MIN_INSERTS_HEIGHT_2 ) . map ( |i| ( i, i) ) ;
1390
+ let last = MIN_INSERTS_HEIGHT_2 - 1 ;
1391
+ let mut left: BTreeMap < _ , _ > = pairs. clone ( ) . collect ( ) ;
1392
+ assert_eq ! ( * left. last_key_value( ) . unwrap( ) . 0 , last) ;
1393
+ let right = left. split_off ( & last) ;
1394
+ assert_eq ! ( left. len( ) , MIN_INSERTS_HEIGHT_2 - 1 ) ;
1395
+ assert_eq ! ( right. len( ) , 1 ) ;
1396
+ assert_eq ! ( * left. last_key_value( ) . unwrap( ) . 0 , last - 1 ) ;
1397
+ assert_eq ! ( * right. last_key_value( ) . unwrap( ) . 0 , last) ;
1398
+ }
1399
+
1286
1400
#[ test]
1287
1401
fn test_split_off_large_random_sorted ( ) {
1288
1402
// Miri is too slow
@@ -1319,7 +1433,7 @@ fn test_into_iter_drop_leak_height_0() {
1319
1433
map. insert ( "d" , D ) ;
1320
1434
map. insert ( "e" , D ) ;
1321
1435
1322
- catch_unwind ( move || drop ( map. into_iter ( ) ) ) . ok ( ) ;
1436
+ catch_unwind ( move || drop ( map. into_iter ( ) ) ) . unwrap_err ( ) ;
1323
1437
1324
1438
assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , 5 ) ;
1325
1439
}
@@ -1343,7 +1457,7 @@ fn test_into_iter_drop_leak_height_1() {
1343
1457
DROPS . store ( 0 , Ordering :: SeqCst ) ;
1344
1458
PANIC_POINT . store ( panic_point, Ordering :: SeqCst ) ;
1345
1459
let map: BTreeMap < _ , _ > = ( 0 ..size) . map ( |i| ( i, D ) ) . collect ( ) ;
1346
- catch_unwind ( move || drop ( map. into_iter ( ) ) ) . ok ( ) ;
1460
+ catch_unwind ( move || drop ( map. into_iter ( ) ) ) . unwrap_err ( ) ;
1347
1461
assert_eq ! ( DROPS . load( Ordering :: SeqCst ) , size) ;
1348
1462
}
1349
1463
}
0 commit comments