Skip to content

Commit

Permalink
Optimize Scanning Around Pointer Arithmetic (Part 2) (YARC-Official#183)
Browse files Browse the repository at this point in the history
Includes conversions of multiple instance classes to either structs or static classes for maximal dodging of GC heap allocations.
  • Loading branch information
sonicfind authored Jun 21, 2024
1 parent c0de46a commit 564c381
Show file tree
Hide file tree
Showing 25 changed files with 858 additions and 1,068 deletions.
59 changes: 27 additions & 32 deletions YARG.Core/IO/Ini/IniModifierCreator.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YARG.Core.Song;
using YARG.Core.Utility;

Expand Down Expand Up @@ -38,63 +35,62 @@ public IniModifierCreator(string outputName, ModifierCreatorType type)
this.type = type;
}

public IniModifier CreateModifier<TChar, TDecoder>(YARGTextReader<TChar, TDecoder> reader)
public unsafe IniModifier CreateModifier<TChar>(ref YARGTextContainer<TChar> container, in delegate*<TChar*, long, string> decoder)
where TChar : unmanaged, IConvertible
where TDecoder : IStringDecoder<TChar>, new()
{
return type switch
{
ModifierCreatorType.SortString => new IniModifier(SortString.Convert(ExtractIniString(reader, false))),
ModifierCreatorType.SortString_Chart => new IniModifier(SortString.Convert(ExtractIniString(reader, true))),
ModifierCreatorType.String => new IniModifier(ExtractIniString(reader, false)),
ModifierCreatorType.String_Chart => new IniModifier(ExtractIniString(reader, true)),
_ => CreateNumberModifier(reader.Container),
ModifierCreatorType.SortString => new IniModifier(SortString.Convert(ExtractIniString(ref container, decoder, false))),
ModifierCreatorType.SortString_Chart => new IniModifier(SortString.Convert(ExtractIniString(ref container, decoder, true))),
ModifierCreatorType.String => new IniModifier(ExtractIniString(ref container, decoder, false)),
ModifierCreatorType.String_Chart => new IniModifier(ExtractIniString(ref container, decoder, true)),
_ => CreateNumberModifier(ref container),
};
}

public IniModifier CreateSngModifier(YARGTextContainer<byte> sngContainer, int length)
public IniModifier CreateSngModifier(ref YARGTextContainer<byte> sngContainer, int length)
{
return type switch
{
ModifierCreatorType.SortString => new IniModifier(SortString.Convert(ExtractSngString(sngContainer, length))),
ModifierCreatorType.String => new IniModifier(ExtractSngString(sngContainer, length)),
_ => CreateNumberModifier(sngContainer),
ModifierCreatorType.SortString => new IniModifier(SortString.Convert(ExtractSngString(ref sngContainer, length))),
ModifierCreatorType.String => new IniModifier(ExtractSngString(ref sngContainer, length)),
_ => CreateNumberModifier(ref sngContainer),
};
}

