diff --git a/src/BizHawk.Common/Extensions/StringExtensions.cs b/src/BizHawk.Common/Extensions/StringExtensions.cs
index 400ec5dc8e..2d81f34716 100644
--- a/src/BizHawk.Common/Extensions/StringExtensions.cs
+++ b/src/BizHawk.Common/Extensions/StringExtensions.cs
@@ -183,6 +183,27 @@ public static byte[] ToCharCodepointArray(this string str)
return a;
}
+ /// as , but assumes is 7-bit ASCII to allow for an optimisation
+ /// allocates a new char array only when necessary
+ public static string ToUpperASCIIFast(this string str)
+ {
+ const ushort ASCII_UPCASE_MASK = 0b101111;
+ for (var i = 0; i < str.Length; i++)
+ {
+ if (str[i] is < 'a' or > 'z') continue;
+ var a = new char[str.Length];
+ str.AsSpan(start: 0, length: i).CopyTo(a);
+ a[i] = unchecked((char) (str[i] & ASCII_UPCASE_MASK));
+ while (++i < str.Length)
+ {
+ var c = str[i];
+ a[i] = c is >= 'a' and <= 'z' ? unchecked((char) (c & ASCII_UPCASE_MASK)) : c;
+ }
+ return new(a);
+ }
+ return str;
+ }
+
///
/// splits a given by ,
/// applies to each part, then rejoins them
diff --git a/src/BizHawk.Emulation.Common/Database/Database.cs b/src/BizHawk.Emulation.Common/Database/Database.cs
index 4cf2de773a..4675338e9b 100644
--- a/src/BizHawk.Emulation.Common/Database/Database.cs
+++ b/src/BizHawk.Emulation.Common/Database/Database.cs
@@ -36,7 +36,10 @@ public static class Database
/// The hash to format, this is typically prefixed with a type (e.g. sha1:)
/// formatted hash
private static string FormatHash(string hash)
- => hash.Substring(hash.IndexOf(':') + 1).ToUpperInvariant();
+ {
+ var i = hash.IndexOf(':');
+ return (i < 0 ? hash.Substring(startIndex: i + 1) : hash).ToUpperASCIIFast();
+ }
private static void LoadDatabase_Escape(string line, bool inUser, bool silent)
{