@@ -49,6 +49,14 @@ bitflags! {
4949 }
5050}
5151
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+
5260#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
5361#[ cfg_attr( feature = "nightly" , derive( Encodable , Decodable , HashStable_Generic ) ) ]
5462pub enum IntegerType {
@@ -346,6 +354,33 @@ impl TargetDataLayout {
346354 }
347355 }
348356
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+
349384 #[ inline]
350385 pub fn vector_align ( & self , vec_size : Size ) -> AbiAndPrefAlign {
351386 for & ( size, align) in & self . vector_align {
@@ -473,6 +508,12 @@ impl Size {
473508 Size :: from_bytes ( ( self . bytes ( ) + mask) & !mask)
474509 }
475510
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+
476517 #[ inline]
477518 pub fn is_aligned ( self , align : Align ) -> bool {
478519 let mask = align. bytes ( ) - 1 ;
@@ -967,6 +1008,43 @@ impl WrappingRange {
9671008 }
9681009 }
9691010
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+
9701048 /// Returns `self` with replaced `start`
9711049 #[ inline( always) ]
9721050 pub fn with_start ( mut self , start : u128 ) -> Self {
@@ -984,9 +1062,15 @@ impl WrappingRange {
9841062 /// Returns `true` if `size` completely fills the range.
9851063 #[ inline]
9861064 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 {
9871072 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
9901074 }
9911075}
9921076
@@ -1427,16 +1511,21 @@ impl Niche {
14271511
14281512 pub fn reserve < C : HasDataLayout > ( & self , cx : & C , count : u128 ) -> Option < ( u128 , Scalar ) > {
14291513 assert ! ( count > 0 ) ;
1514+ if count > self . available ( cx) {
1515+ return None ;
1516+ }
14301517
14311518 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 ;
14351521
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 } ) ) ;
14401529 }
14411530
14421531 // Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
@@ -1459,7 +1548,6 @@ impl Niche {
14591548 let end = v. end . wrapping_add ( count) & max_value;
14601549 Some ( ( start, Scalar :: Initialized { value, valid_range : v. with_end ( end) } ) )
14611550 } ;
1462- let distance_end_zero = max_value - v. end ;
14631551 if v. start > v. end {
14641552 // zero is unavailable because wrapping occurs
14651553 move_end ( v)
0 commit comments