aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMary <mary@mary.zone>2022-06-24 19:04:57 +0200
committerGitHub <noreply@github.com>2022-06-24 19:04:57 +0200
commit30ee70a9bc9529772198a51b1b9a605932d2ea96 (patch)
tree93073c3338d139189685fc292c5fd1ad147a2c86
parent232b1012b0c981830ac46bd5024dcc0e35075301 (diff)
time: Make TimeZoneRule blittable and avoid copies (#3361)1.1.156
* time: Make TimeZoneRule blittable and avoid copies This drastically reduce overhead of using TimeZoneRule around the codebase. Effect on games is unknown * Add missing Box type * Ensure we clean the structure still This doesn't perform any copies * Address gdkchan's comments * Simplify Box
-rw-r--r--Ryujinx.Common/Memory/Box.cs12
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForGlue.cs14
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs19
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs122
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs26
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs36
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs9
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs13
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs47
-rw-r--r--Ryujinx.HLE/Utilities/StringUtils.cs6
10 files changed, 157 insertions, 147 deletions
diff --git a/Ryujinx.Common/Memory/Box.cs b/Ryujinx.Common/Memory/Box.cs
new file mode 100644
index 00000000..743cc31d
--- /dev/null
+++ b/Ryujinx.Common/Memory/Box.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Common.Memory
+{
+ public class Box<T> where T : unmanaged
+ {
+ public T Data;
+
+ public Box()
+ {
+ Data = new T();
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForGlue.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForGlue.cs
index 98d4b617..265cec5d 100644
--- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForGlue.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForGlue.cs
@@ -2,7 +2,10 @@ using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.HLE.Utilities;
+using Ryujinx.Memory;
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
@@ -100,15 +103,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
string locationName = StringUtils.ReadInlinedAsciiString(context.RequestData, 0x24);
- ResultCode resultCode = _timeZoneContentManager.LoadTimeZoneRule(out TimeZoneRule rules, locationName);
-
- // Write TimeZoneRule if success
- if (resultCode == ResultCode.Success)
+ using (WritableRegion region = context.Memory.GetWritableRegion(bufferPosition, Unsafe.SizeOf<TimeZoneRule>()))
{
- MemoryHelper.Write(context.Memory, bufferPosition, rules);
- }
+ ref TimeZoneRule rules = ref MemoryMarshal.Cast<byte, TimeZoneRule>(region.Memory.Span)[0];
- return resultCode;
+ return _timeZoneContentManager.LoadTimeZoneRule(ref rules, locationName);
+ }
}
[CommandHipc(100)]
diff --git a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs
index 202099b0..24032999 100644
--- a/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/StaticService/ITimeZoneServiceForPsc.cs
@@ -4,9 +4,12 @@ using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
using Ryujinx.HLE.Utilities;
+using Ryujinx.Memory;
using System;
using System.Diagnostics;
using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.StaticService
{
@@ -165,11 +168,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
using (MemoryStream timeZoneBinaryStream = new MemoryStream(temp))
{
- result = _timeZoneManager.ParseTimeZoneRuleBinary(out TimeZoneRule timeZoneRule, timeZoneBinaryStream);
-
- if (result == ResultCode.Success)
+ using (WritableRegion region = context.Memory.GetWritableRegion(timeZoneRuleBufferPosition, Unsafe.SizeOf<TimeZoneRule>()))
{
- MemoryHelper.Write(context.Memory, timeZoneRuleBufferPosition, timeZoneRule);
+ ref TimeZoneRule rule = ref MemoryMarshal.Cast<byte, TimeZoneRule>(region.Memory.Span)[0];
+
+ result = _timeZoneManager.ParseTimeZoneRuleBinary(ref rule, timeZoneBinaryStream);
}
}
@@ -199,9 +202,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
throw new InvalidOperationException();
}
- TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, bufferPosition);
+ ReadOnlySpan<TimeZoneRule> rules = MemoryMarshal.Cast<byte, TimeZoneRule>(context.Memory.GetSpan(bufferPosition, (int)bufferSize));
- ResultCode resultCode = _timeZoneManager.ToCalendarTime(rules, posixTime, out CalendarInfo calendar);
+ ResultCode resultCode = _timeZoneManager.ToCalendarTime(in rules[0], posixTime, out CalendarInfo calendar);
if (resultCode == 0)
{
@@ -244,9 +247,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.StaticService
throw new InvalidOperationException();
}
- TimeZoneRule rules = MemoryHelper.Read<TimeZoneRule>(context.Memory, inBufferPosition);
+ ReadOnlySpan<TimeZoneRule> rules = MemoryMarshal.Cast<byte, TimeZoneRule>(context.Memory.GetSpan(inBufferPosition, (int)inBufferSize));
- ResultCode resultCode = _timeZoneManager.ToPosixTime(rules, calendarTime, out long posixTime);
+ ResultCode resultCode = _timeZoneManager.ToPosixTime(in rules[0], calendarTime, out long posixTime);
if (resultCode == ResultCode.Success)
{
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs
index e1cdc16b..6cd16f75 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZone.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common;
+using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.Utilities;
using System;
@@ -38,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
new int[] { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
- private const string TimeZoneDefaultRule = ",M4.1.0,M10.5.0";
+ private static readonly byte[] TimeZoneDefaultRule = Encoding.ASCII.GetBytes(",M4.1.0,M10.5.0");
[StructLayout(LayoutKind.Sequential, Pack = 0x4, Size = 0x10)]
private struct CalendarTimeInternal
@@ -133,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return (t1 - t0) == SecondsPerRepeat;
}
- private static bool TimeTypeEquals(TimeZoneRule outRules, byte aIndex, byte bIndex)
+ private static bool TimeTypeEquals(in TimeZoneRule outRules, byte aIndex, byte bIndex)
{
if (aIndex < 0 || aIndex >= outRules.TypeCount || bIndex < 0 || bIndex >= outRules.TypeCount)
{
@@ -150,7 +151,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
StringUtils.CompareCStr(outRules.Chars[a.AbbreviationListIndex..], outRules.Chars[b.AbbreviationListIndex..]) == 0;
}
- private static int GetQZName(ReadOnlySpan<char> name, int namePosition, char delimiter)
+ private static int GetQZName(ReadOnlySpan<byte> name, int namePosition, char delimiter)
{
int i = namePosition;
@@ -162,13 +163,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return i;
}
- private static int GetTZName(char[] name, int namePosition)
+ private static int GetTZName(ReadOnlySpan<byte> name, int namePosition)
{
int i = namePosition;
char c;
- while ((c = name[i]) != '\0' && !char.IsDigit(c) && c != ',' && c != '-' && c != '+')
+ while ((c = (char)name[i]) != '\0' && !char.IsDigit(c) && c != ',' && c != '-' && c != '+')
{
i++;
}
@@ -176,7 +177,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return i;
}
- private static bool GetNum(char[] name, ref int namePosition, out int num, int min, int max)
+ private static bool GetNum(ReadOnlySpan<byte> name, ref int namePosition, out int num, int min, int max)
{
num = 0;
@@ -185,7 +186,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false;
}
- char c = name[namePosition];
+ char c = (char)name[namePosition];
if (!char.IsDigit(c))
{
@@ -205,7 +206,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false;
}
- c = name[namePosition];
+ c = (char)name[namePosition];
}
while (char.IsDigit(c));
@@ -217,7 +218,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true;
}
- private static bool GetSeconds(char[] name, ref int namePosition, out int seconds)
+ private static bool GetSeconds(ReadOnlySpan<byte> name, ref int namePosition, out int seconds)
{
seconds = 0;
@@ -266,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true;
}
- private static bool GetOffset(char[] name, ref int namePosition, ref int offset)
+ private static bool GetOffset(ReadOnlySpan<byte> name, ref int namePosition, ref int offset)
{
bool isNegative = false;
@@ -304,7 +305,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return true;
}
- private static bool GetRule(char[] name, ref int namePosition, out Rule rule)
+ private static bool GetRule(ReadOnlySpan<byte> name, ref int namePosition, out Rule rule)
{
rule = new Rule();
@@ -347,7 +348,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerWekk - 1);
}
- else if (char.IsDigit(name[namePosition]))
+ else if (char.IsDigit((char)name[namePosition]))
{
rule.Type = RuleType.DayOfYear;
isValid = GetNum(name, ref namePosition, out rule.Day, 0, DaysPerLYear - 1);
@@ -385,19 +386,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return 0;
}
- private static bool ParsePosixName(ReadOnlySpan<char> name, out TimeZoneRule outRules, bool lastDitch)
+ private static bool ParsePosixName(ReadOnlySpan<byte> name, ref TimeZoneRule outRules, bool lastDitch)
{
- outRules = new TimeZoneRule
- {
- Ats = new long[TzMaxTimes],
- Types = new byte[TzMaxTimes],
- Ttis = new TimeTypeInfo[TzMaxTypes],
- Chars = new char[TzCharsArraySize]
- };
+ outRules = new TimeZoneRule();
int stdLen;
- ReadOnlySpan<char> stdName = name;
+ ReadOnlySpan<byte> stdName = name;
int namePosition = 0;
int stdOffset = 0;
@@ -428,7 +423,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
}
else
{
- namePosition = GetTZName(name.ToArray(), namePosition);
+ namePosition = GetTZName(name, namePosition);
stdLen = namePosition;
}
@@ -449,7 +444,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
int destLen = 0;
int dstOffset = 0;
- ReadOnlySpan<char> destName = name.Slice(namePosition);
+ ReadOnlySpan<byte> destName = name.Slice(namePosition);
if (TzCharsArraySize < charCount)
{
@@ -476,7 +471,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
else
{
destName = name.Slice(namePosition);
- namePosition = GetTZName(name.ToArray(), namePosition);
+ namePosition = GetTZName(name, namePosition);
destLen = namePosition;
}
@@ -507,7 +502,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
if (name[namePosition] == '\0')
{
- name = TimeZoneDefaultRule.ToCharArray();
+ name = TimeZoneDefaultRule;
namePosition = 0;
}
@@ -515,7 +510,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
namePosition++;
- bool IsRuleValid = GetRule(name.ToArray(), ref namePosition, out Rule start);
+ bool IsRuleValid = GetRule(name, ref namePosition, out Rule start);
if (!IsRuleValid)
{
return false;
@@ -526,7 +521,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return false;
}
- IsRuleValid = GetRule(name.ToArray(), ref namePosition, out Rule end);
+ IsRuleValid = GetRule(name, ref namePosition, out Rule end);
if (!IsRuleValid)
{
return false;
@@ -738,7 +733,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
}
charsPosition += stdLen;
- outRules.Chars[charsPosition++] = '\0';
+ outRules.Chars[charsPosition++] = 0;
if (destLen != 0)
{
@@ -746,7 +741,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
outRules.Chars[charsPosition + i] = destName[i];
}
- outRules.Chars[charsPosition + destLen] = '\0';
+ outRules.Chars[charsPosition + destLen] = 0;
}
return true;
@@ -882,20 +877,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
}
}
- internal static bool ParsePosixName(string name, out TimeZoneRule outRules)
+ internal static bool ParsePosixName(string name, ref TimeZoneRule outRules)
{
- return ParsePosixName(name.ToCharArray(), out outRules, false);
+ return ParsePosixName(Encoding.ASCII.GetBytes(name), ref outRules, false);
}
- internal static bool ParseTimeZoneBinary(out TimeZoneRule outRules, Stream inputData)
+ internal static bool ParseTimeZoneBinary(ref TimeZoneRule outRules, Stream inputData)
{
- outRules = new TimeZoneRule
- {
- Ats = new long[TzMaxTimes],
- Types = new byte[TzMaxTimes],
- Ttis = new TimeTypeInfo[TzMaxTypes],
- Chars = new char[TzCharsArraySize]
- };
+ outRules = new TimeZoneRule();
BinaryReader reader = new BinaryReader(inputData);
@@ -1020,10 +1009,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
outRules.Ttis[i] = ttis;
}
- Encoding.ASCII.GetChars(p[..outRules.CharCount].ToArray()).CopyTo(outRules.Chars.AsSpan());
+ p[..outRules.CharCount].CopyTo(outRules.Chars);
p = p[outRules.CharCount..];
- outRules.Chars[outRules.CharCount] = '\0';
+ outRules.Chars[outRules.CharCount] = 0;
for (int i = 0; i < outRules.TypeCount; i++)
{
@@ -1077,27 +1066,30 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
throw new InvalidOperationException();
}
- char[] tempName = new char[TzNameMax + 1];
+ byte[] tempName = new byte[TzNameMax + 1];
Array.Copy(workBuffer, position, tempName, 0, nRead);
if (nRead > 2 && tempName[0] == '\n' && tempName[nRead - 1] == '\n' && outRules.TypeCount + 2 <= TzMaxTypes)
{
- tempName[nRead - 1] = '\0';
+ tempName[nRead - 1] = 0;
- char[] name = new char[TzNameMax];
+ byte[] name = new byte[TzNameMax];
Array.Copy(tempName, 1, name, 0, nRead - 1);
- if (ParsePosixName(name, out TimeZoneRule tempRules, false))
+ Box<TimeZoneRule> tempRulesBox = new Box<TimeZoneRule>();
+ ref TimeZoneRule tempRules = ref tempRulesBox.Data;
+
+ if (ParsePosixName(name, ref tempRulesBox.Data, false))
{
int abbreviationCount = 0;
charCount = outRules.CharCount;
- Span<char> chars = outRules.Chars;
+ Span<byte> chars = outRules.Chars;
for (int i = 0; i < tempRules.TypeCount; i++)
{
- ReadOnlySpan<char> tempChars = tempRules.Chars;
- ReadOnlySpan<char> tempAbbreviation = tempChars[tempRules.Ttis[i].AbbreviationListIndex..];
+ ReadOnlySpan<byte> tempChars = tempRules.Chars;
+ ReadOnlySpan<byte> tempAbbreviation = tempChars[tempRules.Ttis[i].AbbreviationListIndex..];
int j;
@@ -1175,7 +1167,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
for (int i = 1; i < outRules.TimeCount; i++)
{
- if (TimeTypeEquals(outRules, outRules.Types[i], outRules.Types[0]) && DifferByRepeat(outRules.Ats[i], outRules.Ats[0]))
+ if (TimeTypeEquals(in outRules, outRules.Types[i], outRules.Types[0]) && DifferByRepeat(outRules.Ats[i], outRules.Ats[0]))
{
outRules.GoBack = true;
break;
@@ -1184,7 +1176,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
for (int i = outRules.TimeCount - 2; i >= 0; i--)
{
- if (TimeTypeEquals(outRules, outRules.Types[outRules.TimeCount - 1], outRules.Types[i]) && DifferByRepeat(outRules.Ats[outRules.TimeCount - 1], outRules.Ats[i]))
+ if (TimeTypeEquals(in outRules, outRules.Types[outRules.TimeCount - 1], outRules.Types[i]) && DifferByRepeat(outRules.Ats[outRules.TimeCount - 1], outRules.Ats[i]))
{
outRules.GoAhead = true;
break;
@@ -1259,10 +1251,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
long remainingSeconds = time % SecondsPerDay;
calendarTime = new CalendarTimeInternal();
- calendarAdditionalInfo = new CalendarAdditionalInfo()
- {
- TimezoneName = new char[8]
- };
+ calendarAdditionalInfo = new CalendarAdditionalInfo();
while (timeDays < 0 || timeDays >= YearLengths[IsLeap((int)year)])
{
@@ -1353,13 +1342,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return 0;
}
- private static ResultCode ToCalendarTimeInternal(TimeZoneRule rules, long time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo)
+ private static ResultCode ToCalendarTimeInternal(in TimeZoneRule rules, long time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo)
{
calendarTime = new CalendarTimeInternal();
- calendarAdditionalInfo = new CalendarAdditionalInfo()
- {
- TimezoneName = new char[8]
- };
+ calendarAdditionalInfo = new CalendarAdditionalInfo();
ResultCode result;
@@ -1398,7 +1384,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return ResultCode.TimeNotFound;
}
- result = ToCalendarTimeInternal(rules, newTime, out calendarTime, out calendarAdditionalInfo);
+ result = ToCalendarTimeInternal(in rules, newTime, out calendarTime, out calendarAdditionalInfo);
if (result != 0)
{
return result;
@@ -1450,17 +1436,17 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
calendarAdditionalInfo.IsDaySavingTime = rules.Ttis[ttiIndex].IsDaySavingTime;
- ReadOnlySpan<char> timeZoneAbbreviation = rules.Chars.AsSpan()[rules.Ttis[ttiIndex].AbbreviationListIndex..];
+ ReadOnlySpan<byte> timeZoneAbbreviation = rules.Chars[rules.Ttis[ttiIndex].AbbreviationListIndex..];
int timeZoneSize = Math.Min(StringUtils.LengthCstr(timeZoneAbbreviation), 8);
- timeZoneAbbreviation[..timeZoneSize].CopyTo(calendarAdditionalInfo.TimezoneName.AsSpan());
+ timeZoneAbbreviation[..timeZoneSize].CopyTo(calendarAdditionalInfo.TimezoneName.ToSpan());
}
return result;
}
- private static ResultCode ToPosixTimeInternal(TimeZoneRule rules, CalendarTimeInternal calendarTime, out long posixTime)
+ private static ResultCode ToPosixTimeInternal(in TimeZoneRule rules, CalendarTimeInternal calendarTime, out long posixTime)
{
posixTime = 0;
@@ -1604,7 +1590,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
int direction;
- ResultCode result = ToCalendarTimeInternal(rules, pivot, out CalendarTimeInternal candidateCalendarTime, out _);
+ ResultCode result = ToCalendarTimeInternal(in rules, pivot, out CalendarTimeInternal candidateCalendarTime, out _);
if (result != 0)
{
if (pivot > 0)
@@ -1675,9 +1661,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return ResultCode.Success;
}
- internal static ResultCode ToCalendarTime(TimeZoneRule rules, long time, out CalendarInfo calendar)
+ internal static ResultCode ToCalendarTime(in TimeZoneRule rules, long time, out CalendarInfo calendar)
{
- ResultCode result = ToCalendarTimeInternal(rules, time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo);
+ ResultCode result = ToCalendarTimeInternal(in rules, time, out CalendarTimeInternal calendarTime, out CalendarAdditionalInfo calendarAdditionalInfo);
calendar = new CalendarInfo()
{
@@ -1697,7 +1683,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result;
}
- internal static ResultCode ToPosixTime(TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
+ internal static ResultCode ToPosixTime(in TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
{
CalendarTimeInternal calendarTimeInternal = new CalendarTimeInternal()
{
@@ -1710,7 +1696,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
Second = calendarTime.Second
};
- return ToPosixTimeInternal(rules, calendarTimeInternal, out posixTime);
+ return ToPosixTimeInternal(in rules, calendarTimeInternal, out posixTime);
}
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
index 141c2b4a..081e45a2 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
@@ -16,7 +16,7 @@ using System;
using System.Collections.Generic;
using System.IO;
-using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule;
+using TimeZoneRuleBox = Ryujinx.Common.Memory.Box<Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule>;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
@@ -149,7 +149,11 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
continue;
}
- TimeZone.ParseTimeZoneBinary(out TimeZoneRule tzRule, tzif.Get.AsStream());
+ TimeZoneRuleBox tzRuleBox = new TimeZoneRuleBox();
+ ref TimeZoneRule tzRule = ref tzRuleBox.Data;
+
+ TimeZone.ParseTimeZoneBinary(ref tzRule, tzif.Get.AsStream());
+
TimeTypeInfo ttInfo;
if (tzRule.TimeCount > 0) // Find the current transition period
@@ -174,10 +178,10 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
continue;
}
- var abbrStart = tzRule.Chars.AsSpan(ttInfo.AbbreviationListIndex);
- int abbrEnd = abbrStart.IndexOf('\0');
+ var abbrStart = tzRule.Chars[ttInfo.AbbreviationListIndex..];
+ int abbrEnd = abbrStart.IndexOf((byte)0);
- outList.Add((ttInfo.GmtOffset, locName, abbrStart.Slice(0, abbrEnd).ToString()));
+ outList.Add((ttInfo.GmtOffset, locName, abbrStart[..abbrEnd].ToString()));
}
}
@@ -276,15 +280,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return (ResultCode)result.Value;
}
- internal ResultCode LoadTimeZoneRule(out TimeZoneRule outRules, string locationName)
+ internal ResultCode LoadTimeZoneRule(ref TimeZoneRule rules, string locationName)
{
- outRules = new TimeZoneRule
- {
- Ats = new long[TzMaxTimes],
- Types = new byte[TzMaxTimes],
- Ttis = new TimeTypeInfo[TzMaxTypes],
- Chars = new char[TzCharsArraySize]
- };
+ rules = default;
if (!HasTimeZoneBinaryTitle())
{
@@ -295,7 +293,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
if (result == ResultCode.Success)
{
- result = Manager.ParseTimeZoneRuleBinary(out outRules, timeZoneBinaryStream);
+ result = Manager.ParseTimeZoneRuleBinary(ref rules, timeZoneBinaryStream);
ncaFile.Dispose();
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs
index 1a80365a..736bc102 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneManager.cs
@@ -1,14 +1,14 @@
-using Ryujinx.HLE.HOS.Services.Time.Clock;
+using Ryujinx.Common.Memory;
+using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.Utilities;
using System.IO;
-using static Ryujinx.HLE.HOS.Services.Time.TimeZone.TimeZoneRule;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
class TimeZoneManager
{
private bool _isInitialized;
- private TimeZoneRule _myRules;
+ private Box<TimeZoneRule> _myRules;
private string _deviceLocationName;
private UInt128 _timeZoneRuleVersion;
private uint _totalLocationNameCount;
@@ -21,15 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
_deviceLocationName = "UTC";
_timeZoneRuleVersion = new UInt128();
_lock = new object();
-
- // Empty rules
- _myRules = new TimeZoneRule
- {
- Ats = new long[TzMaxTimes],
- Types = new byte[TzMaxTimes],
- Ttis = new TimeTypeInfo[TzMaxTypes],
- Chars = new char[TzCharsArraySize]
- };
+ _myRules = new Box<TimeZoneRule>();
_timeZoneUpdateTimePoint = SteadyClockTimePoint.GetRandom();
}
@@ -78,7 +70,9 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
lock (_lock)
{
- bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out TimeZoneRule rules, timeZoneBinaryStream);
+ Box<TimeZoneRule> rules = new Box<TimeZoneRule>();
+
+ bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(ref rules.Data, timeZoneBinaryStream);
if (timeZoneConversionSuccess)
{
@@ -154,13 +148,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result;
}
- public ResultCode ParseTimeZoneRuleBinary(out TimeZoneRule outRules, Stream timeZoneBinaryStream)
+ public ResultCode ParseTimeZoneRuleBinary(ref TimeZoneRule outRules, Stream timeZoneBinaryStream)
{
ResultCode result = ResultCode.Success;
lock (_lock)
{
- bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(out outRules, timeZoneBinaryStream);
+ bool timeZoneConversionSuccess = TimeZone.ParseTimeZoneBinary(ref outRules, timeZoneBinaryStream);
if (!timeZoneConversionSuccess)
{
@@ -208,7 +202,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
if (_isInitialized)
{
- result = ToCalendarTime(_myRules, time, out calendar);
+ result = ToCalendarTime(in _myRules.Data, time, out calendar);
}
else
{
@@ -220,13 +214,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result;
}
- public ResultCode ToCalendarTime(TimeZoneRule rules, long time, out CalendarInfo calendar)
+ public ResultCode ToCalendarTime(in TimeZoneRule rules, long time, out CalendarInfo calendar)
{
ResultCode result;
lock (_lock)
{
- result = TimeZone.ToCalendarTime(rules, time, out calendar);
+ result = TimeZone.ToCalendarTime(in rules, time, out calendar);
}
return result;
@@ -240,7 +234,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
if (_isInitialized)
{
- result = ToPosixTime(_myRules, calendarTime, out posixTime);
+ result = ToPosixTime(in _myRules.Data, calendarTime, out posixTime);
}
else
{
@@ -252,13 +246,13 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
return result;
}
- public ResultCode ToPosixTime(TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
+ public ResultCode ToPosixTime(in TimeZoneRule rules, CalendarTime calendarTime, out long posixTime)
{
ResultCode result;
lock (_lock)
{
- result = TimeZone.ToPosixTime(rules, calendarTime, out posixTime);
+ result = TimeZone.ToPosixTime(in rules, calendarTime, out posixTime);
}
return result;
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs
index ef9b87e7..a84a2785 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/CalendarAdditionalInfo.cs
@@ -1,4 +1,5 @@
-using System.Runtime.InteropServices;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
@@ -8,14 +9,12 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
public uint DayOfWeek;
public uint DayOfYear;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public char[] TimezoneName;
+ public Array8<byte> TimezoneName;
[MarshalAs(UnmanagedType.I1)]
public bool IsDaySavingTime;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
- public char[] Padding;
+ public Array3<byte> Padding;
public int GmtOffset;
}
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs
index 399e0700..6a490baf 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeTypeInfo.cs
@@ -1,17 +1,19 @@
-using System.Runtime.InteropServices;
+using Ryujinx.Common.Memory;
+using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
- [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 4)]
+ [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 4)]
struct TimeTypeInfo
{
+ public const int Size = 0x10;
+
public int GmtOffset;
[MarshalAs(UnmanagedType.I1)]
public bool IsDaySavingTime;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
- public char[] Padding1;
+ public Array3<byte> Padding1;
public int AbbreviationListIndex;
@@ -21,7 +23,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
[MarshalAs(UnmanagedType.I1)]
public bool IsGMT;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
- public char[] Padding2;
+ public ushort Padding2;
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs
index 1af7a81a..705ff025 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/Types/TimeZoneRule.cs
@@ -1,16 +1,18 @@
-using System.Runtime.InteropServices;
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
{
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x4000, CharSet = CharSet.Ansi)]
struct TimeZoneRule
{
- public const int TzMaxTypes = 128;
- public const int TzMaxChars = 50;
- public const int TzMaxLeaps = 50;
- public const int TzMaxTimes = 1000;
- public const int TzNameMax = 255;
- public const int TzCharsArraySize = 2 * (TzNameMax + 1);
+ public const int TzMaxTypes = 128;
+ public const int TzMaxChars = 50;
+ public const int TzMaxLeaps = 50;
+ public const int TzMaxTimes = 1000;
+ public const int TzNameMax = 255;
+ public const int TzCharsArraySize = 2 * (TzNameMax + 1);
public int TimeCount;
public int TypeCount;
@@ -22,17 +24,32 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
[MarshalAs(UnmanagedType.I1)]
public bool GoAhead;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)]
- public long[] Ats;
+ [StructLayout(LayoutKind.Sequential, Size = sizeof(long) * TzMaxTimes)]
+ private struct AtsStorageStruct {}
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTimes)]
- public byte[] Types;
+ private AtsStorageStruct _ats;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzMaxTypes)]
- public TimeTypeInfo[] Ttis;
+ public Span<long> Ats => SpanHelpers.AsSpan<AtsStorageStruct, long>(ref _ats);
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = TzCharsArraySize)]
- public char[] Chars;
+ [StructLayout(LayoutKind.Sequential, Size = sizeof(byte) * TzMaxTimes)]
+ private struct TypesStorageStruct {}
+
+ private TypesStorageStruct _types;
+
+ public Span<byte> Types => SpanHelpers.AsByteSpan<TypesStorageStruct>(ref _types);
+
+ [StructLayout(LayoutKind.Sequential, Size = TimeTypeInfo.Size * TzMaxTimes)]
+ private struct TimeTypeInfoStorageStruct { }
+
+ private TimeTypeInfoStorageStruct _ttis;
+
+ public Span<TimeTypeInfo> Ttis => SpanHelpers.AsSpan<TimeTypeInfoStorageStruct, TimeTypeInfo>(ref _ttis);
+
+ [StructLayout(LayoutKind.Sequential, Size = sizeof(byte) * TzCharsArraySize)]
+ private struct CharsStorageStruct {}
+
+ private CharsStorageStruct _chars;
+ public Span<byte> Chars => SpanHelpers.AsByteSpan(ref _chars);
public int DefaultType;
}
diff --git a/Ryujinx.HLE/Utilities/StringUtils.cs b/Ryujinx.HLE/Utilities/StringUtils.cs
index 3027139b..269f9b55 100644
--- a/Ryujinx.HLE/Utilities/StringUtils.cs
+++ b/Ryujinx.HLE/Utilities/StringUtils.cs
@@ -128,7 +128,7 @@ namespace Ryujinx.HLE.Utilities
}
}
- public static int CompareCStr(ReadOnlySpan<char> s1, ReadOnlySpan<char> s2)
+ public static int CompareCStr(ReadOnlySpan<byte> s1, ReadOnlySpan<byte> s2)
{
int s1Index = 0;
int s2Index = 0;
@@ -142,11 +142,11 @@ namespace Ryujinx.HLE.Utilities
return s2[s2Index] - s1[s1Index];
}
- public static int LengthCstr(ReadOnlySpan<char> s)
+ public static int LengthCstr(ReadOnlySpan<byte> s)
{
int i = 0;
- while (s[i] != '\0')
+ while (s[i] != 0)
{
i++;
}