@@ -1503,16 +1503,21 @@ impl Niche {
1503
1503
1504
1504
pub fn reserve < C : HasDataLayout > ( & self , cx : & C , count : u128 ) -> Option < ( u128 , Scalar ) > {
1505
1505
assert ! ( count > 0 ) ;
1506
+ if count > self . available ( cx) {
1507
+ return None ;
1508
+ }
1506
1509
1507
1510
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 ;
1511
1513
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 } ) ) ;
1516
1521
}
1517
1522
1518
1523
// Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
@@ -1535,7 +1540,6 @@ impl Niche {
1535
1540
let end = v. end . wrapping_add ( count) & max_value;
1536
1541
Some ( ( start, Scalar :: Initialized { value, valid_range : v. with_end ( end) } ) )
1537
1542
} ;
1538
- let distance_end_zero = max_value - v. end ;
1539
1543
if v. start > v. end {
1540
1544
// zero is unavailable because wrapping occurs
1541
1545
move_end ( v)
0 commit comments