Skip to content

Commit f6d564e

Browse files
authored
Trim some overheads for "r"/"o" DateTime parsing (#82925)
We were doing some unnecessary work on these fast paths. I also noticed and cleaned up an unnecessary delegate involved in Hebrew number parsing.
1 parent 732ae12 commit f6d564e

File tree

1 file changed

+31
-52
lines changed

1 file changed

+31
-52
lines changed

src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeParse.cs

Lines changed: 31 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ internal static class DateTimeParse
1313
{
1414
internal const int MaxDateTimeNumberDigits = 8;
1515

16-
internal delegate bool MatchNumberDelegate(ref __DTString str, int digitLen, out int result);
17-
18-
private static readonly MatchNumberDelegate s_hebrewNumberParser = new MatchNumberDelegate(MatchHebrewDigits);
19-
2016
internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style)
2117
{
2218
DateTimeResult result = default; // The buffer to store the parsing result.
@@ -3071,7 +3067,7 @@ private static bool ParseISO8601(scoped ref DateTimeRawInfo raw, ref __DTString
30713067
//
30723068
////////////////////////////////////////////////////////////////////////
30733069

3074-
internal static bool MatchHebrewDigits(ref __DTString str, int digitLen, out int number)
3070+
internal static bool MatchHebrewDigits(ref __DTString str, out int number)
30753071
{
30763072
number = 0;
30773073

@@ -3919,12 +3915,21 @@ private static string ExpandPredefinedFormat(ReadOnlySpan<char> format, scoped r
39193915
case 's': // Sortable format (in local time)
39203916
case 'o':
39213917
case 'O': // Round Trip Format
3922-
ConfigureFormatOS(ref dtfi, ref parseInfo);
3918+
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
3919+
dtfi = DateTimeFormatInfo.InvariantInfo;
39233920
break;
3921+
39243922
case 'r':
39253923
case 'R': // RFC 1123 Standard. (in Universal time)
3926-
ConfigureFormatR(ref dtfi, ref parseInfo, ref result);
3924+
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
3925+
dtfi = DateTimeFormatInfo.InvariantInfo;
3926+
3927+
if ((result.flags & ParseFlags.CaptureOffset) != 0)
3928+
{
3929+
result.flags |= ParseFlags.Rfc1123Pattern;
3930+
}
39273931
break;
3932+
39283933
case 'u': // Universal time format in sortable format.
39293934
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
39303935
dtfi = DateTimeFormatInfo.InvariantInfo;
@@ -3934,6 +3939,7 @@ private static string ExpandPredefinedFormat(ReadOnlySpan<char> format, scoped r
39343939
result.flags |= ParseFlags.UtcSortPattern;
39353940
}
39363941
break;
3942+
39373943
case 'U': // Universal time format with culture-dependent format.
39383944
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
39393945
result.flags |= ParseFlags.TimeZoneUsed;
@@ -3971,22 +3977,6 @@ private static bool ParseJapaneseEraStart(ref __DTString str, DateTimeFormatInfo
39713977
return true;
39723978
}
39733979

3974-
private static void ConfigureFormatR(scoped ref DateTimeFormatInfo dtfi, scoped ref ParsingInfo parseInfo, scoped ref DateTimeResult result)
3975-
{
3976-
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
3977-
dtfi = DateTimeFormatInfo.InvariantInfo;
3978-
if ((result.flags & ParseFlags.CaptureOffset) != 0)
3979-
{
3980-
result.flags |= ParseFlags.Rfc1123Pattern;
3981-
}
3982-
}
3983-
3984-
private static void ConfigureFormatOS(scoped ref DateTimeFormatInfo dtfi, scoped ref ParsingInfo parseInfo)
3985-
{
3986-
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
3987-
dtfi = DateTimeFormatInfo.InvariantInfo;
3988-
}
3989-
39903980
// Given a specified format character, parse and update the parsing result.
39913981
//
39923982
private static bool ParseByFormat(
@@ -4025,9 +4015,9 @@ private static bool ParseByFormat(
40254015
}
40264016
parseResult = ParseDigits(ref str, tokenLen, out tempYear);
40274017
}
4028-
if (!parseResult && parseInfo.fCustomNumberParser)
4018+
if (!parseResult && parseInfo.fUseHebrewNumberParser)
40294019
{
4030-
parseResult = parseInfo.parseNumberDelegate(ref str, tokenLen, out tempYear);
4020+
parseResult = MatchHebrewDigits(ref str, out tempYear);
40314021
}
40324022
if (!parseResult)
40334023
{
@@ -4045,8 +4035,8 @@ private static bool ParseByFormat(
40454035
{
40464036
if (!ParseDigits(ref str, tokenLen, out tempMonth))
40474037
{
4048-
if (!parseInfo.fCustomNumberParser ||
4049-
!parseInfo.parseNumberDelegate(ref str, tokenLen, out tempMonth))
4038+
if (!parseInfo.fUseHebrewNumberParser ||
4039+
!MatchHebrewDigits(ref str, out tempMonth))
40504040
{
40514041
result.SetBadDateTimeFailure();
40524042
return false;
@@ -4087,8 +4077,8 @@ private static bool ParseByFormat(
40874077

40884078
if (!ParseDigits(ref str, tokenLen, out tempDay))
40894079
{
4090-
if (!parseInfo.fCustomNumberParser ||
4091-
!parseInfo.parseNumberDelegate(ref str, tokenLen, out tempDay))
4080+
if (!parseInfo.fUseHebrewNumberParser ||
4081+
!MatchHebrewDigits(ref str, out tempDay))
40924082
{
40934083
result.SetBadDateTimeFailure();
40944084
return false;
@@ -4583,10 +4573,7 @@ private static bool DoStrictParse(
45834573
DateTimeFormatInfo dtfi,
45844574
scoped ref DateTimeResult result)
45854575
{
4586-
ParsingInfo parseInfo = default;
4587-
parseInfo.Init();
4588-
4589-
parseInfo.calendar = dtfi.Calendar;
4576+
var parseInfo = new ParsingInfo(dtfi.Calendar);
45904577
parseInfo.fAllowInnerWhite = ((styles & DateTimeStyles.AllowInnerWhite) != 0);
45914578
parseInfo.fAllowTrailingWhite = ((styles & DateTimeStyles.AllowTrailingWhite) != 0);
45924579

@@ -4597,17 +4584,13 @@ private static bool DoStrictParse(
45974584
// Fast-paths for common and important formats/configurations.
45984585
if (styles == DateTimeStyles.None)
45994586
{
4600-
switch (formatParamChar)
4587+
switch (formatParamChar | 0x20)
46014588
{
4602-
case 'R':
46034589
case 'r':
4604-
ConfigureFormatR(ref dtfi, ref parseInfo, ref result);
4605-
return ParseFormatR(s, ref parseInfo, ref result);
4590+
return TryParseFormatR(s, ref result);
46064591

4607-
case 'O':
46084592
case 'o':
4609-
ConfigureFormatOS(ref dtfi, ref parseInfo);
4610-
return ParseFormatO(s, ref result);
4593+
return TryParseFormatO(s, ref result);
46114594
}
46124595
}
46134596

@@ -4623,11 +4606,7 @@ private static bool DoStrictParse(
46234606

46244607
result.calendar = parseInfo.calendar;
46254608

4626-
if (parseInfo.calendar.ID == CalendarId.HEBREW)
4627-
{
4628-
parseInfo.parseNumberDelegate = s_hebrewNumberParser;
4629-
parseInfo.fCustomNumberParser = true;
4630-
}
4609+
parseInfo.fUseHebrewNumberParser = parseInfo.calendar.ID == CalendarId.HEBREW;
46314610

46324611
// Reset these values to negative one so that we could throw exception
46334612
// if we have parsed every item twice.
@@ -4787,7 +4766,7 @@ private static bool DoStrictParse(
47874766
return DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly);
47884767
}
47894768

4790-
private static bool ParseFormatR(ReadOnlySpan<char> source, scoped ref ParsingInfo parseInfo, scoped ref DateTimeResult result)
4769+
private static bool TryParseFormatR(ReadOnlySpan<char> source, scoped ref DateTimeResult result)
47914770
{
47924771
// Example:
47934772
// Tue, 03 Jan 2017 08:08:05 GMT
@@ -4965,8 +4944,8 @@ private static bool ParseFormatR(ReadOnlySpan<char> source, scoped ref ParsingIn
49654944
return false;
49664945
}
49674946

4968-
// Validate that the parsed date is valid according to the calendar.
4969-
if (!parseInfo.calendar.TryToDateTime(year, month, day, hour, minute, second, 0, 0, out result.parsedDate))
4947+
// Validate that the parsed date is valid.
4948+
if (!DateTime.TryCreate(year, month, day, hour, minute, second, 0, out result.parsedDate))
49704949
{
49714950
result.SetFailure(ParseFailureKind.Format_BadDateTimeCalendar);
49724951
return false;
@@ -4982,7 +4961,7 @@ private static bool ParseFormatR(ReadOnlySpan<char> source, scoped ref ParsingIn
49824961
return true;
49834962
}
49844963

4985-
private static bool ParseFormatO(ReadOnlySpan<char> source, scoped ref DateTimeResult result)
4964+
private static bool TryParseFormatO(ReadOnlySpan<char> source, scoped ref DateTimeResult result)
49864965
{
49874966
// Examples:
49884967
// 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone)
@@ -6186,11 +6165,11 @@ internal struct ParsingInfo
61866165
internal bool fUseTwoDigitYear;
61876166
internal bool fAllowInnerWhite;
61886167
internal bool fAllowTrailingWhite;
6189-
internal bool fCustomNumberParser;
6190-
internal DateTimeParse.MatchNumberDelegate parseNumberDelegate;
6168+
internal bool fUseHebrewNumberParser;
61916169

6192-
internal void Init()
6170+
public ParsingInfo(Calendar calendar)
61936171
{
6172+
this.calendar = calendar;
61946173
dayOfWeek = -1;
61956174
timeMark = DateTimeParse.TM.NotSet;
61966175
}

0 commit comments

Comments
 (0)