Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trim some overheads for "r"/"o" DateTime parsing #82925

Merged
merged 1 commit into from
Mar 4, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ internal static class DateTimeParse
{
internal const int MaxDateTimeNumberDigits = 8;

internal delegate bool MatchNumberDelegate(ref __DTString str, int digitLen, out int result);

private static readonly MatchNumberDelegate s_hebrewNumberParser = new MatchNumberDelegate(MatchHebrewDigits);

internal static DateTime ParseExact(ReadOnlySpan<char> s, ReadOnlySpan<char> format, DateTimeFormatInfo dtfi, DateTimeStyles style)
{
DateTimeResult result = default; // The buffer to store the parsing result.
Expand Down Expand Up @@ -3070,7 +3066,7 @@ private static bool ParseISO8601(scoped ref DateTimeRawInfo raw, ref __DTString
//
////////////////////////////////////////////////////////////////////////

internal static bool MatchHebrewDigits(ref __DTString str, int digitLen, out int number)
internal static bool MatchHebrewDigits(ref __DTString str, out int number)
{
number = 0;

Expand Down Expand Up @@ -3790,12 +3786,21 @@ private static string ExpandPredefinedFormat(ReadOnlySpan<char> format, scoped r
case 's': // Sortable format (in local time)
case 'o':
case 'O': // Round Trip Format
ConfigureFormatOS(ref dtfi, ref parseInfo);
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
dtfi = DateTimeFormatInfo.InvariantInfo;
break;

case 'r':
case 'R': // RFC 1123 Standard. (in Universal time)
ConfigureFormatR(ref dtfi, ref parseInfo, ref result);
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
dtfi = DateTimeFormatInfo.InvariantInfo;

if ((result.flags & ParseFlags.CaptureOffset) != 0)
{
result.flags |= ParseFlags.Rfc1123Pattern;
}
break;

case 'u': // Universal time format in sortable format.
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
dtfi = DateTimeFormatInfo.InvariantInfo;
Expand All @@ -3805,6 +3810,7 @@ private static string ExpandPredefinedFormat(ReadOnlySpan<char> format, scoped r
result.flags |= ParseFlags.UtcSortPattern;
}
break;

case 'U': // Universal time format with culture-dependent format.
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
result.flags |= ParseFlags.TimeZoneUsed;
Expand Down Expand Up @@ -3842,22 +3848,6 @@ private static bool ParseJapaneseEraStart(ref __DTString str, DateTimeFormatInfo
return true;
}

private static void ConfigureFormatR(scoped ref DateTimeFormatInfo dtfi, scoped ref ParsingInfo parseInfo, scoped ref DateTimeResult result)
{
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
dtfi = DateTimeFormatInfo.InvariantInfo;
if ((result.flags & ParseFlags.CaptureOffset) != 0)
{
result.flags |= ParseFlags.Rfc1123Pattern;
}
}

private static void ConfigureFormatOS(scoped ref DateTimeFormatInfo dtfi, scoped ref ParsingInfo parseInfo)
{
parseInfo.calendar = GregorianCalendar.GetDefaultInstance();
dtfi = DateTimeFormatInfo.InvariantInfo;
}

// Given a specified format character, parse and update the parsing result.
//
private static bool ParseByFormat(
Expand Down Expand Up @@ -3896,9 +3886,9 @@ private static bool ParseByFormat(
}
parseResult = ParseDigits(ref str, tokenLen, out tempYear);
}
if (!parseResult && parseInfo.fCustomNumberParser)
if (!parseResult && parseInfo.fUseHebrewNumberParser)
{
parseResult = parseInfo.parseNumberDelegate(ref str, tokenLen, out tempYear);
parseResult = MatchHebrewDigits(ref str, out tempYear);
}
if (!parseResult)
{
Expand All @@ -3916,8 +3906,8 @@ private static bool ParseByFormat(
{
if (!ParseDigits(ref str, tokenLen, out tempMonth))
{
if (!parseInfo.fCustomNumberParser ||
!parseInfo.parseNumberDelegate(ref str, tokenLen, out tempMonth))
if (!parseInfo.fUseHebrewNumberParser ||
!MatchHebrewDigits(ref str, out tempMonth))
{
result.SetBadDateTimeFailure();
return false;
Expand Down Expand Up @@ -3958,8 +3948,8 @@ private static bool ParseByFormat(

if (!ParseDigits(ref str, tokenLen, out tempDay))
{
if (!parseInfo.fCustomNumberParser ||
!parseInfo.parseNumberDelegate(ref str, tokenLen, out tempDay))
if (!parseInfo.fUseHebrewNumberParser ||
!MatchHebrewDigits(ref str, out tempDay))
{
result.SetBadDateTimeFailure();
return false;
Expand Down Expand Up @@ -4454,10 +4444,7 @@ private static bool DoStrictParse(
DateTimeFormatInfo dtfi,
scoped ref DateTimeResult result)
{
ParsingInfo parseInfo = default;
parseInfo.Init();

parseInfo.calendar = dtfi.Calendar;
var parseInfo = new ParsingInfo(dtfi.Calendar);
parseInfo.fAllowInnerWhite = ((styles & DateTimeStyles.AllowInnerWhite) != 0);
parseInfo.fAllowTrailingWhite = ((styles & DateTimeStyles.AllowTrailingWhite) != 0);

Expand All @@ -4468,17 +4455,13 @@ private static bool DoStrictParse(
// Fast-paths for common and important formats/configurations.
if (styles == DateTimeStyles.None)
{
switch (formatParamChar)
switch (formatParamChar | 0x20)
{
case 'R':
case 'r':
ConfigureFormatR(ref dtfi, ref parseInfo, ref result);
return ParseFormatR(s, ref parseInfo, ref result);
return TryParseFormatR(s, ref result);

case 'O':
case 'o':
ConfigureFormatOS(ref dtfi, ref parseInfo);
return ParseFormatO(s, ref result);
return TryParseFormatO(s, ref result);
}
}

Expand All @@ -4494,11 +4477,7 @@ private static bool DoStrictParse(

result.calendar = parseInfo.calendar;

if (parseInfo.calendar.ID == CalendarId.HEBREW)
{
parseInfo.parseNumberDelegate = s_hebrewNumberParser;
parseInfo.fCustomNumberParser = true;
}
parseInfo.fUseHebrewNumberParser = parseInfo.calendar.ID == CalendarId.HEBREW;

// Reset these values to negative one so that we could throw exception
// if we have parsed every item twice.
Expand Down Expand Up @@ -4658,7 +4637,7 @@ private static bool DoStrictParse(
return DetermineTimeZoneAdjustments(ref result, styles, bTimeOnly);
}

private static bool ParseFormatR(ReadOnlySpan<char> source, scoped ref ParsingInfo parseInfo, scoped ref DateTimeResult result)
private static bool TryParseFormatR(ReadOnlySpan<char> source, scoped ref DateTimeResult result)
{
// Example:
// Tue, 03 Jan 2017 08:08:05 GMT
Expand Down Expand Up @@ -4836,8 +4815,8 @@ private static bool ParseFormatR(ReadOnlySpan<char> source, scoped ref ParsingIn
return false;
}

// Validate that the parsed date is valid according to the calendar.
if (!parseInfo.calendar.TryToDateTime(year, month, day, hour, minute, second, 0, 0, out result.parsedDate))
// Validate that the parsed date is valid.
if (!DateTime.TryCreate(year, month, day, hour, minute, second, 0, out result.parsedDate))
{
result.SetFailure(ParseFailureKind.FormatBadDateTimeCalendar, nameof(SR.Format_BadDateTimeCalendar));
return false;
Expand All @@ -4853,7 +4832,7 @@ private static bool ParseFormatR(ReadOnlySpan<char> source, scoped ref ParsingIn
return true;
}

private static bool ParseFormatO(ReadOnlySpan<char> source, scoped ref DateTimeResult result)
private static bool TryParseFormatO(ReadOnlySpan<char> source, scoped ref DateTimeResult result)
{
// Examples:
// 2017-06-12T05:30:45.7680000 (interpreted as local time wrt to current time zone)
Expand Down Expand Up @@ -6036,11 +6015,11 @@ internal struct ParsingInfo
internal bool fUseTwoDigitYear;
internal bool fAllowInnerWhite;
internal bool fAllowTrailingWhite;
internal bool fCustomNumberParser;
internal DateTimeParse.MatchNumberDelegate parseNumberDelegate;
internal bool fUseHebrewNumberParser;

internal void Init()
public ParsingInfo(Calendar calendar)
{
this.calendar = calendar;
dayOfWeek = -1;
timeMark = DateTimeParse.TM.NotSet;
}
Expand Down