Reduce use of pointer in the LoadTimeZoneRule logic

This commit is contained in:
Thog 2019-07-03 13:12:56 +02:00
commit d3968e933e
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6

View file

@ -197,30 +197,38 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return i; return i;
} }
private static unsafe char* GetQZName(char* name, char delimiter) private static int GetQZName(char[] name, int namePosition, char delimiter)
{ {
while (*name != '\0' && *name != delimiter) int i = namePosition;
while (name[i] != '\0' && name[i] != delimiter)
{ {
name++; i++;
} }
return name; return i;
} }
private static unsafe char* GetTZName(char* name) private static int GetTZName(char[] name, int namePosition)
{ {
while (*name != '\0' && !char.IsDigit(*name) && *name != ',' && *name != '-' && *name != '+') int i = namePosition;
char c = name[i];
while (c != '\0' && !char.IsDigit(c) && c != ',' && c != '-' && c != '+')
{ {
name++; c = name[i];
} i++;
return name;
} }
private static unsafe bool GetNum(ref char* name, out int num, int min, int max) return i;
}
private static bool GetNum(char[] name, ref int namePosition, out int num, int min, int max)
{ {
num = 0; num = 0;
char c = *name; char c = name[namePosition];
if (!char.IsDigit(c)) if (!char.IsDigit(c))
{ {
@ -235,7 +243,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false; return false;
} }
c = *++name; c = name[++namePosition];
} }
while (char.IsDigit(c)); while (char.IsDigit(c));
@ -247,33 +255,33 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true; return true;
} }
private static unsafe bool GetSeconds(ref char* name, out int seconds) private static bool GetSeconds(char[] name, ref int namePosition, out int seconds)
{ {
seconds = 0; seconds = 0;
int num; int num;
bool isValid = GetNum(ref name, out num, 0, HoursPerDays * DaysPerWekk - 1); bool isValid = GetNum(name, ref namePosition, out num, 0, HoursPerDays * DaysPerWekk - 1);
if (!isValid) if (!isValid)
{ {
return false; return false;
} }
seconds = num * SecondsPerHour; seconds = num * SecondsPerHour;
if (*name == ':') if (name[namePosition] == ':')
{ {
name++; namePosition++;
isValid = GetNum(ref name, out num, 0, MinutesPerHour - 1); isValid = GetNum(name, ref namePosition, out num, 0, MinutesPerHour - 1);
if (!isValid) if (!isValid)
{ {
return false; return false;
} }
seconds += num * SecondsPerMinute; seconds += num * SecondsPerMinute;
if (*name == ':') if (name[namePosition] == ':')
{ {
name++; namePosition++;
isValid = GetNum(ref name, out num, 0, SecondsPerMinute); isValid = GetNum(name, ref namePosition, out num, 0, SecondsPerMinute);
if (!isValid) if (!isValid)
{ {
return false; return false;
@ -285,21 +293,21 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true; return true;
} }
private static unsafe bool GetOffset(ref char* name, ref int offset) private static bool GetOffset(char[] name, ref int namePosition, ref int offset)
{ {
bool isNegative = false; bool isNegative = false;
if (*name == '-') if (name[namePosition] == '-')
{ {
isNegative = true; isNegative = true;
name++; namePosition++;
} }
else if (*name == '+') else if (name[namePosition] == '+')
{ {
name++; namePosition++;
} }
bool isValid = GetSeconds(ref name, out offset); bool isValid = GetSeconds(name, ref namePosition, out offset);
if (!isValid) if (!isValid)
{ {
return false; return false;
@ -313,53 +321,53 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true; return true;
} }
private static unsafe bool GetRule(ref char* name, out Rule rule) private static bool GetRule(char[] name, ref int namePosition, out Rule rule)
{ {
rule = new Rule(); rule = new Rule();
bool isValid = false; bool isValid = false;
if (*name == 'J') if (name[namePosition] == 'J')
{ {
name++; namePosition++;
rule.Type = RuleType.JulianDay; rule.Type = RuleType.JulianDay;
isValid = GetNum(ref name, out rule.Day, 1, DaysPerNYear); isValid = GetNum(name, ref namePosition, out rule.Day, 1, DaysPerNYear);
} }
else if (*name == 'M') else if (name[namePosition] == 'M')
{ {
name++; namePosition++;
rule.Type = RuleType.MonthNthDayOfWeek; rule.Type = RuleType.MonthNthDayOfWeek;
isValid = GetNum(ref name, out rule.Month, 1, MonthsPerYear); isValid = GetNum(name, ref namePosition, out rule.Month, 1, MonthsPerYear);
if (!isValid) if (!isValid)
{ {
return false; return false;
} }
if (*name++ != '.') if (name[namePosition++] != '.')
{ {
return false; return false;
} }
isValid = GetNum(ref name, out rule.Week, 1, 5); isValid = GetNum(name, ref namePosition, out rule.Week, 1, 5);
if (!isValid) if (!isValid)
{ {
return false; return false;
} }
if (*name++ != '.') if (name[namePosition++] != '.')
{ {
return false; return false;
} }
isValid = GetNum(ref name, out rule.Day, 0, DaysPerWekk - 1); isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerWekk - 1);
} }
else if (char.IsDigit(*name)) else if (char.IsDigit(name[namePosition]))
{ {
rule.Type = RuleType.DayOfYear; rule.Type = RuleType.DayOfYear;
isValid = GetNum(ref name, out rule.Day, 0, DaysPerLYear - 1); isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerLYear - 1);
} }
else else
{ {
@ -371,10 +379,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false; return false;
} }
if (*name == '/') if (name[namePosition] == '/')
{ {
name++; namePosition++;
return GetOffset(ref name, ref rule.TransitionTime); return GetOffset(name, ref namePosition, ref rule.TransitionTime);
} }
else else
{ {
@ -394,7 +402,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return 0; return 0;
} }
private static unsafe bool ParsePosixName(char* name, out TimeZoneRule outRules, bool lastDitch) private static bool ParsePosixName(Span<char> name, out TimeZoneRule outRules, bool lastDitch)
{ {
outRules = new TimeZoneRule outRules = new TimeZoneRule
{ {
@ -406,39 +414,48 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
int stdLen; int stdLen;
char* stdName = name; int namePosition = 0;
Span<char> stdName = name;
int stdOffset = 0; int stdOffset = 0;
if (lastDitch) if (lastDitch)
{ {
stdLen = 3; stdLen = 3;
name += stdLen; namePosition += stdLen;
} }
else else
{ {
if (*name == '<') if (name[namePosition] == '<')
{ {
name++; namePosition++;
stdName = name;
name = GetQZName(name, '>'); stdName = name.Slice(namePosition);
if (*name != '>')
int stdNamePosition = namePosition;
namePosition = GetQZName(name.ToArray(), namePosition, '>');
if (name[namePosition] != '>')
{ {
return false; return false;
} }
stdLen = (int)(name - stdName);
name++; stdLen = namePosition - stdNamePosition;
namePosition++;
} }
else else
{ {
name = GetTZName(name); namePosition = GetTZName(name.ToArray(), namePosition);
stdLen = (int)(name - stdName); stdLen = namePosition;
} }
if (stdLen == 0) if (stdLen == 0)
{ {
return false; return false;
} }
bool isValid = GetOffset(ref name, ref stdOffset);
bool isValid = GetOffset(name.ToArray(), ref namePosition, ref stdOffset);
if (!isValid) if (!isValid)
{ {
return false; return false;
@ -449,31 +466,35 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
int destLen = 0; int destLen = 0;
int dstOffset = 0; int dstOffset = 0;
char* destName = name; Span<char> destName = name.Slice(namePosition);
if (TzCharsArraySize < charCount) if (TzCharsArraySize < charCount)
{ {
return false; return false;
} }
if (*name != '\0') if (name[namePosition] != '\0')
{ {
if (*name == '<') if (name[namePosition] == '<')
{ {
destName = ++name; destName = name.Slice(++namePosition);
name = GetQZName(name, '>'); int destNamePosition = namePosition;
if (*name != '>')
namePosition = GetQZName(name.ToArray(), namePosition, '>');
if (name[namePosition] != '>')
{ {
return false; return false;
} }
destLen = (int)(name - destName);
name++; destLen = namePosition - destNamePosition;
namePosition++;
} }
else else
{ {
destName = name; destName = name.Slice(namePosition);
name = GetTZName(name); namePosition = GetTZName(name.ToArray(), namePosition);
destLen = (int)(name - destName); destLen = namePosition;
} }
if (destLen == 0) if (destLen == 0)
@ -481,15 +502,16 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false; return false;
} }
charCount += (int)destLen + 1; charCount += destLen + 1;
if (TzCharsArraySize < charCount) if (TzCharsArraySize < charCount)
{ {
return false; return false;
} }
if (*name != '\0' && *name != ',' && *name != ';') if (name[namePosition] != '\0' && name[namePosition] != ',' && name[namePosition] != ';')
{ {
bool isValid = GetOffset(ref name, ref dstOffset); bool isValid = GetOffset(name.ToArray(), ref namePosition, ref dstOffset);
if (!isValid) if (!isValid)
{ {
return false; return false;
@ -500,36 +522,34 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
dstOffset = stdOffset - SecondsPerHour; dstOffset = stdOffset - SecondsPerHour;
} }
if (*name == '\0') if (name[namePosition] == '\0')
{ {
fixed (char* defaultTz = TimeZoneDefaultRule.ToCharArray()) name = TimeZoneDefaultRule.ToCharArray();
{ namePosition = 0;
name = defaultTz;
}
} }
if (*name == ',' || *name == ';') if (name[namePosition] == ',' || name[namePosition] == ';')
{ {
name++; namePosition++;
bool IsRuleValid = GetRule(ref name, out Rule start); bool IsRuleValid = GetRule(name.ToArray(), ref namePosition, out Rule start);
if (!IsRuleValid) if (!IsRuleValid)
{ {
return false; return false;
} }
if (*name++ != ',') if (name[namePosition++] != ',')
{ {
return false; return false;
} }
IsRuleValid = GetRule(ref name, out Rule end); IsRuleValid = GetRule(name.ToArray(), ref namePosition, out Rule end);
if (!IsRuleValid) if (!IsRuleValid)
{ {
return false; return false;
} }
if (*name != '\0') if (name[namePosition] != '\0')
{ {
return false; return false;
} }
@ -639,7 +659,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
} }
else else
{ {
if (*name == '\0') if (name[namePosition] == '\0')
{ {
return false; return false;
} }
@ -727,25 +747,23 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
outRules.CharCount = charCount; outRules.CharCount = charCount;
fixed (char* chars = outRules.Chars) int charsPosition = 0;
{
char* cp = chars;
for (int i = 0; i < stdLen; i++) for (int i = 0; i < stdLen; i++)
{ {
cp[i] = stdName[i]; outRules.Chars[i] = stdName[i];
} }
cp += stdLen;
*cp++ = '\0'; charsPosition += stdLen;
outRules.Chars[charsPosition++] = '\0';
if (destLen != 0) if (destLen != 0)
{ {
for (int i = 0; i < destLen; i++) for (int i = 0; i < destLen; i++)
{ {
cp[i] = destName[i]; outRules.Chars[charsPosition + i] = destName[i];
}
*(cp + destLen) = '\0';
} }
outRules.Chars[charsPosition + destLen] = '\0';
} }
return true; return true;
@ -883,13 +901,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
public static bool ParsePosixName(string name, out TimeZoneRule outRules) public static bool ParsePosixName(string name, out TimeZoneRule outRules)
{ {
unsafe return ParsePosixName(name.ToCharArray(), out outRules, false);
{
fixed (char *namePtr = name.ToCharArray())
{
return ParsePosixName(namePtr, out outRules, false);
}
}
} }
public static unsafe bool LoadTimeZoneRules(out TimeZoneRule outRules, Stream inputData) public static unsafe bool LoadTimeZoneRules(out TimeZoneRule outRules, Stream inputData)
@ -1081,16 +1093,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
char[] name = new char[TzNameMax + 1]; char[] tempName = new char[TzNameMax + 1];
Array.Copy(workBuffer, position, name, 0, nread); Array.Copy(workBuffer, position, tempName, 0, nread);
if (nread > 2 && name[0] == '\n' && name[nread - 1] == '\n' && outRules.TypeCount + 2 <= TzMaxTypes) if (nread > 2 && tempName[0] == '\n' && tempName[nread - 1] == '\n' && outRules.TypeCount + 2 <= TzMaxTypes)
{ {
name[nread - 1] = '\0'; tempName[nread - 1] = '\0';
fixed (char* namePtr = &name[1]) char[] name = new char[TzNameMax];
{ Array.Copy(tempName, 1, name, 0, nread - 1);
if (ParsePosixName(namePtr, out TimeZoneRule tempRules, false))
if (ParsePosixName(name, out TimeZoneRule tempRules, false))
{ {
int abbreviationCount = 0; int abbreviationCount = 0;
charCount = outRules.CharCount; charCount = outRules.CharCount;
@ -1125,6 +1138,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
} }
charCount = j + abbreviationLength + 1; charCount = j + abbreviationLength + 1;
tempRules.Ttis[i].AbbreviationListIndex = j; tempRules.Ttis[i].AbbreviationListIndex = j;
abbreviationCount++; abbreviationCount++;
} }
@ -1156,6 +1170,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{ {
outRules.Ats[outRules.TimeCount] = tempRules.Ats[i]; outRules.Ats[outRules.TimeCount] = tempRules.Ats[i];
outRules.Types[outRules.TimeCount] = (byte)(outRules.TypeCount + (byte)tempRules.Types[i]); outRules.Types[outRules.TimeCount] = (byte)(outRules.TypeCount + (byte)tempRules.Types[i]);
outRules.TimeCount++; outRules.TimeCount++;
i++; i++;
} }
@ -1168,7 +1183,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
} }
} }
} }
}
if (outRules.TypeCount == 0) if (outRules.TypeCount == 0)
{ {