@@ -1082,7 +1082,19 @@ fn render_memory_layout(
1082
1082
1083
1083
if config. niches {
1084
1084
if let Some ( niches) = layout. niches ( ) {
1085
- format_to ! ( label, "niches = {niches}, " ) ;
1085
+ if niches > 1024 {
1086
+ if niches. is_power_of_two ( ) {
1087
+ format_to ! ( label, "niches = 2{}, " , pwr2_to_exponent( niches) ) ;
1088
+ } else if is_pwr2plus1 ( niches) {
1089
+ format_to ! ( label, "niches = 2{} + 1, " , pwr2_to_exponent( niches - 1 ) ) ;
1090
+ } else if is_pwr2minus1 ( niches) {
1091
+ format_to ! ( label, "niches = 2{} - 1, " , pwr2_to_exponent( niches + 1 ) ) ;
1092
+ } else {
1093
+ format_to ! ( label, "niches = a lot, " ) ;
1094
+ }
1095
+ } else {
1096
+ format_to ! ( label, "niches = {niches}, " ) ;
1097
+ }
1086
1098
}
1087
1099
}
1088
1100
label. pop ( ) ; // ' '
@@ -1210,3 +1222,74 @@ fn render_dyn_compatibility(
1210
1222
}
1211
1223
}
1212
1224
}
1225
+
1226
+ fn is_pwr2minus1 ( val : u128 ) -> bool {
1227
+ val == u128:: MAX || ( val + 1 ) . is_power_of_two ( )
1228
+ }
1229
+
1230
+ fn is_pwr2plus1 ( val : u128 ) -> bool {
1231
+ val != 0 && ( val - 1 ) . is_power_of_two ( )
1232
+ }
1233
+
1234
+ /// Formats a power of two as an exponent of two, i.e. 16 => ⁴. Note that `num` MUST be a power
1235
+ /// of 2, or this function will panic.
1236
+ fn pwr2_to_exponent ( num : u128 ) -> String {
1237
+ const DIGITS : [ char ; 10 ] = [ '⁰' , '¹' , '²' , '³' , '⁴' , '⁵' , '⁶' , '⁷' , '⁸' , '⁹' ] ;
1238
+ assert_eq ! ( num. count_ones( ) , 1 ) ;
1239
+ num. trailing_zeros ( )
1240
+ . to_string ( )
1241
+ . chars ( )
1242
+ . map ( |c| c. to_digit ( 10 ) . unwrap ( ) as usize )
1243
+ . map ( |idx| DIGITS [ idx] )
1244
+ . collect :: < String > ( )
1245
+ }
1246
+
1247
+ #[ cfg( test) ]
1248
+ mod tests {
1249
+ use super :: * ;
1250
+
1251
+ const TESTERS : [ u128 ; 10 ] = [ 0 , 1 , 2 , 3 , 4 , 255 , 256 , 257 , u128:: MAX - 1 , u128:: MAX ] ;
1252
+
1253
+ #[ test]
1254
+ fn test_is_pwr2minus1 ( ) {
1255
+ const OUTCOMES : [ bool ; 10 ] =
1256
+ [ true , true , false , true , false , true , false , false , false , true ] ;
1257
+ for ( test, expected) in TESTERS . iter ( ) . zip ( OUTCOMES ) {
1258
+ let actual = is_pwr2minus1 ( * test) ;
1259
+ assert_eq ! ( actual, expected, "is_pwr2minu1({test}) gave {actual}, expected {expected}" ) ;
1260
+ }
1261
+ }
1262
+
1263
+ #[ test]
1264
+ fn test_is_pwr2plus1 ( ) {
1265
+ const OUTCOMES : [ bool ; 10 ] =
1266
+ [ false , false , true , true , false , false , false , true , false , false ] ;
1267
+ for ( test, expected) in TESTERS . iter ( ) . zip ( OUTCOMES ) {
1268
+ let actual = is_pwr2plus1 ( * test) ;
1269
+ assert_eq ! ( actual, expected, "is_pwr2plus1({test}) gave {actual}, expected {expected}" ) ;
1270
+ }
1271
+ }
1272
+
1273
+ #[ test]
1274
+ fn test_pwr2_to_exponent ( ) {
1275
+ const TESTERS : [ u128 ; 9 ] = [
1276
+ 1 ,
1277
+ 2 ,
1278
+ 4 ,
1279
+ 8 ,
1280
+ 16 ,
1281
+ 9223372036854775808 ,
1282
+ 18446744073709551616 ,
1283
+ 36893488147419103232 ,
1284
+ 170141183460469231731687303715884105728 ,
1285
+ ] ;
1286
+ const OUTCOMES : [ & str ; 9 ] = [ "⁰" , "¹" , "²" , "³" , "⁴" , "⁶³" , "⁶⁴" , "⁶⁵" , "¹²⁷" ] ;
1287
+ for ( test, expected) in TESTERS . iter ( ) . zip ( OUTCOMES ) {
1288
+ let actual = pwr2_to_exponent ( * test) ;
1289
+ assert_eq ! (
1290
+ actual, expected,
1291
+ "pwr2_to_exponent({test}) returned {actual}, expected {expected}" ,
1292
+ ) ;
1293
+ }
1294
+ }
1295
+ }
0 commit comments