Skip to content

Commit 99bb7aa

Browse files
committed
Create a hot path for GetFloatingPointMaxDigitsAndPrecision
1 parent 92b0d26 commit 99bb7aa

File tree

1 file changed

+41
-27
lines changed

1 file changed

+41
-27
lines changed

src/libraries/System.Private.CoreLib/src/System/Number.Formatting.cs

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -412,19 +412,48 @@ internal static unsafe void DecimalToNumber(scoped ref decimal d, ref NumberBuff
412412
number.CheckConsistency();
413413
}
414414

415+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
415416
private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int precision, NumberFormatInfo info, out bool isSignificantDigits)
416417
{
418+
// We want to fast path the common case of no format and general format + precision.
419+
// These are commonly encountered and the full switch is otherwise large enough to show up in hot path profiles
420+
417421
if (fmt == 0)
418422
{
419423
isSignificantDigits = true;
420424
return precision;
421425
}
422426

423-
int maxDigits = precision;
427+
// Bitwise-or with space (' ') converts any uppercase character to
428+
// lowercase and keeps unsupported characters as something unsupported.
429+
fmt |= ' ';
424430

425-
switch (fmt | 0x20)
431+
if (fmt == 'g')
426432
{
427-
case 'c':
433+
// The general format uses the precision specifier to indicate the number of significant
434+
// digits to format. This defaults to the shortest roundtrippable string. Additionally,
435+
// given that we can't return zero significant digits, we treat 0 as returning the shortest
436+
// roundtrippable string as well.
437+
438+
isSignificantDigits = true;
439+
440+
if (precision == 0)
441+
{
442+
precision = -1;
443+
return 0;
444+
}
445+
return precision;
446+
}
447+
448+
return Slow(fmt, ref precision, info, out isSignificantDigits);
449+
450+
static int Slow(char fmt, ref int precision, NumberFormatInfo info, out bool isSignificantDigits)
451+
{
452+
int maxDigits = precision;
453+
454+
switch (fmt)
455+
{
456+
case 'c':
428457
{
429458
// The currency format uses the precision specifier to indicate the number of
430459
// decimal digits to format. This defaults to NumberFormatInfo.CurrencyDecimalDigits.
@@ -438,7 +467,7 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci
438467
break;
439468
}
440469

441-
case 'e':
470+
case 'e':
442471
{
443472
// The exponential format uses the precision specifier to indicate the number of
444473
// decimal digits to format. This defaults to 6. However, the exponential format
@@ -456,8 +485,8 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci
456485
break;
457486
}
458487

459-
case 'f':
460-
case 'n':
488+
case 'f':
489+
case 'n':
461490
{
462491
// The fixed-point and number formats use the precision specifier to indicate the number
463492
// of decimal digits to format. This defaults to NumberFormatInfo.NumberDecimalDigits.
@@ -471,23 +500,7 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci
471500
break;
472501
}
473502

474-
case 'g':
475-
{
476-
// The general format uses the precision specifier to indicate the number of significant
477-
// digits to format. This defaults to the shortest roundtrippable string. Additionally,
478-
// given that we can't return zero significant digits, we treat 0 as returning the shortest
479-
// roundtrippable string as well.
480-
481-
if (precision == 0)
482-
{
483-
precision = -1;
484-
}
485-
isSignificantDigits = true;
486-
487-
break;
488-
}
489-
490-
case 'p':
503+
case 'p':
491504
{
492505
// The percent format uses the precision specifier to indicate the number of
493506
// decimal digits to format. This defaults to NumberFormatInfo.PercentDecimalDigits.
@@ -505,7 +518,7 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci
505518
break;
506519
}
507520

508-
case 'r':
521+
case 'r':
509522
{
510523
// The roundtrip format ignores the precision specifier and always returns the shortest
511524
// roundtrippable string.
@@ -516,14 +529,15 @@ private static int GetFloatingPointMaxDigitsAndPrecision(char fmt, ref int preci
516529
break;
517530
}
518531

519-
default:
532+
default:
520533
{
521534
ThrowHelper.ThrowFormatException_BadFormatSpecifier();
522535
goto case 'r'; // unreachable
523536
}
524-
}
537+
}
525538

526-
return maxDigits;
539+
return maxDigits;
540+
}
527541
}
528542

529543
public static string FormatFloat<TNumber>(TNumber value, string? format, NumberFormatInfo info)

0 commit comments

Comments
 (0)