From ae4324032a48ee08a808354673f47536e76759d0 Mon Sep 17 00:00:00 2001 From: Andrey Sukharev Date: Thu, 19 Jan 2023 01:25:16 +0300 Subject: [PATCH] Optimize string memory usage. Use Spans and StringBuilders where possible (#3933) * Optimize string memory usage. Use ReadOnlySpan and StringBuilder where possible. * Fix copypaste error * Code generator review fixes * Use if statement instead of switch * Code style fixes Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com> * Another code style fix * Styling fix Co-authored-by: Mary-nyan * Styling fix Co-authored-by: gdkchan Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com> Co-authored-by: Mary-nyan Co-authored-by: gdkchan --- ARMeilleure/Decoders/OpCodeTable.cs | 12 +++--- ARMeilleure/Translation/PTC/Ptc.cs | 8 ++-- ARMeilleure/Translation/PTC/PtcProfiler.cs | 8 ++-- .../ViewModels/ControllerSettingsViewModel.cs | 2 +- Ryujinx.Common/Utilities/UInt128Utils.cs | 3 +- .../Glsl/Instructions/InstGenMemory.cs | 40 ++++++++++++------- .../Glsl/Instructions/InstGenPacking.cs | 3 +- Ryujinx.Graphics.Shader/Decoders/InstTable.cs | 11 ++--- Ryujinx.HLE/FileSystem/VirtualFileSystem.cs | 4 +- .../SoftwareKeyboard/InlineResponses.cs | 2 +- .../SoftwareKeyboardRendererBase.cs | 39 ++++++++++++------ .../Demangler/Ast/IntegerLiteral.cs | 3 +- .../HOS/Diagnostics/Demangler/Demangler.cs | 26 ++++++------ .../HOS/Services/Account/Acc/Types/UserId.cs | 5 ++- .../HOS/Services/Sockets/Nsd/IManager.cs | 3 +- Ryujinx.Horizon.Generators/CodeGenerator.cs | 15 ++++--- .../Kernel/SyscallGenerator.cs | 2 +- Ryujinx/Ui/Windows/AmiiboWindow.cs | 11 ++--- Ryujinx/Ui/Windows/ControllerWindow.cs | 2 +- 19 files changed, 118 insertions(+), 81 deletions(-) diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index 3f24986c57..54abb1418f 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -1339,7 +1339,7 @@ namespace ARMeilleure.Decoders private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp) { - string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16); + string reversedEncoding = $"{encoding.AsSpan(16)}{encoding.AsSpan(0, 16)}"; MakeOp reversedMakeOp = (inst, address, opCode) => makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16)); @@ -1353,7 +1353,7 @@ namespace ARMeilleure.Decoders string thumbEncoding = encoding; if (thumbEncoding.StartsWith("<<<<")) { - thumbEncoding = "1110" + thumbEncoding.Substring(4); + thumbEncoding = $"1110{thumbEncoding.AsSpan(4)}"; } SetT32(thumbEncoding, name, emitter, makeOpT32); } @@ -1365,19 +1365,19 @@ namespace ARMeilleure.Decoders string thumbEncoding = encoding; if (thumbEncoding.StartsWith("11110100")) { - thumbEncoding = "11111001" + encoding.Substring(8); + thumbEncoding = $"11111001{encoding.AsSpan(8)}"; } else if (thumbEncoding.StartsWith("1111001x")) { - thumbEncoding = "111x1111" + encoding.Substring(8); + thumbEncoding = $"111x1111{encoding.AsSpan(8)}"; } else if (thumbEncoding.StartsWith("11110010")) { - thumbEncoding = "11101111" + encoding.Substring(8); + thumbEncoding = $"11101111{encoding.AsSpan(8)}"; } else if (thumbEncoding.StartsWith("11110011")) { - thumbEncoding = "11111111" + encoding.Substring(8); + thumbEncoding = $"11111111{encoding.AsSpan(8)}"; } else { diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index e5b4623d2e..e5e0b2a541 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -183,8 +183,8 @@ namespace ARMeilleure.Translation.PTC private void PreLoad() { - string fileNameActual = string.Concat(CachePathActual, ".cache"); - string fileNameBackup = string.Concat(CachePathBackup, ".cache"); + string fileNameActual = $"{CachePathActual}.cache"; + string fileNameBackup = $"{CachePathBackup}.cache"; FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoBackup = new FileInfo(fileNameBackup); @@ -400,8 +400,8 @@ namespace ARMeilleure.Translation.PTC try { - string fileNameActual = string.Concat(CachePathActual, ".cache"); - string fileNameBackup = string.Concat(CachePathBackup, ".cache"); + string fileNameActual = $"{CachePathActual}.cache"; + string fileNameBackup = $"{CachePathBackup}.cache"; FileInfo fileInfoActual = new FileInfo(fileNameActual); diff --git a/ARMeilleure/Translation/PTC/PtcProfiler.cs b/ARMeilleure/Translation/PTC/PtcProfiler.cs index 0d5546283b..030ccff5fa 100644 --- a/ARMeilleure/Translation/PTC/PtcProfiler.cs +++ b/ARMeilleure/Translation/PTC/PtcProfiler.cs @@ -125,8 +125,8 @@ namespace ARMeilleure.Translation.PTC { _lastHash = default; - string fileNameActual = string.Concat(_ptc.CachePathActual, ".info"); - string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info"); + string fileNameActual = $"{_ptc.CachePathActual}.info"; + string fileNameBackup = $"{_ptc.CachePathBackup}.info"; FileInfo fileInfoActual = new FileInfo(fileNameActual); FileInfo fileInfoBackup = new FileInfo(fileNameBackup); @@ -246,8 +246,8 @@ namespace ARMeilleure.Translation.PTC { _waitEvent.Reset(); - string fileNameActual = string.Concat(_ptc.CachePathActual, ".info"); - string fileNameBackup = string.Concat(_ptc.CachePathBackup, ".info"); + string fileNameActual = $"{_ptc.CachePathActual}.info"; + string fileNameBackup = $"{_ptc.CachePathBackup}.info"; FileInfo fileInfoActual = new FileInfo(fileNameActual); diff --git a/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs b/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs index 82a75788de..5d5ca5f83b 100644 --- a/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs +++ b/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs @@ -435,7 +435,7 @@ namespace Ryujinx.Ava.UI.ViewModels if (str.Length > MaxSize) { - return str.Substring(0, MaxSize - Ellipsis.Length) + Ellipsis; + return $"{str.AsSpan(0, MaxSize - Ellipsis.Length)}{Ellipsis}"; } return str; diff --git a/Ryujinx.Common/Utilities/UInt128Utils.cs b/Ryujinx.Common/Utilities/UInt128Utils.cs index 8cc437d17f..af8521b4e9 100644 --- a/Ryujinx.Common/Utilities/UInt128Utils.cs +++ b/Ryujinx.Common/Utilities/UInt128Utils.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; namespace Ryujinx.Common.Utilities { @@ -6,7 +7,7 @@ namespace Ryujinx.Common.Utilities { public static UInt128 FromHex(string hex) { - return new UInt128((ulong)Convert.ToInt64(hex.Substring(0, 16), 16), (ulong)Convert.ToInt64(hex.Substring(16), 16)); + return new UInt128(ulong.Parse(hex.AsSpan(0, 16), NumberStyles.HexNumber), ulong.Parse(hex.AsSpan(16), NumberStyles.HexNumber)); } public static UInt128 CreateRandom() diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs index 3dbd73b27e..263eada6f2 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs @@ -2,6 +2,7 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation; using Ryujinx.Graphics.Shader.StructuredIr; using Ryujinx.Graphics.Shader.Translation; using System; +using System.Text; using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper; using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; @@ -44,11 +45,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions bool isArray = (texOp.Type & SamplerType.Array) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; - string texCall; + var texCallBuilder = new StringBuilder(); if (texOp.Inst == Instruction.ImageAtomic) { - texCall = (texOp.Flags & TextureFlags.AtomicMask) switch { + texCallBuilder.Append((texOp.Flags & TextureFlags.AtomicMask) switch { TextureFlags.Add => "imageAtomicAdd", TextureFlags.Minimum => "imageAtomicMin", TextureFlags.Maximum => "imageAtomicMax", @@ -60,11 +61,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions TextureFlags.Swap => "imageAtomicExchange", TextureFlags.CAS => "imageAtomicCompSwap", _ => "imageAtomicAdd", - }; + }); } else { - texCall = texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"; + texCallBuilder.Append(texOp.Inst == Instruction.ImageLoad ? "imageLoad" : "imageStore"); } int srcIndex = isBindless ? 1 : 0; @@ -83,7 +84,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr); - texCall += "(" + imageName; + texCallBuilder.Append('('); + texCallBuilder.Append(imageName); int coordsCount = texOp.Type.GetDimensions(); @@ -91,7 +93,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions void Append(string str) { - texCall += ", " + str; + texCallBuilder.Append(", "); + texCallBuilder.Append(str); } string ApplyScaling(string vector) @@ -107,11 +110,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions if (pCount == 3 && isArray) { // The array index is not scaled, just x and y. - vector = "ivec3(Helper_TexelFetchScale((" + vector + ").xy, " + scaleIndex + "), (" + vector + ").z)"; + vector = $"ivec3(Helper_TexelFetchScale(({vector}).xy, {scaleIndex}), ({vector}).z)"; } else if (pCount == 2 && !isArray) { - vector = "Helper_TexelFetchScale(" + vector + ", " + scaleIndex + ")"; + vector = $"Helper_TexelFetchScale({vector}, {scaleIndex})"; } } @@ -127,7 +130,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions elems[index] = Src(AggregateType.S32); } - Append(ApplyScaling("ivec" + pCount + "(" + string.Join(", ", elems) + ")")); + Append(ApplyScaling($"ivec{pCount}({string.Join(", ", elems)})")); } else { @@ -164,7 +167,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions _ => string.Empty }; - Append(prefix + "vec4(" + string.Join(", ", cElems) + ")"); + Append($"{prefix}vec4({string.Join(", ", cElems)})"); } if (texOp.Inst == Instruction.ImageAtomic) @@ -185,19 +188,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions Append(value); - texCall += ")"; + texCallBuilder.Append(')'); if (type != AggregateType.S32) { - texCall = "int(" + texCall + ")"; + texCallBuilder + .Insert(0, "int(") + .Append(')'); } } else { - texCall += ")" + (texOp.Inst == Instruction.ImageLoad ? GetMaskMultiDest(texOp.Index) : ""); + texCallBuilder.Append(')'); + + if (texOp.Inst == Instruction.ImageLoad) + { + texCallBuilder.Append(GetMaskMultiDest(texOp.Index)); + } } - return texCall; + return texCallBuilder.ToString(); } public static string LoadAttribute(CodeGenContext context, AstOperation operation) @@ -827,7 +837,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions private static string GetMask(int index) { - return '.' + "rgba".Substring(index, 1); + return $".{"rgba".AsSpan(index, 1)}"; } private static string GetMaskMultiDest(int mask) diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs index ecb90c1e08..5a888e9c52 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs @@ -1,4 +1,5 @@ using Ryujinx.Graphics.Shader.StructuredIr; +using System; using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper; using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; @@ -49,7 +50,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions private static string GetMask(int index) { - return '.' + "xy".Substring(index, 1); + return $".{"xy".AsSpan(index, 1)}"; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/Decoders/InstTable.cs b/Ryujinx.Graphics.Shader/Decoders/InstTable.cs index 911f158161..eaa77930b7 100644 --- a/Ryujinx.Graphics.Shader/Decoders/InstTable.cs +++ b/Ryujinx.Graphics.Shader/Decoders/InstTable.cs @@ -1,4 +1,5 @@ using Ryujinx.Graphics.Shader.Instructions; +using System; namespace Ryujinx.Graphics.Shader.Decoders { @@ -329,18 +330,18 @@ namespace Ryujinx.Graphics.Shader.Decoders private static void Add(string encoding, InstName name, InstEmitter emitter, InstProps props = InstProps.None) { - encoding = encoding.Substring(0, EncodingBits); + ReadOnlySpan encodingPart = encoding.AsSpan(0, EncodingBits); - int bit = encoding.Length - 1; + int bit = encodingPart.Length - 1; int value = 0; int xMask = 0; int xBits = 0; - int[] xPos = new int[encoding.Length]; + int[] xPos = new int[encodingPart.Length]; - for (int index = 0; index < encoding.Length; index++, bit--) + for (int index = 0; index < encodingPart.Length; index++, bit--) { - char chr = encoding[index]; + char chr = encodingPart[index]; if (chr == '1') { diff --git a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 95a2fcdac0..0b91d3a2df 100644 --- a/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -141,8 +141,8 @@ namespace Ryujinx.HLE.FileSystem return $"{rawPath}:/"; } - string basePath = rawPath.Substring(0, firstSeparatorOffset); - string fileName = rawPath.Substring(firstSeparatorOffset + 1); + var basePath = rawPath.AsSpan(0, firstSeparatorOffset); + var fileName = rawPath.AsSpan(firstSeparatorOffset + 1); return $"{basePath}:/{fileName}"; } diff --git a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/InlineResponses.cs b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/InlineResponses.cs index d48227a0f9..c3e45d4691 100644 --- a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/InlineResponses.cs +++ b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/InlineResponses.cs @@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard for (int maxStr = text.Length; maxStr >= 0; maxStr--) { // This loop will probably will run only once. - bytes = encoding.GetBytes(text.Substring(0, maxStr)); + bytes = encoding.GetBytes(text, 0, maxStr); if (bytes.Length <= maxSize) { break; diff --git a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs index 8216a65ee4..71835e2da3 100644 --- a/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs +++ b/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs @@ -292,20 +292,35 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard _logoPosition = new Point(logoPositionX, logoPositionY); } - - private RectangleF MeasureString(string text, Font font) + private static RectangleF MeasureString(string text, Font font) { RendererOptions options = new RendererOptions(font); - FontRectangle rectangle = TextMeasurer.Measure(text == "" ? " " : text, options); if (text == "") { - return new RectangleF(0, rectangle.Y, 0, rectangle.Height); + FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options); + + return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height); } - else + + FontRectangle rectangle = TextMeasurer.Measure(text, options); + + return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); + } + + private static RectangleF MeasureString(ReadOnlySpan text, Font font) + { + RendererOptions options = new RendererOptions(font); + + if (text == "") { - return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); + FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options); + return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height); } + + FontRectangle rectangle = TextMeasurer.Measure(text, options); + + return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); } private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUiState state) @@ -354,8 +369,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard cursorBrush = _selectionBoxBrush; cursorPen = _selectionBoxPen; - string textUntilBegin = state.InputText.Substring(0, state.CursorBegin); - string textUntilEnd = state.InputText.Substring(0, state.CursorEnd); + ReadOnlySpan textUntilBegin = state.InputText.AsSpan(0, state.CursorBegin); + ReadOnlySpan textUntilEnd = state.InputText.AsSpan(0, state.CursorEnd); var selectionBeginRectangle = MeasureString(textUntilBegin, _inputTextFont); var selectionEndRectangle = MeasureString(textUntilEnd , _inputTextFont); @@ -374,9 +389,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard { // Show the blinking cursor. - int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin); - string textUntilCursor = state.InputText.Substring(0, cursorBegin); - var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont); + int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin); + ReadOnlySpan textUntilCursor = state.InputText.AsSpan(0, cursorBegin); + var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont); cursorVisible = true; cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X; @@ -387,7 +402,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard if (state.CursorBegin < state.InputText.Length) { - textUntilCursor = state.InputText.Substring(0, cursorBegin + 1); + textUntilCursor = state.InputText.AsSpan(0, cursorBegin + 1); cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont); cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X; } diff --git a/Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs b/Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs index 951faa5549..ea048d7682 100644 --- a/Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs +++ b/Ryujinx.HLE/HOS/Diagnostics/Demangler/Ast/IntegerLiteral.cs @@ -1,4 +1,5 @@ using System.IO; +using System; namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast { @@ -25,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast if (_literalValue[0] == 'n') { writer.Write("-"); - writer.Write(_literalValue.Substring(1)); + writer.Write(_literalValue.AsSpan(1)); } else { diff --git a/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs b/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs index be5b753924..a6618eca4d 100644 --- a/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs +++ b/Ryujinx.HLE/HOS/Diagnostics/Demangler/Demangler.cs @@ -32,9 +32,9 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler private bool ConsumeIf(string toConsume) { - string mangledPart = Mangled.Substring(_position); + var mangledPart = Mangled.AsSpan(_position); - if (mangledPart.StartsWith(toConsume)) + if (mangledPart.StartsWith(toConsume.AsSpan())) { _position += toConsume.Length; @@ -44,14 +44,14 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler return false; } - private string PeekString(int offset = 0, int length = 1) + private ReadOnlySpan PeekString(int offset = 0, int length = 1) { if (_position + offset >= length) { return null; } - return Mangled.Substring(_position + offset, length); + return Mangled.AsSpan(_position + offset, length); } private char Peek(int offset = 0) @@ -101,8 +101,8 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler private int ParseSeqId() { - string part = Mangled.Substring(_position); - int seqIdLen = 0; + ReadOnlySpan part = Mangled.AsSpan(_position); + int seqIdLen = 0; for (; seqIdLen < part.Length; seqIdLen++) { @@ -114,7 +114,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler _position += seqIdLen; - return FromBase36(part.Substring(0, seqIdLen)); + return FromBase36(new string(part[..seqIdLen])); } // ::= S _ @@ -900,8 +900,8 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler private int ParsePositiveNumber() { - string part = Mangled.Substring(_position); - int numberLength = 0; + ReadOnlySpan part = Mangled.AsSpan(_position); + int numberLength = 0; for (; numberLength < part.Length; numberLength++) { @@ -918,7 +918,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler return -1; } - return int.Parse(part.AsSpan(0, numberLength)); + return int.Parse(part[..numberLength]); } private string ParseNumber(bool isSigned = false) @@ -933,8 +933,8 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler return null; } - string part = Mangled.Substring(_position); - int numberLength = 0; + ReadOnlySpan part = Mangled.AsSpan(_position); + int numberLength = 0; for (; numberLength < part.Length; numberLength++) { @@ -946,7 +946,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler _position += numberLength; - return part.Substring(0, numberLength); + return new string(part[..numberLength]); } // ::= diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserId.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserId.cs index 1793067d0c..e5577a94bf 100644 --- a/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserId.cs +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserId.cs @@ -1,5 +1,6 @@ using LibHac.Account; using System; +using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -35,8 +36,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc throw new ArgumentException("Invalid Hex value!", nameof(hex)); } - Low = Convert.ToInt64(hex.Substring(16), 16); - High = Convert.ToInt64(hex.Substring(0, 16), 16); + Low = long.Parse(hex.AsSpan(16), NumberStyles.HexNumber); + High = long.Parse(hex.AsSpan(0, 16), NumberStyles.HexNumber); } public void Write(BinaryWriter binaryWriter) diff --git a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs index 14bdd476ca..b098e2edc0 100644 --- a/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs +++ b/Ryujinx.HLE/HOS/Services/Sockets/Nsd/IManager.cs @@ -4,6 +4,7 @@ using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Services.Settings; using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager; using Ryujinx.HLE.HOS.Services.Sockets.Nsd.Types; +using System; using System.Text; namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd @@ -370,7 +371,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd return result; } - byte environmentType = identifier.Substring(0, 2) switch + byte environmentType = identifier.AsSpan(0, 2) switch { "lp" => (byte)ApplicationServerEnvironmentType.Lp, "sd" => (byte)ApplicationServerEnvironmentType.Sd, diff --git a/Ryujinx.Horizon.Generators/CodeGenerator.cs b/Ryujinx.Horizon.Generators/CodeGenerator.cs index 3a479eb74c..29e1c75c89 100644 --- a/Ryujinx.Horizon.Generators/CodeGenerator.cs +++ b/Ryujinx.Horizon.Generators/CodeGenerator.cs @@ -4,9 +4,10 @@ namespace Ryujinx.Horizon.Generators { class CodeGenerator { - private const string Indent = " "; + private const int IndentLength = 4; + private readonly StringBuilder _sb; - private string _currentIndent; + private int _currentIndentCount; public CodeGenerator() { @@ -32,12 +33,15 @@ namespace Ryujinx.Horizon.Generators public void IncreaseIndentation() { - _currentIndent += Indent; + _currentIndentCount++; } public void DecreaseIndentation() { - _currentIndent = _currentIndent.Substring(0, _currentIndent.Length - Indent.Length); + if (_currentIndentCount - 1 >= 0) + { + _currentIndentCount--; + } } public void AppendLine() @@ -47,7 +51,8 @@ namespace Ryujinx.Horizon.Generators public void AppendLine(string text) { - _sb.AppendLine(_currentIndent + text); + _sb.Append(' ', IndentLength * _currentIndentCount); + _sb.AppendLine(text); } public override string ToString() diff --git a/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs index f2a8770306..8bc0800c13 100644 --- a/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs +++ b/Ryujinx.Horizon.Kernel.Generators/Kernel/SyscallGenerator.cs @@ -417,7 +417,7 @@ namespace Ryujinx.Horizon.Generators.Kernel private static string GetPrefixedArgName(string name) { - return ArgVariablePrefix + name[0].ToString().ToUpperInvariant() + name.Substring(1); + return ArgVariablePrefix + char.ToUpperInvariant(name[0]) + name.Substring(1); } private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode) diff --git a/Ryujinx/Ui/Windows/AmiiboWindow.cs b/Ryujinx/Ui/Windows/AmiiboWindow.cs index a8b0212385..9140a14e90 100644 --- a/Ryujinx/Ui/Windows/AmiiboWindow.cs +++ b/Ryujinx/Ui/Windows/AmiiboWindow.cs @@ -344,7 +344,7 @@ namespace Ryujinx.Ui.Windows string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Head + amiibo.Tail == _amiiboCharsComboBox.ActiveId).Image; - string usageString = ""; + var usageStringBuilder = new StringBuilder(); for (int i = 0; i < _amiiboList.Count; i++) { @@ -358,19 +358,20 @@ namespace Ryujinx.Ui.Windows { foreach (AmiiboApiUsage usageItem in item.AmiiboUsage) { - usageString += Environment.NewLine + $"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}"; + usageStringBuilder.Append(Environment.NewLine); + usageStringBuilder.Append($"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}"); writable = usageItem.Write; } } } - if (usageString.Length == 0) + if (usageStringBuilder.Length == 0) { - usageString = "Unknown."; + usageStringBuilder.Append("Unknown."); } - _gameUsageLabel.Text = $"Usage{(writable ? " (Writable)" : "")} : {usageString}"; + _gameUsageLabel.Text = $"Usage{(writable ? " (Writable)" : "")} : {usageStringBuilder}"; } } diff --git a/Ryujinx/Ui/Windows/ControllerWindow.cs b/Ryujinx/Ui/Windows/ControllerWindow.cs index 002f8fe22b..8c3a43c853 100644 --- a/Ryujinx/Ui/Windows/ControllerWindow.cs +++ b/Ryujinx/Ui/Windows/ControllerWindow.cs @@ -246,7 +246,7 @@ namespace Ryujinx.Ui.Windows if (str.Length > MaxSize) { - return str.Substring(0, MaxSize - ShrinkChars.Length) + ShrinkChars; + return $"{str.AsSpan(0, MaxSize - ShrinkChars.Length)}{ShrinkChars}"; } return str;