@@ -1503,16 +1503,21 @@ impl Niche {
15031503
15041504 pub fn reserve < C : HasDataLayout > ( & self , cx : & C , count : u128 ) -> Option < ( u128 , Scalar ) > {
15051505 assert ! ( count > 0 ) ;
1506+ if count > self . available ( cx) {
1507+ return None ;
1508+ }
15061509
15071510 let Self { value, valid_range : v, .. } = * self ;
1508- let size = value. size ( cx) ;
1509- assert ! ( size. bits( ) <= 128 ) ;
1510- let max_value = size. unsigned_int_max ( ) ;
1511+ let max_value = value. size ( cx) . unsigned_int_max ( ) ;
1512+ let distance_end_zero = max_value - v. end ;
15111513
1512- let niche = v. end . wrapping_add ( 1 ) ..v. start ;
1513- let available = niche. end . wrapping_sub ( niche. start ) & max_value;
1514- if count > available {
1515- return None ;
1514+ // Null-pointer optimization. This is guaranteed by Rust (at least for `Option<_>`),
1515+ // and offers better codegen opportunities.
1516+ if count == 1 && matches ! ( value, Pointer ( _) ) && !v. contains ( 0 ) {
1517+ // Select which bound to move to minimize the number of lost niches.
1518+ let valid_range =
1519+ if v. start - 1 > distance_end_zero { v. with_end ( 0 ) } else { v. with_start ( 0 ) } ;
1520+ return Some ( ( 0 , Scalar :: Initialized { value, valid_range } ) ) ;
15161521 }
15171522
15181523 // Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
@@ -1535,7 +1540,6 @@ impl Niche {
15351540 let end = v. end . wrapping_add ( count) & max_value;
15361541 Some ( ( start, Scalar :: Initialized { value, valid_range : v. with_end ( end) } ) )
15371542 } ;
1538- let distance_end_zero = max_value - v. end ;
15391543 if v. start > v. end {
15401544 // zero is unavailable because wrapping occurs
15411545 move_end ( v)
0 commit comments