Skip to content

Commit 5331a65

Browse files
committed
feat: optimize static MIME registry for 10.1.1
1 parent 0631286 commit 5331a65

20 files changed

Lines changed: 706 additions & 126 deletions

‎Directory.Build.props‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
<RepositoryUrl>https://github.com/managedcode/MimeTypes</RepositoryUrl>
1818
<PackageProjectUrl>https://github.com/managedcode/MimeTypes</PackageProjectUrl>
1919
<Product>Managed Code - MimeTypes</Product>
20-
<Version>10.0.13</Version>
21-
<PackageVersion>10.0.13</PackageVersion>
20+
<Version>10.1.1</Version>
21+
<PackageVersion>10.1.1</PackageVersion>
2222

2323
</PropertyGroup>
2424
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
2525
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
2626
</PropertyGroup>
2727
<ItemGroup>
28-
<None Include="$(SolutionDir)\logo.png" Pack="true" Visible="false" PackagePath="\"/>
29-
<None Include="$(SolutionDir)\README.md" Pack="true" Visible="false" PackagePath="\"/>
28+
<None Include="$(MSBuildThisFileDirectory)logo.png" Pack="true" Visible="false" PackagePath="\"/>
29+
<None Include="$(MSBuildThisFileDirectory)README.md" Pack="true" Visible="false" PackagePath="\"/>
3030
</ItemGroup>
3131
<ItemGroup>
3232
<PackageReference Update="DotNet.ReproducibleBuilds" Version="1.2.25">
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<IsPackable>false</IsPackable>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<PackageReference Include="BenchmarkDotNet" Version="0.15.8" />
11+
<ProjectReference Include="..\ManagedCode.MimeTypes\ManagedCode.MimeTypes.csproj" />
12+
</ItemGroup>
13+
<ItemGroup>
14+
<None Include="..\ManagedCode.MimeTypes\mimeTypes.json" Link="mimeTypes.json" CopyToOutputDirectory="PreserveNewest" />
15+
</ItemGroup>
16+
</Project>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Jobs;
3+
using ManagedCode.MimeTypes;
4+
5+
namespace ManagedCode.MimeTypes.Benchmarks;
6+
7+
[MemoryDiagnoser]
8+
[ShortRunJob]
9+
public class MimeLookupBenchmarks
10+
{
11+
private readonly MemoryStream _pdf = new("%PDF-1.7\n"u8.ToArray());
12+
13+
[GlobalSetup]
14+
public void Setup()
15+
{
16+
MimeHelper.WarmUp();
17+
}
18+
19+
[Benchmark(Baseline = true)]
20+
public string GeneratedProperty() => MimeHelper.PNG;
21+
22+
[Benchmark]
23+
public string BareExtensionLookup() => MimeHelper.GetMimeType("png");
24+
25+
[Benchmark]
26+
public string FileNameLookup() => MimeHelper.GetMimeType("assets/photo.png");
27+
28+
[Benchmark]
29+
public string CompoundExtensionLookup() => MimeHelper.GetMimeType("types/module.d.ts");
30+
31+
[Benchmark]
32+
public IReadOnlyCollection<string> CachedReverseLookup() => MimeHelper.GetExtensions("image/jpeg");
33+
34+
[Benchmark]
35+
public bool CachedMetadataLookup() => MimeHelper.TryGetMimeTypeInfo("application/pdf", out _);
36+
37+
[Benchmark]
38+
public IReadOnlyCollection<MimeTypeInfo> CachedMetadataCatalog() => MimeHelper.GetKnownMimeTypes();
39+
40+
[Benchmark]
41+
public MimeTypeCategory CategoryLookup() => MimeHelper.GetMimeCategory("application/ld+json");
42+
43+
[Benchmark]
44+
public string ContentSignatureLookup()
45+
{
46+
_pdf.Position = 0;
47+
return MimeHelper.GetMimeTypeByContent(_pdf);
48+
}
49+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using BenchmarkDotNet.Running;
2+
3+
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System.Collections.Frozen;
2+
using System.Collections.Immutable;
3+
using System.Text.Json;
4+
using BenchmarkDotNet.Attributes;
5+
using BenchmarkDotNet.Jobs;
6+
7+
namespace ManagedCode.MimeTypes.Benchmarks;
8+
9+
[MemoryDiagnoser]
10+
[ShortRunJob]
11+
public class RegistryInitializationBenchmarks
12+
{
13+
private (string Extension, string Mime)[] _mappings = null!;
14+
private byte[] _registryJson = null!;
15+
16+
[Params(1_700)]
17+
public int MappingCount { get; set; }
18+
19+
[GlobalSetup]
20+
public void Setup()
21+
{
22+
_mappings = Enumerable.Range(0, MappingCount)
23+
.Select(static index => ($"ext{index}", $"application/x-type-{index % 600}"))
24+
.ToArray();
25+
_registryJson = File.ReadAllBytes(Path.Combine(AppContext.BaseDirectory, "mimeTypes.json"));
26+
}
27+
28+
[Benchmark(Baseline = true)]
29+
public ImmutableDictionary<string, string> LegacyIncrementalImmutableInitialization()
30+
{
31+
var mappings = ImmutableDictionary.Create<string, string>(StringComparer.OrdinalIgnoreCase);
32+
foreach (var mapping in _mappings)
33+
{
34+
mappings = mappings.SetItem(mapping.Extension, mapping.Mime);
35+
}
36+
37+
return mappings;
38+
}
39+
40+
[Benchmark]
41+
public ImmutableDictionary<string, string> BatchBuilderInitialization()
42+
{
43+
var mappings = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
44+
foreach (var mapping in _mappings)
45+
{
46+
mappings[mapping.Extension] = mapping.Mime;
47+
}
48+
49+
return mappings.ToImmutable();
50+
}
51+
52+
[Benchmark]
53+
public (ImmutableDictionary<string, string> MutableSnapshot, FrozenDictionary<string, string> BuiltInIndex) BatchStaticCachesInitialization()
54+
{
55+
var mappings = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);
56+
foreach (var mapping in _mappings)
57+
{
58+
mappings[mapping.Extension] = mapping.Mime;
59+
}
60+
61+
return (mappings.ToImmutable(), mappings.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase));
62+
}
63+
64+
[Benchmark]
65+
public int ParseSourceRegistryJson()
66+
{
67+
using var document = JsonDocument.Parse(_registryJson);
68+
return document.RootElement.GetRawText().Length;
69+
}
70+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
; Shipped analyzer releases
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
; Unshipped analyzer release
2+
3+
### New Rules
4+
5+
Rule ID | Category | Severity | Notes
6+
--------|----------|----------|-------
7+
MIME001 | MimeTypes | Error | MIME catalog input was not found
8+
MIME002 | MimeTypes | Info | MIME catalog loaded successfully
9+
MIME003 | MimeTypes | Error | MIME source generation failed

‎ManagedCode.MimeTypes.Generator/ManagedCode.MimeTypes.Generator.csproj‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,24 @@
44
<LangVersion>14</LangVersion>
55
<IsPackable>false</IsPackable>
66
<Nullable>enable</Nullable>
7-
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
7+
<TargetFramework>netstandard2.0</TargetFramework>
8+
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
89
</PropertyGroup>
910

1011
<ItemGroup>
1112
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" PrivateAssets="all" />
13+
<PackageReference Include="System.Text.Json" Version="8.0.5" PrivateAssets="all" />
1214
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0">
1315
<PrivateAssets>all</PrivateAssets>
1416
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1517
</PackageReference>
1618
</ItemGroup>
1719

20+
<ItemGroup>
21+
<AdditionalFiles Include="AnalyzerReleases.Shipped.md" />
22+
<AdditionalFiles Include="AnalyzerReleases.Unshipped.md" />
23+
</ItemGroup>
24+
1825
<PropertyGroup>
1926
<GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
2027
</PropertyGroup>

0 commit comments

Comments
 (0)