Skip to content

Commit 0c8ea83

Browse files
committed
Improve extension normalization performance
1 parent adc69d8 commit 0c8ea83

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

ManagedCode.MimeTypes/MimeHelper.cs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public static partial class MimeHelper
3131

3232
private static readonly Regex ScriptPattern = new(@"^(?:application|text)/(?:javascript|ecmascript|x-php|x-sh|x-shellscript|x-python|x-ruby|x-perl)$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
3333

34+
private static readonly SearchValues<char> QueryFragmentSeparators = SearchValues.Create("?#");
35+
3436
private static readonly HashSet<string> ScriptMimeSet = new(StringComparer.OrdinalIgnoreCase)
3537
{
3638
"application/javascript",
@@ -403,7 +405,7 @@ private static IEnumerable<string> EnumerateExtensionCandidates(string value)
403405
yield break;
404406
}
405407

406-
var separatorIndex = trimmed.IndexOfAny(new[] { '?', '#' });
408+
var separatorIndex = trimmed.AsSpan().IndexOfAny(QueryFragmentSeparators);
407409
if (separatorIndex >= 0)
408410
{
409411
trimmed = trimmed[..separatorIndex];
@@ -441,10 +443,12 @@ private static IEnumerable<string> EnumerateExtensionCandidates(string value)
441443
}
442444

443445
var yielded = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
446+
var sanitized = fileName.Trim('.');
444447
var index = fileName.IndexOf('.');
445448
while (index >= 0 && index < fileName.Length - 1)
446449
{
447-
var candidate = fileName[(index + 1)..].Trim('.');
450+
var remainder = fileName[(index + 1)..];
451+
var candidate = remainder.Trim('.');
448452
if (candidate.Length > 0 && yielded.Add(candidate))
449453
{
450454
yield return candidate;
@@ -453,7 +457,6 @@ private static IEnumerable<string> EnumerateExtensionCandidates(string value)
453457
index = fileName.IndexOf('.', index + 1);
454458
}
455459

456-
var sanitized = fileName.Trim('.');
457460
if (sanitized.Length > 0 && yielded.Add(sanitized))
458461
{
459462
yield return sanitized;
@@ -467,8 +470,41 @@ private static string NormalizeExtensionKey(string extension)
467470
return string.Empty;
468471
}
469472

470-
var normalized = extension.Trim().TrimStart('.');
471-
return normalized.ToLowerInvariant();
473+
var span = extension.AsSpan();
474+
475+
var start = 0;
476+
var end = span.Length - 1;
477+
478+
while (start <= end && char.IsWhiteSpace(span[start]))
479+
{
480+
start++;
481+
}
482+
483+
while (end >= start && char.IsWhiteSpace(span[end]))
484+
{
485+
end--;
486+
}
487+
488+
while (start <= end && span[start] == '.')
489+
{
490+
start++;
491+
}
492+
493+
if (start > end)
494+
{
495+
return string.Empty;
496+
}
497+
498+
var length = end - start + 1;
499+
500+
return string.Create(length, (extension, start, length), static (destination, state) =>
501+
{
502+
var (source, offset, count) = state;
503+
for (var i = 0; i < count; i++)
504+
{
505+
destination[i] = char.ToLowerInvariant(source[offset + i]);
506+
}
507+
});
472508
}
473509

474510
private static void RegisterMimeTypeInternal(string extension, string mime)

0 commit comments

Comments
 (0)