private IniModifier CreateNumberModifier<TChar>(YARGTextContainer<TChar> container)
private IniModifier CreateNumberModifier<TChar>(ref YARGTextContainer<TChar> container)
where TChar : unmanaged, IConvertible
{
switch (type)
{
case ModifierCreatorType.UInt64:
{
container.ExtractUInt64(out ulong value);
container.TryExtractUInt64(out ulong value);
return new IniModifier(value);
}
case ModifierCreatorType.Int64:
{
container.ExtractInt64(out long value);
container.TryExtractInt64(out long value);
return new IniModifier(value);
}
case ModifierCreatorType.UInt32:
{
container.ExtractUInt32(out uint value);
container.TryExtractUInt32(out uint value);
return new IniModifier(value);
}
case ModifierCreatorType.Int32:
{
container.ExtractInt32(out int value);
container.TryExtractInt32(out int value);
return new IniModifier(value);
}
case ModifierCreatorType.UInt16:
{
container.ExtractUInt16(out ushort value);
container.TryExtractUInt16(out ushort value);
return new IniModifier(value);
}
case ModifierCreatorType.Int16:
{
container.ExtractInt16(out short value);
container.TryExtractInt16(out short value);
return new IniModifier(value);
}
case ModifierCreatorType.Bool:
Expand All @@ -103,21 +99,21 @@ private IniModifier CreateNumberModifier<TChar>(YARGTextContainer<TChar> contain
}
case ModifierCreatorType.Float:
{
container.ExtractFloat(out float value);
container.TryExtractFloat(out float value);
return new IniModifier(value);
}
case ModifierCreatorType.Double:
{
container.ExtractDouble(out double value);
container.TryExtractDouble(out double value);
return new IniModifier(value);
}
case ModifierCreatorType.UInt64Array:
{
long l2 = -1;
if (container.ExtractInt64(out long l1))
if (container.TryExtractInt64(out long l1))
{
YARGTextReader.SkipWhitespace(container);
if (!container.ExtractInt64(out l2))
YARGTextReader.SkipWhitespace(ref container);
if (!container.TryExtractInt64(out l2))
{
l2 = -1;
}
Expand All @@ -133,16 +129,15 @@ private IniModifier CreateNumberModifier<TChar>(YARGTextContainer<TChar> contain
}
}

private static string ExtractIniString<TChar, TDecoder>(YARGTextReader<TChar, TDecoder> reader, bool isChartFile)
private static unsafe string ExtractIniString<TChar>(ref YARGTextContainer<TChar> container, in delegate*<TChar*, long, string> decoder, bool isChartFile)
where TChar : unmanaged, IConvertible
where TDecoder : IStringDecoder<TChar>, new()
{
return RichTextUtils.ReplaceColorNames(reader.ExtractText(isChartFile));
return RichTextUtils.ReplaceColorNames(YARGTextReader.ExtractText(ref container, decoder, isChartFile));
}

private static unsafe string ExtractSngString(YARGTextContainer<byte> sngContainer, int length)
private static unsafe string ExtractSngString(ref YARGTextContainer<byte> sngContainer, int length)
{
return RichTextUtils.ReplaceColorNames(Encoding.UTF8.GetString(sngContainer.Data.Ptr + sngContainer.Position, length));
return RichTextUtils.ReplaceColorNames(Encoding.UTF8.GetString(sngContainer.Position, length));
}
}
}
}
70 changes: 28 additions & 42 deletions YARG.Core/IO/Ini/YARGIniReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,21 @@

