@@ -1099,19 +1099,53 @@ impl Niche {
10991099 assert ! ( size. bits( ) <= 128 ) ;
11001100 let max_value = size. unsigned_int_max ( ) ;
11011101
1102- if count > max_value {
1102+ let niche = v. end . wrapping_add ( 1 ) ..v. start ;
1103+ let available = niche. end . wrapping_sub ( niche. start ) & max_value;
1104+ if count > available {
11031105 return None ;
11041106 }
11051107
1106- // Compute the range of invalid values being reserved.
1107- let start = v. end . wrapping_add ( 1 ) & max_value;
1108- let end = v. end . wrapping_add ( count) & max_value;
1109-
1110- if v. contains ( end) {
1111- return None ;
1108+ // Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
1109+ // Given an eventual `Option<T>`, we try to maximize the chance for `None` to occupy the niche of zero.
1110+ // This is accomplished by prefering enums with 2 variants(`count==1`) and always taking the shortest path to niche zero.
1111+ // Having `None` in niche zero can enable some special optimizations.
1112+ //
1113+ // Bound selection criteria:
1114+ // 1. Select closest to zero given wrapping semantics.
1115+ // 2. Avoid moving past zero if possible.
1116+ //
1117+ // In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly.
1118+ // If niche zero is already reserved, the selection of bounds are of little interest.
1119+ let move_start = |v : WrappingRange | {
1120+ let start = v. start . wrapping_sub ( 1 ) & max_value;
1121+ Some ( ( start, Scalar { value, valid_range : v. with_start ( start) } ) )
1122+ } ;
1123+ let move_end = |v : WrappingRange | {
1124+ let start = v. end . wrapping_add ( 1 ) & max_value;
1125+ let end = v. end . wrapping_add ( count) & max_value;
1126+ Some ( ( start, Scalar { value, valid_range : v. with_end ( end) } ) )
1127+ } ;
1128+ let distance_end_zero = max_value - v. end ;
1129+ if v. start > v. end {
1130+ // zero is unavailable because wrapping occurs
1131+ move_end ( v)
1132+ } else if v. start <= distance_end_zero {
1133+ if count <= v. start {
1134+ move_start ( v)
1135+ } else {
1136+ // moved past zero, use other bound
1137+ move_end ( v)
1138+ }
1139+ } else {
1140+ let end = v. end . wrapping_add ( count) & max_value;
1141+ let overshot_zero = ( 1 ..=v. end ) . contains ( & end) ;
1142+ if overshot_zero {
1143+ // moved past zero, use other bound
1144+ move_start ( v)
1145+ } else {
1146+ move_end ( v)
1147+ }
11121148 }
1113-
1114- Some ( ( start, Scalar { value, valid_range : v. with_end ( end) } ) )
11151149 }
11161150}
11171151
0 commit comments