@@ -49,6 +49,14 @@ bitflags! {
49
49
}
50
50
}
51
51
52
+ /// Which niches (beyond the `null` niche) are available on references.
53
+ #[ derive( Default , Copy , Clone , Hash , Debug , Eq , PartialEq ) ]
54
+ #[ cfg_attr( feature = "nightly" , derive( Encodable , Decodable , HashStable_Generic ) ) ]
55
+ pub struct ReferenceNichePolicy {
56
+ pub size : bool ,
57
+ pub align : bool ,
58
+ }
59
+
52
60
#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
53
61
#[ cfg_attr( feature = "nightly" , derive( Encodable , Decodable , HashStable_Generic ) ) ]
54
62
pub enum IntegerType {
@@ -346,6 +354,33 @@ impl TargetDataLayout {
346
354
}
347
355
}
348
356
357
+ #[ inline]
358
+ pub fn target_usize_max ( & self ) -> u64 {
359
+ self . pointer_size . unsigned_int_max ( ) . try_into ( ) . unwrap ( )
360
+ }
361
+
362
+ #[ inline]
363
+ pub fn target_isize_min ( & self ) -> i64 {
364
+ self . pointer_size . signed_int_min ( ) . try_into ( ) . unwrap ( )
365
+ }
366
+
367
+ #[ inline]
368
+ pub fn target_isize_max ( & self ) -> i64 {
369
+ self . pointer_size . signed_int_max ( ) . try_into ( ) . unwrap ( )
370
+ }
371
+
372
+ /// Returns the (inclusive) range of possible addresses for an allocation with
373
+ /// the given size and alignment.
374
+ ///
375
+ /// Note that this doesn't take into account target-specific limitations.
376
+ #[ inline]
377
+ pub fn address_range_for ( & self , size : Size , align : Align ) -> ( u64 , u64 ) {
378
+ let end = Size :: from_bytes ( self . target_usize_max ( ) ) ;
379
+ let min = align. bytes ( ) ;
380
+ let max = ( end - size) . align_down_to ( align) . bytes ( ) ;
381
+ ( min, max)
382
+ }
383
+
349
384
#[ inline]
350
385
pub fn vector_align ( & self , vec_size : Size ) -> AbiAndPrefAlign {
351
386
for & ( size, align) in & self . vector_align {
@@ -473,6 +508,12 @@ impl Size {
473
508
Size :: from_bytes ( ( self . bytes ( ) + mask) & !mask)
474
509
}
475
510
511
+ #[ inline]
512
+ pub fn align_down_to ( self , align : Align ) -> Size {
513
+ let mask = align. bytes ( ) - 1 ;
514
+ Size :: from_bytes ( self . bytes ( ) & !mask)
515
+ }
516
+
476
517
#[ inline]
477
518
pub fn is_aligned ( self , align : Align ) -> bool {
478
519
let mask = align. bytes ( ) - 1 ;
@@ -967,6 +1008,43 @@ impl WrappingRange {
967
1008
}
968
1009
}
969
1010
1011
+ /// Returns `true` if `range` is contained in `self`.
1012
+ #[ inline( always) ]
1013
+ pub fn contains_range < I : Into < u128 > + Ord > ( & self , range : RangeInclusive < I > ) -> bool {
1014
+ if range. is_empty ( ) {
1015
+ return true ;
1016
+ }
1017
+
1018
+ let ( vmin, vmax) = range. into_inner ( ) ;
1019
+ let ( vmin, vmax) = ( vmin. into ( ) , vmax. into ( ) ) ;
1020
+
1021
+ if self . start <= self . end {
1022
+ self . start <= vmin && vmax <= self . end
1023
+ } else {
1024
+ // The last check is needed to cover the following case:
1025
+ // `vmin ... start, end ... vmax`. In this special case there is no gap
1026
+ // between `start` and `end` so we must return true.
1027
+ self . start <= vmin || vmax <= self . end || self . start == self . end + 1
1028
+ }
1029
+ }
1030
+
1031
+ /// Returns `true` if `range` has an overlap with `self`.
1032
+ #[ inline( always) ]
1033
+ pub fn overlaps_range < I : Into < u128 > + Ord > ( & self , range : RangeInclusive < I > ) -> bool {
1034
+ if range. is_empty ( ) {
1035
+ return false ;
1036
+ }
1037
+
1038
+ let ( vmin, vmax) = range. into_inner ( ) ;
1039
+ let ( vmin, vmax) = ( vmin. into ( ) , vmax. into ( ) ) ;
1040
+
1041
+ if self . start <= self . end {
1042
+ self . start <= vmax && vmin <= self . end
1043
+ } else {
1044
+ self . start <= vmax || vmin <= self . end
1045
+ }
1046
+ }
1047
+
970
1048
/// Returns `self` with replaced `start`
971
1049
#[ inline( always) ]
972
1050
pub fn with_start ( mut self , start : u128 ) -> Self {
@@ -984,9 +1062,15 @@ impl WrappingRange {
984
1062
/// Returns `true` if `size` completely fills the range.
985
1063
#[ inline]
986
1064
pub fn is_full_for ( & self , size : Size ) -> bool {
1065
+ debug_assert ! ( self . is_in_range_for( size) ) ;
1066
+ self . start == ( self . end . wrapping_add ( 1 ) & size. unsigned_int_max ( ) )
1067
+ }
1068
+
1069
+ /// Returns `true` if the range is valid for `size`.
1070
+ #[ inline( always) ]
1071
+ pub fn is_in_range_for ( & self , size : Size ) -> bool {
987
1072
let max_value = size. unsigned_int_max ( ) ;
988
- debug_assert ! ( self . start <= max_value && self . end <= max_value) ;
989
- self . start == ( self . end . wrapping_add ( 1 ) & max_value)
1073
+ self . start <= max_value && self . end <= max_value
990
1074
}
991
1075
}
992
1076
@@ -1427,16 +1511,21 @@ impl Niche {
1427
1511
1428
1512
pub fn reserve < C : HasDataLayout > ( & self , cx : & C , count : u128 ) -> Option < ( u128 , Scalar ) > {
1429
1513
assert ! ( count > 0 ) ;
1514
+ if count > self . available ( cx) {
1515
+ return None ;
1516
+ }
1430
1517
1431
1518
let Self { value, valid_range : v, .. } = * self ;
1432
- let size = value. size ( cx) ;
1433
- assert ! ( size. bits( ) <= 128 ) ;
1434
- let max_value = size. unsigned_int_max ( ) ;
1519
+ let max_value = value. size ( cx) . unsigned_int_max ( ) ;
1520
+ let distance_end_zero = max_value - v. end ;
1435
1521
1436
- let niche = v. end . wrapping_add ( 1 ) ..v. start ;
1437
- let available = niche. end . wrapping_sub ( niche. start ) & max_value;
1438
- if count > available {
1439
- return None ;
1522
+ // Null-pointer optimization. This is guaranteed by Rust (at least for `Option<_>`),
1523
+ // and offers better codegen opportunities.
1524
+ if count == 1 && matches ! ( value, Pointer ( _) ) && !v. contains ( 0 ) {
1525
+ // Select which bound to move to minimize the number of lost niches.
1526
+ let valid_range =
1527
+ if v. start - 1 > distance_end_zero { v. with_end ( 0 ) } else { v. with_start ( 0 ) } ;
1528
+ return Some ( ( 0 , Scalar :: Initialized { value, valid_range } ) ) ;
1440
1529
}
1441
1530
1442
1531
// Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
@@ -1459,7 +1548,6 @@ impl Niche {
1459
1548
let end = v. end . wrapping_add ( count) & max_value;
1460
1549
Some ( ( start, Scalar :: Initialized { value, valid_range : v. with_end ( end) } ) )
1461
1550
} ;
1462
- let distance_end_zero = max_value - v. end ;
1463
1551
if v. start > v. end {
1464
1552
// zero is unavailable because wrapping occurs
1465
1553
move_end ( v)
0 commit comments