Skip to content

Commit

Permalink
feat: Optimize and fix issues (#206)
Browse files Browse the repository at this point in the history
- Create benchmarks to assess basic formatting and parsing, including flags enumerations.
- Add benchmark reports for formatting and parsing enumeration values.
- The JSON converter now supports flags enumerations.
- Only generate metadata classes when an `EnumGeneratorAttribute` is present.
- Removed the `Formatter` and `Parser` classes to improve inlining and performance.
- Added support for generating metadata for JSON-serialized values.
- Organized interlocked generator code.
- Implemented the ability to generate the `ToJsonString` extension method and variants of `TryParseJsonString` factory methods.
- Added support for case-insensitive reading of JSON values on generated JSON converters.

BREAKING CHANGE: Removed parsing of comma-separated values for non-flag enumerations.
  • Loading branch information
skarllot authored Oct 6, 2024
1 parent fc2c3c7 commit 6581648
Show file tree
Hide file tree
Showing 129 changed files with 10,968 additions and 8,277 deletions.
9 changes: 9 additions & 0 deletions EnumUtilities.sln
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{45CCED50-B3C
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0BEA25FB-CD38-4C71-B002-F72F966A2824}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{23E5FDE1-F962-4FBE-B97E-2275D246542F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnumUtilities.Generators", "gen\EnumUtilities.Generators\EnumUtilities.Generators.csproj", "{E59B1284-D38F-4397-93E5-0DA3356ACE63}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnumUtilities", "src\EnumUtilities\EnumUtilities.csproj", "{02B0B1F0-42E6-43C3-B9C2-F06A089AD1F5}"
Expand All @@ -28,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnumUtilities.Generators.In
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnumUtilities.Tests", "tests\EnumUtilities.Tests\EnumUtilities.Tests.csproj", "{8242CFFA-AA6F-46CC-8FC0-EC62BA21E91F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnumUtilities.Benchmark", "perf\EnumUtilities.Benchmark\EnumUtilities.Benchmark.csproj", "{2F22069E-EB66-4394-AFA9-78B95F8C97EC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -42,6 +46,7 @@ Global
{E59B1284-D38F-4397-93E5-0DA3356ACE63} = {B003C044-6A35-4ABD-9B4C-8FF0C46220CD}
{AA4D1754-CB69-4333-8898-65FFFB38BEEE} = {0BEA25FB-CD38-4C71-B002-F72F966A2824}
{8242CFFA-AA6F-46CC-8FC0-EC62BA21E91F} = {0BEA25FB-CD38-4C71-B002-F72F966A2824}
{2F22069E-EB66-4394-AFA9-78B95F8C97EC} = {23E5FDE1-F962-4FBE-B97E-2275D246542F}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{02B0B1F0-42E6-43C3-B9C2-F06A089AD1F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand All @@ -64,5 +69,9 @@ Global
{8242CFFA-AA6F-46CC-8FC0-EC62BA21E91F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8242CFFA-AA6F-46CC-8FC0-EC62BA21E91F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8242CFFA-AA6F-46CC-8FC0-EC62BA21E91F}.Release|Any CPU.Build.0 = Release|Any CPU
{2F22069E-EB66-4394-AFA9-78B95F8C97EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F22069E-EB66-4394-AFA9-78B95F8C97EC}.Release|Any CPU.Build.0 = Release|Any CPU
{2F22069E-EB66-4394-AFA9-78B95F8C97EC}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{2F22069E-EB66-4394-AFA9-78B95F8C97EC}.Debug|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
```
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4169/23H2/2023Update/SunValley3)
AMD Ryzen 5 1600, 1 CPU, 12 logical and 6 physical cores
.NET SDK 8.0.401
[Host] : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
MediumRun : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
Job=MediumRun Arguments=Default NuGetReferences=Default
IterationCount=15 LaunchCount=2 WarmupCount=10
```
| Method | Elf | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
|------------------ |---------- |-----------:|----------:|----------:|------:|--------:|----------:|------------:|
| **BuiltInParse** | **0** | **14.092 ns** | **0.0950 ns** | **0.1362 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | 0 | 10.113 ns | 0.1324 ns | 0.1982 ns | 0.72 | 0.02 | - | NA |
| EnumsNetParse | 0 | 13.221 ns | 1.0329 ns | 1.5140 ns | 0.94 | 0.11 | - | NA |
| NetEscapadesParse | 0 | 12.523 ns | 0.1352 ns | 0.2024 ns | 0.89 | 0.02 | - | NA |
| RaiqubParse | 0 | 8.948 ns | 0.0174 ns | 0.0250 ns | 0.64 | 0.01 | - | NA |
| | | | | | | | | |
| **BuiltInParse** | **1000** | **17.552 ns** | **0.0592 ns** | **0.0830 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | 1000 | 14.647 ns | 0.1684 ns | 0.2520 ns | 0.83 | 0.01 | - | NA |
| EnumsNetParse | 1000 | 15.446 ns | 0.2096 ns | 0.3006 ns | 0.88 | 0.02 | - | NA |
| NetEscapadesParse | 1000 | 17.396 ns | 0.2157 ns | 0.3229 ns | 0.99 | 0.02 | - | NA |
| RaiqubParse | 1000 | 11.993 ns | 0.1449 ns | 0.2124 ns | 0.68 | 0.01 | - | NA |
| | | | | | | | | |
| **BuiltInParse** | **Aredhel** | **155.198 ns** | **0.9888 ns** | **1.4494 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | Aredhel | 16.344 ns | 0.3097 ns | 0.4342 ns | 0.11 | 0.00 | - | NA |
| EnumsNetParse | Aredhel | 23.796 ns | 0.1843 ns | 0.2701 ns | 0.15 | 0.00 | - | NA |
| NetEscapadesParse | Aredhel | 4.154 ns | 0.0123 ns | 0.0168 ns | 0.03 | 0.00 | - | NA |
| RaiqubParse | Aredhel | 30.648 ns | 0.1663 ns | 0.2438 ns | 0.20 | 0.00 | - | NA |
| | | | | | | | | |
| **BuiltInParse** | **Galadriel** | **24.391 ns** | **0.1304 ns** | **0.1870 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | Galadriel | 17.397 ns | 0.0476 ns | 0.0667 ns | 0.71 | 0.01 | - | NA |
| EnumsNetParse | Galadriel | 27.588 ns | 1.8840 ns | 2.5788 ns | 1.13 | 0.10 | - | NA |
| NetEscapadesParse | Galadriel | 4.981 ns | 0.0165 ns | 0.0236 ns | 0.20 | 0.00 | - | NA |
| RaiqubParse | Galadriel | 15.842 ns | 0.0658 ns | 0.0943 ns | 0.65 | 0.01 | - | NA |
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
```
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4169/23H2/2023Update/SunValley3)
AMD Ryzen 5 1600, 1 CPU, 12 logical and 6 physical cores
.NET SDK 8.0.402
[Host] : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
MediumRun : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
Job=MediumRun Arguments=Default NuGetReferences=Default
IterationCount=15 LaunchCount=2 WarmupCount=10
```
| Method | Elf | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
|--------------------- |---------- |-----------:|----------:|----------:|-----------:|------:|--------:|-------:|----------:|------------:|
| **BuiltInToString** | **0** | **22.5497 ns** | **0.5939 ns** | **0.8705 ns** | **22.2127 ns** | **1.00** | **0.05** | **0.0057** | **24 B** | **1.00** |
| FastEnumToString | 0 | 2.8814 ns | 0.0507 ns | 0.0711 ns | 2.8769 ns | 0.13 | 0.01 | - | - | 0.00 |
| EnumsNetAsString | 0 | 3.2005 ns | 0.0897 ns | 0.1343 ns | 3.1692 ns | 0.14 | 0.01 | - | - | 0.00 |
| NetEscapadesToString | 0 | 23.6147 ns | 0.6926 ns | 1.0366 ns | 23.3105 ns | 1.05 | 0.06 | 0.0057 | 24 B | 1.00 |
| RaiqubToString | 0 | 1.1136 ns | 0.0399 ns | 0.0585 ns | 1.1042 ns | 0.05 | 0.00 | - | - | 0.00 |
| | | | | | | | | | | |
| **BuiltInToString** | **Galadriel** | **17.8062 ns** | **0.4506 ns** | **0.6744 ns** | **17.9230 ns** | **1.00** | **0.05** | **0.0057** | **24 B** | **1.00** |
| FastEnumToString | Galadriel | 1.1964 ns | 0.0613 ns | 0.0838 ns | 1.1702 ns | 0.07 | 0.01 | - | - | 0.00 |
| EnumsNetAsString | Galadriel | 1.3942 ns | 0.0218 ns | 0.0292 ns | 1.3933 ns | 0.08 | 0.00 | - | - | 0.00 |
| NetEscapadesToString | Galadriel | 0.5302 ns | 0.0167 ns | 0.0235 ns | 0.5234 ns | 0.03 | 0.00 | - | - | 0.00 |
| RaiqubToString | Galadriel | 1.0603 ns | 0.0301 ns | 0.0441 ns | 1.0709 ns | 0.06 | 0.00 | - | - | 0.00 |
| | | | | | | | | | | |
| **BuiltInToString** | **Aredhel** | **19.4398 ns** | **0.5728 ns** | **0.8215 ns** | **19.1657 ns** | **1.00** | **0.06** | **0.0057** | **24 B** | **1.00** |
| FastEnumToString | Aredhel | 1.1834 ns | 0.0423 ns | 0.0606 ns | 1.1547 ns | 0.06 | 0.00 | - | - | 0.00 |
| EnumsNetAsString | Aredhel | 1.4383 ns | 0.0378 ns | 0.0554 ns | 1.4201 ns | 0.07 | 0.00 | - | - | 0.00 |
| NetEscapadesToString | Aredhel | 0.8025 ns | 0.1880 ns | 0.2696 ns | 0.6311 ns | 0.04 | 0.01 | - | - | 0.00 |
| RaiqubToString | Aredhel | 1.0795 ns | 0.0120 ns | 0.0160 ns | 1.0742 ns | 0.06 | 0.00 | - | - | 0.00 |
| | | | | | | | | | | |
| **BuiltInToString** | **1000** | **30.5595 ns** | **0.7356 ns** | **1.0783 ns** | **30.5367 ns** | **1.00** | **0.05** | **0.0134** | **56 B** | **1.00** |
| FastEnumToString | 1000 | 10.5993 ns | 0.2819 ns | 0.4219 ns | 10.4117 ns | 0.35 | 0.02 | 0.0076 | 32 B | 0.57 |
| EnumsNetAsString | 1000 | 12.8773 ns | 0.2627 ns | 0.3683 ns | 12.7960 ns | 0.42 | 0.02 | 0.0076 | 32 B | 0.57 |
| NetEscapadesToString | 1000 | 31.9137 ns | 0.4518 ns | 0.6479 ns | 31.7924 ns | 1.05 | 0.04 | 0.0134 | 56 B | 1.00 |
| RaiqubToString | 1000 | 15.8590 ns | 0.3727 ns | 0.5578 ns | 15.7718 ns | 0.52 | 0.03 | 0.0076 | 32 B | 0.57 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
```
BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4169/23H2/2023Update/SunValley3)
AMD Ryzen 5 1600, 1 CPU, 12 logical and 6 physical cores
.NET SDK 8.0.401
[Host] : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
MediumRun : .NET 8.0.8 (8.0.824.36612), X64 RyuJIT AVX2
Job=MediumRun Arguments=Default NuGetReferences=Default
IterationCount=15 LaunchCount=2 WarmupCount=10
```
| Method | Permissions | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
|------------------ |--------------------- |-------------:|-----------:|-----------:|------:|--------:|----------:|------------:|
| **BuiltInParse** | **0** | **13.987 ns** | **0.0470 ns** | **0.0674 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | 0 | 9.442 ns | 0.0244 ns | 0.0325 ns | 0.68 | 0.00 | - | NA |
| EnumsNetParse | 0 | 47.279 ns | 1.1095 ns | 1.6607 ns | 3.38 | 0.12 | - | NA |
| NetEscapadesParse | 0 | 10.073 ns | 0.0595 ns | 0.0814 ns | 0.72 | 0.01 | - | NA |
| RaiqubParse | 0 | 10.300 ns | 0.0915 ns | 0.1341 ns | 0.74 | 0.01 | - | NA |
| | | | | | | | | |
| **BuiltInParse** | **Delet(...) Move [39]** | **309.194 ns** | **1.6450 ns** | **2.4112 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | Delet(...) Move [39] | NA | NA | NA | ? | ? | NA | ? |
| EnumsNetParse | Delet(...) Move [39] | 286.000 ns | 1.6095 ns | 2.3083 ns | 0.93 | 0.01 | - | NA |
| NetEscapadesParse | Delet(...) Move [39] | NA | NA | NA | ? | ? | NA | ? |
| RaiqubParse | Delet(...) Move [39] | 224.670 ns | 0.7306 ns | 1.0709 ns | 0.73 | 0.01 | - | NA |
| | | | | | | | | |
| **BuiltInParse** | **Read, Write** | **63.240 ns** | **0.3288 ns** | **0.4819 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | Read, Write | NA | NA | NA | ? | ? | NA | ? |
| EnumsNetParse | Read, Write | 95.609 ns | 0.7829 ns | 1.0975 ns | 1.51 | 0.02 | - | NA |
| NetEscapadesParse | Read, Write | NA | NA | NA | ? | ? | NA | ? |
| RaiqubParse | Read, Write | 55.005 ns | 0.2825 ns | 0.4052 ns | 0.87 | 0.01 | - | NA |
| | | | | | | | | |
| **BuiltInParse** | **Read(...)lock [245]** | **2,783.170 ns** | **17.6501 ns** | **23.5624 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | Read(...)lock [245] | NA | NA | NA | ? | ? | NA | ? |
| EnumsNetParse | Read(...)lock [245] | 1,659.957 ns | 19.1646 ns | 26.8661 ns | 0.60 | 0.01 | - | NA |
| NetEscapadesParse | Read(...)lock [245] | NA | NA | NA | ? | ? | NA | ? |
| RaiqubParse | Read(...)lock [245] | 1,539.143 ns | 5.4026 ns | 7.5737 ns | 0.55 | 0.01 | - | NA |
| | | | | | | | | |
| **BuiltInParse** | **Restore** | **79.891 ns** | **0.4963 ns** | **0.7428 ns** | **1.00** | **0.01** | **-** | **NA** |
| FastEnumParse | Restore | 16.590 ns | 0.3468 ns | 0.5083 ns | 0.21 | 0.01 | - | NA |
| EnumsNetParse | Restore | 55.787 ns | 0.5216 ns | 0.7646 ns | 0.70 | 0.01 | - | NA |
| NetEscapadesParse | Restore | 3.887 ns | 0.0278 ns | 0.0399 ns | 0.05 | 0.00 | - | NA |
| RaiqubParse | Restore | 33.789 ns | 0.0832 ns | 0.1138 ns | 0.42 | 0.00 | - | NA |

Benchmarks with issues:
BigFlagsEnumParse.FastEnumParse: MediumRun(IterationCount=15, LaunchCount=2, WarmupCount=10) [Permissions=Delet(...) Move [39]]
BigFlagsEnumParse.NetEscapadesParse: MediumRun(IterationCount=15, LaunchCount=2, WarmupCount=10) [Permissions=Delet(...) Move [39]]
BigFlagsEnumParse.FastEnumParse: MediumRun(IterationCount=15, LaunchCount=2, WarmupCount=10) [Permissions=Read, Write]
BigFlagsEnumParse.NetEscapadesParse: MediumRun(IterationCount=15, LaunchCount=2, WarmupCount=10) [Permissions=Read, Write]
BigFlagsEnumParse.FastEnumParse: MediumRun(IterationCount=15, LaunchCount=2, WarmupCount=10) [Permissions=Read(...)lock [245]]
BigFlagsEnumParse.NetEscapadesParse: MediumRun(IterationCount=15, LaunchCount=2, WarmupCount=10) [Permissions=Read(...)lock [245]]
Loading

0 comments on commit 6581648

Please sign in to comment.