@@ -1099,19 +1099,53 @@ impl Niche {
1099
1099
assert ! ( size. bits( ) <= 128 ) ;
1100
1100
let max_value = size. unsigned_int_max ( ) ;
1101
1101
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 {
1103
1105
return None ;
1104
1106
}
1105
1107
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
+ }
1112
1148
}
1113
-
1114
- Some ( ( start, Scalar { value, valid_range : v. with_end ( end) } ) )
1115
1149
}
1116
1150
}
1117
1151
0 commit comments