namespace YARG.Core.IO.Ini
{
public static class YARGIniReader
public static unsafe class YARGIniReader
{
public static Dictionary<string, IniSection> ReadIniFile(FileInfo iniFile, Dictionary<string, Dictionary<string, IniModifierCreator>> sections)
{
try
{
using var bytes = MemoryMappedArray.Load(iniFile);
var byteReader = YARGTextLoader.TryLoadByteText(bytes);
if (byteReader != null)
return ProcessIni(byteReader, sections);
if (YARGTextReader.TryLoadByteText(bytes, out var byteContainer))
{
return ProcessIni(ref byteContainer, &StringDecoder.Decode, sections);
}

using var chars = YARGTextLoader.ConvertToChar(bytes);
var charReader = new YARGTextReader<char, CharStringDecoder>(chars, 0);
return ProcessIni(charReader, sections);
using var chars = YARGTextReader.ConvertToChar(bytes);
var charContainer = new YARGTextContainer<char>(chars, 0);
return ProcessIni(ref charContainer, &StringDecoder.Decode, sections);

}
catch (Exception ex)
Expand All @@ -30,79 +31,64 @@ public static Dictionary<string, IniSection> ReadIniFile(FileInfo iniFile, Dicti
}
}

private static Dictionary<string, IniSection> ProcessIni<TChar, TDecoder>(YARGTextReader<TChar, TDecoder> reader, Dictionary<string, Dictionary<string, IniModifierCreator>> sections)
private static Dictionary<string, IniSection> ProcessIni<TChar>(ref YARGTextContainer<TChar> container, in delegate*<TChar*, long, string> decoder, Dictionary<string, Dictionary<string, IniModifierCreator>> sections)
where TChar : unmanaged, IConvertible
where TDecoder : IStringDecoder<TChar>, new()
{
Dictionary<string, IniSection> modifierMap = new();
while (TrySection(reader, out string section))
while (TrySection(ref container, decoder, out string section))
{
if (sections.TryGetValue(section, out var nodes))
modifierMap[section] = ExtractModifiers(reader, ref nodes);
modifierMap[section] = ExtractModifiers(ref container, decoder, ref nodes);
else
reader.SkipLinesUntil('[');
YARGTextReader.SkipLinesUntil(ref container, '[');
}
return modifierMap;
}

private static bool TrySection<TChar, TDecoder>(YARGTextReader<TChar, TDecoder> reader, out string section)
private static bool TrySection<TChar>(ref YARGTextContainer<TChar> container, in delegate*<TChar*, long, string> decoder, out string section)
where TChar : unmanaged, IConvertible
where TDecoder : IStringDecoder<TChar>, new()
{
section = string.Empty;
if (reader.Container.IsEndOfFile())
if (container.IsAtEnd())
{
return false;
}

if (!reader.Container.IsCurrentCharacter('['))
if (!container.IsCurrentCharacter('['))
{
reader.SkipLinesUntil('[');
if (reader.Container.IsEndOfFile())
if (!YARGTextReader.SkipLinesUntil(ref container, '['))
{
return false;
}
}
section = reader.PeekLine().ToLower();
section = YARGTextReader.PeekLine(ref container, decoder).ToLower();
return true;
}

private static IniSection ExtractModifiers<TChar, TDecoder>(YARGTextReader<TChar, TDecoder> reader, ref Dictionary<string, IniModifierCreator> validNodes)
private static IniSection ExtractModifiers<TChar>(ref YARGTextContainer<TChar> container, in delegate*<TChar*, long, string> decoder, ref Dictionary<string, IniModifierCreator> validNodes)
where TChar : unmanaged, IConvertible
where TDecoder : IStringDecoder<TChar>, new()
{
Dictionary<string, List<IniModifier>> modifiers = new();
reader.GotoNextLine();
while (IsStillCurrentSection(reader))
while (IsStillCurrentSection(ref container))
{
string name = reader.ExtractModifierName().ToLower();
string name = YARGTextReader.ExtractModifierName(ref container, decoder).ToLower();
if (validNodes.TryGetValue(name, out var node))
{
var mod = node.CreateModifier(reader);
var mod = node.CreateModifier(ref container, decoder);
if (modifiers.TryGetValue(node.outputName, out var list))
list.Add(mod);
else
modifiers.Add(node.outputName, new() { mod });
}
reader.GotoNextLine();
}
return new IniSection(modifiers);
}

private static bool IsStillCurrentSection<TChar, TDecoder>(YARGTextReader<TChar, TDecoder> reader)
private static bool IsStillCurrentSection<TChar>(ref YARGTextContainer<TChar> container)
where TChar : unmanaged, IConvertible
where TDecoder : IStringDecoder<TChar>, new()
{
return !reader.Container.IsEndOfFile() && !reader.Container.IsCurrentCharacter('[');
}

private static bool FindNextTrack<TChar, TDecoder>(YARGTextReader<TChar, TDecoder> reader)
where TChar : unmanaged, IConvertible
where TDecoder : IStringDecoder<TChar>, new()
{
while (reader.Container.Position < reader.Container.Length)
{
if (reader.Container.Data[reader.Container.Position].ToChar(null) == '[')
return true;
++reader.Container.Position;
}
return false;
YARGTextReader.GotoNextLine(ref container);
return !container.IsAtEnd() && !container.IsCurrentCharacter('[');
}
}
}
3 changes: 2 additions & 1 deletion YARG.Core/IO/Midi/YARGMidiFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public MidiFileEnumerator(YARGMidiFile file)

public bool MoveNext()
{
_current?.Dispose();
_current = file.LoadNextTrack();
return _current != null;
}
Expand All @@ -94,7 +95,7 @@ public void Reset()

public void Dispose()
{
//throw new NotImplementedException();
_current?.Dispose();
}
}
}
Expand Down
Loading

0 comments on commit 564c381

Please sign in to comment.