├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── generic-build.yml │ └── nuget-release.yml ├── .gitignore ├── .globalconfig ├── FastHash.sln ├── FastHash.sln.DotSettings ├── Imports ├── Benchmarks.props ├── Console.props ├── Examples.props ├── Library.props └── Tests.props ├── LICENSE.txt ├── Locals ├── Directory.Build.props └── Directory.Packages.props ├── README.md └── Src ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.Analyzers.props ├── Directory.Packages.props ├── FastHash.Benchmarks ├── Code │ ├── BenchmarkHelper.cs │ ├── MbPrSecColumn.cs │ └── MbPrSecColumnAttribute.cs ├── FastHash.Benchmarks.csproj ├── HashBenchmarks.cs ├── Index32Benchmarks.cs ├── Index64Benchmarks.cs ├── MixerBenchmarks.cs ├── Multiply64Benchmarks.cs ├── Program.cs ├── ReadAlignedBenchmarks.cs └── ReadUnalignedBenchmarks.cs ├── FastHash.Examples ├── FastHash.Examples.csproj └── Program.cs ├── FastHash.TestShared ├── FastHash.TestShared.csproj ├── MixSpec32.cs ├── MixSpec64.cs └── Mult.cs ├── FastHash.Tests ├── FastHash.Tests.csproj ├── GeneralTests.cs ├── HashTests.cs ├── IndexTests.cs ├── MixerTests.cs ├── MultTests.cs └── Single │ ├── CityHashTests.cs │ ├── DjbHashTests.cs │ ├── FarmHashTests.cs │ ├── FarshHashTests.cs │ ├── FnvHashTests.cs │ ├── GxHashTests.cs │ ├── HighwayHashTests.cs │ ├── PolymurHashTests.cs │ ├── SipHashTests.cs │ ├── WyHashTests.cs │ ├── Xx2HashTests.cs │ └── Xx3HashTests.cs └── FastHash ├── AesniHash ├── AesniHash128.cs └── AesniHash64.cs ├── CityHash ├── CityHash128.cs ├── CityHash128Unsafe.cs ├── CityHash32.cs ├── CityHash32Unsafe.cs ├── CityHash64.cs ├── CityHash64Unsafe.cs ├── CityHashConstants.cs ├── CityHashShared.cs └── CityHashUnsafeShared.cs ├── DjbHash ├── Djb2Hash32.cs ├── Djb2Hash32Unsafe.cs ├── Djb2Hash64.cs ├── Djb2Hash64Unsafe.cs └── DjbHashConstants.cs ├── FarmHash ├── FarmHash32.cs ├── FarmHash32Unsafe.cs ├── FarmHash64.cs ├── FarmHash64Unsafe.cs └── FarmHashConstants.cs ├── FarshHash ├── FarshHash64.cs ├── FarshHash64Unsafe.cs └── FarshHashConstants.cs ├── FastHash.csproj ├── FnvHash ├── Fnv1aHash32.cs ├── Fnv1aHash32Unsafe.cs ├── Fnv1aHash64.cs ├── Fnv1aHash64Unsafe.cs └── FnvHashConstants.cs ├── GxHash ├── GxHash128.cs ├── GxHash32.cs ├── GxHash64.cs └── GxHashShared.cs ├── HighwayHash ├── HighwayHash64Unsafe.cs ├── HighwayHashConstants.cs └── HighwayHashState.cs ├── MarvinHash ├── MarvinHash32.cs └── MarvinHash64.cs ├── MeowHash ├── MeowHash128Unsafe.cs └── MeowHash64Unsafe.cs ├── Misc ├── IsExternalInit.cs └── Utilities.cs ├── MixFunctions.cs ├── MurmurHash ├── Murmur3Hash128.cs ├── Murmur3Hash128Unsafe.cs ├── Murmur3Hash32.cs ├── Murmur3Hash32Unsafe.cs └── MurmurHashConstants.cs ├── PolymurHash ├── Polymur2Hash64.cs └── PolymurConstants.cs ├── Properties └── GlobalUsings.cs ├── SipHash ├── SipHash64.cs ├── SipHash64Unsafe.cs └── SipHashConstants.cs ├── SuperFastHash ├── SuperFastHash32.cs └── SuperFastHash32Unsafe.cs ├── UInt128.cs ├── WyHash ├── Wy3Hash64.cs ├── Wy3Hash64Unsafe.cs └── WyHashConstants.cs └── XxHash ├── Xx2Hash32.cs ├── Xx2Hash32Unsafe.cs ├── Xx2Hash64.cs ├── Xx2Hash64Unsafe.cs ├── Xx3Hash128.cs ├── Xx3Hash128Unsafe.cs ├── Xx3Hash64.cs ├── Xx3Hash64Unsafe.cs ├── XxHashConstants.cs ├── XxHashShared.cs └── XxHashUnsafeShared.cs /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | trim_trailing_whitespace = true 6 | insert_final_newline = false 7 | max_line_length = 180 8 | 9 | # XML based formats 10 | [*.{appxmanifest,axml,build,config,csproj,dbml,discomap,dtd,jsproj,lsproj,njsproj,nuspec,proj,props,resw,resx,StyleCop,targets,tasks,vbproj,xml,xsd}] 11 | indent_style = space 12 | indent_size = 2 13 | tab_width = 2 14 | ij_xml_space_inside_empty_tag = true 15 | ij_xml_keep_blank_lines = 1 16 | 17 | # JSON based formats 18 | [*.{json,resjson}] 19 | indent_style = space 20 | indent_size = 2 21 | tab_width = 2 22 | 23 | # Web languages 24 | [*.{css,htm,html,js}] 25 | indent_style = space 26 | indent_size = 2 27 | tab_width = 2 28 | 29 | # Programming languages 30 | [*.{asax,ascx,aspx,axaml,cs,cshtml}] 31 | indent_style = space 32 | indent_size = 4 33 | tab_width = 4 34 | 35 | # Analyzer settings 36 | roslynator_accessibility_modifiers = explicit 37 | roslynator_enum_has_flag_style = method 38 | roslynator_object_creation_type_style = explicit 39 | roslynator_use_var_instead_of_implicit_object_creation = false 40 | csharp_style_namespace_declarations = file_scoped:error 41 | dotnet_public_api_analyzer.require_api_files = true # Disable the requirement for projects to have a PublicAPI.Shipped.txt file 42 | 43 | # Csharp styles 44 | csharp_new_line_before_members_in_object_initializers = false 45 | csharp_preferred_modifier_order = public, private, protected, internal, new, sealed, static, unsafe, override, extern, async, virtual, abstract, volatile, readonly:suggestion 46 | csharp_preserve_single_line_blocks = true 47 | csharp_space_after_cast = false 48 | csharp_style_var_elsewhere = false:none 49 | csharp_style_var_when_type_is_apparent = false:none 50 | 51 | # ReSharper properties 52 | resharper_align_multiline_calls_chain = true 53 | resharper_arguments_skip_single = true 54 | resharper_blank_lines_after_block_statements = 0 55 | resharper_blank_lines_after_start_comment = 0 56 | resharper_blank_lines_around_auto_property = 1 57 | resharper_blank_lines_around_property = 1 58 | resharper_blank_lines_around_single_line_type = 0 59 | resharper_braces_for_fixed = required_for_multiline 60 | resharper_braces_for_for = required_for_multiline 61 | resharper_braces_for_foreach = required_for_multiline 62 | resharper_braces_for_ifelse = required_for_multiline 63 | resharper_braces_for_lock = required_for_multiline 64 | resharper_braces_for_using = required_for_multiline 65 | resharper_braces_for_while = required_for_multiline 66 | resharper_csharp_blank_lines_around_field = 0 67 | resharper_csharp_blank_lines_around_invocable = 1 68 | resharper_csharp_empty_block_style = together_same_line 69 | resharper_csharp_keep_blank_lines_in_code = 1 70 | resharper_csharp_keep_blank_lines_in_declarations = 1 71 | resharper_csharp_max_line_length = 2081 72 | resharper_csharp_space_before_trailing_comment = true 73 | resharper_csharp_wrap_lines = false 74 | resharper_csharp_wrap_parameters_style = chop_if_long 75 | resharper_indent_preprocessor_other = do_not_change 76 | resharper_instance_members_qualify_declared_in = this_class 77 | resharper_keep_existing_attribute_arrangement = true 78 | resharper_keep_existing_enum_arrangement = false 79 | resharper_local_function_body = expression_body 80 | resharper_method_or_operator_body = expression_body 81 | resharper_nested_ternary_style = compact 82 | resharper_object_creation_when_type_evident = explicitly_typed 83 | resharper_place_accessorholder_attribute_on_same_line = false 84 | resharper_place_accessor_attribute_on_same_line = true 85 | resharper_place_expr_accessor_on_single_line = true 86 | resharper_place_expr_method_on_single_line = true 87 | resharper_place_expr_property_on_single_line = true 88 | resharper_place_field_attribute_on_same_line = false 89 | resharper_place_simple_embedded_statement_on_same_line = false 90 | resharper_place_simple_initializer_on_single_line = true 91 | resharper_remove_blank_lines_near_braces_in_code = true 92 | resharper_remove_blank_lines_near_braces_in_declarations = true 93 | resharper_space_after_attributes = false 94 | resharper_space_between_attribute_sections = false 95 | resharper_space_within_empty_braces = false 96 | resharper_space_within_single_line_array_initializer_braces = true 97 | resharper_wrap_object_and_collection_initializer_style = chop_always 98 | resharper_space_before_trailing_comment = true 99 | resharper_xmldoc_indent_text = ZeroIndent 100 | resharper_xmldoc_max_line_length = 300 101 | resharper_xmldoc_attribute_indent = align_by_first_attribute 102 | resharper_xmldoc_keep_user_linebreaks = true 103 | resharper_parentheses_non_obvious_operations = none, multiplicative, additive, arithmetic, shift, bitwise_and, bitwise_exclusive_or, bitwise_inclusive_or, bitwise 104 | 105 | # Microsoft .NET properties 106 | csharp_style_var_for_built_in_types = false:suggestion -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Linux scripts 2 | *.sh text eol=lf 3 | *.py text diff=python eol=lf 4 | 5 | # Linux configs 6 | *.conf text eol=lf 7 | *.yml text eol=lf 8 | 9 | # Windows scripts 10 | *.ps1 text eol=crlf 11 | *.cmd text eol=crlf 12 | *.bat text eol=crlf 13 | 14 | # Source code files 15 | *.cs text diff=csharp 16 | *.cshtml text 17 | *.json text 18 | *.xml text 19 | *.html text diff=html 20 | *.css text diff=css 21 | *.scss text diff=css 22 | *.js text 23 | *.csproj text 24 | *.targets text ident 25 | *.sln text 26 | 27 | # Images 28 | *.svg text 29 | 30 | # Text files 31 | *.txt text 32 | *.md text 33 | *.markdowm text 34 | 35 | ############################### 36 | # Git Large File System (LFS) # 37 | ############################### 38 | 39 | # Archives 40 | *.7z filter=lfs diff=lfs merge=lfs -text 41 | *.rar filter=lfs diff=lfs merge=lfs -text 42 | *.br filter=lfs diff=lfs merge=lfs -text 43 | *.gz filter=lfs diff=lfs merge=lfs -text 44 | *.tar filter=lfs diff=lfs merge=lfs -text 45 | *.zip filter=lfs diff=lfs merge=lfs -text 46 | 47 | # Documents 48 | *.pdf filter=lfs diff=lfs merge=lfs -text 49 | *.doc filter=lfs diff=lfs merge=lfs -text 50 | *.docx filter=lfs diff=lfs merge=lfs -text 51 | 52 | # Images 53 | *.gif filter=lfs diff=lfs merge=lfs -text 54 | *.ico filter=lfs diff=lfs merge=lfs -text 55 | *.jpg filter=lfs diff=lfs merge=lfs -text 56 | *.png filter=lfs diff=lfs merge=lfs -text 57 | *.psd filter=lfs diff=lfs merge=lfs -text 58 | *.webp filter=lfs diff=lfs merge=lfs -text 59 | *.bmp filter=lfs diff=lfs merge=lfs -text 60 | 61 | # Fonts 62 | *.woff2 filter=lfs diff=lfs merge=lfs -text 63 | 64 | # Other 65 | *.exe filter=lfs diff=lfs merge=lfs -text -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [Genbox] 2 | custom: http://paypal.me/IanQvist 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report a bug 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | * [ ] I hereby verify that I am a sponsor. 11 | 12 | Sponsorship is required before you can submit bug reports. See https://github.com/sponsors/Genbox 13 | 14 | **Describe the bug** 15 | What is the bug about? 16 | 17 | **How to reproduce?** 18 | Describe steps to reproduce the bug. Please include code to reproduce if possible. 19 | 20 | **Expected behavior** 21 | Describe what you expected to happen. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a feature for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | * [ ] I hereby verify that I am a sponsor. 11 | 12 | Sponsorship is required before you can submit feature requests. See https://github.com/sponsors/Genbox 13 | 14 | **Describe the feature** 15 | Provide a short description of the feature. Why would you like the feature? 16 | If the feature makes changes to an existing or new API please provide an example. 17 | -------------------------------------------------------------------------------- /.github/workflows/generic-build.yml: -------------------------------------------------------------------------------- 1 | name: Generic build 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | tags-ignore: 8 | - '**' 9 | 10 | env: 11 | DOTNET_EnableDiagnostics: 0 12 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 13 | DOTNET_NOLOGO: true 14 | DOTNET_CLI_TELEMETRY_OPTOUT: true 15 | DOTNET_GENERATE_ASPNET_CERTIFICATE: false 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v3 23 | - name: Setup .NET Core 7.0 24 | uses: actions/setup-dotnet@v3 25 | with: 26 | dotnet-version: '7.0.x' 27 | - name: Build 28 | run: dotnet build -c Release FastHash.sln -------------------------------------------------------------------------------- /.github/workflows/nuget-release.yml: -------------------------------------------------------------------------------- 1 | name: Nuget release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '[0-9]+.[0-9]+.[0-9]+**' 7 | 8 | env: 9 | DOTNET_EnableDiagnostics: 0 10 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 11 | DOTNET_NOLOGO: true 12 | DOTNET_CLI_TELEMETRY_OPTOUT: true 13 | DOTNET_GENERATE_ASPNET_CERTIFICATE: false 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Setup .NET Core 7.0 22 | uses: actions/setup-dotnet@v3 23 | with: 24 | dotnet-version: '7.0.x' 25 | - name: Pack release 26 | run: dotnet pack -c Release -o tmp FastHash.sln 27 | - name: Upload to nuget 28 | run: dotnet nuget push --skip-duplicate -k ${{secrets.NUGET_KEY}} -s https://api.nuget.org/v3/index.json tmp/* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build results 2 | [Bb]in/ 3 | [Oo]bj/ 4 | [Ll]og/ 5 | 6 | # NuGet Packages 7 | *.nupkg 8 | *.snupkg 9 | 10 | # Others 11 | *.pfx 12 | *.publishsettings 13 | 14 | # SQL Server files 15 | *.mdf 16 | *.ldf 17 | *.ndf 18 | 19 | # Visual Studio cache folder 20 | .vs/ 21 | 22 | # Rider cache folder 23 | .idea/ 24 | *.sln.DotSettings.user 25 | 26 | # Benchmark.Net artifact folder 27 | *BenchmarkDotNet.Artifacts/ -------------------------------------------------------------------------------- /FastHash.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32112.339 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Items", "_Items", "{EF1D19B3-97F1-4504-95AB-BE249F5BF29A}" 7 | ProjectSection(SolutionItems) = preProject 8 | .gitattributes = .gitattributes 9 | .gitignore = .gitignore 10 | LICENSE.txt = LICENSE.txt 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Imports", "_Imports", "{C17720CD-1FBA-4181-A15D-5E361643B534}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Github", "_Github", "{9301EE8C-BC1F-4169-A4F6-629E904E1AFB}" 17 | ProjectSection(SolutionItems) = preProject 18 | .github\FUNDING.yml = .github\FUNDING.yml 19 | EndProjectSection 20 | EndProject 21 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IssueTemplates", "IssueTemplates", "{3DF56598-0F2D-4D4A-B4A9-18C1CAA0D6B0}" 22 | ProjectSection(SolutionItems) = preProject 23 | .github\ISSUE_TEMPLATE\bug_report.md = .github\ISSUE_TEMPLATE\bug_report.md 24 | .github\ISSUE_TEMPLATE\feature_request.md = .github\ISSUE_TEMPLATE\feature_request.md 25 | EndProjectSection 26 | EndProject 27 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workflows", "Workflows", "{01EB71A8-87A4-410E-9AC9-8C0F0F6EA7BB}" 28 | ProjectSection(SolutionItems) = preProject 29 | .github\workflows\generic-build.yml = .github\workflows\generic-build.yml 30 | .github\workflows\nuget-release.yml = .github\workflows\nuget-release.yml 31 | EndProjectSection 32 | EndProject 33 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Local", "Local", "{008D0251-18C2-4B29-99BB-718EF8E7DC85}" 34 | ProjectSection(SolutionItems) = preProject 35 | Locals\Directory.Build.props = Locals\Directory.Build.props 36 | Locals\Directory.Packages.props = Locals\Directory.Packages.props 37 | EndProjectSection 38 | EndProject 39 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Managed", "Managed", "{A112EE96-0FDF-460B-9F35-F4A8608DE4CD}" 40 | ProjectSection(SolutionItems) = preProject 41 | Src\Directory.Build.targets = Src\Directory.Build.targets 42 | Src\Directory.Build.props = Src\Directory.Build.props 43 | EndProjectSection 44 | EndProject 45 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{28F1C9B8-268B-46C3-97B4-73CB90CD9E2A}" 46 | ProjectSection(SolutionItems) = preProject 47 | Src\Directory.Packages.props = Src\Directory.Packages.props 48 | Src\Directory.Packages.Analyzers.props = Src\Directory.Packages.Analyzers.props 49 | EndProjectSection 50 | EndProject 51 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Project", "Project", "{6A21A9F3-0DB5-48D1-9097-E2A327734844}" 52 | ProjectSection(SolutionItems) = preProject 53 | Imports\Benchmarks.props = Imports\Benchmarks.props 54 | Imports\Examples.props = Imports\Examples.props 55 | Imports\Library.props = Imports\Library.props 56 | Imports\Tests.props = Imports\Tests.props 57 | EndProjectSection 58 | EndProject 59 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHash", "Src\FastHash\FastHash.csproj", "{A74CB252-3544-40BD-A166-15A25B07B856}" 60 | EndProject 61 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHash.Benchmarks", "Src\FastHash.Benchmarks\FastHash.Benchmarks.csproj", "{6AF9A9F2-68DE-4FC8-A7EF-60AD142D594A}" 62 | EndProject 63 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHash.Tests", "Src\FastHash.Tests\FastHash.Tests.csproj", "{54D07448-1E1E-4292-A39A-E1676607C662}" 64 | EndProject 65 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHash.TestShared", "Src\FastHash.TestShared\FastHash.TestShared.csproj", "{9443A0FE-29C8-47D1-B015-A630DA5B4D5F}" 66 | EndProject 67 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastHash.Examples", "Src\FastHash.Examples\FastHash.Examples.csproj", "{F0B90C1B-9455-4078-BAD9-B77A83CDAE18}" 68 | EndProject 69 | Global 70 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 71 | Debug|Any CPU = Debug|Any CPU 72 | Release|Any CPU = Release|Any CPU 73 | EndGlobalSection 74 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 75 | {A74CB252-3544-40BD-A166-15A25B07B856}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 76 | {A74CB252-3544-40BD-A166-15A25B07B856}.Debug|Any CPU.Build.0 = Debug|Any CPU 77 | {A74CB252-3544-40BD-A166-15A25B07B856}.Release|Any CPU.ActiveCfg = Release|Any CPU 78 | {A74CB252-3544-40BD-A166-15A25B07B856}.Release|Any CPU.Build.0 = Release|Any CPU 79 | {6AF9A9F2-68DE-4FC8-A7EF-60AD142D594A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 80 | {6AF9A9F2-68DE-4FC8-A7EF-60AD142D594A}.Debug|Any CPU.Build.0 = Debug|Any CPU 81 | {6AF9A9F2-68DE-4FC8-A7EF-60AD142D594A}.Release|Any CPU.ActiveCfg = Release|Any CPU 82 | {6AF9A9F2-68DE-4FC8-A7EF-60AD142D594A}.Release|Any CPU.Build.0 = Release|Any CPU 83 | {54D07448-1E1E-4292-A39A-E1676607C662}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 84 | {54D07448-1E1E-4292-A39A-E1676607C662}.Debug|Any CPU.Build.0 = Debug|Any CPU 85 | {54D07448-1E1E-4292-A39A-E1676607C662}.Release|Any CPU.ActiveCfg = Release|Any CPU 86 | {54D07448-1E1E-4292-A39A-E1676607C662}.Release|Any CPU.Build.0 = Release|Any CPU 87 | {9443A0FE-29C8-47D1-B015-A630DA5B4D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 88 | {9443A0FE-29C8-47D1-B015-A630DA5B4D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU 89 | {9443A0FE-29C8-47D1-B015-A630DA5B4D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU 90 | {9443A0FE-29C8-47D1-B015-A630DA5B4D5F}.Release|Any CPU.Build.0 = Release|Any CPU 91 | {F0B90C1B-9455-4078-BAD9-B77A83CDAE18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 92 | {F0B90C1B-9455-4078-BAD9-B77A83CDAE18}.Debug|Any CPU.Build.0 = Debug|Any CPU 93 | {F0B90C1B-9455-4078-BAD9-B77A83CDAE18}.Release|Any CPU.ActiveCfg = Release|Any CPU 94 | {F0B90C1B-9455-4078-BAD9-B77A83CDAE18}.Release|Any CPU.Build.0 = Release|Any CPU 95 | EndGlobalSection 96 | GlobalSection(SolutionProperties) = preSolution 97 | HideSolutionNode = FALSE 98 | EndGlobalSection 99 | GlobalSection(ExtensibilityGlobals) = postSolution 100 | SolutionGuid = {A9354605-C154-495A-B990-F6AB329CDE39} 101 | EndGlobalSection 102 | GlobalSection(NestedProjects) = preSolution 103 | {3DF56598-0F2D-4D4A-B4A9-18C1CAA0D6B0} = {9301EE8C-BC1F-4169-A4F6-629E904E1AFB} 104 | {01EB71A8-87A4-410E-9AC9-8C0F0F6EA7BB} = {9301EE8C-BC1F-4169-A4F6-629E904E1AFB} 105 | {008D0251-18C2-4B29-99BB-718EF8E7DC85} = {C17720CD-1FBA-4181-A15D-5E361643B534} 106 | {A112EE96-0FDF-460B-9F35-F4A8608DE4CD} = {C17720CD-1FBA-4181-A15D-5E361643B534} 107 | {28F1C9B8-268B-46C3-97B4-73CB90CD9E2A} = {A112EE96-0FDF-460B-9F35-F4A8608DE4CD} 108 | {6A21A9F3-0DB5-48D1-9097-E2A327734844} = {A112EE96-0FDF-460B-9F35-F4A8608DE4CD} 109 | EndGlobalSection 110 | EndGlobal 111 | -------------------------------------------------------------------------------- /FastHash.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True 7 | True 8 | True 9 | True 10 | True 11 | True 12 | True 13 | True 14 | True 15 | True 16 | True -------------------------------------------------------------------------------- /Imports/Benchmarks.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Imports/Console.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | false 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Imports/Examples.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Imports/Library.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | 6 | 7 | 8 | 9 | <_Parameter1>$(AssemblyName).Tests 10 | 11 | 12 | <_Parameter1>$(AssemblyName).Benchmarks 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Imports/Tests.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Ian Qvist 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Locals/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | High performance non-cryptographic hash functions 5 | hash non-cryptographic 6 | 7 | 8 | -------------------------------------------------------------------------------- /Locals/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ian Qvist 6 | Copyright 2024, by Ian Qvist. All rights reserved. 7 | 8 | 9 | 10 | 11 | 12 | true 13 | true 14 | true 15 | 16 | 17 | Genbox.$(MSBuildProjectName) 18 | Genbox.$(MSBuildProjectName) 19 | 20 | 21 | latest 22 | enable 23 | strict 24 | true 25 | 0 26 | 27 | 28 | true 29 | 30 | 31 | Git 32 | https://github.com/Genbox/$(MSBuildProjectName) 33 | MIT 34 | false 35 | 36 | 37 | $(IncludeAnalyzers) 38 | false 39 | true 40 | all 41 | latest 42 | 43 | 44 | false 45 | true 46 | 47 | 48 | 2 49 | 500 50 | none 51 | 52 | 53 | true 54 | true 55 | 56 | 57 | true 58 | false 59 | true 60 | snupkg 61 | 62 | 63 | true 64 | all 65 | low 66 | 67 | 68 | 69 | true 70 | false 71 | 72 | 73 | 74 | 75 | 5 76 | 77 | 78 | 79 | <_LastDot>$(MSBuildProjectName.LastIndexOf('.', StringComparison.Ordinal)) 80 | $(MSBuildProjectName.Substring(0, $(_LastDot))) 81 | $(MSBuildProjectName.Substring($([MSBuild]::Add($(_LastDot), 1)))) 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | true 17 | README.md 18 | 19 | 20 | 21 | 22 | 23 | 24 | $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).0 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Src/Directory.Packages.Analyzers.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Src/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/Code/BenchmarkHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.Benchmarks.Code; 2 | 3 | public static class BenchmarkHelper 4 | { 5 | public static byte[] GetRandomBytes(int count) 6 | { 7 | byte[] bytes = GC.AllocateUninitializedArray(count); 8 | Random r = new Random(42); 9 | r.NextBytes(bytes); 10 | return bytes; 11 | } 12 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/Code/MbPrSecColumn.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using BenchmarkDotNet.Columns; 3 | using BenchmarkDotNet.Mathematics; 4 | using BenchmarkDotNet.Reports; 5 | using BenchmarkDotNet.Running; 6 | 7 | namespace Genbox.FastHash.Benchmarks.Code; 8 | 9 | public class MbPrSecColumn : IColumn 10 | { 11 | private readonly int _size; 12 | 13 | public MbPrSecColumn(int size = 0) 14 | { 15 | _size = size; 16 | } 17 | 18 | public string Id => nameof(MbPrSecColumn); 19 | public string ColumnName => "MiB/s"; 20 | 21 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase) 22 | { 23 | Statistics? stats = summary[benchmarkCase].ResultStatistics; 24 | 25 | if (stats == null) 26 | return "?"; 27 | 28 | //Number of operations as determined by the Count parameter 29 | 30 | int size = _size; 31 | 32 | if (size == 0) 33 | size = int.Parse(benchmarkCase.Parameters["Size"].ToString()!, NumberFormatInfo.InvariantInfo); 34 | 35 | //Mean is in nanoseconds, which is 1.000.000.000x less than a second 36 | double time = stats.Mean / 1000 / 1000 / 1000; 37 | 38 | double opsPrSec = (size / 1024f / 1024) / time; 39 | return opsPrSec.ToString("N0", NumberFormatInfo.InvariantInfo); 40 | } 41 | 42 | public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false; 43 | public bool IsAvailable(Summary summary) => true; 44 | public bool AlwaysShow => true; 45 | public ColumnCategory Category => ColumnCategory.Custom; 46 | public bool IsNumeric => true; 47 | public UnitType UnitType => UnitType.Dimensionless; 48 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => GetValue(summary, benchmarkCase); 49 | public int PriorityInCategory => 1; 50 | public override string ToString() => ColumnName; 51 | public string Legend => "Mibibytes pr. second"; 52 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/Code/MbPrSecColumnAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.Benchmarks.Code; 2 | 3 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] 4 | public sealed class MbPrSecColumnAttribute : ColumnConfigBaseAttribute 5 | { 6 | public MbPrSecColumnAttribute(int size = 0) : base(new MbPrSecColumn(size)) {} 7 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/FastHash.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/Index32Benchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Order; 2 | using Genbox.FastHash.Benchmarks.Code; 3 | using Genbox.FastHash.CityHash; 4 | using Genbox.FastHash.DjbHash; 5 | using Genbox.FastHash.FarmHash; 6 | using Genbox.FastHash.FnvHash; 7 | using Genbox.FastHash.MarvinHash; 8 | using Genbox.FastHash.MurmurHash; 9 | using Genbox.FastHash.SuperFastHash; 10 | using Genbox.FastHash.XxHash; 11 | 12 | namespace Genbox.FastHash.Benchmarks; 13 | 14 | [MbPrSecColumn(4)] 15 | [Orderer(SummaryOrderPolicy.FastestToSlowest)] 16 | public class Index32Benchmarks 17 | { 18 | private readonly uint _value = 12808241; 19 | 20 | [Benchmark] 21 | public uint CityHash32Test() => CityHash32.ComputeIndex(_value); 22 | 23 | [Benchmark] 24 | public uint Djb2Hash32Test() => Djb2Hash32.ComputeIndex(_value); 25 | 26 | [Benchmark] 27 | public uint FarmHash32Test() => FarmHash32.ComputeIndex(_value); 28 | 29 | [Benchmark] 30 | public uint Fnv1aHash32Test() => Fnv1aHash32.ComputeIndex(_value); 31 | 32 | [Benchmark] 33 | public uint MarvinHash32Test() => MarvinHash32.ComputeIndex(_value); 34 | 35 | [Benchmark] 36 | public uint Murmur3Hash32Test() => Murmur3Hash32.ComputeIndex(_value); 37 | 38 | [Benchmark] 39 | public uint SuperFastHash32Test() => SuperFastHash32.ComputeIndex(_value); 40 | 41 | [Benchmark] 42 | public uint Xx2Hash32Test() => Xx2Hash32.ComputeIndex(_value); 43 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/Index64Benchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Order; 2 | using Genbox.FastHash.Benchmarks.Code; 3 | using Genbox.FastHash.CityHash; 4 | using Genbox.FastHash.DjbHash; 5 | using Genbox.FastHash.FarmHash; 6 | using Genbox.FastHash.FnvHash; 7 | using Genbox.FastHash.PolymurHash; 8 | using Genbox.FastHash.SipHash; 9 | using Genbox.FastHash.WyHash; 10 | using Genbox.FastHash.XxHash; 11 | 12 | namespace Genbox.FastHash.Benchmarks; 13 | 14 | [MbPrSecColumn(8)] 15 | [Orderer(SummaryOrderPolicy.FastestToSlowest)] 16 | public class Index64Benchmarks 17 | { 18 | private readonly ulong _value = 12808224424451380151UL; 19 | 20 | [Benchmark] 21 | public ulong CityHash64Test() => CityHash64.ComputeIndex(_value); 22 | 23 | [Benchmark] 24 | public ulong Djb2Hash64Test() => Djb2Hash64.ComputeIndex(_value); 25 | 26 | [Benchmark] 27 | public ulong FarmHash64Test() => FarmHash64.ComputeIndex(_value); 28 | 29 | [Benchmark] 30 | public ulong Fnv1aHash64Test() => Fnv1aHash64.ComputeIndex(_value); 31 | 32 | [Benchmark] 33 | public ulong Polymur2Hash64Test() => Polymur2Hash64.ComputeIndex(_value); 34 | 35 | [Benchmark] 36 | public ulong SipHash64Test() => SipHash64.ComputeIndex(_value); 37 | 38 | [Benchmark] 39 | public ulong Wy3Hash64Test() => Wy3Hash64.ComputeIndex(_value); 40 | 41 | [Benchmark] 42 | public ulong Xx2Hash64Test() => Xx2Hash64.ComputeIndex(_value); 43 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/MixerBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Order; 2 | using Genbox.FastHash.TestShared; 3 | using static Genbox.FastHash.MixFunctions; 4 | 5 | namespace Genbox.FastHash.Benchmarks; 6 | 7 | [Orderer(SummaryOrderPolicy.FastestToSlowest)] 8 | public class MixerBenchmarks 9 | { 10 | [Benchmark] 11 | [ArgumentsSource(nameof(GetMix64))] 12 | public ulong Mix64(MixSpec64 spec) => spec.Func(42); 13 | 14 | [Benchmark] 15 | [ArgumentsSource(nameof(GetMix32))] 16 | public ulong Mix32(MixSpec32 spec) => spec.Func(42); 17 | 18 | public static IEnumerable GetMix64() 19 | { 20 | yield return [new MixSpec64(AA_xmxmx_Murmur_64)]; 21 | yield return [new MixSpec64(JM_mrm_Depth7_64)]; 22 | yield return [new MixSpec64(JM_mxm_Depth8_64)]; 23 | yield return [new MixSpec64(JM_xmx_Depth9_64)]; 24 | yield return [new MixSpec64(JM_mxma_Depth11_64)]; 25 | yield return [new MixSpec64(JM_mxmx_Depth11_64)]; 26 | yield return [new MixSpec64(JM_xmrx_Depth12_64)]; 27 | yield return [new MixSpec64(JM_mxmxm_Depth13_64)]; 28 | yield return [new MixSpec64(JM_mxrmx_Depth14_64)]; 29 | yield return [new MixSpec64(JM_mxmxmx_Depth15_64)]; 30 | yield return [new MixSpec64(JM_xmxmx_Mx2_64)]; 31 | yield return [new MixSpec64(JM_xmxmxmx_Mx3_64)]; 32 | yield return [new MixSpec64(PE_rrxrrxmxmx_rrmxmx_64)]; 33 | yield return [new MixSpec64(PE_rrxrrmrrxrrxmx_rrxmrrxmsx0_64)]; 34 | yield return [new MixSpec64(PE_xmxmx_Moremur_64)]; 35 | yield return [new MixSpec64(PE_rrxrrxmxxmxx_Nasam_64)]; 36 | yield return [new MixSpec64(DS_xmxmx_Mix01_64)]; 37 | yield return [new MixSpec64(DS_xmxmx_Mix02_64)]; 38 | yield return [new MixSpec64(DS_xmxmx_Mix03_64)]; 39 | yield return [new MixSpec64(DS_xmxmx_Mix04_64)]; 40 | yield return [new MixSpec64(DS_xmxmx_Mix05_64)]; 41 | yield return [new MixSpec64(DS_xmxmx_Mix06_64)]; 42 | yield return [new MixSpec64(DS_xmxmx_Mix07_64)]; 43 | yield return [new MixSpec64(DS_xmxmx_Mix08_64)]; 44 | yield return [new MixSpec64(DS_xmxmx_Mix09_64)]; 45 | yield return [new MixSpec64(DS_xmxmx_Mix10_64)]; 46 | yield return [new MixSpec64(DS_xmxmx_Mix11_64)]; 47 | yield return [new MixSpec64(DS_xmxmx_Mix12_64)]; 48 | yield return [new MixSpec64(DS_xmxmx_Mix13_64)]; 49 | yield return [new MixSpec64(DS_xmxmx_Mix14_64)]; 50 | yield return [new MixSpec64(EZ_xmx_FastHash_64)]; 51 | yield return [new MixSpec64(DL_xmxmx_Lea_64)]; 52 | yield return [new MixSpec64(DE_xmxmx_Degski_64)]; 53 | yield return [new MixSpec64(YC_xmxmx_XXH2_64)]; 54 | yield return [new MixSpec64(YC_xmx_XXH3_64)]; 55 | yield return [new MixSpec64(GP_mxxmxxm_CityHash_64)]; 56 | yield return [new MixSpec64(PK_rlxrlx_Umash_64)]; 57 | yield return [new MixSpec64(WF_amx_Wymix_64)]; 58 | yield return [new MixSpec64(WF_amxmx_Wymix_64)]; 59 | yield return [new MixSpec64(TE_rlxrlmrlxrlx_AxMix_64)]; 60 | } 61 | 62 | public static IEnumerable GetMix32() 63 | { 64 | yield return [new MixSpec32(AA_xmxmx_Murmur_32)]; 65 | yield return [new MixSpec32(DE_xmxmx_Degski_32)]; 66 | yield return [new MixSpec32(FP_xsxxmx_Fp64_32)]; 67 | yield return [new MixSpec32(YC_xmxmx_XXH2_32)]; 68 | yield return [new MixSpec32(CW_xmxmx_LowBias_32)]; 69 | yield return [new MixSpec32(CW_xmxmxmx_Triple_32)]; 70 | } 71 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/Multiply64Benchmarks.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.TestShared; 2 | 3 | namespace Genbox.FastHash.Benchmarks; 4 | 5 | public class Multiply64Benchmarks 6 | { 7 | private readonly ulong _valA = 10280214UL; 8 | private readonly ulong _valB = 89244214UL; 9 | 10 | [Benchmark] 11 | public (ulong, ulong) MathBigMul() => Mult.MathBigMul(_valA, _valB); 12 | 13 | [Benchmark] 14 | public (ulong, ulong) XxHashMul() => Mult.XxHashMul(_valA, _valB); 15 | 16 | [Benchmark] 17 | public (ulong, ulong) Bmi2Mul() => Mult.Bmi2Mul(_valA, _valB); 18 | 19 | [Benchmark] 20 | public (ulong, ulong) Scalar32Mul() => Mult.Scalar32Mul(_valA, _valB); 21 | 22 | [Benchmark] 23 | public (ulong, ulong) Scalar64Mul() => Mult.Scalar64Mul(_valA, _valB); 24 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Analysers; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Jobs; 4 | using BenchmarkDotNet.Reports; 5 | using BenchmarkDotNet.Running; 6 | using BenchmarkDotNet.Validators; 7 | 8 | namespace Genbox.FastHash.Benchmarks; 9 | 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | IConfig config = ManualConfig.CreateMinimumViable() 15 | .AddJob(new Job(new RunMode 16 | { 17 | LaunchCount = 1, 18 | WarmupCount = 3, 19 | MinIterationCount = 3, 20 | MaxIterationCount = 10 21 | }, Job.InProcess)) 22 | .AddAnalyser(EnvironmentAnalyser.Default, 23 | MinIterationTimeAnalyser.Default, 24 | RuntimeErrorAnalyser.Default, 25 | BaselineCustomAnalyzer.Default, 26 | HideColumnsAnalyser.Default) 27 | .AddValidator(BaselineValidator.FailOnError, 28 | SetupCleanupValidator.FailOnError, 29 | JitOptimizationsValidator.FailOnError, 30 | RunModeValidator.FailOnError, 31 | GenericBenchmarksValidator.DontFailOnError, 32 | DeferredExecutionValidator.FailOnError, 33 | ParamsAllValuesValidator.FailOnError, 34 | ParamsValidator.FailOnError) 35 | .WithOption(ConfigOptions.DisableLogFile, true) 36 | .WithSummaryStyle(SummaryStyle.Default.WithMaxParameterColumnWidth(50)); 37 | 38 | BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config); 39 | } 40 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/ReadAlignedBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using BenchmarkDotNet.Order; 3 | using Genbox.FastHash.Benchmarks.Code; 4 | 5 | namespace Genbox.FastHash.Benchmarks; 6 | 7 | [MbPrSecColumn] 8 | [Orderer(SummaryOrderPolicy.FastestToSlowest)] 9 | public class ReadAlignedBenchmarks 10 | { 11 | private byte[] _testData; 12 | 13 | [Params(8, 32, 128, 1024, 1024 * 1024 * 32)] 14 | public int Size { get; set; } 15 | 16 | [GlobalSetup] 17 | public void Setup() 18 | { 19 | _testData = BenchmarkHelper.GetRandomBytes(Size); 20 | } 21 | 22 | [Benchmark] 23 | public ulong OneAtTheTime() 24 | { 25 | ulong acc = 0; 26 | 27 | for (int i = 0; i < _testData.Length; i++) 28 | acc += _testData[i]; 29 | 30 | return acc; 31 | } 32 | 33 | [Benchmark] 34 | public ulong AlignedFourAtTheTime() 35 | { 36 | ulong acc = 0; 37 | 38 | for (int i = 0; i < _testData.Length; i += 4) 39 | { 40 | acc += _testData[i]; 41 | acc += _testData[i + 1]; 42 | acc += _testData[i + 2]; 43 | acc += _testData[i + 3]; 44 | } 45 | 46 | return acc; 47 | } 48 | 49 | [Benchmark] 50 | public ulong AlignedIntegers32() 51 | { 52 | ulong acc = 0; 53 | 54 | uint[] intArr = Unsafe.As(ref _testData); 55 | int items = _testData.Length / sizeof(uint); 56 | 57 | for (int i = 0; i < items; i++) 58 | acc += intArr[i]; 59 | 60 | return acc; 61 | } 62 | 63 | [Benchmark] 64 | public ulong AlignedIntegers64() 65 | { 66 | ulong acc = 0; 67 | 68 | ulong[] intArr = Unsafe.As(ref _testData); 69 | int items = _testData.Length / sizeof(ulong); 70 | 71 | for (int i = 0; i < items; i++) 72 | acc += intArr[i]; 73 | 74 | return acc; 75 | } 76 | } -------------------------------------------------------------------------------- /Src/FastHash.Benchmarks/ReadUnalignedBenchmarks.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using BenchmarkDotNet.Order; 3 | using Genbox.FastHash.Benchmarks.Code; 4 | 5 | namespace Genbox.FastHash.Benchmarks; 6 | 7 | [MbPrSecColumn] 8 | [Orderer(SummaryOrderPolicy.FastestToSlowest)] 9 | public class ReadUnalignedBenchmarks 10 | { 11 | private byte[] _testData; 12 | 13 | [Params(7, 31, 127, 1023, 1024 * 1024 * 31)] 14 | public int Size { get; set; } 15 | 16 | [GlobalSetup] 17 | public void Setup() 18 | { 19 | _testData = BenchmarkHelper.GetRandomBytes(Size); 20 | } 21 | 22 | [Benchmark(Baseline = true)] 23 | public ulong OneAtTheTime() 24 | { 25 | ulong acc = 0; 26 | 27 | for (int i = 0; i < _testData.Length; i++) 28 | acc += _testData[i]; 29 | 30 | return acc; 31 | } 32 | 33 | [Benchmark] 34 | public ulong OneAtTheTimeUnsafe() 35 | { 36 | ulong acc = 0; 37 | 38 | ref byte ptr = ref _testData[0]; 39 | 40 | for (int i = 0; i < _testData.Length; i++) 41 | acc += Unsafe.Add(ref ptr, i); //This avoids the bounds check 42 | 43 | return acc; 44 | } 45 | 46 | [Benchmark] 47 | public ulong UnalignedIntegers32() 48 | { 49 | ulong acc = 0; 50 | 51 | uint[] intArr = Unsafe.As(ref _testData); 52 | 53 | int count = _testData.Length; 54 | uint chunks = (uint)Math.DivRem(count, sizeof(uint), out int rem); 55 | 56 | while (chunks > 0) 57 | { 58 | acc += intArr[chunks]; 59 | chunks--; 60 | } 61 | 62 | byte[] localPtr = _testData; 63 | 64 | //There is 0-3 byes left. Read 2. 65 | if ((rem & 0b_0010) != 0) 66 | { 67 | acc += localPtr[rem]; 68 | acc += localPtr[rem - 1]; 69 | rem -= 2; 70 | } 71 | 72 | //Read last byte if any 73 | if ((rem & 0b_0001) != 0) 74 | acc += localPtr[rem]; 75 | 76 | return acc; 77 | } 78 | 79 | [Benchmark] 80 | public ulong UnalignedIntegers64() 81 | { 82 | ulong acc = 0; 83 | 84 | ulong[] intArr = Unsafe.As(ref _testData); 85 | 86 | int count = _testData.Length; 87 | uint chunks = (uint)Math.DivRem(count, sizeof(ulong), out int rem); //Cast to uint to have the while below do an optimized check 88 | 89 | while (chunks > 0u) 90 | { 91 | acc += intArr[chunks]; 92 | chunks--; 93 | } 94 | 95 | byte[] localPtr = _testData; //Local reference avoids bounds check 96 | 97 | //There is 0-7 byes left. Read 4. 98 | if ((rem & 0b_0100) != 0) 99 | { 100 | acc += localPtr[rem]; 101 | acc += localPtr[rem - 1]; 102 | acc += localPtr[rem - 2]; 103 | acc += localPtr[rem - 3]; 104 | rem -= 4; 105 | } 106 | 107 | //There is 0-3 byes left. Read 2. 108 | if ((rem & 0b_0010) != 0) 109 | { 110 | acc += localPtr[rem]; 111 | acc += localPtr[rem - 1]; 112 | rem -= 2; 113 | } 114 | 115 | //Read last byte if any 116 | if ((rem & 0b_0001) != 0) 117 | acc += localPtr[rem]; 118 | 119 | return acc; 120 | } 121 | } -------------------------------------------------------------------------------- /Src/FastHash.Examples/FastHash.Examples.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | true 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Src/FastHash.Examples/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.Examples; 2 | 3 | public static class Program 4 | { 5 | public static void Main() 6 | { 7 | //Nothing for now 8 | } 9 | } -------------------------------------------------------------------------------- /Src/FastHash.TestShared/FastHash.TestShared.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | net8.0 7 | true 8 | false 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Src/FastHash.TestShared/MixSpec32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Genbox.FastHash.TestShared; 4 | 5 | public record MixSpec32(Func Func, [CallerArgumentExpression(nameof(Func))]string Name = "") 6 | { 7 | public override string ToString() => Name; 8 | } -------------------------------------------------------------------------------- /Src/FastHash.TestShared/MixSpec64.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Genbox.FastHash.TestShared; 4 | 5 | public record MixSpec64(Func Func, [CallerArgumentExpression(nameof(Func))]string Name = "") 6 | { 7 | public override string ToString() => Name; 8 | } -------------------------------------------------------------------------------- /Src/FastHash.TestShared/Mult.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System.Runtime.Intrinsics.X86; 3 | 4 | namespace Genbox.FastHash.TestShared; 5 | 6 | public static class Mult 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static (ulong, ulong) MathBigMul(ulong a, ulong b) 10 | { 11 | ulong high = Math.BigMul(a, b, out ulong low); 12 | return (low, high); 13 | } 14 | 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static (ulong, ulong) XxHashMul(ulong a, ulong b) 17 | { 18 | unchecked 19 | { 20 | ulong y = b & 0xFFFFFFFF; 21 | ulong lo_lo = (uint)(a & 0xFFFFFFFF) * (ulong)(uint)y; 22 | ulong y1 = b & 0xFFFFFFFF; 23 | ulong hi_lo = (uint)(a >> 32) * (ulong)(uint)y1; 24 | ulong y2 = b >> 32; 25 | ulong lo_hi = (uint)(a & 0xFFFFFFFF) * (ulong)(uint)y2; 26 | ulong y3 = b >> 32; 27 | ulong hi_hi = (uint)(a >> 32) * (ulong)(uint)y3; 28 | 29 | ulong cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; 30 | ulong upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; 31 | ulong lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); 32 | return (lower, upper); 33 | } 34 | } 35 | 36 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 37 | public static unsafe (ulong, ulong) Bmi2Mul(ulong a, ulong b) 38 | { 39 | ulong low; 40 | ulong high = Bmi2.X64.MultiplyNoFlags(a, b, &low); 41 | return (low, high); 42 | } 43 | 44 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 45 | public static (ulong, ulong) Scalar32Mul(ulong a, ulong b) 46 | { 47 | unchecked 48 | { 49 | uint al = (uint)a; 50 | uint ah = (uint)(a >> 32); 51 | uint bl = (uint)b; 52 | uint bh = (uint)(b >> 32); 53 | 54 | ulong mull = (ulong)al * bl; 55 | ulong t = ((ulong)ah * bl) + (mull >> 32); 56 | ulong tl = ((ulong)al * bh) + (uint)t; 57 | 58 | ulong low = (tl << 32) | (uint)mull; 59 | ulong high = ((ulong)ah * bh) + (t >> 32) + (tl >> 32); 60 | return (low, high); 61 | } 62 | } 63 | 64 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 65 | public static (ulong, ulong) Scalar64Mul(ulong a, ulong b) 66 | { 67 | unchecked 68 | { 69 | ulong lo = a * b; 70 | 71 | ulong x0 = (uint)a; 72 | ulong x1 = a >> 32; 73 | 74 | ulong y0 = (uint)b; 75 | ulong y1 = b >> 32; 76 | 77 | ulong p11 = x1 * y1; 78 | ulong p01 = x0 * y1; 79 | ulong p10 = x1 * y0; 80 | ulong p00 = x0 * y0; 81 | 82 | ulong middle = p10 + (p00 >> 32) + (uint)p01; 83 | ulong hi = p11 + (middle >> 32) + (p01 >> 32); 84 | 85 | return (lo, hi); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/FastHash.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Src/FastHash.Tests/GeneralTests.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Security.Cryptography; 3 | using Genbox.FastHash.DjbHash; 4 | 5 | namespace Genbox.FastHash.Tests; 6 | 7 | public class GeneralTests 8 | { 9 | [Theory, MemberData(nameof(GetAllTypesOf))] 10 | public void CheckAllHaveCorrectName(Type type) 11 | { 12 | Assert.True(type.Name.EndsWith("32", StringComparison.Ordinal) || 13 | type.Name.EndsWith("32Unsafe", StringComparison.Ordinal) || 14 | type.Name.EndsWith("64", StringComparison.Ordinal) || 15 | type.Name.EndsWith("64Unsafe", StringComparison.Ordinal) || 16 | type.Name.EndsWith("128", StringComparison.Ordinal) || 17 | type.Name.EndsWith("128Unsafe", StringComparison.Ordinal)); 18 | } 19 | 20 | public static TheoryData GetAllTypesOf() 21 | { 22 | TheoryData data = new TheoryData(); 23 | 24 | Assembly assembly = typeof(Djb2Hash32).GetTypeInfo().Assembly; 25 | 26 | foreach (Type type in assembly.GetTypes()) 27 | { 28 | if (type.Name.Contains("Shared", StringComparison.Ordinal) || type.Name.Contains("Constants", StringComparison.Ordinal)) 29 | continue; 30 | 31 | if (type.Name == "MixFunctions") 32 | continue; 33 | 34 | if (type.IsPublic && type.IsAbstract && type.IsSealed) 35 | data.Add(type); 36 | } 37 | 38 | return data; 39 | } 40 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/IndexTests.cs: -------------------------------------------------------------------------------- 1 | using System.Buffers.Binary; 2 | using System.Diagnostics.CodeAnalysis; 3 | using Genbox.FastHash.CityHash; 4 | using Genbox.FastHash.DjbHash; 5 | using Genbox.FastHash.FarmHash; 6 | using Genbox.FastHash.FnvHash; 7 | using Genbox.FastHash.MarvinHash; 8 | using Genbox.FastHash.MurmurHash; 9 | using Genbox.FastHash.SipHash; 10 | using Genbox.FastHash.SuperFastHash; 11 | using Genbox.FastHash.WyHash; 12 | using Genbox.FastHash.XxHash; 13 | 14 | namespace Genbox.FastHash.Tests; 15 | 16 | [SuppressMessage("Design", "CA1034:Nested types should not be visible")] 17 | public class IndexTests 18 | { 19 | [Theory] 20 | [MemberData(nameof(Create32))] 21 | public void Check32(Tuple32 c) 22 | { 23 | byte[] valueBytes = new byte[4]; 24 | 25 | for (int i = 0; i <= 32; i++) 26 | { 27 | uint value = 1u << i; 28 | uint h1 = c.Index(value); 29 | 30 | BinaryPrimitives.WriteUInt32LittleEndian(valueBytes, value); 31 | uint h2 = c.Hash(valueBytes); 32 | 33 | Assert.Equal(h2, h1); 34 | } 35 | } 36 | 37 | [Theory] 38 | [MemberData(nameof(Create64))] 39 | public void Check64(Tuple64 c) 40 | { 41 | byte[] valueBytes = new byte[8]; 42 | 43 | for (int i = 0; i <= 64; i++) 44 | { 45 | ulong value = 1ul << i; 46 | ulong h1 = c.Index(value); 47 | 48 | BinaryPrimitives.WriteUInt64LittleEndian(valueBytes, value); 49 | ulong h2 = c.Hash(valueBytes); 50 | 51 | Assert.Equal(h2, h1); 52 | } 53 | } 54 | 55 | public static TheoryData Create32() => new TheoryData 56 | { 57 | new Tuple32(nameof(CityHash32), CityHash32.ComputeIndex, CityHash32.ComputeHash), 58 | new Tuple32(nameof(Djb2Hash32), Djb2Hash32.ComputeIndex, Djb2Hash32.ComputeHash), 59 | new Tuple32(nameof(FarmHash32), FarmHash32.ComputeIndex, FarmHash32.ComputeHash), 60 | new Tuple32(nameof(Fnv1aHash32), Fnv1aHash32.ComputeIndex, Fnv1aHash32.ComputeHash), 61 | new Tuple32(nameof(MarvinHash32), MarvinHash32.ComputeIndex, static x => MarvinHash32.ComputeHash(x)), 62 | new Tuple32(nameof(Murmur3Hash32), Murmur3Hash32.ComputeIndex, static x => Murmur3Hash32.ComputeHash(x)), 63 | new Tuple32(nameof(SuperFastHash32), SuperFastHash32.ComputeIndex, SuperFastHash32.ComputeHash), 64 | new Tuple32(nameof(Xx2Hash32), Xx2Hash32.ComputeIndex, static x => Xx2Hash32.ComputeHash(x)), 65 | }; 66 | 67 | public static TheoryData Create64() => new TheoryData 68 | { 69 | new Tuple64(nameof(CityHash64), CityHash64.ComputeIndex, CityHash64.ComputeHash), 70 | new Tuple64(nameof(Djb2Hash64), Djb2Hash64.ComputeIndex, Djb2Hash64.ComputeHash), 71 | new Tuple64(nameof(FarmHash64), FarmHash64.ComputeIndex, static x => FarmHash64.ComputeHash(x)), 72 | new Tuple64(nameof(Fnv1aHash64), Fnv1aHash64.ComputeIndex, Fnv1aHash64.ComputeHash), 73 | new Tuple64(nameof(SipHash64), static x => SipHash64.ComputeIndex(x), static x => SipHash64.ComputeHash(x)), 74 | new Tuple64(nameof(Wy3Hash64), Wy3Hash64.ComputeIndex, static x => Wy3Hash64.ComputeHash(x)), 75 | new Tuple64(nameof(Xx2Hash64), Xx2Hash64.ComputeIndex, static x => Xx2Hash64.ComputeHash(x)), 76 | }; 77 | 78 | public record struct Tuple32(string Name, Func Index, Func, uint> Hash) : IXunitSerializable 79 | { 80 | public void Deserialize(IXunitSerializationInfo info) => Name = info.GetValue(nameof(Name)); 81 | public void Serialize(IXunitSerializationInfo info) => info.AddValue(nameof(Name), Name); 82 | public override string ToString() => Name; 83 | } 84 | 85 | public record struct Tuple64(string Name, Func Index, Func, ulong> Hash) : IXunitSerializable 86 | { 87 | public void Deserialize(IXunitSerializationInfo info) => Name = info.GetValue(nameof(Name)); 88 | public void Serialize(IXunitSerializationInfo info) => info.AddValue(nameof(Name), Name); 89 | public override string ToString() => Name; 90 | } 91 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/MixerTests.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.TestShared; 2 | using static Genbox.FastHash.MixFunctions; 3 | 4 | namespace Genbox.FastHash.Tests; 5 | 6 | public class MixerTests 7 | { 8 | [Theory] 9 | [MemberData(nameof(GetFunctions))] 10 | public void RandomDistributionTest(MixSpec64 spec) 11 | { 12 | int[] buckets = new int[100]; 13 | const uint iterations = 1_000_000; 14 | 15 | for (ulong i = 0; i < iterations; i++) 16 | { 17 | ulong index = spec.Func(i) % (ulong)buckets.Length; 18 | buckets[index]++; 19 | } 20 | 21 | float onePercent = (float)iterations / buckets.Length; 22 | float fraction = onePercent * 0.04f; //4% 23 | 24 | //There should be 1% items in each bucket. We test if there are 4% of 1% deviation 25 | foreach (int val in buckets) 26 | Assert.True(Math.Abs(onePercent - val) < fraction); 27 | } 28 | 29 | public static TheoryData GetFunctions() => new TheoryData 30 | { 31 | new MixSpec64(AA_xmxmx_Murmur_64), 32 | new MixSpec64(JM_xmxmxmx_Mx3_64), 33 | new MixSpec64(PE_xmxmx_Moremur_64), 34 | new MixSpec64(YC_xmxmx_XXH2_64), 35 | new MixSpec64(EZ_xmx_FastHash_64), 36 | new MixSpec64(PE_rrxrrxmxxmxx_Nasam_64), 37 | }; 38 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/MultTests.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.TestShared; 2 | 3 | namespace Genbox.FastHash.Tests; 4 | 5 | public class MultTests 6 | { 7 | private readonly ulong _valA = 10280214UL; 8 | private readonly ulong _valB = 89244214UL; 9 | private readonly (ulong, ulong) _result = (917449618181796, 0); 10 | 11 | [Fact] 12 | public void MathBigMul() => Assert.Equal(_result, Mult.MathBigMul(_valA, _valB)); 13 | 14 | [Fact] 15 | public void XxHashMul() => Assert.Equal(_result, Mult.XxHashMul(_valA, _valB)); 16 | 17 | [Fact] 18 | public void Bmi2Mul() => Assert.Equal(_result, Mult.Bmi2Mul(_valA, _valB)); 19 | 20 | [Fact] 21 | public void Scalar32Mul() => Assert.Equal(_result, Mult.Scalar32Mul(_valA, _valB)); 22 | 23 | [Fact] 24 | public void Scalar64Mul() => Assert.Equal(_result, Mult.Scalar64Mul(_valA, _valB)); 25 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/Single/DjbHashTests.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.DjbHash; 2 | 3 | namespace Genbox.FastHash.Tests.Single; 4 | 5 | public class DjbHashTests 6 | { 7 | [Fact] 8 | public void Djb2Hash32IndexTest() 9 | { 10 | uint val = 1u; 11 | for (int i = 1; i <= 32; i++) 12 | { 13 | uint h1 = Djb2Hash32.ComputeHash(BitConverter.GetBytes(val)); 14 | uint h2 = Djb2Hash32.ComputeIndex(val); 15 | Assert.Equal(h1, h2); 16 | 17 | val <<= 1; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/Single/FnvHashTests.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.FnvHash; 2 | 3 | namespace Genbox.FastHash.Tests.Single; 4 | 5 | public class FnvHashTests 6 | { 7 | [Fact] 8 | public void Fnv1aHash32IndexTest() 9 | { 10 | uint val = 1u; 11 | for (int i = 1; i <= 32; i++) 12 | { 13 | uint h1 = Fnv1aHash32.ComputeHash(BitConverter.GetBytes(val)); 14 | uint h2 = Fnv1aHash32.ComputeIndex(val); 15 | Assert.Equal(h1, h2); 16 | 17 | val <<= 1; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/Single/GxHashTests.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using Genbox.FastHash.GxHash; 3 | 4 | namespace Genbox.FastHash.Tests.Single; 5 | 6 | public class GxHashTests 7 | { 8 | [Fact] 9 | public void ValuesTest() 10 | { 11 | Assert.Equal(456576800u, GxHash32.ComputeHash(Array.Empty().AsSpan(), 0)); 12 | Assert.Equal(978957914u, GxHash32.ComputeHash(new byte[1].AsSpan(), 0)); 13 | Assert.Equal(3325885698u, GxHash32.ComputeHash(new byte[1000].AsSpan(), 0)); 14 | Assert.Equal(1827274036u, GxHash32.ComputeHash(MemoryMarshal.AsBytes("hello world".AsSpan()), 123)); 15 | } 16 | 17 | [Fact] 18 | public void SanityChecks() 19 | { 20 | HashSet hashes = new HashSet(); 21 | 22 | // Check that zero filled inputs are hashes differently depending on their size 23 | byte[] bytes = new byte[1000]; 24 | for (int i = 0; i < bytes.Length; i++) 25 | { 26 | ReadOnlySpan slice = bytes.AsSpan().Slice(0, i); 27 | ulong hash = GxHash64.ComputeHash(slice, 42); 28 | Assert.NotEqual(0UL, hash); 29 | Assert.True(hashes.Add(hash)); 30 | } 31 | 32 | // Check that zero padding affects output hash 33 | hashes.Clear(); 34 | bytes[0] = 123; 35 | for (int i = 0; i < bytes.Length; i++) 36 | { 37 | ReadOnlySpan slice = bytes.AsSpan().Slice(0, i); 38 | ulong hash = GxHash64.ComputeHash(slice, 42); 39 | Assert.NotEqual(0UL, hash); 40 | Assert.True(hashes.Add(hash)); 41 | } 42 | } 43 | 44 | [Fact] 45 | public void AllBytesAreRead() 46 | { 47 | for (int s = 0; s < 1200; s++) 48 | { 49 | byte[] bytes = new byte[s]; 50 | uint hash = GxHash32.ComputeHash(bytes, 42); 51 | 52 | for (int i = 0; i < s; i++) 53 | { 54 | byte swap = bytes[i]; 55 | bytes[i] = 82; 56 | uint newHash = GxHash32.ComputeHash(bytes, 42); 57 | bytes[i] = swap; 58 | 59 | Assert.NotEqual(hash, newHash); 60 | } 61 | } 62 | } 63 | 64 | [Theory] 65 | [InlineData(1, 0, 1)] 66 | [InlineData(1, 0, 16)] 67 | [InlineData(1, 0, 32)] 68 | [InlineData(16, 0, 16)] 69 | [InlineData(16, 0, 32)] 70 | [InlineData(16, 16, 32)] 71 | [InlineData(16, 32, 48)] 72 | [InlineData(32, 0, 32)] 73 | [InlineData(32, 0, 64)] 74 | [InlineData(32, 32, 64)] 75 | [InlineData(32, 64, 96)] 76 | public void BytesOrderMatters(int swapSize, int swapPositionA, int swapPositionB) 77 | { 78 | Random rnd = new Random(123); 79 | byte[] bytes = new byte[255]; 80 | rnd.NextBytes(bytes); 81 | 82 | uint hash = GxHash32.ComputeHash(bytes, 0); 83 | 84 | SwapBytes(bytes, swapPositionA, swapPositionB, swapSize); 85 | 86 | uint hashAfterSwap = GxHash32.ComputeHash(bytes, 0); 87 | 88 | Assert.NotEqual(hash, hashAfterSwap); 89 | } 90 | 91 | private static void SwapBytes(Span span, int pos1, int pos2, int n) 92 | { 93 | // Check if the input parameters are valid 94 | if (pos1 < 0 || pos2 < 0 || n < 0) 95 | throw new ArgumentOutOfRangeException("Positions and length must be non-negative."); 96 | 97 | if (pos1 + n > span.Length || pos2 + n > span.Length) 98 | throw new ArgumentOutOfRangeException("Positions and length must be within the span's length."); 99 | 100 | // Perform the swap 101 | Span temp = stackalloc byte[n]; 102 | span.Slice(pos1, n).CopyTo(temp); 103 | span.Slice(pos2, n).CopyTo(span.Slice(pos1, n)); 104 | temp.CopyTo(span.Slice(pos2, n)); 105 | } 106 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/Single/HighwayHashTests.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.HighwayHash; 2 | 3 | namespace Genbox.FastHash.Tests.Single; 4 | 5 | public class HighwayHashTests 6 | { 7 | private const uint kMaxSize = 64; 8 | 9 | private static readonly ulong[] _testKeys = 10 | [ 11 | 0x0706050403020100UL, 0x0F0E0D0C0B0A0908UL, 12 | 0x1716151413121110UL, 0x1F1E1D1C1B1A1918UL 13 | ]; 14 | 15 | private static readonly ulong[] _testKeys2 = 16 | [ 17 | 1ul, 2ul, 18 | 3ul, 4ul 19 | ]; 20 | 21 | private readonly ulong[] Expected64 = 22 | [ 23 | 0x907A56DE22C26E53ul, 0x7EAB43AAC7CDDD78ul, 0xB8D0569AB0B53D62ul, 24 | 0x5C6BEFAB8A463D80ul, 0xF205A46893007EDAul, 0x2B8A1668E4A94541ul, 25 | 0xBD4CCC325BEFCA6Ful, 0x4D02AE1738F59482ul, 0xE1205108E55F3171ul, 26 | 0x32D2644EC77A1584ul, 0xF6E10ACDB103A90Bul, 0xC3BBF4615B415C15ul, 27 | 0x243CC2040063FA9Cul, 0xA89A58CE65E641FFul, 0x24B031A348455A23ul, 28 | 0x40793F86A449F33Bul, 0xCFAB3489F97EB832ul, 0x19FE67D2C8C5C0E2ul, 29 | 0x04DD90A69C565CC2ul, 0x75D9518E2371C504ul, 0x38AD9B1141D3DD16ul, 30 | 0x0264432CCD8A70E0ul, 0xA9DB5A6288683390ul, 0xD7B05492003F028Cul, 31 | 0x205F615AEA59E51Eul, 0xEEE0C89621052884ul, 0x1BFC1A93A7284F4Ful, 32 | 0x512175B5B70DA91Dul, 0xF71F8976A0A2C639ul, 0xAE093FEF1F84E3E7ul, 33 | 0x22CA92B01161860Ful, 0x9FC7007CCF035A68ul, 0xA0C964D9ECD580FCul, 34 | 0x2C90F73CA03181FCul, 0x185CF84E5691EB9Eul, 0x4FC1F5EF2752AA9Bul, 35 | 0xF5B7391A5E0A33EBul, 0xB9B84B83B4E96C9Cul, 0x5E42FE712A5CD9B4ul, 36 | 0xA150F2F90C3F97DCul, 0x7FA522D75E2D637Dul, 0x181AD0CC0DFFD32Bul, 37 | 0x3889ED981E854028ul, 0xFB4297E8C586EE2Dul, 0x6D064A45BB28059Cul, 38 | 0x90563609B3EC860Cul, 0x7AA4FCE94097C666ul, 0x1326BAC06B911E08ul, 39 | 0xB926168D2B154F34ul, 0x9919848945B1948Dul, 0xA2A98FC534825EBEul, 40 | 0xE9809095213EF0B6ul, 0x582E5483707BC0E9ul, 0x086E9414A88A6AF5ul, 41 | 0xEE86B98D20F6743Dul, 0xF89B7FF609B1C0A7ul, 0x4C7D9CC19E22C3E8ul, 42 | 0x9A97005024562A6Ful, 0x5DD41CF423E6EBEFul, 0xDF13609C0468E227ul, 43 | 0x6E0DA4F64188155Aul, 0xB755BA4B50D7D4A1ul, 0x887A3484647479BDul, 44 | 0xAB8EEBE9BF2139A0ul, 0x75542C5D4CD2A6FFul 45 | ]; 46 | 47 | [Fact] 48 | public void HighwayHash64Test() 49 | { 50 | byte[] data = new byte[kMaxSize + 1]; 51 | byte i; 52 | for (i = 0; i <= kMaxSize; i++) 53 | { 54 | data[i] = i; 55 | TestHash64(Expected64[i], data, i, _testKeys); 56 | } 57 | 58 | for (i = 0; i < 33; i++) 59 | data[i] = (byte)(128 + i); 60 | TestHash64(0x53c516cce478cad7ul, data, 33, _testKeys2); 61 | } 62 | 63 | private unsafe void TestHash64(ulong expected, byte[] data, int size, ulong[] key) 64 | { 65 | fixed (byte* ptr = data) 66 | { 67 | ulong hash = HighwayHash64Unsafe.ComputeHash(ptr, size, key[0], key[1], key[2], key[3]); 68 | Assert.Equal(expected, hash); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/Single/SipHashTests.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.SipHash; 2 | 3 | namespace Genbox.FastHash.Tests.Single; 4 | 5 | public class SipHashTests 6 | { 7 | private const int MaxLength = 64; 8 | 9 | private static readonly byte[][] _vectors = 10 | [ 11 | [0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72], 12 | [0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74], 13 | [0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d], 14 | [0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85], 15 | [0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf], 16 | [0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18], 17 | [0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb], 18 | [0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab], 19 | [0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93], 20 | [0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e], 21 | [0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a], 22 | [0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4], 23 | [0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75], 24 | [0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14], 25 | [0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7], 26 | [0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1], 27 | [0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f], 28 | [0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69], 29 | [0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b], 30 | [0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb], 31 | [0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe], 32 | [0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0], 33 | [0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93], 34 | [0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8], 35 | [0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8], 36 | [0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc], 37 | [0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17], 38 | [0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f], 39 | [0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde], 40 | [0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6], 41 | [0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad], 42 | [0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32], 43 | [0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71], 44 | [0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7], 45 | [0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12], 46 | [0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15], 47 | [0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31], 48 | [0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02], 49 | [0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca], 50 | [0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a], 51 | [0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e], 52 | [0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad], 53 | [0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18], 54 | [0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4], 55 | [0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9], 56 | [0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9], 57 | [0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb], 58 | [0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0], 59 | [0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6], 60 | [0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7], 61 | [0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee], 62 | [0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1], 63 | [0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a], 64 | [0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81], 65 | [0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f], 66 | [0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24], 67 | [0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7], 68 | [0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea], 69 | [0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60], 70 | [0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66], 71 | [0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c], 72 | [0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f], 73 | [0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5], 74 | [0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95] 75 | ]; 76 | 77 | private static readonly byte[] _key = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; 78 | 79 | [Fact] 80 | public void TestVectors() 81 | { 82 | for (int i = 0; i < MaxLength; ++i) 83 | { 84 | byte[] data = new byte[i]; 85 | for (int j = 0; j < i; j++) 86 | data[j] = (byte)j; 87 | 88 | ToULongs(_key, out ulong k0, out ulong k1); 89 | 90 | ulong result = SipHash64.ComputeHash(data, k0, k1); 91 | ulong expected = BitConverter.ToUInt64(_vectors[i], 0); 92 | Assert.Equal(expected, result); 93 | } 94 | } 95 | 96 | [Fact] 97 | public void TestVectorsUnsafe() 98 | { 99 | for (int i = 0; i < MaxLength; ++i) 100 | { 101 | byte[] data = new byte[i]; 102 | for (int j = 0; j < i; j++) 103 | data[j] = (byte)j; 104 | 105 | ToULongs(_key, out ulong k0, out ulong k1); 106 | 107 | unsafe 108 | { 109 | fixed (byte* ptr = data) 110 | { 111 | ulong result = SipHash64Unsafe.ComputeHash(ptr, data.Length, k0, k1); 112 | ulong expected = BitConverter.ToUInt64(_vectors[i], 0); 113 | Assert.Equal(expected, result); 114 | } 115 | } 116 | } 117 | } 118 | 119 | private static unsafe void ToULongs(byte[] data, out ulong a, out ulong b) 120 | { 121 | fixed (byte* ptr = data) 122 | { 123 | ulong* ulPtr = (ulong*)ptr; 124 | a = *ulPtr++; 125 | b = *ulPtr; 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/Single/WyHashTests.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Genbox.FastHash.WyHash; 3 | 4 | namespace Genbox.FastHash.Tests.Single; 5 | 6 | public class WyHashTests 7 | { 8 | [Theory] 9 | [InlineData(0, "", 0x42bc986dc5eec4d3)] 10 | [InlineData(1, "a", 0x84508dc903c31551)] 11 | [InlineData(2, "abc", 0x0bc54887cfc9ecb1)] 12 | [InlineData(3, "message digest", 0x6e2ff3298208a67c)] 13 | [InlineData(4, "abcdefghijklmnopqrstuvwxyz", 0x9a64e42e897195b9)] 14 | [InlineData(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 0x9199383239c32554)] 15 | [InlineData(6, "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 0x7c1ccf6bba30f5a5)] 16 | public void TestVectors(int seed, string value, ulong hash) 17 | { 18 | ulong h = Wy3Hash64.ComputeHash(Encoding.ASCII.GetBytes(value), (ulong)seed); 19 | Assert.Equal(hash, h); 20 | } 21 | 22 | [Fact] 23 | public void Wy3Hash64IndexTest() 24 | { 25 | ulong val = 1ul; 26 | for (int i = 1; i <= 64; i++) 27 | { 28 | ulong h1 = Wy3Hash64.ComputeHash(BitConverter.GetBytes(val)); 29 | ulong h2 = Wy3Hash64.ComputeIndex(val); 30 | Assert.Equal(h1, h2); 31 | 32 | val <<= 1; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /Src/FastHash.Tests/Single/Xx2HashTests.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.XxHash; 2 | 3 | namespace Genbox.FastHash.Tests.Single; 4 | 5 | public class Xx2HashTests 6 | { 7 | private const uint PRIME32 = 2654435761U; 8 | private const ulong PRIME64 = 11400714785074694797UL; 9 | private readonly byte[] _sanityBuffer; 10 | 11 | //Source: https://github.com/Cyan4973/xxHash/blob/dev/cli/xsum_sanity_check.c#L99 12 | private static readonly (int len, uint seed, uint result)[] _testVectors32 = 13 | [ 14 | (0, 0, 0x02CC5D05U), 15 | (0, PRIME32, 0x36B78AE7U), 16 | (1, 0, 0xCF65B03EU), 17 | (1, PRIME32, 0xB4545AA4U), 18 | (14, 0, 0x1208E7E2U), 19 | (14, PRIME32, 0x6AF1D1FEU), 20 | (222, 0, 0x5BD11DBDU), 21 | (222, PRIME32, 0x58803C5FU) 22 | ]; 23 | 24 | private static readonly (int, uint, ulong)[] _testVectors64 = 25 | [ 26 | (0, 0, 0xEF46DB3751D8E999UL), 27 | (0, PRIME32, 0xAC75FDA2929B17EFUL), 28 | (1, 0, 0xE934A84ADB052768UL), 29 | (1, PRIME32, 0x5014607643A9B4C3UL), 30 | (4, 0, 0x9136A0DCA57457EEUL), 31 | (14, 0, 0x8282DCC4994E35C8UL), 32 | (14, PRIME32, 0xC3BD6BF63DEB6DF0UL), 33 | (222, 0, 0xB641AE8CB691C174UL), 34 | (222, PRIME32, 0x20CB8AB7AE10C14AUL) 35 | ]; 36 | 37 | public Xx2HashTests() 38 | { 39 | _sanityBuffer = new byte[2367]; 40 | 41 | ulong byteGen = PRIME32; 42 | for (int i = 0; i < _sanityBuffer.Length; i++) 43 | { 44 | _sanityBuffer[i] = (byte)(byteGen >> 56); 45 | byteGen = unchecked(byteGen * PRIME64); 46 | } 47 | } 48 | 49 | [Fact] 50 | public unsafe void Xx2Hash32TestVectors() 51 | { 52 | for (int i = 0; i < _testVectors32.Length; i++) 53 | { 54 | (int len, uint seed, uint result) = _testVectors32[i]; 55 | Assert.Equal(result, Xx2Hash32.ComputeHash(_sanityBuffer[..len], seed)); 56 | 57 | fixed (byte* ptr = _sanityBuffer[..len]) 58 | Assert.Equal(result, Xx2Hash32Unsafe.ComputeHash(ptr, len, seed)); 59 | } 60 | } 61 | 62 | [Fact] 63 | public unsafe void Xx2Hash64TestVectors() 64 | { 65 | for (int i = 0; i < _testVectors64.Length / 3; i++) 66 | { 67 | (int len, uint seed, ulong result) = _testVectors64[i]; 68 | Assert.Equal(Xx2Hash64.ComputeHash(_sanityBuffer[..len], seed), result); 69 | 70 | fixed (byte* ptr = _sanityBuffer[..len]) 71 | Assert.Equal(Xx2Hash64Unsafe.ComputeHash(ptr, len, seed), result); 72 | } 73 | } 74 | 75 | [Fact] 76 | public void Xx2HashIndexTest() 77 | { 78 | ulong val = 1ul; 79 | for (int i = 1; i <= 64; i++) 80 | { 81 | ulong h1 = Xx2Hash64.ComputeHash(BitConverter.GetBytes(val)); 82 | ulong h2 = Xx2Hash64.ComputeIndex(val); 83 | Assert.Equal(h1, h2); 84 | 85 | val <<= 1; 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /Src/FastHash/AesniHash/AesniHash128.cs: -------------------------------------------------------------------------------- 1 | #if NET8_0 2 | using System.Buffers.Binary; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.Intrinsics; 6 | using System.Runtime.Intrinsics.X86; 7 | 8 | namespace Genbox.FastHash.AesniHash; 9 | 10 | public static class AesniHash128 11 | { 12 | public static UInt128 ComputeHash(ReadOnlySpan data, uint seed = 0) 13 | { 14 | Vector128 res = Hash128(data, seed); 15 | return Unsafe.As, UInt128>(ref res); 16 | } 17 | 18 | [SuppressMessage("Major Code Smell", "S907:\"goto\" statement should not be used")] 19 | internal static Vector128 Hash128(ReadOnlySpan data, uint seed = 0) 20 | { 21 | uint len = (uint)data.Length; 22 | 23 | Vector128 a = Vector128.Create(seed).AsByte(); 24 | Vector128 b = Vector128.Create(len).AsByte(); 25 | 26 | Vector128 m = Vector128.Create(0x89abcdef, 0x01234567, 0xffff0000, 0xdeadbeef).AsByte(); 27 | Vector128 s = Vector128.Create((byte)12, 8, 4, 0, 13, 9, 5, 1, 14, 10, 6, 2, 15, 11, 7, 3); 28 | 29 | int msg = 0; 30 | 31 | if (len > 80) 32 | { 33 | Vector128 c = Aes.Encrypt(b, m); 34 | Vector128 d = Aes.Decrypt(a, m); 35 | a = Aes.Encrypt(a, m); 36 | b = Aes.Decrypt(b, m); 37 | 38 | do 39 | { 40 | a = Sse2.Xor(a, Vector128.Create(data[msg..])); 41 | b = Sse2.Xor(b, Vector128.Create(data[(msg + 16)..])); 42 | c = Sse2.Xor(c, Vector128.Create(data[(msg + 32)..])); 43 | d = Sse2.Xor(d, Vector128.Create(data[(msg + 48)..])); 44 | a = Ssse3.Shuffle(Aes.Encrypt(a, m), s); 45 | b = Ssse3.Shuffle(Aes.Decrypt(b, m), s); 46 | c = Ssse3.Shuffle(Aes.Encrypt(c, m), s); 47 | d = Ssse3.Shuffle(Aes.Decrypt(d, m), s); 48 | msg += 64; 49 | len -= 64; 50 | } while (len > 80); 51 | 52 | c = Aes.Encrypt(a, c); 53 | d = Aes.Decrypt(b, d); 54 | a = Aes.Encrypt(c, d); 55 | b = Aes.Decrypt(d, c); 56 | } 57 | 58 | while (len >= 16) 59 | { 60 | Mix(Vector128.Create(data[msg..])); 61 | msg += 16; 62 | len -= 16; 63 | } 64 | 65 | ulong x = 0; 66 | switch (len) 67 | { 68 | case 15: 69 | x |= (ulong)data[msg + 14] << 48; 70 | goto case 14; 71 | case 14: 72 | x |= (ulong)data[msg + 13] << 40; 73 | goto case 13; 74 | case 13: 75 | x |= (ulong)data[msg + 12] << 32; 76 | goto case 12; 77 | case 12: 78 | x |= BinaryPrimitives.ReadUInt32LittleEndian(data[(msg + 8)..]); 79 | Mix(Vector128.Create(BinaryPrimitives.ReadUInt64LittleEndian(data[msg..]), x).AsByte()); 80 | break; 81 | case 11: 82 | x |= (uint)data[msg + 10] << 16; 83 | goto case 10; 84 | case 10: 85 | x |= (uint)data[msg + 9] << 8; 86 | goto case 9; 87 | case 9: 88 | x |= data[msg + 8]; 89 | goto case 8; 90 | case 8: 91 | Mix(Vector128.Create(BinaryPrimitives.ReadUInt64LittleEndian(data), x).AsByte()); 92 | break; 93 | case 7: 94 | x |= (ulong)data[msg + 4] << 48; 95 | goto case 6; 96 | case 6: 97 | x |= (ulong)data[msg + 4] << 40; 98 | goto case 5; 99 | case 5: 100 | x |= (ulong)data[msg + 4] << 32; 101 | goto case 4; 102 | case 4: 103 | x |= BinaryPrimitives.ReadUInt32LittleEndian(data[msg..]); 104 | Mix(Vector128.Create(x, 0).AsByte()); 105 | break; 106 | case 3: 107 | x |= (uint)data[msg + 2] << 16; 108 | goto case 2; 109 | case 2: 110 | x |= (uint)data[msg + 1] << 8; 111 | goto case 1; 112 | case 1: 113 | x |= data[msg]; 114 | Mix(Vector128.Create(x, 0).AsByte()); 115 | break; 116 | default: // try to keep m & s from register spilling 117 | a = Sse2.Add(a, s); 118 | b = Sse2.Add(b, m); 119 | break; 120 | } 121 | 122 | return Aes.Encrypt(a, b); 123 | 124 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 125 | void Mix(Vector128 x2) 126 | { 127 | a = Aes.Encrypt(x2, a); 128 | a = Aes.Encrypt(a, m); 129 | b = Ssse3.Shuffle(Sse2.Xor(x2, b), s); 130 | b = Ssse3.Shuffle(Aes.Decrypt(b, m), s); 131 | } 132 | } 133 | } 134 | #endif -------------------------------------------------------------------------------- /Src/FastHash/AesniHash/AesniHash64.cs: -------------------------------------------------------------------------------- 1 | #if NET8_0 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.Intrinsics; 4 | 5 | namespace Genbox.FastHash.AesniHash; 6 | 7 | public static class AesniHash64 8 | { 9 | public static ulong ComputeHash(ReadOnlySpan data, uint seed = 0) 10 | { 11 | Vector128 res = AesniHash128.Hash128(data, seed); 12 | return Unsafe.As, ulong>(ref res); 13 | } 14 | } 15 | #endif -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHash128.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.CityHash.CityHashShared; 2 | using static Genbox.FastHash.CityHash.CityHashConstants; 3 | 4 | namespace Genbox.FastHash.CityHash; 5 | 6 | public static class CityHash128 7 | { 8 | public static UInt128 ComputeHash(ReadOnlySpan data) 9 | { 10 | uint len = (uint)data.Length; 11 | 12 | if (len >= 16) 13 | { 14 | UInt128 seed = new UInt128(Read64(data), Read64(data, 8) + K0); 15 | return CityHash128WithSeed(data.Slice(16, (int)(len - 16)), len - 16, seed); 16 | } 17 | 18 | return CityHash128WithSeed(data, len, new UInt128(K0, K1)); 19 | } 20 | 21 | public static UInt128 ComputeHash(ReadOnlySpan data, UInt128 seed) => CityHash128WithSeed(data, (uint)data.Length, seed); 22 | 23 | // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings 24 | // of any length representable in signed long. Based on City and Murmur. 25 | private static UInt128 CityMurmur(ReadOnlySpan s, uint len, UInt128 seed) 26 | { 27 | ulong a = seed.Low; 28 | ulong b = seed.High; 29 | ulong c = 0; 30 | ulong d = 0; 31 | if (len <= 16) 32 | { 33 | a = ShiftMix(a * K1) * K1; 34 | c = (b * K1) + HashLen0to16(s, len); 35 | d = ShiftMix(a + (len >= 8 ? Read64(s) : c)); 36 | } 37 | else 38 | { 39 | c = HashLen16(Read64(s, len - 8) + K1, a); 40 | d = HashLen16(b + len, c + Read64(s, len - 16)); 41 | a += d; 42 | // len > 16 here, so do...while is safe 43 | uint offset = 0; 44 | do 45 | { 46 | a ^= ShiftMix(Read64(s, offset) * K1) * K1; 47 | a *= K1; 48 | b ^= a; 49 | c ^= ShiftMix(Read64(s, offset + 8) * K1) * K1; 50 | c *= K1; 51 | d ^= c; 52 | offset += 16; 53 | len -= 16; 54 | } while (len > 16); 55 | } 56 | a = HashLen16(a, c); 57 | b = HashLen16(d, b); 58 | return new UInt128(a ^ b, HashLen16(b, a)); 59 | } 60 | 61 | private static UInt128 CityHash128WithSeed(ReadOnlySpan s, uint len, UInt128 seed) 62 | { 63 | if (len < 128) 64 | return CityMurmur(s, len, seed); 65 | 66 | // We expect len >= 128 to be the common case. Keep 56 bytes of state: 67 | // v, w, x, y, and z. 68 | UInt128 v, w; 69 | ulong x = seed.Low; 70 | ulong y = seed.High; 71 | ulong z = len * K1; 72 | v.Low = (RotateRight(y ^ K1, 49) * K1) + Read64(s); 73 | v.High = (RotateRight(v.Low, 42) * K1) + Read64(s, 8); 74 | w.Low = (RotateRight(y + z, 35) * K1) + x; 75 | w.High = RotateRight(x + Read64(s, 88), 53) * K1; 76 | 77 | // This is the same inner loop as CityHash64(), manually unrolled. 78 | uint offset = 0; 79 | do 80 | { 81 | x = RotateRight(x + y + v.Low + Read64(s, offset + 8), 37) * K1; 82 | y = RotateRight(y + v.High + Read64(s, offset + 48), 42) * K1; 83 | x ^= w.High; 84 | y += v.Low + Read64(s, offset + 40); 85 | z = RotateRight(z + w.Low, 33) * K1; 86 | v = WeakHashLen32WithSeeds(s, offset + 0, v.High * K1, x + w.Low); 87 | w = WeakHashLen32WithSeeds(s, offset + 32, z + w.High, y + Read64(s, offset + 16)); 88 | Swap(ref z, ref x); 89 | offset += 64; 90 | x = RotateRight(x + y + v.Low + Read64(s, offset + 8), 37) * K1; 91 | y = RotateRight(y + v.High + Read64(s, offset + 48), 42) * K1; 92 | x ^= w.High; 93 | y += v.Low + Read64(s, offset + 40); 94 | z = RotateRight(z + w.Low, 33) * K1; 95 | v = WeakHashLen32WithSeeds(s, offset, v.High * K1, x + w.Low); 96 | w = WeakHashLen32WithSeeds(s, offset + 32, z + w.High, y + Read64(s, offset + 16)); 97 | Swap(ref z, ref x); 98 | offset += 64; 99 | len -= 128; 100 | } while (len >= 128); 101 | x += RotateRight(v.Low + z, 49) * K0; 102 | y = (y * K0) + RotateRight(w.High, 37); 103 | z = (z * K0) + RotateRight(w.Low, 27); 104 | w.Low *= 9; 105 | v.Low *= K0; 106 | // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. 107 | for (uint tail_done = 0; tail_done < len;) 108 | { 109 | tail_done += 32; 110 | y = (RotateRight(x + y, 42) * K0) + v.High; 111 | w.Low += Read64(s, offset + len - tail_done + 16); 112 | x = (x * K0) + w.Low; 113 | z += w.High + Read64(s, offset + len - tail_done); 114 | w.High += v.Low; 115 | v = WeakHashLen32WithSeeds(s, offset + len - tail_done, v.Low + z, v.High); 116 | v.Low *= K0; 117 | } 118 | // At this point our 56 bytes of state should contain more than 119 | // enough information for a strong 128-bit hash. We use two 120 | // different 56-byte-to-8-byte hashes to get a 16-byte final result. 121 | x = HashLen16(x, v.Low); 122 | y = HashLen16(y + z, w.Low); 123 | return new UInt128(HashLen16(x + v.High, w.High) + y, HashLen16(x + w.High, y + v.High)); 124 | } 125 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHash128Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.CityHash.CityHashShared; 2 | using static Genbox.FastHash.CityHash.CityHashUnsafeShared; 3 | using static Genbox.FastHash.CityHash.CityHashConstants; 4 | 5 | namespace Genbox.FastHash.CityHash; 6 | 7 | public static class CityHash128Unsafe 8 | { 9 | public static unsafe UInt128 ComputeHash(byte* data, int length) 10 | { 11 | uint len = (uint)length; 12 | if (len >= 16) 13 | { 14 | UInt128 seed = new UInt128(Read64(data), Read64(data + 8) + K0); 15 | return CityHash128WithSeed(data + 16, len - 16, seed); 16 | } 17 | 18 | return CityHash128WithSeed(data, len, new UInt128(K0, K1)); 19 | } 20 | 21 | public static unsafe UInt128 ComputeHash(byte* data, int length, UInt128 seed) 22 | { 23 | uint len = (uint)length; 24 | return CityHash128WithSeed(data, len, seed); 25 | } 26 | 27 | // A subroutine for CityHash128(). Returns a decent 128-bit hash for strings 28 | // of any length representable in signed long. Based on City and Murmur. 29 | private static unsafe UInt128 CityMurmur(byte* s, uint len, UInt128 seed) 30 | { 31 | ulong a = seed.Low; 32 | ulong b = seed.High; 33 | ulong c = 0; 34 | ulong d = 0; 35 | if (len <= 16) 36 | { 37 | a = ShiftMix(a * K1) * K1; 38 | c = (b * K1) + HashLen0to16(s, len); 39 | d = ShiftMix(a + (len >= 8 ? Read64(s) : c)); 40 | } 41 | else 42 | { 43 | c = HashLen16(Read64(s + len - 8) + K1, a); 44 | d = HashLen16(b + len, c + Read64(s + len - 16)); 45 | a += d; 46 | // len > 16 here, so do...while is safe 47 | do 48 | { 49 | a ^= ShiftMix(Read64(s) * K1) * K1; 50 | a *= K1; 51 | b ^= a; 52 | c ^= ShiftMix(Read64(s + 8) * K1) * K1; 53 | c *= K1; 54 | d ^= c; 55 | s += 16; 56 | len -= 16; 57 | } while (len > 16); 58 | } 59 | a = HashLen16(a, c); 60 | b = HashLen16(d, b); 61 | return new UInt128(a ^ b, HashLen16(b, a)); 62 | } 63 | 64 | private static unsafe UInt128 CityHash128WithSeed(byte* s, uint len, UInt128 seed) 65 | { 66 | if (len < 128) 67 | return CityMurmur(s, len, seed); 68 | 69 | // We expect len >= 128 to be the common case. Keep 56 bytes of state: 70 | // v, w, x, y, and z. 71 | UInt128 v, w; 72 | ulong x = seed.Low; 73 | ulong y = seed.High; 74 | ulong z = len * K1; 75 | v.Low = (RotateRight(y ^ K1, 49) * K1) + Read64(s); 76 | v.High = (RotateRight(v.Low, 42) * K1) + Read64(s + 8); 77 | w.Low = (RotateRight(y + z, 35) * K1) + x; 78 | w.High = RotateRight(x + Read64(s + 88), 53) * K1; 79 | 80 | // This is the same inner loop as CityHash64(), manually unrolled. 81 | do 82 | { 83 | x = RotateRight(x + y + v.Low + Read64(s + 8), 37) * K1; 84 | y = RotateRight(y + v.High + Read64(s + 48), 42) * K1; 85 | x ^= w.High; 86 | y += v.Low + Read64(s + 40); 87 | z = RotateRight(z + w.Low, 33) * K1; 88 | v = WeakHashLen32WithSeeds(s, v.High * K1, x + w.Low); 89 | w = WeakHashLen32WithSeeds(s + 32, z + w.High, y + Read64(s + 16)); 90 | Swap(ref z, ref x); 91 | s += 64; 92 | x = RotateRight(x + y + v.Low + Read64(s + 8), 37) * K1; 93 | y = RotateRight(y + v.High + Read64(s + 48), 42) * K1; 94 | x ^= w.High; 95 | y += v.Low + Read64(s + 40); 96 | z = RotateRight(z + w.Low, 33) * K1; 97 | v = WeakHashLen32WithSeeds(s, v.High * K1, x + w.Low); 98 | w = WeakHashLen32WithSeeds(s + 32, z + w.High, y + Read64(s + 16)); 99 | Swap(ref z, ref x); 100 | s += 64; 101 | len -= 128; 102 | } while (len >= 128); 103 | x += RotateRight(v.Low + z, 49) * K0; 104 | y = (y * K0) + RotateRight(w.High, 37); 105 | z = (z * K0) + RotateRight(w.Low, 27); 106 | w.Low *= 9; 107 | v.Low *= K0; 108 | // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. 109 | for (uint tail_done = 0; tail_done < len;) 110 | { 111 | tail_done += 32; 112 | y = (RotateRight(x + y, 42) * K0) + v.High; 113 | w.Low += Read64(s + len - tail_done + 16); 114 | x = (x * K0) + w.Low; 115 | z += w.High + Read64(s + len - tail_done); 116 | w.High += v.Low; 117 | v = WeakHashLen32WithSeeds(s + len - tail_done, v.Low + z, v.High); 118 | v.Low *= K0; 119 | } 120 | // At this point our 56 bytes of state should contain more than 121 | // enough information for a strong 128-bit hash. We use two 122 | // different 56-byte-to-8-byte hashes to get a 16-byte final result. 123 | x = HashLen16(x, v.Low); 124 | y = HashLen16(y + z, w.Low); 125 | return new UInt128(HashLen16(x + v.High, w.High) + y, HashLen16(x + w.High, y + v.High)); 126 | } 127 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.CityHash.CityHashShared; 3 | using static Genbox.FastHash.CityHash.CityHashConstants; 4 | 5 | namespace Genbox.FastHash.CityHash; 6 | 7 | public static class CityHash32 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static uint ComputeIndex(uint input) 11 | { 12 | uint b = (uint)(sbyte)(input & 0xFF); 13 | uint c = 9 ^ b; 14 | 15 | b = (b * C1) + (uint)(sbyte)((input >> 8) & 0xFF); 16 | c ^= b; 17 | 18 | b = (b * C1) + (uint)(sbyte)((input >> 16) & 0xFF); 19 | c ^= b; 20 | 21 | b = (b * C1) + (uint)(sbyte)((input >> 24) & 0xFF); 22 | c ^= b; 23 | return AA_xmxmx_Murmur_32(Mur(b, Mur(4, c))); 24 | } 25 | 26 | public static uint ComputeHash(ReadOnlySpan data) 27 | { 28 | uint len = (uint)data.Length; 29 | 30 | if (len <= 24) 31 | return len <= 12 ? len <= 4 ? Hash32Len0to4(data, len) : Hash32Len5to12(data, len) : Hash32Len13to24(data, len); 32 | 33 | // len > 24 34 | uint h = len, g = C1 * h, f = g; 35 | uint a0 = RotateRight(Read32(data, len - 4) * C1, 17) * C2; 36 | uint a1 = RotateRight(Read32(data, len - 8) * C1, 17) * C2; 37 | uint a2 = RotateRight(Read32(data, len - 16) * C1, 17) * C2; 38 | uint a3 = RotateRight(Read32(data, len - 12) * C1, 17) * C2; 39 | uint a4 = RotateRight(Read32(data, len - 20) * C1, 17) * C2; 40 | h ^= a0; 41 | h = RotateRight(h, 19); 42 | h = (h * 5) + 0xe6546b64; 43 | h ^= a2; 44 | h = RotateRight(h, 19); 45 | h = (h * 5) + 0xe6546b64; 46 | g ^= a1; 47 | g = RotateRight(g, 19); 48 | g = (g * 5) + 0xe6546b64; 49 | g ^= a3; 50 | g = RotateRight(g, 19); 51 | g = (g * 5) + 0xe6546b64; 52 | f += a4; 53 | f = RotateRight(f, 19); 54 | f = (f * 5) + 0xe6546b64; 55 | uint iters = (len - 1) / 20; 56 | uint offset = 0; 57 | do 58 | { 59 | a0 = RotateRight(Read32(data, offset) * C1, 17) * C2; 60 | a1 = Read32(data, offset + 4); 61 | a2 = RotateRight(Read32(data, offset + 8) * C1, 17) * C2; 62 | a3 = RotateRight(Read32(data, offset + 12) * C1, 17) * C2; 63 | a4 = Read32(data, offset + 16); 64 | h ^= a0; 65 | h = RotateRight(h, 18); 66 | h = (h * 5) + 0xe6546b64; 67 | f += a1; 68 | f = RotateRight(f, 19); 69 | f = f * C1; 70 | g += a2; 71 | g = RotateRight(g, 18); 72 | g = (g * 5) + 0xe6546b64; 73 | h ^= a3 + a1; 74 | h = RotateRight(h, 19); 75 | h = (h * 5) + 0xe6546b64; 76 | g ^= a4; 77 | g = ByteSwap(g) * 5; 78 | h += a4 * 5; 79 | h = ByteSwap(h); 80 | f += a0; 81 | Permute3(ref f, ref h, ref g); 82 | offset += 20; 83 | } while (--iters != 0); 84 | g = RotateRight(g, 11) * C1; 85 | g = RotateRight(g, 17) * C1; 86 | f = RotateRight(f, 11) * C1; 87 | f = RotateRight(f, 17) * C1; 88 | h = RotateRight(h + g, 19); 89 | h = (h * 5) + 0xe6546b64; 90 | h = RotateRight(h, 17) * C1; 91 | h = RotateRight(h + f, 19); 92 | h = (h * 5) + 0xe6546b64; 93 | h = RotateRight(h, 17) * C1; 94 | return h; 95 | } 96 | 97 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 98 | internal static uint Hash32Len0to4(ReadOnlySpan s, uint len) 99 | { 100 | uint b = 0; 101 | uint c = 9; 102 | for (int i = 0; i < len; i++) 103 | { 104 | uint v = (uint)(sbyte)s[i]; 105 | b = (b * C1) + v; 106 | c ^= b; 107 | } 108 | return AA_xmxmx_Murmur_32(Mur(b, Mur(len, c))); 109 | } 110 | 111 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 112 | internal static uint Hash32Len5to12(ReadOnlySpan s, uint len) 113 | { 114 | uint a = len, b = a * 5, c = 9, d = b; 115 | a += Read32(s); 116 | b += Read32(s, len - 4); 117 | c += Read32(s, (len >> 1) & 4); 118 | return AA_xmxmx_Murmur_32(Mur(c, Mur(b, Mur(a, d)))); 119 | } 120 | 121 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 122 | internal static uint Hash32Len13to24(ReadOnlySpan s, uint len) 123 | { 124 | uint a = Read32(s, (len >> 1) - 4); 125 | uint b = Read32(s, 4); 126 | uint c = Read32(s, len - 8); 127 | uint d = Read32(s, len >> 1); 128 | uint e = Read32(s); 129 | uint f = Read32(s, len - 4); 130 | uint h = len; 131 | 132 | return AA_xmxmx_Murmur_32(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h))))))); 133 | } 134 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHash32Unsafe.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.CityHash.CityHashShared; 3 | using static Genbox.FastHash.CityHash.CityHashConstants; 4 | 5 | namespace Genbox.FastHash.CityHash; 6 | 7 | public static class CityHash32Unsafe 8 | { 9 | public static unsafe uint ComputeHash(byte* data, int length) 10 | { 11 | uint len = (uint)length; 12 | 13 | if (len <= 24) 14 | return len <= 12 ? len <= 4 ? Hash32Len0to4(data, len) : Hash32Len5to12(data, len) : Hash32Len13to24(data, len); 15 | 16 | // len > 24 17 | uint h = len, g = C1 * h, f = g; 18 | uint a0 = RotateRight(Read32(data + len - 4) * C1, 17) * C2; 19 | uint a1 = RotateRight(Read32(data + len - 8) * C1, 17) * C2; 20 | uint a2 = RotateRight(Read32(data + len - 16) * C1, 17) * C2; 21 | uint a3 = RotateRight(Read32(data + len - 12) * C1, 17) * C2; 22 | uint a4 = RotateRight(Read32(data + len - 20) * C1, 17) * C2; 23 | h ^= a0; 24 | h = RotateRight(h, 19); 25 | h = (h * 5) + 0xe6546b64; 26 | h ^= a2; 27 | h = RotateRight(h, 19); 28 | h = (h * 5) + 0xe6546b64; 29 | g ^= a1; 30 | g = RotateRight(g, 19); 31 | g = (g * 5) + 0xe6546b64; 32 | g ^= a3; 33 | g = RotateRight(g, 19); 34 | g = (g * 5) + 0xe6546b64; 35 | f += a4; 36 | f = RotateRight(f, 19); 37 | f = (f * 5) + 0xe6546b64; 38 | uint iters = (len - 1) / 20; 39 | do 40 | { 41 | a0 = RotateRight(Read32(data) * C1, 17) * C2; 42 | a1 = Read32(data + 4); 43 | a2 = RotateRight(Read32(data + 8) * C1, 17) * C2; 44 | a3 = RotateRight(Read32(data + 12) * C1, 17) * C2; 45 | a4 = Read32(data + 16); 46 | h ^= a0; 47 | h = RotateRight(h, 18); 48 | h = (h * 5) + 0xe6546b64; 49 | f += a1; 50 | f = RotateRight(f, 19); 51 | f = f * C1; 52 | g += a2; 53 | g = RotateRight(g, 18); 54 | g = (g * 5) + 0xe6546b64; 55 | h ^= a3 + a1; 56 | h = RotateRight(h, 19); 57 | h = (h * 5) + 0xe6546b64; 58 | g ^= a4; 59 | g = ByteSwap(g) * 5; 60 | h += a4 * 5; 61 | h = ByteSwap(h); 62 | f += a0; 63 | Permute3(ref f, ref h, ref g); 64 | data += 20; 65 | } while (--iters != 0); 66 | g = RotateRight(g, 11) * C1; 67 | g = RotateRight(g, 17) * C1; 68 | f = RotateRight(f, 11) * C1; 69 | f = RotateRight(f, 17) * C1; 70 | h = RotateRight(h + g, 19); 71 | h = (h * 5) + 0xe6546b64; 72 | h = RotateRight(h, 17) * C1; 73 | h = RotateRight(h + f, 19); 74 | h = (h * 5) + 0xe6546b64; 75 | h = RotateRight(h, 17) * C1; 76 | return h; 77 | } 78 | 79 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 80 | internal static unsafe uint Hash32Len0to4(byte* s, uint len) 81 | { 82 | uint b = 0; 83 | uint c = 9; 84 | for (int i = 0; i < len; i++) 85 | { 86 | uint v = (uint)(sbyte)*(s + i); 87 | b = (b * C1) + v; 88 | c ^= b; 89 | } 90 | return AA_xmxmx_Murmur_32(Mur(b, Mur(len, c))); 91 | } 92 | 93 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 94 | internal static unsafe uint Hash32Len5to12(byte* s, uint len) 95 | { 96 | uint a = len, b = len * 5, c = 9, d = b; 97 | a += Read32(s); 98 | b += Read32(s + len - 4); 99 | c += Read32(s + ((len >> 1) & 4)); 100 | return AA_xmxmx_Murmur_32(Mur(c, Mur(b, Mur(a, d)))); 101 | } 102 | 103 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 104 | internal static unsafe uint Hash32Len13to24(byte* s, uint len) 105 | { 106 | uint a = Read32(s - 4 + (len >> 1)); 107 | uint b = Read32(s + 4); 108 | uint c = Read32(s + len - 8); 109 | uint d = Read32(s + (len >> 1)); 110 | uint e = Read32(s); 111 | uint f = Read32(s + len - 4); 112 | uint h = len; 113 | 114 | return AA_xmxmx_Murmur_32(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h))))))); 115 | } 116 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHash64.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.CityHash.CityHashShared; 3 | using static Genbox.FastHash.CityHash.CityHashConstants; 4 | 5 | namespace Genbox.FastHash.CityHash; 6 | 7 | public static class CityHash64 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static ulong ComputeIndex(ulong input) 11 | { 12 | const ulong mul = K2 + 16; 13 | ulong d = (RotateRight(input + K2, 25) + input) * mul; 14 | ulong a = (((RotateRight(input, 37) * mul) + input + K2) ^ d) * mul; 15 | a ^= a >> 47; 16 | ulong b = (d ^ a) * mul; 17 | b ^= b >> 47; 18 | b *= mul; 19 | return b; 20 | } 21 | 22 | public static ulong ComputeHash(ReadOnlySpan data) => CityHash64Internal(data); 23 | 24 | public static ulong ComputeHash(ReadOnlySpan data, ulong seed) => CityHash64WithSeeds(data, K2, seed); 25 | 26 | public static ulong ComputeHash(ReadOnlySpan data, ulong seed1, ulong seed2) => CityHash64WithSeeds(data, seed1, seed2); 27 | 28 | private static ulong CityHash64Internal(ReadOnlySpan s) 29 | { 30 | uint len = (uint)s.Length; 31 | 32 | if (len <= 32) 33 | { 34 | if (len <= 16) 35 | return HashLen0to16(s, len); 36 | return HashLen17to32(s, len); 37 | } 38 | if (len <= 64) 39 | return HashLen33to64(s, len); 40 | 41 | // For strings over 64 bytes we hash the end first, and then as we 42 | // loop we keep 56 bytes of state: v, w, x, y, and z. 43 | ulong x = Read64(s, len - 40); 44 | ulong y = Read64(s, len - 16) + Read64(s, len - 56); 45 | ulong z = HashLen16(Read64(s, len - 48) + len, Read64(s, len - 24)); 46 | UInt128 v = WeakHashLen32WithSeeds(s, len - 64, len, z); 47 | UInt128 w = WeakHashLen32WithSeeds(s, len - 32, y + K1, x); 48 | x = (x * K1) + Read64(s); 49 | 50 | // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. 51 | len = (len - 1) & ~63u; 52 | uint offset = 0; 53 | do 54 | { 55 | x = RotateRight(x + y + v.Low + Read64(s, offset + 8), 37) * K1; 56 | y = RotateRight(y + v.High + Read64(s, offset + 48), 42) * K1; 57 | x ^= w.High; 58 | y += v.Low + Read64(s, offset + 40); 59 | z = RotateRight(z + w.Low, 33) * K1; 60 | v = WeakHashLen32WithSeeds(s, offset, v.High * K1, x + w.Low); 61 | w = WeakHashLen32WithSeeds(s, offset + 32, z + w.High, y + Read64(s, offset + 16)); 62 | Swap(ref z, ref x); 63 | offset += 64; 64 | len -= 64; 65 | } while (len != 0); 66 | return HashLen16(HashLen16(v.Low, w.Low) + (ShiftMix(y) * K1) + z, HashLen16(v.High, w.High) + x); 67 | } 68 | 69 | private static ulong CityHash64WithSeeds(ReadOnlySpan s, ulong seed0, ulong seed1) => HashLen16(CityHash64Internal(s) - seed0, seed1); 70 | 71 | // This probably works well for 16-byte strings as well, but it may be overkill in that case. 72 | private static ulong HashLen17to32(ReadOnlySpan s, uint len) 73 | { 74 | ulong mul = K2 + (len * 2); 75 | ulong a = Read64(s) * K1; 76 | ulong b = Read64(s, 8); 77 | ulong c = Read64(s, len - 8) * mul; 78 | ulong d = Read64(s, len - 16) * K2; 79 | return HashLen16(RotateRight(a + b, 43) + RotateRight(c, 30) + d, a + RotateRight(b + K2, 18) + c, mul); 80 | } 81 | 82 | // Return an 8-byte hash for 33 to 64 bytes. 83 | private static ulong HashLen33to64(ReadOnlySpan s, uint len) 84 | { 85 | ulong mul = K2 + (len * 2); 86 | ulong a = Read64(s) * K2; 87 | ulong b = Read64(s, 8); 88 | ulong c = Read64(s, len - 24); 89 | ulong d = Read64(s, len - 32); 90 | ulong e = Read64(s, 16) * K2; 91 | ulong f = Read64(s, 24) * 9; 92 | ulong g = Read64(s, len - 8); 93 | ulong h = Read64(s, len - 16) * mul; 94 | ulong u = RotateRight(a + g, 43) + ((RotateRight(b, 30) + c) * 9); 95 | ulong v = ((a + g) ^ d) + f + 1; 96 | ulong w = ByteSwap((u + v) * mul) + h; 97 | ulong x = RotateRight(e + f, 42) + c; 98 | ulong y = (ByteSwap((v + w) * mul) + g) * mul; 99 | ulong z = e + f + c; 100 | a = ByteSwap(((x + z) * mul) + y) + b; 101 | b = ShiftMix(((z + a) * mul) + d + h) * mul; 102 | return b + x; 103 | } 104 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.CityHash.CityHashShared; 2 | using static Genbox.FastHash.CityHash.CityHashUnsafeShared; 3 | using static Genbox.FastHash.CityHash.CityHashConstants; 4 | 5 | namespace Genbox.FastHash.CityHash; 6 | 7 | public static class CityHash64Unsafe 8 | { 9 | public static unsafe ulong ComputeHash(byte* data, int length) 10 | { 11 | uint len = (uint)length; 12 | return CityHash64(data, len); 13 | } 14 | 15 | public static unsafe ulong ComputeHash(byte* data, int length, ulong seed) 16 | { 17 | uint len = (uint)length; 18 | return CityHash64WithSeeds(data, len, K2, seed); 19 | } 20 | 21 | public static unsafe ulong ComputeHash(byte* data, int length, ulong seed1, ulong seed2) 22 | { 23 | uint len = (uint)length; 24 | return CityHash64WithSeeds(data, len, seed1, seed2); 25 | } 26 | 27 | private static unsafe ulong CityHash64(byte* s, uint len) 28 | { 29 | if (len <= 32) 30 | { 31 | if (len <= 16) 32 | return HashLen0to16(s, len); 33 | return HashLen17to32(s, len); 34 | } 35 | if (len <= 64) 36 | return HashLen33to64(s, len); 37 | 38 | // For strings over 64 bytes we hash the end first, and then as we 39 | // loop we keep 56 bytes of state: v, w, x, y, and z. 40 | ulong x = Read64(s + len - 40); 41 | ulong y = Read64(s + len - 16) + Read64(s + len - 56); 42 | ulong z = HashLen16(Read64(s + len - 48) + len, Read64(s + len - 24)); 43 | UInt128 v = WeakHashLen32WithSeeds(s + len - 64, len, z); 44 | UInt128 w = WeakHashLen32WithSeeds(s + len - 32, y + K1, x); 45 | x = (x * K1) + Read64(s); 46 | 47 | // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. 48 | len = (len - 1) & ~63u; 49 | do 50 | { 51 | x = RotateRight(x + y + v.Low + Read64(s + 8), 37) * K1; 52 | y = RotateRight(y + v.High + Read64(s + 48), 42) * K1; 53 | x ^= w.High; 54 | y += v.Low + Read64(s + 40); 55 | z = RotateRight(z + w.Low, 33) * K1; 56 | v = WeakHashLen32WithSeeds(s, v.High * K1, x + w.Low); 57 | w = WeakHashLen32WithSeeds(s + 32, z + w.High, y + Read64(s + 16)); 58 | Swap(ref z, ref x); 59 | s += 64; 60 | len -= 64; 61 | } while (len != 0); 62 | return HashLen16(HashLen16(v.Low, w.Low) + (ShiftMix(y) * K1) + z, HashLen16(v.High, w.High) + x); 63 | } 64 | 65 | private static unsafe ulong CityHash64WithSeeds(byte* s, uint len, ulong seed0, ulong seed1) => HashLen16(CityHash64(s, len) - seed0, seed1); 66 | 67 | // This probably works well for 16-byte strings as well, but it may be overkill in that case. 68 | private static unsafe ulong HashLen17to32(byte* s, uint len) 69 | { 70 | ulong mul = K2 + (len * 2); 71 | ulong a = Read64(s) * K1; 72 | ulong b = Read64(s + 8); 73 | ulong c = Read64(s + len - 8) * mul; 74 | ulong d = Read64(s + len - 16) * K2; 75 | return HashLen16(RotateRight(a + b, 43) + RotateRight(c, 30) + d, a + RotateRight(b + K2, 18) + c, mul); 76 | } 77 | 78 | // Return an 8-byte hash for 33 to 64 bytes. 79 | private static unsafe ulong HashLen33to64(byte* s, uint len) 80 | { 81 | ulong mul = K2 + (len * 2); 82 | ulong a = Read64(s) * K2; 83 | ulong b = Read64(s + 8); 84 | ulong c = Read64(s + len - 24); 85 | ulong d = Read64(s + len - 32); 86 | ulong e = Read64(s + 16) * K2; 87 | ulong f = Read64(s + 24) * 9; 88 | ulong g = Read64(s + len - 8); 89 | ulong h = Read64(s + len - 16) * mul; 90 | ulong u = RotateRight(a + g, 43) + ((RotateRight(b, 30) + c) * 9); 91 | ulong v = ((a + g) ^ d) + f + 1; 92 | ulong w = ByteSwap((u + v) * mul) + h; 93 | ulong x = RotateRight(e + f, 42) + c; 94 | ulong y = (ByteSwap((v + w) * mul) + g) * mul; 95 | ulong z = e + f + c; 96 | a = ByteSwap(((x + z) * mul) + y) + b; 97 | b = ShiftMix(((z + a) * mul) + d + h) * mul; 98 | return b + x; 99 | } 100 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.CityHash; 2 | 3 | internal static class CityHashConstants 4 | { 5 | // Some primes between 2^63 and 2^64 for various uses. 6 | internal const ulong K0 = 0xc3a5c85c97cb3127UL; 7 | internal const ulong K1 = 0xb492b66fbe98f273UL; 8 | internal const ulong K2 = 0x9ae16a3b2f90404fUL; 9 | 10 | // Magic numbers for 32-bit hashing. Copied from Murmur3. 11 | internal const uint C1 = 0xcc9e2d51; 12 | internal const uint C2 = 0x1b873593; 13 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHashShared.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.CityHash.CityHashConstants; 3 | 4 | namespace Genbox.FastHash.CityHash; 5 | 6 | internal static class CityHashShared 7 | { 8 | internal static ulong HashLen0to16(ReadOnlySpan s, uint len) 9 | { 10 | if (len >= 8) 11 | { 12 | ulong mul = K2 + (len * 2); 13 | ulong a = Read64(s) + K2; 14 | ulong b = Read64(s, len - 8); 15 | ulong c = (RotateRight(b, 37) * mul) + a; 16 | ulong d = (RotateRight(a, 25) + b) * mul; 17 | return HashLen16(c, d, mul); 18 | } 19 | if (len >= 4) 20 | { 21 | ulong mul = K2 + (len * 2); 22 | ulong a = Read32(s); 23 | return HashLen16(len + (a << 3), Read32(s, len - 4), mul); 24 | } 25 | if (len > 0) 26 | { 27 | byte a = s[0]; 28 | byte b = s[(int)(len >> 1)]; 29 | byte c = s[(int)(len - 1)]; 30 | uint y = a + ((uint)b << 8); 31 | uint z = len + ((uint)c << 2); 32 | return ShiftMix((y * K2) ^ (z * K0)) * K2; 33 | } 34 | return K2; 35 | } 36 | 37 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 38 | internal static uint Mur(uint a, uint h) 39 | { 40 | // Helper from Murmur3 for combining two 32-bit values. 41 | 42 | //IQV: The rotate constants are different than murmur 43 | a *= C1; 44 | a = RotateRight(a, 17); 45 | a *= C2; 46 | h ^= a; 47 | h = RotateRight(h, 19); 48 | return (h * 5) + 0xe6546b64; 49 | } 50 | 51 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 52 | internal static ulong ShiftMix(ulong val) => val ^ (val >> 47); 53 | 54 | // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. 55 | internal static UInt128 WeakHashLen32WithSeeds(ReadOnlySpan s, uint offset, ulong a, ulong b) 56 | { 57 | return WeakHashLen32WithSeeds(Read64(s, offset), 58 | Read64(s, offset + 8), 59 | Read64(s, offset + 16), 60 | Read64(s, offset + 24), 61 | a, 62 | b); 63 | } 64 | 65 | // Return a 16-byte hash for 48 bytes. Quick and dirty. 66 | // Callers do best to use "random-looking" values for a and b. 67 | internal static UInt128 WeakHashLen32WithSeeds(ulong w, ulong x, ulong y, ulong z, ulong a, ulong b) 68 | { 69 | a += w; 70 | b = RotateRight(b + a + z, 21); 71 | ulong c = a; 72 | a += x; 73 | a += y; 74 | b += RotateRight(a, 44); 75 | return new UInt128(a + z, b + c); 76 | } 77 | 78 | internal static void Permute3(ref T a, ref T b, ref T c) 79 | { 80 | Swap(ref a, ref b); 81 | Swap(ref a, ref c); 82 | } 83 | 84 | internal static ulong HashLen16(ulong h1, ulong h2, ulong seed = 0x9ddfea08eb382d69UL) 85 | { 86 | // Murmur-inspired hashing. 87 | ulong a = (h1 ^ h2) * seed; 88 | a ^= a >> 47; 89 | ulong b = (h2 ^ a) * seed; 90 | b ^= b >> 47; 91 | b *= seed; 92 | return b; 93 | } 94 | } -------------------------------------------------------------------------------- /Src/FastHash/CityHash/CityHashUnsafeShared.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.CityHash.CityHashConstants; 2 | using static Genbox.FastHash.CityHash.CityHashShared; 3 | 4 | namespace Genbox.FastHash.CityHash; 5 | 6 | internal static class CityHashUnsafeShared 7 | { 8 | internal static unsafe ulong HashLen0to16(byte* s, uint len) 9 | { 10 | if (len >= 8) 11 | { 12 | ulong mul = K2 + (len * 2); 13 | ulong a = Read64(s) + K2; 14 | ulong b = Read64(s + len - 8); 15 | ulong c = (RotateRight(b, 37) * mul) + a; 16 | ulong d = (RotateRight(a, 25) + b) * mul; 17 | return HashLen16(c, d, mul); 18 | } 19 | if (len >= 4) 20 | { 21 | ulong mul = K2 + (len * 2); 22 | ulong a = Read32(s); 23 | return HashLen16(len + (a << 3), Read32(s + len - 4), mul); 24 | } 25 | if (len > 0) 26 | { 27 | byte a = s[0]; 28 | byte b = s[len >> 1]; 29 | byte c = s[len - 1]; 30 | uint y = a + ((uint)b << 8); 31 | uint z = len + ((uint)c << 2); 32 | return ShiftMix((y * K2) ^ (z * K0)) * K2; 33 | } 34 | return K2; 35 | } 36 | 37 | // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. 38 | internal static unsafe UInt128 WeakHashLen32WithSeeds(byte* s, ulong a, ulong b) 39 | { 40 | return CityHashShared.WeakHashLen32WithSeeds(Read64(s), 41 | Read64(s + 8), 42 | Read64(s + 16), 43 | Read64(s + 24), 44 | a, 45 | b); 46 | } 47 | } -------------------------------------------------------------------------------- /Src/FastHash/DjbHash/Djb2Hash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.DjbHash.DjbHashConstants; 3 | 4 | namespace Genbox.FastHash.DjbHash; 5 | 6 | public static class Djb2Hash32 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint ComputeIndex(uint input) 10 | { 11 | uint hash = InitHash; 12 | hash = ((hash << 5) + hash) ^ (input & 0xFF); 13 | hash = ((hash << 5) + hash) ^ ((input >> 8) & 0xFF); 14 | hash = ((hash << 5) + hash) ^ ((input >> 16) & 0xFF); 15 | hash = ((hash << 5) + hash) ^ ((input >> 24) & 0xFF); 16 | return hash; 17 | } 18 | 19 | public static uint ComputeHash(ReadOnlySpan data) 20 | { 21 | uint hash = InitHash; 22 | 23 | for (int i = 0; i < data.Length; i++) 24 | hash = ((hash << 5) + hash) ^ data[i]; 25 | 26 | return hash; 27 | } 28 | } -------------------------------------------------------------------------------- /Src/FastHash/DjbHash/Djb2Hash32Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.DjbHash.DjbHashConstants; 2 | 3 | namespace Genbox.FastHash.DjbHash; 4 | 5 | public static class Djb2Hash32Unsafe 6 | { 7 | public static unsafe uint ComputeHash(byte* data, int length) 8 | { 9 | uint hash = InitHash; 10 | 11 | for (int i = 0; i < length; i++) 12 | hash = ((hash << 5) + hash) ^ data[i]; 13 | 14 | return hash; 15 | } 16 | } -------------------------------------------------------------------------------- /Src/FastHash/DjbHash/Djb2Hash64.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.DjbHash.DjbHashConstants; 3 | 4 | namespace Genbox.FastHash.DjbHash; 5 | 6 | public static class Djb2Hash64 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static ulong ComputeIndex(ulong input) 10 | { 11 | ulong hash = InitHash; 12 | hash = ((hash << 5) + hash) ^ (input & 0xFF); 13 | hash = ((hash << 5) + hash) ^ ((input >> 8) & 0xFF); 14 | hash = ((hash << 5) + hash) ^ ((input >> 16) & 0xFF); 15 | hash = ((hash << 5) + hash) ^ ((input >> 24) & 0xFF); 16 | hash = ((hash << 5) + hash) ^ ((input >> 32) & 0xFF); 17 | hash = ((hash << 5) + hash) ^ ((input >> 40) & 0xFF); 18 | hash = ((hash << 5) + hash) ^ ((input >> 48) & 0xFF); 19 | hash = ((hash << 5) + hash) ^ ((input >> 56) & 0xFF); 20 | return hash; 21 | } 22 | 23 | public static ulong ComputeHash(ReadOnlySpan data) 24 | { 25 | ulong hash = InitHash; 26 | 27 | for (int i = 0; i < data.Length; i++) 28 | hash = ((hash << 5) + hash) ^ data[i]; 29 | 30 | return hash; 31 | } 32 | } -------------------------------------------------------------------------------- /Src/FastHash/DjbHash/Djb2Hash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.DjbHash.DjbHashConstants; 2 | 3 | namespace Genbox.FastHash.DjbHash; 4 | 5 | public static class Djb2Hash64Unsafe 6 | { 7 | public static unsafe ulong ComputeHash(byte* data, int length) 8 | { 9 | ulong hash = InitHash; 10 | 11 | for (int i = 0; i < length; i++) 12 | hash = ((hash << 5) + hash) ^ data[i]; 13 | 14 | return hash; 15 | } 16 | } -------------------------------------------------------------------------------- /Src/FastHash/DjbHash/DjbHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.DjbHash; 2 | 3 | internal static class DjbHashConstants 4 | { 5 | internal const int InitHash = 5381; 6 | } -------------------------------------------------------------------------------- /Src/FastHash/FarmHash/FarmHash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Genbox.FastHash.CityHash; 3 | using static Genbox.FastHash.CityHash.CityHashShared; 4 | using static Genbox.FastHash.FarmHash.FarmHashConstants; 5 | 6 | namespace Genbox.FastHash.FarmHash; 7 | 8 | public static class FarmHash32 9 | { 10 | // farmhashmk is a seeded version of CityHash 11 | // farmhashcc is a non-seeded version of CityHash 12 | // The non-seeded version is a slightly modified version of CityHash for inputs larger than 24, and identical with CityHash on lengths less than 24. 13 | 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static uint ComputeIndex(uint input) 16 | { 17 | uint b = (uint)(sbyte)(input & 0xFF); 18 | uint c = 9 ^ b; 19 | 20 | b = (b * C1) + (uint)(sbyte)((input >> 8) & 0xFF); 21 | c ^= b; 22 | 23 | b = (b * C1) + (uint)(sbyte)((input >> 16) & 0xFF); 24 | c ^= b; 25 | 26 | b = (b * C1) + (uint)(sbyte)((input >> 24) & 0xFF); 27 | c ^= b; 28 | return AA_xmxmx_Murmur_32(Mur(b, Mur(4, c))); 29 | } 30 | 31 | public static uint ComputeHash(ReadOnlySpan data, uint seed) 32 | { 33 | uint len = (uint)data.Length; 34 | 35 | if (len <= 24) 36 | { 37 | if (len >= 13) return Hash32Len13to24(data, len, seed * C1); 38 | if (len >= 5) return Hash32Len5to12(data, len, seed); 39 | return Hash32Len0to4(data, len, seed); 40 | } 41 | uint h = Hash32Len13to24(data, 24, seed ^ len); 42 | return Mur(ComputeHash(data.Slice(24)) + seed, h); 43 | } 44 | 45 | public static uint ComputeHash(ReadOnlySpan data) 46 | { 47 | uint len = (uint)data.Length; 48 | 49 | if (len <= 24) 50 | return len <= 12 ? len <= 4 ? CityHash32.Hash32Len0to4(data, len) : CityHash32.Hash32Len5to12(data, len) : CityHash32.Hash32Len13to24(data, len); 51 | 52 | // len > 24 53 | uint h = len, g = C1 * len, f = g; 54 | { 55 | uint a0 = RotateRight(Read32(data, len - 4) * C1, 17) * C2; 56 | uint a1 = RotateRight(Read32(data, len - 8) * C1, 17) * C2; 57 | uint a2 = RotateRight(Read32(data, len - 16) * C1, 17) * C2; 58 | uint a3 = RotateRight(Read32(data, len - 12) * C1, 17) * C2; 59 | uint a4 = RotateRight(Read32(data, len - 20) * C1, 17) * C2; 60 | h ^= a0; 61 | h = RotateRight(h, 19); 62 | h = (h * 5) + 0xe6546b64; 63 | h ^= a2; 64 | h = RotateRight(h, 19); 65 | h = (h * 5) + 0xe6546b64; 66 | g ^= a1; 67 | g = RotateRight(g, 19); 68 | g = (g * 5) + 0xe6546b64; 69 | g ^= a3; 70 | g = RotateRight(g, 19); 71 | g = (g * 5) + 0xe6546b64; 72 | f += a4; 73 | f = RotateRight(f, 19); 74 | f = (f * 5) + 0xe6546b64; 75 | } 76 | uint iters = (len - 1) / 20; 77 | int offset = 0; 78 | do 79 | { 80 | uint a0 = RotateRight(Read32(data, offset) * C1, 17) * C2; 81 | uint a1 = Read32(data, offset + 4); 82 | uint a2 = RotateRight(Read32(data, offset + 8) * C1, 17) * C2; 83 | uint a3 = RotateRight(Read32(data, offset + 12) * C1, 17) * C2; 84 | uint a4 = Read32(data, offset + 16); 85 | h ^= a0; 86 | h = RotateRight(h, 18); 87 | h = (h * 5) + 0xe6546b64; 88 | f += a1; 89 | f = RotateRight(f, 19); 90 | f = f * C1; 91 | g += a2; 92 | g = RotateRight(g, 18); 93 | g = (g * 5) + 0xe6546b64; 94 | h ^= a3 + a1; 95 | h = RotateRight(h, 19); 96 | h = (h * 5) + 0xe6546b64; 97 | g ^= a4; 98 | g = ByteSwap(g) * 5; 99 | h += a4 * 5; 100 | h = ByteSwap(h); 101 | f += a0; 102 | Permute3(ref f, ref h, ref g); 103 | offset += 20; 104 | } while (--iters != 0); 105 | g = RotateRight(g, 11) * C1; 106 | g = RotateRight(g, 17) * C1; 107 | f = RotateRight(f, 11) * C1; 108 | f = RotateRight(f, 17) * C1; 109 | h = RotateRight(h + g, 19); 110 | h = (h * 5) + 0xe6546b64; 111 | h = RotateRight(h, 17) * C1; 112 | h = RotateRight(h + f, 19); 113 | h = (h * 5) + 0xe6546b64; 114 | h = RotateRight(h, 17) * C1; 115 | return h; 116 | } 117 | 118 | private static uint Hash32Len0to4(ReadOnlySpan s, uint len, uint seed) 119 | { 120 | uint b = seed; 121 | uint c = 9; 122 | for (int i = 0; i < len; i++) 123 | { 124 | uint v = (uint)(sbyte)s[i]; 125 | b = (b * C1) + v; 126 | c ^= b; 127 | } 128 | return AA_xmxmx_Murmur_32(Mur(b, Mur(len, c))); 129 | } 130 | 131 | private static uint Hash32Len5to12(ReadOnlySpan s, uint len, uint seed) 132 | { 133 | uint a = len, b = len * 5, c = 9, d = b + seed; 134 | a += Read32(s); 135 | b += Read32(s, len - 4); 136 | c += Read32(s, (len >> 1) & 4); 137 | return AA_xmxmx_Murmur_32(seed ^ Mur(c, Mur(b, Mur(a, d)))); 138 | } 139 | 140 | private static uint Hash32Len13to24(ReadOnlySpan s, uint len, uint seed) 141 | { 142 | uint a = Read32(s, (len >> 1) - 4); 143 | uint b = Read32(s, 4); 144 | uint c = Read32(s, len - 8); 145 | uint d = Read32(s, len >> 1); 146 | uint e = Read32(s); 147 | uint f = Read32(s, len - 4); 148 | uint h = (d * C1) + len + seed; 149 | a = RotateRight(a, 12) + f; 150 | h = Mur(c, h) + a; 151 | a = RotateRight(a, 3) + c; 152 | h = Mur(e, h) + a; 153 | a = RotateRight(a + f, 12) + d; 154 | h = Mur(b ^ seed, h) + a; 155 | return AA_xmxmx_Murmur_32(h); 156 | } 157 | } -------------------------------------------------------------------------------- /Src/FastHash/FarmHash/FarmHash32Unsafe.cs: -------------------------------------------------------------------------------- 1 | using Genbox.FastHash.CityHash; 2 | using static Genbox.FastHash.CityHash.CityHashShared; 3 | using static Genbox.FastHash.FarmHash.FarmHashConstants; 4 | 5 | namespace Genbox.FastHash.FarmHash; 6 | 7 | public static class FarmHash32Unsafe 8 | { 9 | // farmhashmk is a seeded version of CityHash 10 | // farmhashcc is a non-seeded version of CityHash 11 | // The non-seeded version is a slightly modified version of CityHash for inputs larger than 24, and identical with CityHash on lengths less than 24. 12 | 13 | public static unsafe uint ComputeHash(byte* data, int length, uint seed) 14 | { 15 | uint len = (uint)length; 16 | 17 | if (len <= 24) 18 | { 19 | if (len >= 13) return Hash32Len13to24(data, len, seed * C1); 20 | if (len >= 5) return Hash32Len5to12(data, len, seed); 21 | return Hash32Len0to4(data, len, seed); 22 | } 23 | uint h = Hash32Len13to24(data, 24, seed ^ len); 24 | return Mur(ComputeHash(data + 24, length - 24) + seed, h); 25 | } 26 | 27 | public static unsafe uint ComputeHash(byte* data, int length) 28 | { 29 | uint len = (uint)length; 30 | 31 | if (len <= 24) 32 | return len <= 12 ? len <= 4 ? CityHash32Unsafe.Hash32Len0to4(data, len) : CityHash32Unsafe.Hash32Len5to12(data, len) : CityHash32Unsafe.Hash32Len13to24(data, len); 33 | 34 | // len > 24 35 | uint h = len, g = C1 * len, f = g; 36 | { 37 | uint a0 = RotateRight(Read32(data + len - 4) * C1, 17) * C2; 38 | uint a1 = RotateRight(Read32(data + len - 8) * C1, 17) * C2; 39 | uint a2 = RotateRight(Read32(data + len - 16) * C1, 17) * C2; 40 | uint a3 = RotateRight(Read32(data + len - 12) * C1, 17) * C2; 41 | uint a4 = RotateRight(Read32(data + len - 20) * C1, 17) * C2; 42 | h ^= a0; 43 | h = RotateRight(h, 19); 44 | h = (h * 5) + 0xe6546b64; 45 | h ^= a2; 46 | h = RotateRight(h, 19); 47 | h = (h * 5) + 0xe6546b64; 48 | g ^= a1; 49 | g = RotateRight(g, 19); 50 | g = (g * 5) + 0xe6546b64; 51 | g ^= a3; 52 | g = RotateRight(g, 19); 53 | g = (g * 5) + 0xe6546b64; 54 | f += a4; 55 | f = RotateRight(f, 19); 56 | f = (f * 5) + 0xe6546b64; 57 | } 58 | uint iters = (len - 1) / 20; 59 | do 60 | { 61 | uint a0 = RotateRight(Read32(data) * C1, 17) * C2; 62 | uint a1 = Read32(data + 4); 63 | uint a2 = RotateRight(Read32(data + 8) * C1, 17) * C2; 64 | uint a3 = RotateRight(Read32(data + 12) * C1, 17) * C2; 65 | uint a4 = Read32(data + 16); 66 | h ^= a0; 67 | h = RotateRight(h, 18); 68 | h = (h * 5) + 0xe6546b64; 69 | f += a1; 70 | f = RotateRight(f, 19); 71 | f = f * C1; 72 | g += a2; 73 | g = RotateRight(g, 18); 74 | g = (g * 5) + 0xe6546b64; 75 | h ^= a3 + a1; 76 | h = RotateRight(h, 19); 77 | h = (h * 5) + 0xe6546b64; 78 | g ^= a4; 79 | g = ByteSwap(g) * 5; 80 | h += a4 * 5; 81 | h = ByteSwap(h); 82 | f += a0; 83 | Permute3(ref f, ref h, ref g); 84 | data += 20; 85 | } while (--iters != 0); 86 | g = RotateRight(g, 11) * C1; 87 | g = RotateRight(g, 17) * C1; 88 | f = RotateRight(f, 11) * C1; 89 | f = RotateRight(f, 17) * C1; 90 | h = RotateRight(h + g, 19); 91 | h = (h * 5) + 0xe6546b64; 92 | h = RotateRight(h, 17) * C1; 93 | h = RotateRight(h + f, 19); 94 | h = (h * 5) + 0xe6546b64; 95 | h = RotateRight(h, 17) * C1; 96 | return h; 97 | } 98 | 99 | private static unsafe uint Hash32Len0to4(byte* s, uint len, uint seed) 100 | { 101 | uint b = seed; 102 | uint c = 9; 103 | for (uint i = 0; i < len; i++) 104 | { 105 | uint v = (uint)(sbyte)s[i]; 106 | b = (b * C1) + v; 107 | c ^= b; 108 | } 109 | return AA_xmxmx_Murmur_32(Mur(b, Mur(len, c))); 110 | } 111 | 112 | private static unsafe uint Hash32Len5to12(byte* s, uint len, uint seed) 113 | { 114 | uint a = len, b = len * 5, c = 9, d = b + seed; 115 | a += Read32(s); 116 | b += Read32(s + len - 4); 117 | c += Read32(s + ((len >> 1) & 4)); 118 | return AA_xmxmx_Murmur_32(seed ^ Mur(c, Mur(b, Mur(a, d)))); 119 | } 120 | 121 | private static unsafe uint Hash32Len13to24(byte* s, uint len, uint seed) 122 | { 123 | uint a = Read32(s - 4 + (len >> 1)); 124 | uint b = Read32(s + 4); 125 | uint c = Read32(s + len - 8); 126 | uint d = Read32(s + (len >> 1)); 127 | uint e = Read32(s); 128 | uint f = Read32(s + len - 4); 129 | uint h = (d * C1) + len + seed; 130 | a = RotateRight(a, 12) + f; 131 | h = Mur(c, h) + a; 132 | a = RotateRight(a, 3) + c; 133 | h = Mur(e, h) + a; 134 | a = RotateRight(a + f, 12) + d; 135 | h = Mur(b ^ seed, h) + a; 136 | return AA_xmxmx_Murmur_32(h); 137 | } 138 | } -------------------------------------------------------------------------------- /Src/FastHash/FarmHash/FarmHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.FarmHash; 2 | 3 | internal static class FarmHashConstants 4 | { 5 | // Some primes between 2^63 and 2^64 for various uses. 6 | internal const ulong K0 = 0xc3a5c85c97cb3127U; 7 | internal const ulong K1 = 0xb492b66fbe98f273U; 8 | internal const ulong K2 = 0x9ae16a3b2f90404fU; 9 | 10 | // Magic numbers for 32-bit hashing. Copied from Murmur3. 11 | internal const uint C1 = 0xcc9e2d51; 12 | internal const uint C2 = 0x1b873593; 13 | } -------------------------------------------------------------------------------- /Src/FastHash/FarshHash/FarshHash64.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.FarshHash.FarshHashConstants; 3 | 4 | namespace Genbox.FastHash.FarshHash; 5 | 6 | public static class FarshHash64 7 | { 8 | public static ulong ComputeHash(ReadOnlySpan data, ulong seed = 0) 9 | { 10 | ulong sum = seed; 11 | uint length = (uint)data.Length; 12 | int offset = 0; 13 | 14 | while (length >= STRIPE) 15 | { 16 | ulong h = farsh_full_block(data, offset); 17 | sum = farsh_combine(sum, h); 18 | offset += STRIPE; 19 | length -= STRIPE; 20 | } 21 | 22 | if (length > 0) 23 | { 24 | ulong h = farsh_partial_block(data, offset); 25 | sum = farsh_combine(sum, h); 26 | } 27 | 28 | return farsh_final(sum) ^ FARSH_KEYS[0]; /* ensure that zeroes at the end of data will affect the hash value */ 29 | } 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | private static ulong farsh_full_block(ReadOnlySpan data, int offset) 33 | { 34 | // STRIPE bytes of key material plus extra keys for hashes up to 1024 bits long 35 | 36 | ulong sum = 0; 37 | uint i; 38 | uint j = 0; 39 | for (i = 0; i < STRIPE; i += 8, j += 2) 40 | { 41 | uint val1 = Read32(data, (uint)offset + i); 42 | uint val2 = Read32(data, (uint)offset + i + sizeof(uint)); 43 | sum += (val1 + FARSH_KEYS[j]) * (ulong)(val2 + FARSH_KEYS[j + 1]); 44 | } 45 | 46 | return sum; 47 | } 48 | 49 | private static ulong farsh_partial_block(ReadOnlySpan data, int offset) 50 | { 51 | ulong sum = 0; 52 | int keyindex = 0; 53 | int length = data.Length; 54 | 55 | uint chunks = (uint)((length - offset) >> 3); 56 | 57 | for (; chunks > 0; chunks--) 58 | { 59 | uint val1 = Read32(data, offset); 60 | uint val2 = Read32(data, offset + sizeof(uint)); 61 | sum += (val1 + FARSH_KEYS[keyindex]) * (ulong)(val2 + FARSH_KEYS[keyindex + 1]); 62 | offset += 8; 63 | keyindex += 2; 64 | } 65 | 66 | uint v1; 67 | uint v2; 68 | 69 | uint remaining = (uint)(length - offset); 70 | 71 | switch (remaining) 72 | { 73 | case 7: 74 | v1 = Read32(data, offset); 75 | offset += 4; 76 | v2 = (uint)(data[0 + offset] | (data[1 + offset] << 8) | (data[2 + offset] << 16)); 77 | sum += (v1 + FARSH_KEYS[keyindex]) * (ulong)(v2 + FARSH_KEYS[keyindex + 1]); 78 | break; 79 | case 6: 80 | v1 = Read32(data, offset); 81 | offset += 4; 82 | v2 = Read16(data, offset); 83 | sum += (v1 + FARSH_KEYS[keyindex]) * (ulong)(v2 + FARSH_KEYS[keyindex + 1]); 84 | break; 85 | case 5: 86 | v1 = Read32(data, offset); 87 | offset += 4; 88 | v2 = data[offset]; 89 | sum += (v1 + FARSH_KEYS[keyindex]) * (ulong)(v2 + FARSH_KEYS[keyindex + 1]); 90 | break; 91 | case 4: 92 | v1 = Read32(data, offset); 93 | sum += (v1 + FARSH_KEYS[keyindex]) * (ulong)FARSH_KEYS[keyindex + 1]; 94 | break; 95 | case 3: 96 | v1 = (uint)(data[0 + offset] | (data[1 + offset] << 8) | (data[2 + offset] << 16)); 97 | sum += (v1 + FARSH_KEYS[keyindex]) * (ulong)FARSH_KEYS[keyindex + 1]; 98 | break; 99 | case 2: 100 | v1 = Read16(data, offset); 101 | sum += (v1 + FARSH_KEYS[keyindex]) * (ulong)FARSH_KEYS[keyindex + 1]; 102 | break; 103 | case 1: 104 | v1 = data[offset]; 105 | sum += (v1 + FARSH_KEYS[keyindex]) * (ulong)FARSH_KEYS[keyindex + 1]; 106 | break; 107 | } 108 | 109 | return sum; 110 | } 111 | 112 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 113 | private static ulong farsh_combine(ulong sum, ulong h) 114 | { 115 | h *= PRIME64_2; 116 | h += h >> 31; 117 | h *= PRIME64_1; 118 | sum ^= h; 119 | sum = ((sum + (sum >> 27)) * PRIME64_1) + PRIME64_4; 120 | return sum; 121 | } 122 | 123 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 124 | private static uint farsh_final(ulong sum) 125 | { 126 | sum ^= sum >> 33; 127 | sum *= PRIME64_2; 128 | sum ^= sum >> 29; 129 | sum *= PRIME64_3; 130 | return (uint)sum ^ (uint)(sum >> 32); 131 | } 132 | } -------------------------------------------------------------------------------- /Src/FastHash/FarshHash/FarshHash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.FarshHash.FarshHashConstants; 3 | 4 | namespace Genbox.FastHash.FarshHash; 5 | 6 | public static class FarshHash64Unsafe 7 | { 8 | public static unsafe ulong ComputeHash(byte* data, int length, ulong seed = 0) 9 | { 10 | ulong sum = seed; 11 | 12 | uint* uptr = (uint*)data; 13 | 14 | while (length >= STRIPE) 15 | { 16 | ulong h = farsh_full_block(uptr); 17 | sum = farsh_combine(sum, h); 18 | uptr += STRIPE_ELEMENTS; 19 | length -= STRIPE; 20 | } 21 | 22 | if (length > 0) 23 | { 24 | ulong h = farsh_partial_block(uptr, length); 25 | sum = farsh_combine(sum, h); 26 | } 27 | 28 | return farsh_final(sum) ^ FARSH_KEYS[0]; /* ensure that zeroes at the end of data will affect the hash value */ 29 | } 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | private static unsafe ulong farsh_full_block(uint* data) 33 | { 34 | // STRIPE bytes of key material plus extra keys for hashes up to 1024 bits long 35 | ulong sum = 0; 36 | int i; 37 | 38 | for (i = 0; i < STRIPE_ELEMENTS; i += 2) 39 | sum += (data[i] + FARSH_KEYS[i]) * (ulong)(data[i + 1] + FARSH_KEYS[i + 1]); 40 | 41 | return sum; 42 | } 43 | 44 | private static unsafe ulong farsh_partial_block(uint* data, int length) 45 | { 46 | ulong sum = 0; 47 | int elements = (length / sizeof(uint)) & ~1; 48 | int i; 49 | 50 | for (i = 0; i < elements; i += 2) 51 | { 52 | sum += (data[i] + FARSH_KEYS[i]) * (ulong)(data[i + 1] + FARSH_KEYS[i + 1]); 53 | length -= 8; 54 | } 55 | 56 | data += elements; 57 | 58 | uint v1; 59 | uint v2; 60 | 61 | byte* ptr = (byte*)data; 62 | 63 | switch (length) 64 | { 65 | case 7: 66 | v1 = Read32(ptr); 67 | ptr += 4; 68 | v2 = (uint)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16)); 69 | sum += (v1 + FARSH_KEYS[i]) * (ulong)(v2 + FARSH_KEYS[i + 1]); 70 | break; 71 | case 6: 72 | v1 = Read32(ptr); 73 | ptr += 4; 74 | v2 = Read16(ptr); 75 | sum += (v1 + FARSH_KEYS[i]) * (ulong)(v2 + FARSH_KEYS[i + 1]); 76 | break; 77 | case 5: 78 | v1 = Read32(ptr); 79 | ptr += 4; 80 | v2 = *ptr; 81 | sum += (v1 + FARSH_KEYS[i]) * (ulong)(v2 + FARSH_KEYS[i + 1]); 82 | break; 83 | case 4: 84 | v1 = Read32(ptr); 85 | sum += (v1 + FARSH_KEYS[i]) * (ulong)FARSH_KEYS[i + 1]; 86 | break; 87 | case 3: 88 | v1 = (uint)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16)); 89 | sum += (v1 + FARSH_KEYS[i]) * (ulong)FARSH_KEYS[i + 1]; 90 | break; 91 | case 2: 92 | v1 = Read16(ptr); 93 | sum += (v1 + FARSH_KEYS[i]) * (ulong)FARSH_KEYS[i + 1]; 94 | break; 95 | case 1: 96 | v1 = *ptr; 97 | sum += (v1 + FARSH_KEYS[i]) * (ulong)FARSH_KEYS[i + 1]; 98 | break; 99 | } 100 | 101 | return sum; 102 | } 103 | 104 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 105 | private static ulong farsh_combine(ulong sum, ulong h) 106 | { 107 | h *= PRIME64_2; 108 | h += h >> 31; 109 | h *= PRIME64_1; 110 | sum ^= h; 111 | sum = ((sum + (sum >> 27)) * PRIME64_1) + PRIME64_4; 112 | return sum; 113 | } 114 | 115 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 116 | private static uint farsh_final(ulong sum) 117 | { 118 | sum ^= sum >> 33; 119 | sum *= PRIME64_2; 120 | sum ^= sum >> 29; 121 | sum *= PRIME64_3; 122 | return (uint)sum ^ (uint)(sum >> 32); 123 | } 124 | } -------------------------------------------------------------------------------- /Src/FastHash/FarshHash/FarshHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.FarshHash; 2 | 3 | internal static class FarshHashConstants 4 | { 5 | private const int FARSH_BASE_KEY_SIZE = 1024; /* size of user-supplied key required to compute 32-bit hash with index 0 */ 6 | 7 | internal const int STRIPE = FARSH_BASE_KEY_SIZE; 8 | internal const int STRIPE_ELEMENTS = STRIPE / sizeof(uint); /* should be power of 2 due to use of 'x % STRIPE_ELEMENTS' below */ 9 | 10 | internal const ulong PRIME64_1 = 0x9E3779B185EBCA87UL; 11 | internal const ulong PRIME64_2 = 0xC2B2AE3D27D4EB4FUL; 12 | internal const ulong PRIME64_3 = 0x165667B19E3779F9UL; 13 | internal const ulong PRIME64_4 = 0x85EBCA77C2B2AE63UL; 14 | 15 | internal static readonly uint[] FARSH_KEYS = 16 | [ 17 | 0xb8fe6c39, 0x23a44bbe, 0x7c01812c, 0xf721ad1c, 0xded46de9, 0x839097db, 0x7240a4a4, 0xb7b3671f, 0xcb79e64e, 0xccc0e578, 0x825ad07d, 0xccff7221, 0xb8084674, 0xf743248e, 0xe03590e6, 0x813a264c, 0x3c2852bb, 0x91c300cb, 0x88d0658b, 0x1b532ea3, 0x71644897, 0xa20df94e, 0x3819ef46, 0xa9deacd8, 0xa8fa763f, 0xe39c343f, 0xf9dcbbc7, 0xc70b4f1d, 0x8a51e04b, 0xcdb45931, 0xc89f7ec9, 0xd9787364, 0x4f6a0752, 0xa79b079c, 0x8fc49499, 0x8ec9b7a9, 0x33c92249, 0x4eb6404f, 0xfb2afb4e, 0xa4814255, 0x2f0e1b98, 0xace93b24, 0x188850cd, 0x6c5c74a7, 0x66fa4404, 0xeac5ac83, 0x34d3ebc3, 0xc581a0ff, 0xfa1363eb, 0x170ddd51, 0xb7f0da49, 0xd3165526, 0x29d4689e, 0x2b16be58, 0x7d47a1fc, 0x8ff8b8d1, 0x7ad031ce, 0x45cb3a8f, 0x95160428, 0xafd7fbca, 0xbb4b407e, 0x995274a4, 0xeb9a2d93, 0x3be78908, 0xed475f6c, 0x919cd8f2, 0xd3861e5a, 0x6e31390c, 0xfe6a3a49, 0xdcad0914, 0x06508beb, 0xa88399f3, 0xb058112f, 0xe8b0fa79, 0x29b4da06, 0xedc253fb, 0xc3e96dad, 0x6e372b83, 0x4f78b153, 0xfffa6e86, 0x21beeeec, 0x01caea02, 0x1267e50d, 0x11e6092f, 0xe819d298, 0x832f80dd, 0x0c4e2477, 0xbc7886eb, 0x01506637, 0x8ba89668, 0x6d11e7a0, 0xfc12fd15, 0x86a54c19, 0x593ce3dd, 0xd2b13fe5, 0x8e772b53, 0xae4a60cc, 0x647a3b1b, 0x547786e0, 0x3ec4378e, 0x8d7acf89, 0xca36f947, 0x0e89d5ef, 0xaada6a3c, 0x6da4a109, 0x9ac6e11c, 0x686691ef, 0xa357bd2b, 0xd16f1b9a, 0x38c70303, 0x7d4622b3, 0x2968fa8f, 0x8ca5bcb9, 0xfcd61005, 0x228b5e96, 0x2c9dcc19, 0x57cf243c, 0x3c53f9c1, 0x0cc7952c, 0x686de4f0, 0x93a747b5, 0x4e87a510, 0x975e91ae, 0x4c10b98e, 0x8a7f068c, 0x346b19ab, 0x353ca625, 0xf20a50e0, 0xce9921f6, 0xdf66e014, 0x0a11ef4b, 0x8bc84ddf, 0x84d25d22, 0xc823936d, 0x94741ec3, 0x88278a60, 0xb8649331, 0x7a707a10, 0x7292cad6, 0xa7c644c2, 0xbd156bfa, 0x646c9578, 0xb7f4dfd5, 0x9f8277a7, 0x7013924e, 0xad674cc3, 0x2cae9d05, 0x912a9a22, 0xf67c53fa, 0x8d7e22a9, 0x59ae372b, 0x850199f3, 0x63a2102c, 0xd6ff1261, 0x56738ee1, 0xaa95145b, 0xfdd12832, 0x5b684deb, 0x0784de94, 0xaa62390e, 0xbb7ccf19, 0x0fefd572, 0x565b41ca, 0x2206d202, 0x2d608479, 0x4c0fcd3d, 0xd36d3be3, 0x155a9a65, 0x10f9e732, 0xac9b0f1e, 0x1f72a03b, 0xea9440ae, 18 | 0x5b674b4f, 0x31a827d1, 0xecca954f, 0x3d2cd61e, 0x768d3da4, 0x93745ac1, 0x1d5d58cb, 0x4b86f3b6, 0x2aba923a, 0x0e65814c, 0x8ae063d9, 0xcd6969b0, 0x36641585, 0x742af59d, 0x613a1316, 0x338ea471, 0x47861af3, 0x30479dc3, 0x1270a481, 0x08771069, 0xe3c4f0d2, 0x0229874c, 0x5a8a3bc1, 0xe30d9733, 0xd05be5a2, 0xe2af31ba, 0x222049f9, 0x9f923b6a, 0x033f64ec, 0xe528b62b, 0x8201efbd, 0x2107d877, 0xd8312ef1, 0xa5679f99, 0x1730b51b, 0x752616d2, 0x05305909, 0x0dca440b, 0x2093cdd9, 0x6409ab50, 0xba5c8ecc, 0x8d4708ea, 0x429f0917, 0xb762fab0, 0x5161ea75, 0x45eba0eb, 0xb6f34b41, 0x52047123, 0xe4181523, 0x8d74e90a, 0x54fa401c, 0xddda0cc7, 0x63df182a, 0xc6403ef6, 0x348ec6e8, 0xb9ff57f5, 0xf652b8bd, 0x0f86b0f3, 0xfb3a088a, 0x4dc71533, 0x7b3617d2, 0xa34e87eb, 0xba2a9bdd, 0xe3381306, 0x14bad6bb, 0xc96dc7c2, 0x333b54b6, 0x9be47cfa, 0x1dcf9299, 0xe7ea5f99, 0xb38feacd, 0xc3cfe2f7, 0x5b87e822, 0x39c5ab56, 0x18f4a18f, 0x2d484d9c, 0x4163d519, 0x79769e98, 0xf58a67f0, 0x40590c02, 0x319671c0, 0x266b133a, 0xaf81b287, 0x6a31f737, 0xe3bc0197, 0x55079913, 0x9f72c696, 0x363e00c8, 0x53153947, 0xebfd127f, 0x00f60519, 0x46a6b62a, 0x93b83380, 0x3fe29324, 0xdfc67091, 0x0f62386d, 0xdc375e79, 0x8fea3f3e, 0xdf8463d0, 0x3702fa7b, 0x3954435e, 0x87caa648, 0xa9158bee, 0x08f30c25, 0x66b82936, 0xe7fc3feb, 0x183c5450, 0xd7ef4345, 0x798c7963, 0xc02cf557, 0x098553d1, 0xfa4312aa, 0xe29ef883, 0x7caf128d, 0x74b3a07d, 0xc8efdf5b, 0x8db23782, 0x2c409f4a, 0xdae469da, 0x4d3e1b3f, 0x2e7b9a58, 0xc83e3753, 0xcefd96a6, 0x44ddb068, 0x5faed141, 0xdee7d0f1, 0xc223dbb4, 0x7bfbe104, 0x114d6e1d, 0x52039cd5, 0x307c0a9c, 0xa6289c12, 0x20ee8b3e, 0x03724b0b, 0xba68ae4a, 0x93c5f2a1, 0x9af27bb2, 0x480f0eba, 0xc14c6bbe, 0xe7331f87, 0xf0104df4, 0x22c05363, 0xb7e6d08a, 0x6f15c449, 0x4b9ee2cd, 0x6b2c78ae, 0x25ed2673, 0xb6256596, 0x99ad4803, 0x654f8f10, 0xe89eca64, 0xd9a506df, 0x530dc5fa, 0xfe75be5c, 0xa543833d, 0xf739fd45, 0x1605b488, 0xe50f614a, 0xe930df83, 0x4540195d, 0xf2da0f32, 0x6b04f79c, 0xe3c73c99, 0xb3a5265c, 0x5a1be07d, 0xbda13d2a, 0xeddc281c, 0xe9d9a39a, 0xde9beff1, 0x573c1747, 0x40be5b3e, 0x3756e968, 19 | 0x968077b6, 0x6525a28f, 0x747d0735, 0x8a0ec11d, 0x49c03af5, 0xf3def45b, 0xc3c9214d, 0x9ea2e76d, 0xfad3a715, 0xcaa7ad89, 0xde828e4c, 0xa5769bd5, 0x467cdb5a, 0xd5f2cacb, 0x68ebd182, 0x8d40341a, 0x21556887, 0x000a5f6f, 0x5ad8a473, 0xafe7e886, 0x98997d39, 0x945ad218, 0x46be0c93, 0x93a5bd3a, 0x3ffa4a8c, 0xd834d936, 0x2f022a2a, 0x20791c6b, 0x5db51516, 0x8defeed2, 0x9dee28a5, 0x5188eba7, 0xab4f8c67, 0x48ceac96, 0x2a11e16f, 0xc1593b6d 20 | ]; 21 | } -------------------------------------------------------------------------------- /Src/FastHash/FastHash.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | netstandard2.1;net8.0 7 | true 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Src/FastHash/FnvHash/Fnv1aHash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.FnvHash.FnvHashConstants; 3 | 4 | namespace Genbox.FastHash.FnvHash; 5 | 6 | /// Fowler–Noll–Vo hash implementation 7 | public static class Fnv1aHash32 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static uint ComputeIndex(uint input) 11 | { 12 | uint hash = FNV1_32_INIT; 13 | hash = (hash ^ (input & 0xFF)) * FNV_32_PRIME; 14 | hash = (hash ^ ((input >> 8) & 0xFF)) * FNV_32_PRIME; 15 | hash = (hash ^ ((input >> 16) & 0xFF)) * FNV_32_PRIME; 16 | hash = (hash ^ ((input >> 24) & 0xFF)) * FNV_32_PRIME; 17 | return hash; 18 | } 19 | 20 | public static uint ComputeHash(ReadOnlySpan data) 21 | { 22 | uint hash = FNV1_32_INIT; 23 | 24 | for (int i = 0; i < data.Length; i++) 25 | hash = (hash ^ data[i]) * FNV_32_PRIME; 26 | 27 | return hash; 28 | } 29 | } -------------------------------------------------------------------------------- /Src/FastHash/FnvHash/Fnv1aHash32Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.FnvHash.FnvHashConstants; 2 | 3 | namespace Genbox.FastHash.FnvHash; 4 | 5 | /// Fowler–Noll–Vo hash implementation 6 | public static class Fnv1aHash32Unsafe 7 | { 8 | public static unsafe uint ComputeHash(byte* data, int length) 9 | { 10 | uint hash = FNV1_32_INIT; 11 | 12 | for (int i = 0; i < length; i++) 13 | { 14 | hash ^= data[i]; 15 | hash *= FNV_32_PRIME; 16 | } 17 | 18 | return hash; 19 | } 20 | } -------------------------------------------------------------------------------- /Src/FastHash/FnvHash/Fnv1aHash64.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.FnvHash.FnvHashConstants; 3 | 4 | namespace Genbox.FastHash.FnvHash; 5 | 6 | /// Fowler–Noll–Vo hash implementation 7 | public static class Fnv1aHash64 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static ulong ComputeIndex(ulong input) 11 | { 12 | ulong hash = FNV1_64_INIT; 13 | hash = (hash ^ (input & 0xFF)) * FNV_64_PRIME; 14 | hash = (hash ^ ((input >> 8) & 0xFF)) * FNV_64_PRIME; 15 | hash = (hash ^ ((input >> 16) & 0xFF)) * FNV_64_PRIME; 16 | hash = (hash ^ ((input >> 24) & 0xFF)) * FNV_64_PRIME; 17 | hash = (hash ^ ((input >> 32) & 0xFF)) * FNV_64_PRIME; 18 | hash = (hash ^ ((input >> 40) & 0xFF)) * FNV_64_PRIME; 19 | hash = (hash ^ ((input >> 48) & 0xFF)) * FNV_64_PRIME; 20 | hash = (hash ^ ((input >> 56) & 0xFF)) * FNV_64_PRIME; 21 | return hash; 22 | } 23 | 24 | public static ulong ComputeHash(ReadOnlySpan data) 25 | { 26 | ulong hash = FNV1_64_INIT; 27 | 28 | for (int i = 0; i < data.Length; i++) 29 | { 30 | hash ^= data[i]; 31 | hash *= FNV_64_PRIME; 32 | } 33 | 34 | return hash; 35 | } 36 | } -------------------------------------------------------------------------------- /Src/FastHash/FnvHash/Fnv1aHash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.FnvHash.FnvHashConstants; 2 | 3 | namespace Genbox.FastHash.FnvHash; 4 | 5 | /// Fowler–Noll–Vo hash implementation 6 | public static class Fnv1aHash64Unsafe 7 | { 8 | public static unsafe ulong ComputeHash(byte* data, int length) 9 | { 10 | ulong hash = FNV1_64_INIT; 11 | 12 | for (int i = 0; i < length; i++) 13 | { 14 | hash ^= data[i]; 15 | hash *= FNV_64_PRIME; 16 | } 17 | 18 | return hash; 19 | } 20 | } -------------------------------------------------------------------------------- /Src/FastHash/FnvHash/FnvHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.FnvHash; 2 | 3 | internal static class FnvHashConstants 4 | { 5 | internal const uint FNV_32_PRIME = 0x1000193; 6 | internal const uint FNV1_32_INIT = 0x811C9DC5; 7 | 8 | internal const ulong FNV_64_PRIME = 0x100000001B3; 9 | internal const ulong FNV1_64_INIT = 0xCBF29CE484222325; 10 | } -------------------------------------------------------------------------------- /Src/FastHash/GxHash/GxHash128.cs: -------------------------------------------------------------------------------- 1 | #if NET8_0 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.Intrinsics; 4 | 5 | namespace Genbox.FastHash.GxHash; 6 | 7 | public static class GxHash128 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static UInt128 ComputeHash(ReadOnlySpan bytes, long seed = 0) 11 | { 12 | Vector128 hash = GxHashShared.Finalize(GxHashShared.Compress(bytes), seed); 13 | return Unsafe.As, UInt128>(ref hash); 14 | } 15 | } 16 | #endif -------------------------------------------------------------------------------- /Src/FastHash/GxHash/GxHash32.cs: -------------------------------------------------------------------------------- 1 | #if NET8_0 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.Intrinsics; 4 | 5 | namespace Genbox.FastHash.GxHash; 6 | 7 | public static class GxHash32 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static uint ComputeHash(ReadOnlySpan bytes, long seed = 0) => GxHashShared.Finalize(GxHashShared.Compress(bytes), seed).AsUInt32().GetElement(0); 11 | } 12 | #endif -------------------------------------------------------------------------------- /Src/FastHash/GxHash/GxHash64.cs: -------------------------------------------------------------------------------- 1 | #if NET8_0 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.Intrinsics; 4 | 5 | namespace Genbox.FastHash.GxHash; 6 | 7 | public static class GxHash64 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static ulong ComputeHash(ReadOnlySpan bytes, long seed = 0) => GxHashShared.Finalize(GxHashShared.Compress(bytes), seed).AsUInt64().GetElement(0); 11 | } 12 | #endif -------------------------------------------------------------------------------- /Src/FastHash/HighwayHash/HighwayHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.HighwayHash; 2 | 3 | public static class HighwayHashConstants 4 | { 5 | public static readonly ulong[] DefaultKeys = 6 | [ 7 | 0x0706050403020100UL, 0x0F0E0D0C0B0A0908UL, 8 | 0x1716151413121110UL, 0x1F1E1D1C1B1A1918UL 9 | ]; 10 | } -------------------------------------------------------------------------------- /Src/FastHash/HighwayHash/HighwayHashState.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Genbox.FastHash.HighwayHash; 4 | 5 | [StructLayout(LayoutKind.Auto)] 6 | internal struct HighwayHashState 7 | { 8 | internal ulong mul0_0; 9 | internal ulong mul0_1; 10 | internal ulong mul0_2; 11 | internal ulong mul0_3; 12 | internal ulong mul1_0; 13 | internal ulong mul1_1; 14 | internal ulong mul1_2; 15 | internal ulong mul1_3; 16 | internal ulong v0_0; 17 | internal ulong v0_1; 18 | internal ulong v0_2; 19 | internal ulong v0_3; 20 | internal ulong v1_0; 21 | internal ulong v1_1; 22 | internal ulong v1_2; 23 | internal ulong v1_3; 24 | } -------------------------------------------------------------------------------- /Src/FastHash/MarvinHash/MarvinHash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace Genbox.FastHash.MarvinHash; 5 | 6 | public static class MarvinHash32 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint ComputeIndex(uint input) 10 | { 11 | uint p0 = input; 12 | uint p1 = RotateLeft(input, 20); 13 | 14 | p1 += p0; 15 | p0 = RotateLeft(p0, 9); 16 | 17 | p0 ^= p1; 18 | p1 = RotateLeft(p1, 27); 19 | 20 | p1 += p0; 21 | p0 = RotateLeft(p0, 19); 22 | 23 | p1 += 128; 24 | 25 | p0 ^= p1; 26 | p1 = RotateLeft(p1, 20); 27 | 28 | p1 += p0; 29 | p0 = RotateLeft(p0, 9); 30 | 31 | p0 ^= p1; 32 | p1 = RotateLeft(p1, 27); 33 | 34 | p1 += p0; 35 | p0 = RotateLeft(p0, 19); 36 | 37 | p0 ^= p1; 38 | p1 = RotateLeft(p1, 20); 39 | 40 | p1 += p0; 41 | p0 = RotateLeft(p0, 9); 42 | 43 | p0 ^= p1; 44 | p1 = RotateLeft(p1, 27); 45 | 46 | p1 += p0; 47 | p0 = RotateLeft(p0, 19); 48 | 49 | return p0 ^ p1; 50 | } 51 | 52 | public static uint ComputeHash(ReadOnlySpan data, uint seed1 = 0xb79308cd, uint seed2 = 0xced93cd5) 53 | { 54 | MarvinHash64.ComputeHash(ref MemoryMarshal.GetReference(data), (uint)data.Length, ref seed1, ref seed2); 55 | return seed1 ^ seed2; 56 | } 57 | } -------------------------------------------------------------------------------- /Src/FastHash/MeowHash/MeowHash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | #if NET8_0 2 | namespace Genbox.FastHash.MeowHash; 3 | 4 | public static class MeowHash64Unsafe 5 | { 6 | public static unsafe ulong ComputeHash(byte* data, int len) 7 | { 8 | UInt128 res = MeowHash128Unsafe.ComputeHash(data, len); 9 | return res.Low; 10 | } 11 | } 12 | #endif -------------------------------------------------------------------------------- /Src/FastHash/Misc/IsExternalInit.cs: -------------------------------------------------------------------------------- 1 | // 2 | 3 | using System.Diagnostics.CodeAnalysis; 4 | 5 | namespace System.Runtime.CompilerServices; 6 | public class IsExternalInit; -------------------------------------------------------------------------------- /Src/FastHash/Misc/Utilities.cs: -------------------------------------------------------------------------------- 1 | using System.Buffers.Binary; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Genbox.FastHash.Misc; 6 | 7 | internal static class Utilities 8 | { 9 | #region Unsafe read/write 10 | 11 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 12 | internal static unsafe uint Read8(byte* ptr) => *ptr; 13 | 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | internal static unsafe ushort Read16(byte* ptr) => *(ushort*)ptr; 16 | 17 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 18 | internal static unsafe uint Read32(byte* ptr) => *(uint*)ptr; 19 | 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | internal static unsafe ulong Read64(byte* ptr) => *(ulong*)ptr; 22 | 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | internal static unsafe void Write64(byte* ptr, ulong value) => *(ulong*)ptr = value; 25 | 26 | #endregion 27 | 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | internal static ushort Read16(ReadOnlySpan data, int offset) 30 | { 31 | ref byte ptr = ref MemoryMarshal.GetReference(data); 32 | return Unsafe.ReadUnaligned(ref Unsafe.Add(ref ptr, offset)); 33 | } 34 | 35 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 36 | internal static uint Read32(ReadOnlySpan data) 37 | { 38 | ref byte ptr = ref MemoryMarshal.GetReference(data); 39 | return Unsafe.ReadUnaligned(ref ptr); 40 | } 41 | 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | internal static uint Read32(ReadOnlySpan data, uint offset) 44 | { 45 | ref byte ptr = ref MemoryMarshal.GetReference(data); 46 | return Unsafe.ReadUnaligned(ref Unsafe.Add(ref ptr, (IntPtr)offset)); 47 | } 48 | 49 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 50 | internal static uint Read32(ReadOnlySpan data, int offset) 51 | { 52 | ref byte ptr = ref MemoryMarshal.GetReference(data); 53 | return Unsafe.ReadUnaligned(ref Unsafe.Add(ref ptr, offset)); 54 | } 55 | 56 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 57 | internal static ulong Read64(ReadOnlySpan data) 58 | { 59 | ref byte ptr = ref MemoryMarshal.GetReference(data); 60 | return Unsafe.ReadUnaligned(ref ptr); 61 | } 62 | 63 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 64 | internal static ulong Read64(ReadOnlySpan data, uint offset) 65 | { 66 | ref byte ptr = ref MemoryMarshal.GetReference(data); 67 | return Unsafe.ReadUnaligned(ref Unsafe.Add(ref ptr, (IntPtr)offset)); 68 | } 69 | 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | internal static ulong Read64(ReadOnlySpan data, int offset) 72 | { 73 | ref byte ptr = ref MemoryMarshal.GetReference(data); 74 | return Unsafe.ReadUnaligned(ref Unsafe.Add(ref ptr, offset)); 75 | } 76 | 77 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 78 | internal static void Write64(Span data, int offset, ulong value) => Unsafe.WriteUnaligned(ref data[offset], value); 79 | 80 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 81 | internal static void Swap(ref T a, ref T b) => (a, b) = (b, a); 82 | 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | internal static uint ByteSwap(uint input) => BinaryPrimitives.ReverseEndianness(input); 85 | 86 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 87 | internal static ulong ByteSwap(ulong input) => BinaryPrimitives.ReverseEndianness(input); 88 | 89 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 90 | internal static uint RotateRight(uint x, byte r) => (x >> r) | (x << (32 - r)); 91 | 92 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 93 | internal static ulong RotateRight(ulong x, byte r) => (x >> r) | (x << (64 - r)); 94 | 95 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 96 | internal static uint RotateLeft(uint x, byte r) => (x << r) | (x >> (32 - r)); 97 | 98 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 99 | internal static ulong RotateLeft(ulong x, byte r) => (x << r) | (x >> (64 - r)); 100 | 101 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 102 | public static ulong BigMul(ulong a, ulong b, out ulong low) 103 | { 104 | #if NET5_0_OR_GREATER 105 | return Math.BigMul(a, b, out low); 106 | #else 107 | unchecked 108 | { 109 | low = a * b; 110 | 111 | ulong x0 = (uint)a; 112 | ulong x1 = a >> 32; 113 | 114 | ulong y0 = (uint)b; 115 | ulong y1 = b >> 32; 116 | 117 | ulong p11 = x1 * y1; 118 | ulong p01 = x0 * y1; 119 | ulong p10 = x1 * y0; 120 | ulong p00 = x0 * y0; 121 | 122 | ulong middle = p10 + (p00 >> 32) + (uint)p01; 123 | return p11 + (middle >> 32) + (p01 >> 32); 124 | } 125 | #endif 126 | } 127 | } -------------------------------------------------------------------------------- /Src/FastHash/MurmurHash/Murmur3Hash128.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.MurmurHash.MurmurHashConstants; 2 | 3 | namespace Genbox.FastHash.MurmurHash; 4 | 5 | public static class Murmur3Hash128 6 | { 7 | public static UInt128 ComputeHash(ReadOnlySpan data, uint seed = 0) 8 | { 9 | uint length = (uint)data.Length; 10 | uint nBlocks = length / 16; 11 | 12 | ulong h1 = seed; 13 | ulong h2 = seed; 14 | 15 | ulong k1; 16 | ulong k2; 17 | 18 | for (uint i = 0; i < nBlocks; i++) 19 | { 20 | k1 = Read64(data, (i * 2) + 0); 21 | k2 = Read64(data, (i * 2) + 8); 22 | 23 | k1 *= C1_64; 24 | k1 = RotateLeft(k1, 31); 25 | k1 *= C2_64; 26 | h1 ^= k1; 27 | 28 | h1 = RotateLeft(h1, 27); 29 | h1 += h2; 30 | h1 = (h1 * 5) + 0x52dce729; 31 | 32 | k2 *= C2_64; 33 | k2 = RotateLeft(k2, 33); 34 | k2 *= C1_64; 35 | h2 ^= k2; 36 | 37 | h2 = RotateLeft(h2, 31); 38 | h2 += h1; 39 | h2 = (h2 * 5) + 0x38495ab5; 40 | } 41 | 42 | uint rem = length & 15; 43 | 44 | int tail = (int)(length - rem); 45 | 46 | k1 = 0; 47 | k2 = 0; 48 | 49 | switch (rem) 50 | { 51 | case 15: 52 | k2 ^= (ulong)data[tail + 14] << 48; 53 | goto case 14; 54 | case 14: 55 | k2 ^= (ulong)data[tail + 13] << 40; 56 | goto case 13; 57 | case 13: 58 | k2 ^= (ulong)data[tail + 12] << 32; 59 | goto case 12; 60 | case 12: 61 | k2 ^= (ulong)data[tail + 11] << 24; 62 | goto case 11; 63 | case 11: 64 | k2 ^= (ulong)data[tail + 10] << 16; 65 | goto case 10; 66 | case 10: 67 | k2 ^= (ulong)data[tail + 9] << 8; 68 | goto case 9; 69 | case 9: 70 | k2 ^= data[tail + 8]; 71 | 72 | k2 *= C2_64; 73 | k2 = RotateLeft(k2, 33); 74 | k2 *= C1_64; 75 | h2 ^= k2; 76 | 77 | goto case 8; 78 | case 8: 79 | k1 ^= (ulong)data[tail + 7] << 56; 80 | goto case 7; 81 | case 7: 82 | k1 ^= (ulong)data[tail + 6] << 48; 83 | goto case 6; 84 | case 6: 85 | k1 ^= (ulong)data[tail + 5] << 40; 86 | goto case 5; 87 | case 5: 88 | k1 ^= (ulong)data[tail + 4] << 32; 89 | goto case 4; 90 | case 4: 91 | k1 ^= (ulong)data[tail + 3] << 24; 92 | goto case 3; 93 | case 3: 94 | k1 ^= (ulong)data[tail + 2] << 16; 95 | goto case 2; 96 | case 2: 97 | k1 ^= (ulong)data[tail + 1] << 8; 98 | goto case 1; 99 | case 1: 100 | k1 ^= data[0]; 101 | 102 | k1 *= C1_64; 103 | k1 = RotateLeft(k1, 31); 104 | k1 *= C2_64; 105 | h1 ^= k1; 106 | 107 | break; 108 | } 109 | 110 | h1 ^= length; 111 | h2 ^= length; 112 | 113 | h1 += h2; 114 | h2 += h1; 115 | 116 | h1 = AA_xmxmx_Murmur_64(h1); 117 | h2 = AA_xmxmx_Murmur_64(h2); 118 | 119 | h1 += h2; 120 | h2 += h1; 121 | 122 | return new UInt128(h1, h2); 123 | } 124 | } -------------------------------------------------------------------------------- /Src/FastHash/MurmurHash/Murmur3Hash128Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.MurmurHash.MurmurHashConstants; 2 | 3 | namespace Genbox.FastHash.MurmurHash; 4 | 5 | public static class Murmur3Hash128Unsafe 6 | { 7 | public static unsafe UInt128 ComputeHash(byte* data, int length, uint seed = 0) 8 | { 9 | int nblocks = length / 16; 10 | 11 | ulong h1 = seed; 12 | ulong h2 = seed; 13 | 14 | ulong k1; 15 | ulong k2; 16 | 17 | ulong* blocks = (ulong*)data; 18 | 19 | for (int i = 0; i < nblocks; i++) 20 | { 21 | k1 = blocks[(i * 2) + 0]; 22 | k2 = blocks[(i * 2) + 1]; 23 | 24 | k1 *= C1_64; 25 | k1 = RotateLeft(k1, 31); 26 | k1 *= C2_64; 27 | h1 ^= k1; 28 | 29 | h1 = RotateLeft(h1, 27); 30 | h1 += h2; 31 | h1 = (h1 * 5) + 0x52dce729; 32 | 33 | k2 *= C2_64; 34 | k2 = RotateLeft(k2, 33); 35 | k2 *= C1_64; 36 | h2 ^= k2; 37 | 38 | h2 = RotateLeft(h2, 31); 39 | h2 += h1; 40 | h2 = (h2 * 5) + 0x38495ab5; 41 | } 42 | 43 | byte* tail = data + (nblocks * 16); 44 | 45 | k1 = 0; 46 | k2 = 0; 47 | 48 | switch (length & 15) 49 | { 50 | case 15: 51 | k2 ^= (ulong)tail[14] << 48; 52 | goto case 14; 53 | case 14: 54 | k2 ^= (ulong)tail[13] << 40; 55 | goto case 13; 56 | case 13: 57 | k2 ^= (ulong)tail[12] << 32; 58 | goto case 12; 59 | case 12: 60 | k2 ^= (ulong)tail[11] << 24; 61 | goto case 11; 62 | case 11: 63 | k2 ^= (ulong)tail[10] << 16; 64 | goto case 10; 65 | case 10: 66 | k2 ^= (ulong)tail[9] << 8; 67 | goto case 9; 68 | case 9: 69 | k2 ^= (ulong)tail[8] << 0; 70 | 71 | k2 *= C2_64; 72 | k2 = RotateLeft(k2, 33); 73 | k2 *= C1_64; 74 | h2 ^= k2; 75 | 76 | goto case 8; 77 | case 8: 78 | k1 ^= (ulong)tail[7] << 56; 79 | goto case 7; 80 | case 7: 81 | k1 ^= (ulong)tail[6] << 48; 82 | goto case 6; 83 | case 6: 84 | k1 ^= (ulong)tail[5] << 40; 85 | goto case 5; 86 | case 5: 87 | k1 ^= (ulong)tail[4] << 32; 88 | goto case 4; 89 | case 4: 90 | k1 ^= (ulong)tail[3] << 24; 91 | goto case 3; 92 | case 3: 93 | k1 ^= (ulong)tail[2] << 16; 94 | goto case 2; 95 | case 2: 96 | k1 ^= (ulong)tail[1] << 8; 97 | goto case 1; 98 | case 1: 99 | k1 ^= (ulong)tail[0] << 0; 100 | 101 | k1 *= C1_64; 102 | k1 = RotateLeft(k1, 31); 103 | k1 *= C2_64; 104 | h1 ^= k1; 105 | 106 | break; 107 | } 108 | 109 | ulong len = (ulong)length; 110 | h1 ^= len; 111 | h2 ^= len; 112 | 113 | h1 += h2; 114 | h2 += h1; 115 | 116 | h1 = AA_xmxmx_Murmur_64(h1); 117 | h2 = AA_xmxmx_Murmur_64(h2); 118 | 119 | h1 += h2; 120 | h2 += h1; 121 | 122 | return new UInt128(h1, h2); 123 | } 124 | } -------------------------------------------------------------------------------- /Src/FastHash/MurmurHash/Murmur3Hash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.MurmurHash.MurmurHashConstants; 3 | 4 | namespace Genbox.FastHash.MurmurHash; 5 | 6 | public static class Murmur3Hash32 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint ComputeIndex(uint input) 10 | { 11 | input *= C1_32; 12 | input = RotateLeft(input, 15); 13 | input *= C2_32; 14 | 15 | input = RotateLeft(input, 13); 16 | input = (input * 5) + 0xe6546b64; 17 | input ^= 4; 18 | return AA_xmxmx_Murmur_32(input); 19 | } 20 | 21 | public static uint ComputeHash(ReadOnlySpan data, uint seed = 0) 22 | { 23 | uint length = (uint)data.Length; 24 | uint nBlocks = length / 4; 25 | uint h1 = seed; 26 | uint k1; 27 | 28 | uint end = nBlocks * 4; 29 | 30 | for (uint i = 0; i < end; i += 4) 31 | { 32 | k1 = Read32(data, i); 33 | 34 | k1 *= C1_32; 35 | k1 = RotateLeft(k1, 15); 36 | k1 *= C2_32; 37 | 38 | h1 ^= k1; 39 | h1 = RotateLeft(h1, 13); 40 | h1 = (h1 * 5) + 0xe6546b64; 41 | } 42 | 43 | uint rem = length & 3; 44 | 45 | int tail = (int)(length - rem); 46 | k1 = 0; 47 | 48 | switch (rem) 49 | { 50 | case 3: 51 | k1 ^= (uint)data[tail + 2] << 16; 52 | goto case 2; 53 | case 2: 54 | k1 ^= (uint)data[tail + 1] << 8; 55 | goto case 1; 56 | case 1: 57 | k1 ^= data[tail]; 58 | break; 59 | } 60 | 61 | k1 *= C1_32; 62 | k1 = RotateLeft(k1, 15); 63 | k1 *= C2_32; 64 | h1 ^= k1; 65 | 66 | h1 ^= length; 67 | return AA_xmxmx_Murmur_32(h1); 68 | } 69 | } -------------------------------------------------------------------------------- /Src/FastHash/MurmurHash/Murmur3Hash32Unsafe.cs: -------------------------------------------------------------------------------- 1 | using static Genbox.FastHash.MurmurHash.MurmurHashConstants; 2 | 3 | namespace Genbox.FastHash.MurmurHash; 4 | 5 | public static class Murmur3Hash32Unsafe 6 | { 7 | public static unsafe uint ComputeHash(byte* data, int length, uint seed = 0) 8 | { 9 | int nblocks = length / 4; 10 | uint h1 = seed; 11 | uint k1; 12 | 13 | uint* blocks = (uint*)(data + (nblocks * 4)); 14 | 15 | for (int i = -nblocks; i != 0; i++) 16 | { 17 | k1 = blocks[i]; 18 | 19 | k1 *= C1_32; 20 | k1 = RotateLeft(k1, 15); 21 | k1 *= C2_32; 22 | 23 | h1 ^= k1; 24 | h1 = RotateLeft(h1, 13); 25 | h1 = (h1 * 5) + 0xe6546b64; 26 | } 27 | 28 | byte* tail = data + (nblocks * 4); 29 | k1 = 0; 30 | 31 | switch (length & 3) 32 | { 33 | case 3: 34 | k1 ^= (uint)tail[2] << 16; 35 | goto case 2; 36 | case 2: 37 | k1 ^= (uint)tail[1] << 8; 38 | goto case 1; 39 | case 1: 40 | k1 ^= tail[0]; 41 | break; 42 | } 43 | 44 | k1 *= C1_32; 45 | k1 = RotateLeft(k1, 15); 46 | k1 *= C2_32; 47 | h1 ^= k1; 48 | 49 | uint len = (uint)length; 50 | 51 | h1 ^= len; 52 | h1 = AA_xmxmx_Murmur_32(h1); 53 | 54 | return h1; 55 | } 56 | } -------------------------------------------------------------------------------- /Src/FastHash/MurmurHash/MurmurHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.MurmurHash; 2 | 3 | internal static class MurmurHashConstants 4 | { 5 | internal const uint C1_32 = 0xcc9e2d51; 6 | internal const uint C2_32 = 0x1b873593; 7 | 8 | internal const ulong C1_64 = 0x87c37b91114253d5UL; 9 | internal const ulong C2_64 = 0x4cf5ad432745937fUL; 10 | } -------------------------------------------------------------------------------- /Src/FastHash/PolymurHash/PolymurConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.PolymurHash; 2 | 3 | internal static class PolymurConstants 4 | { 5 | internal const ulong POLYMUR_P611 = (1UL << 61) - 1; 6 | internal const ulong POLYMUR_ARBITRARY1 = 0x6a09e667f3bcc908UL; // Completely arbitrary, these 7 | internal const ulong POLYMUR_ARBITRARY2 = 0xbb67ae8584caa73bUL; // are taken from SHA-2, and 8 | internal const ulong POLYMUR_ARBITRARY3 = 0x3c6ef372fe94f82bUL; // are the fractional bits of 9 | internal const ulong POLYMUR_ARBITRARY4 = 0xa54ff53a5f1d36f1UL; // sqrt(p), p = 2, 3, 5, 7. 10 | } -------------------------------------------------------------------------------- /Src/FastHash/Properties/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using static Genbox.FastHash.Misc.Utilities; 2 | global using static Genbox.FastHash.MixFunctions; 3 | -------------------------------------------------------------------------------- /Src/FastHash/SipHash/SipHash64.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.SipHash.SipHashConstants; 3 | 4 | namespace Genbox.FastHash.SipHash; 5 | 6 | public static class SipHash64 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static ulong ComputeIndex(ulong input, ulong seed1 = 0, ulong seed2 = 0, byte cRounds = 2, byte dRounds = 4) 10 | { 11 | ulong v0 = v0Init ^ seed1; 12 | ulong v1 = v1Init ^ seed2; 13 | ulong v2 = v2Init ^ seed1; 14 | ulong v3 = v3Init ^ seed2; 15 | 16 | v3 ^= input; 17 | uint i; 18 | 19 | for (i = 0; i < cRounds; ++i) 20 | SipRound(ref v0, ref v1, ref v2, ref v3); 21 | 22 | v0 ^= input; 23 | v3 ^= 576460752303423488UL; 24 | 25 | for (i = 0; i < cRounds; ++i) 26 | SipRound(ref v0, ref v1, ref v2, ref v3); 27 | 28 | v0 ^= 576460752303423488UL; 29 | v2 ^= 0xFF; 30 | 31 | for (i = 0; i < dRounds; ++i) 32 | SipRound(ref v0, ref v1, ref v2, ref v3); 33 | 34 | return v0 ^ v1 ^ v2 ^ v3; 35 | } 36 | 37 | public static ulong ComputeHash(ReadOnlySpan data, ulong seed1 = 0, ulong seed2 = 0, byte cRounds = 2, byte dRounds = 4) 38 | { 39 | int length = data.Length; 40 | ulong v0 = v0Init; 41 | ulong v1 = v1Init; 42 | ulong v2 = v2Init; 43 | ulong v3 = v3Init; 44 | 45 | int left = length & 7; 46 | ulong b = (ulong)length << 56; 47 | int num = length / 8; 48 | int offset1 = length - left; 49 | uint i; 50 | 51 | v3 ^= seed2; 52 | v2 ^= seed1; 53 | v1 ^= seed2; 54 | v0 ^= seed1; 55 | 56 | for (i = 0; i < num; i++) 57 | { 58 | ulong m = Read64(data, 8 * i); 59 | v3 ^= m; 60 | 61 | for (int j = 0; j < cRounds; ++j) 62 | SipRound(ref v0, ref v1, ref v2, ref v3); 63 | 64 | v0 ^= m; 65 | } 66 | 67 | switch (left) 68 | { 69 | case 7: 70 | b |= (ulong)data[6 + offset1] << 48; 71 | goto case 6; 72 | case 6: 73 | b |= (ulong)data[5 + offset1] << 40; 74 | goto case 5; 75 | case 5: 76 | b |= (ulong)data[4 + offset1] << 32; 77 | goto case 4; 78 | case 4: 79 | b |= (ulong)data[3 + offset1] << 24; 80 | goto case 3; 81 | case 3: 82 | b |= (ulong)data[2 + offset1] << 16; 83 | goto case 2; 84 | case 2: 85 | b |= (ulong)data[1 + offset1] << 8; 86 | goto case 1; 87 | case 1: 88 | b |= data[0 + offset1]; 89 | break; 90 | case 0: 91 | break; 92 | } 93 | 94 | v3 ^= b; 95 | 96 | for (i = 0; i < cRounds; ++i) 97 | SipRound(ref v0, ref v1, ref v2, ref v3); 98 | 99 | v0 ^= b; 100 | v2 ^= 0xFF; 101 | 102 | for (i = 0; i < dRounds; ++i) 103 | SipRound(ref v0, ref v1, ref v2, ref v3); 104 | 105 | return v0 ^ v1 ^ v2 ^ v3; 106 | } 107 | 108 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 109 | private static void SipRound(ref ulong v0, ref ulong v1, ref ulong v2, ref ulong v3) 110 | { 111 | v0 += v1; 112 | v1 = RotateLeft(v1, 13); 113 | v1 ^= v0; 114 | v0 = RotateLeft(v0, 32); 115 | 116 | v2 += v3; 117 | v3 = RotateLeft(v3, 16); 118 | v3 ^= v2; 119 | 120 | v2 += v1; 121 | v1 = RotateLeft(v1, 17); 122 | v1 ^= v2; 123 | v2 = RotateLeft(v2, 32); 124 | 125 | v0 += v3; 126 | v3 = RotateLeft(v3, 21); 127 | v3 ^= v0; 128 | } 129 | } -------------------------------------------------------------------------------- /Src/FastHash/SipHash/SipHash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.SipHash.SipHashConstants; 3 | 4 | namespace Genbox.FastHash.SipHash; 5 | 6 | public static class SipHash64Unsafe 7 | { 8 | public static unsafe ulong ComputeHash(byte* data, int length, ulong seed1 = 0, ulong seed2 = 0, byte cRounds = 2, byte dRounds = 4) 9 | { 10 | ulong v0 = v0Init; 11 | ulong v1 = v1Init; 12 | ulong v2 = v2Init; 13 | ulong v3 = v3Init; 14 | 15 | int left = length & 7; 16 | ulong b = (ulong)length << 56; 17 | int num = length / 8; 18 | int offset1 = length - left; 19 | int i; 20 | 21 | v3 ^= seed2; 22 | v2 ^= seed1; 23 | v1 ^= seed2; 24 | v0 ^= seed1; 25 | 26 | ulong* pInput = (ulong*)data; 27 | ulong* pEnd = pInput + num; 28 | 29 | while (pInput != pEnd) 30 | { 31 | ulong m = *pInput++; 32 | v3 ^= m; 33 | 34 | for (i = 0; i < cRounds; ++i) 35 | SipRound(ref v0, ref v1, ref v2, ref v3); 36 | 37 | v0 ^= m; 38 | } 39 | 40 | switch (left) 41 | { 42 | case 7: 43 | b |= (ulong)data[6 + offset1] << 48; 44 | goto case 6; 45 | case 6: 46 | b |= (ulong)data[5 + offset1] << 40; 47 | goto case 5; 48 | case 5: 49 | b |= (ulong)data[4 + offset1] << 32; 50 | goto case 4; 51 | case 4: 52 | b |= (ulong)data[3 + offset1] << 24; 53 | goto case 3; 54 | case 3: 55 | b |= (ulong)data[2 + offset1] << 16; 56 | goto case 2; 57 | case 2: 58 | b |= (ulong)data[1 + offset1] << 8; 59 | goto case 1; 60 | case 1: 61 | b |= data[0 + offset1]; 62 | break; 63 | case 0: 64 | break; 65 | } 66 | 67 | v3 ^= b; 68 | 69 | for (i = 0; i < cRounds; ++i) 70 | SipRound(ref v0, ref v1, ref v2, ref v3); 71 | 72 | v0 ^= b; 73 | v2 ^= 0xFF; 74 | 75 | for (i = 0; i < dRounds; ++i) 76 | SipRound(ref v0, ref v1, ref v2, ref v3); 77 | 78 | return v0 ^ v1 ^ v2 ^ v3; 79 | } 80 | 81 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 82 | private static void SipRound(ref ulong v0, ref ulong v1, ref ulong v2, ref ulong v3) 83 | { 84 | v0 += v1; 85 | v1 = RotateLeft(v1, 13); 86 | v1 ^= v0; 87 | v0 = RotateLeft(v0, 32); 88 | 89 | v2 += v3; 90 | v3 = RotateLeft(v3, 16); 91 | v3 ^= v2; 92 | 93 | v2 += v1; 94 | v1 = RotateLeft(v1, 17); 95 | v1 ^= v2; 96 | v2 = RotateLeft(v2, 32); 97 | 98 | v0 += v3; 99 | v3 = RotateLeft(v3, 21); 100 | v3 ^= v0; 101 | } 102 | } -------------------------------------------------------------------------------- /Src/FastHash/SipHash/SipHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.SipHash; 2 | 3 | public static class SipHashConstants 4 | { 5 | public const ulong v0Init = 0x736f6d6570736575U; 6 | public const ulong v1Init = 0x646f72616e646f6dU; 7 | public const ulong v2Init = 0x6c7967656e657261U; 8 | public const ulong v3Init = 0x7465646279746573U; 9 | } -------------------------------------------------------------------------------- /Src/FastHash/SuperFastHash/SuperFastHash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Genbox.FastHash.SuperFastHash; 4 | 5 | public static class SuperFastHash32 6 | { 7 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 8 | public static uint ComputeIndex(uint input) 9 | { 10 | uint hash = 4 + (uint)(ushort)input; 11 | hash = (hash << 16) ^ ((input >> 16) << 11) ^ hash; 12 | hash += hash >> 11; 13 | hash ^= hash << 3; 14 | hash += hash >> 5; 15 | hash ^= hash << 4; 16 | hash += hash >> 17; 17 | hash ^= hash << 25; 18 | hash += hash >> 6; 19 | return hash; 20 | } 21 | 22 | public static uint ComputeHash(ReadOnlySpan data) 23 | { 24 | if (data.Length <= 0) 25 | return 0; 26 | 27 | int length = data.Length; 28 | uint hash = (uint)length, tmp; 29 | int rem = length & 3; 30 | length >>= 2; 31 | 32 | int index = 0; 33 | 34 | for (; length > 0; length--) 35 | { 36 | hash += Read16(data, index); 37 | tmp = (uint)((Read16(data, index + 2) << 11) ^ hash); 38 | hash = (hash << 16) ^ tmp; 39 | index += 2 * sizeof(ushort); 40 | hash += hash >> 11; 41 | } 42 | 43 | switch (rem) 44 | { 45 | case 3: 46 | hash += Read16(data, index); 47 | hash ^= hash << 16; 48 | hash ^= (uint)(data[index + sizeof(ushort)] << 18); 49 | hash += hash >> 11; 50 | break; 51 | case 2: 52 | hash += Read16(data, index); 53 | hash ^= hash << 11; 54 | hash += hash >> 17; 55 | break; 56 | case 1: 57 | hash += data[index]; 58 | hash ^= hash << 10; 59 | hash += hash >> 1; 60 | break; 61 | } 62 | 63 | // Force "avalanching" of final 127 bits 64 | hash ^= hash << 3; 65 | hash += hash >> 5; 66 | hash ^= hash << 4; 67 | hash += hash >> 17; 68 | hash ^= hash << 25; 69 | hash += hash >> 6; 70 | 71 | return hash; 72 | } 73 | } -------------------------------------------------------------------------------- /Src/FastHash/SuperFastHash/SuperFastHash32Unsafe.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.SuperFastHash; 2 | 3 | public static class SuperFastHash32Unsafe 4 | { 5 | public static unsafe uint ComputeHash(byte* data, int length) 6 | { 7 | if (data == null || length <= 0) 8 | return 0; 9 | 10 | uint hash = (uint)length, tmp; 11 | int rem = length & 3; 12 | length >>= 2; 13 | 14 | for (; length > 0; length--) 15 | { 16 | hash += Read16(data); 17 | tmp = (uint)((Read16(data + 2) << 11) ^ hash); 18 | hash = (hash << 16) ^ tmp; 19 | data += 2 * sizeof(ushort); 20 | hash += hash >> 11; 21 | } 22 | 23 | switch (rem) 24 | { 25 | case 3: 26 | hash += Read16(data); 27 | hash ^= hash << 16; 28 | hash ^= (uint)(data[sizeof(ushort)] << 18); 29 | hash += hash >> 11; 30 | break; 31 | case 2: 32 | hash += Read16(data); 33 | hash ^= hash << 11; 34 | hash += hash >> 17; 35 | break; 36 | case 1: 37 | hash += *data; 38 | hash ^= hash << 10; 39 | hash += hash >> 1; 40 | break; 41 | } 42 | 43 | // Force "avalanching" of final 127 bits 44 | hash ^= hash << 3; 45 | hash += hash >> 5; 46 | hash ^= hash << 4; 47 | hash += hash >> 17; 48 | hash ^= hash << 25; 49 | hash += hash >> 6; 50 | 51 | return hash; 52 | } 53 | } -------------------------------------------------------------------------------- /Src/FastHash/UInt128.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace Genbox.FastHash; 4 | 5 | [StructLayout(LayoutKind.Sequential)] 6 | public struct UInt128(ulong low, ulong high) 7 | { 8 | public ulong Low = low; 9 | public ulong High = high; 10 | 11 | public override string ToString() => Low + "," + High; 12 | } -------------------------------------------------------------------------------- /Src/FastHash/WyHash/Wy3Hash64.cs: -------------------------------------------------------------------------------- 1 | //#define WYHASH_CONDOM 2 | 3 | //WYHASH_CONDOM protections produce different results: 4 | //1: normal valid behavior 5 | //2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication" 6 | 7 | using System.Runtime.CompilerServices; 8 | using static Genbox.FastHash.WyHash.WyHashConstants; 9 | 10 | namespace Genbox.FastHash.WyHash; 11 | 12 | public static class Wy3Hash64 13 | { 14 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 15 | public static ulong ComputeIndex(ulong input) 16 | { 17 | ulong a = ((ulong)(uint)input << 32) | (uint)(input >> 32); 18 | ulong b = ((ulong)(uint)(input >> 32) << 32) | (uint)input; 19 | 20 | ulong high = BigMul(a ^ 0xe7037ed1a0b428dbul, b ^ 0xa0761d6478bd642ful, out ulong low); 21 | return _wymix(0xe7037ed1a0b428dbul ^ 8, low ^ high); 22 | } 23 | 24 | public static ulong ComputeHash(ReadOnlySpan data, ulong seed = 0, ulong[]? secret = null) 25 | { 26 | secret ??= DefaultSecret; 27 | 28 | int len = data.Length; 29 | seed ^= secret[0]; 30 | ulong a, b; 31 | 32 | if (len <= 16) 33 | { 34 | if (len >= 4) 35 | { 36 | a = ((ulong)Read32(data) << 32) | Read32(data, (len >> 3) << 2); 37 | b = ((ulong)Read32(data, len - 4) << 32) | Read32(data, len - 4 - ((len >> 3) << 2)); 38 | } 39 | else if (len > 0) 40 | { 41 | a = _wyr3(data, len); 42 | b = 0; 43 | } 44 | else 45 | { 46 | a = 0; 47 | b = 0; 48 | } 49 | } 50 | else 51 | { 52 | int i = len; 53 | uint offset = 0; 54 | 55 | if (i > 48) 56 | { 57 | ulong see1 = seed, see2 = seed; 58 | do 59 | { 60 | seed = _wymix(Read64(data, offset) ^ secret[1], Read64(data, offset + 8) ^ seed); 61 | see1 = _wymix(Read64(data, offset + 16) ^ secret[2], Read64(data, offset + 24) ^ see1); 62 | see2 = _wymix(Read64(data, offset + 32) ^ secret[3], Read64(data, offset + 40) ^ see2); 63 | offset += 48; 64 | i -= 48; 65 | } while (i > 48); 66 | seed ^= see1 ^ see2; 67 | } 68 | while (i > 16) 69 | { 70 | uint offset1 = offset + 8; 71 | seed = _wymix(Read64(data, offset) ^ secret[1], Read64(data, offset1) ^ seed); 72 | i -= 16; 73 | offset += 16; 74 | } 75 | a = Read64(data, (uint)(offset + i - 16)); 76 | b = Read64(data, (uint)(offset + i - 8)); 77 | } 78 | return _wymix(secret[1] ^ (uint)len, _wymix(a ^ secret[1], b ^ seed)); 79 | } 80 | 81 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 82 | private static ulong _wyr3(ReadOnlySpan data, int offset = 0) => ((ulong)data[0] << 16) | ((ulong)data[offset >> 1] << 8) | data[offset - 1]; 83 | 84 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 85 | private static void _wymum(ref ulong A, ref ulong B) 86 | { 87 | ulong high = BigMul(A, B, out ulong low); 88 | 89 | #if WYHASH_CONDOM 90 | A ^= low; 91 | B ^= high; 92 | #else 93 | A = low; 94 | B = high; 95 | #endif 96 | } 97 | 98 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 99 | private static ulong _wymix(ulong A, ulong B) 100 | { 101 | _wymum(ref A, ref B); 102 | return A ^ B; 103 | } 104 | } -------------------------------------------------------------------------------- /Src/FastHash/WyHash/Wy3Hash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | //#define WYHASH_CONDOM 2 | 3 | //WYHASH_CONDOM protections produce different results: 4 | //1: normal valid behavior 5 | //2: extra protection against entropy loss (probability=2^-63), aka. "blind multiplication" 6 | 7 | using System.Runtime.CompilerServices; 8 | using static Genbox.FastHash.WyHash.WyHashConstants; 9 | 10 | namespace Genbox.FastHash.WyHash; 11 | 12 | public static class Wy3Hash64Unsafe 13 | { 14 | public static unsafe ulong ComputeHash(byte* data, int length, ulong seed = 0) 15 | { 16 | fixed (ulong* secret = DefaultSecret) 17 | { 18 | uint len = (uint)length; 19 | seed ^= secret[0]; 20 | ulong a, b; 21 | 22 | if (len <= 16) 23 | { 24 | if (len >= 4) 25 | { 26 | a = ((ulong)Read32(data) << 32) | Read32(data + ((len >> 3) << 2)); 27 | b = ((ulong)Read32(data + (len - 4)) << 32) | Read32(data + (len - 4 - ((len >> 3) << 2))); 28 | } 29 | else if (len > 0) 30 | { 31 | a = _wyr3(data, len); 32 | b = 0; 33 | } 34 | else 35 | { 36 | a = 0; 37 | b = 0; 38 | } 39 | } 40 | else 41 | { 42 | uint i = len; 43 | 44 | if (i > 48) 45 | { 46 | ulong see1 = seed, see2 = seed; 47 | do 48 | { 49 | seed = _wymix(Read64(data) ^ secret[1], Read64(data + 8) ^ seed); 50 | see1 = _wymix(Read64(data + 16) ^ secret[2], Read64(data + 24) ^ see1); 51 | see2 = _wymix(Read64(data + 32) ^ secret[3], Read64(data + 40) ^ see2); 52 | data += 48; 53 | i -= 48; 54 | } while (i > 48); 55 | seed ^= see1 ^ see2; 56 | } 57 | while (i > 16) 58 | { 59 | seed = _wymix(Read64(data) ^ secret[1], Read64(data + 8) ^ seed); 60 | i -= 16; 61 | data += 16; 62 | } 63 | a = Read64(data + i - 16); 64 | b = Read64(data + i - 8); 65 | } 66 | return _wymix(secret[1] ^ len, _wymix(a ^ secret[1], b ^ seed)); 67 | } 68 | } 69 | 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | private static unsafe ulong _wyr3(byte* data, uint offset = 0) => ((ulong)data[0] << 16) | ((ulong)data[offset >> 1] << 8) | data[offset - 1]; 72 | 73 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 74 | private static unsafe void _wymum(ulong* A, ulong* B) 75 | { 76 | ulong low; 77 | ulong high = BigMul(*A, *B, out low); 78 | 79 | #if WYHASH_CONDOM 80 | *A ^= low; 81 | *B ^= high; 82 | #else 83 | *A = low; 84 | *B = high; 85 | #endif 86 | } 87 | 88 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 89 | private static unsafe ulong _wymix(ulong A, ulong B) 90 | { 91 | _wymum(&A, &B); 92 | return A ^ B; 93 | } 94 | } -------------------------------------------------------------------------------- /Src/FastHash/WyHash/WyHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.WyHash; 2 | 3 | internal static class WyHashConstants 4 | { 5 | internal static readonly ulong[] DefaultSecret = [0xa0761d6478bd642ful, 0xe7037ed1a0b428dbul, 0x8ebc6af09c88c6e3ul, 0x589965cc75374cc3ul]; 6 | } -------------------------------------------------------------------------------- /Src/FastHash/XxHash/Xx2Hash32.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.XxHash.XxHashConstants; 3 | 4 | namespace Genbox.FastHash.XxHash; 5 | 6 | public static class Xx2Hash32 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static uint ComputeIndex(uint input) 10 | { 11 | uint acc = input * PRIME32_3; 12 | acc += PRIME32_5; 13 | acc += 4; 14 | 15 | uint h32 = RotateLeft(acc, 17) * PRIME32_4; 16 | h32 ^= h32 >> 15; 17 | h32 *= PRIME32_2; 18 | h32 ^= h32 >> 13; 19 | h32 *= PRIME32_3; 20 | h32 ^= h32 >> 16; 21 | return h32; 22 | } 23 | 24 | public static uint ComputeHash(ReadOnlySpan data, uint seed = 0) 25 | { 26 | uint len = (uint)data.Length; 27 | uint h32; 28 | int offset = 0; 29 | 30 | if (len >= 16) 31 | { 32 | uint bEnd = len; 33 | uint limit = bEnd - 15; 34 | uint v1 = seed + PRIME32_1 + PRIME32_2; 35 | uint v2 = seed + PRIME32_2; 36 | uint v3 = seed + 0; 37 | uint v4 = seed - PRIME32_1; 38 | 39 | do 40 | { 41 | v1 = Round(v1, Read32(data, offset)); 42 | offset += 4; 43 | v2 = Round(v2, Read32(data, offset)); 44 | offset += 4; 45 | v3 = Round(v3, Read32(data, offset)); 46 | offset += 4; 47 | v4 = Round(v4, Read32(data, offset)); 48 | offset += 4; 49 | } while (offset < limit); 50 | 51 | h32 = RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); 52 | } 53 | else 54 | h32 = seed + PRIME32_5; 55 | 56 | h32 += len; 57 | len &= 15; 58 | while (len >= 4) 59 | { 60 | h32 += Read32(data, offset) * PRIME32_3; 61 | offset += 4; 62 | h32 = RotateLeft(h32, 17) * PRIME32_4; 63 | len -= 4; 64 | } 65 | 66 | while (len > 0) 67 | { 68 | h32 += data[offset++] * PRIME32_5; 69 | h32 = RotateLeft(h32, 11) * PRIME32_1; 70 | len--; 71 | } 72 | 73 | return YC_xmxmx_XXH2_32(h32); 74 | } 75 | 76 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 77 | private static uint Round(uint seed, uint input) 78 | { 79 | seed += input * PRIME32_2; 80 | seed = RotateLeft(seed, 13); 81 | seed *= PRIME32_1; 82 | return seed; 83 | } 84 | } -------------------------------------------------------------------------------- /Src/FastHash/XxHash/Xx2Hash32Unsafe.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.XxHash.XxHashConstants; 3 | 4 | namespace Genbox.FastHash.XxHash; 5 | 6 | public static class Xx2Hash32Unsafe 7 | { 8 | public static unsafe uint ComputeHash(byte* data, int length, uint seed = 0) 9 | { 10 | uint h32; 11 | 12 | if (length >= 16) 13 | { 14 | byte* bEnd = data + length; 15 | byte* limit = bEnd - 15; 16 | uint v1 = seed + PRIME32_1 + PRIME32_2; 17 | uint v2 = seed + PRIME32_2; 18 | uint v3 = seed + 0; 19 | uint v4 = seed - PRIME32_1; 20 | 21 | do 22 | { 23 | v1 = Round(v1, Read32(data)); 24 | data += 4; 25 | v2 = Round(v2, Read32(data)); 26 | data += 4; 27 | v3 = Round(v3, Read32(data)); 28 | data += 4; 29 | v4 = Round(v4, Read32(data)); 30 | data += 4; 31 | } while (data < limit); 32 | 33 | h32 = RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); 34 | } 35 | else 36 | h32 = seed + PRIME32_5; 37 | 38 | h32 += (uint)length; 39 | length &= 15; 40 | while (length >= 4) 41 | { 42 | h32 += Read32(data) * PRIME32_3; 43 | data += 4; 44 | h32 = RotateLeft(h32, 17) * PRIME32_4; 45 | length -= 4; 46 | } 47 | 48 | while (length > 0) 49 | { 50 | h32 += Read8(data) * PRIME32_5; 51 | data++; 52 | h32 = RotateLeft(h32, 11) * PRIME32_1; 53 | length--; 54 | } 55 | 56 | h32 ^= h32 >> 15; 57 | h32 *= PRIME32_2; 58 | h32 ^= h32 >> 13; 59 | h32 *= PRIME32_3; 60 | h32 ^= h32 >> 16; 61 | 62 | return h32; 63 | } 64 | 65 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 66 | private static uint Round(uint seed, uint input) 67 | { 68 | seed += input * PRIME32_2; 69 | seed = RotateLeft(seed, 13); 70 | seed *= PRIME32_1; 71 | return seed; 72 | } 73 | } -------------------------------------------------------------------------------- /Src/FastHash/XxHash/Xx2Hash64.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.XxHash.XxHashConstants; 3 | 4 | namespace Genbox.FastHash.XxHash; 5 | 6 | public static class Xx2Hash64 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | public static ulong ComputeIndex(ulong input) 10 | { 11 | ulong acc = input * PRIME64_2; 12 | acc = RotateLeft(acc, 31); 13 | acc *= PRIME64_1; 14 | 15 | ulong h64 = (PRIME64_5 + 8) ^ acc; 16 | h64 = (RotateLeft(h64, 27) * PRIME64_1) + PRIME64_4; 17 | h64 ^= h64 >> 33; 18 | h64 *= PRIME64_2; 19 | h64 ^= h64 >> 29; 20 | h64 *= PRIME64_3; 21 | h64 ^= h64 >> 32; 22 | return h64; 23 | } 24 | 25 | public static ulong ComputeHash(ReadOnlySpan data, ulong seed = 0) 26 | { 27 | uint len = (uint)data.Length; 28 | ulong h64; 29 | int offset = 0; 30 | 31 | if (len >= 32) 32 | { 33 | uint bEnd = len; 34 | uint limit = bEnd - 31; 35 | ulong v1 = seed + PRIME64_1 + PRIME64_2; 36 | ulong v2 = seed + PRIME64_2; 37 | ulong v3 = seed + 0; 38 | ulong v4 = seed - PRIME64_1; 39 | 40 | do 41 | { 42 | v1 = Round(v1, Read64(data, offset)); 43 | offset += 8; 44 | v2 = Round(v2, Read64(data, offset)); 45 | offset += 8; 46 | v3 = Round(v3, Read64(data, offset)); 47 | offset += 8; 48 | v4 = Round(v4, Read64(data, offset)); 49 | offset += 8; 50 | } while (offset < limit); 51 | 52 | h64 = RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); 53 | h64 = MergeRound(h64, v1); 54 | h64 = MergeRound(h64, v2); 55 | h64 = MergeRound(h64, v3); 56 | h64 = MergeRound(h64, v4); 57 | } 58 | else 59 | h64 = seed + PRIME64_5; 60 | 61 | h64 += len; 62 | len &= 31; 63 | while (len >= 8) 64 | { 65 | ulong k1 = Round(0, Read64(data, offset)); 66 | offset += 8; 67 | h64 ^= k1; 68 | h64 = (RotateLeft(h64, 27) * PRIME64_1) + PRIME64_4; 69 | len -= 8; 70 | } 71 | 72 | if (len >= 4) 73 | { 74 | h64 ^= Read32(data, offset) * PRIME64_1; 75 | offset += 4; 76 | h64 = (RotateLeft(h64, 23) * PRIME64_2) + PRIME64_3; 77 | len -= 4; 78 | } 79 | 80 | while (len > 0) 81 | { 82 | h64 ^= data[offset++] * PRIME64_5; 83 | h64 = RotateLeft(h64, 11) * PRIME64_1; 84 | len--; 85 | } 86 | 87 | return YC_xmxmx_XXH2_64(h64); 88 | } 89 | 90 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 91 | private static ulong Round(ulong acc, ulong input) 92 | { 93 | acc += input * PRIME64_2; 94 | acc = RotateLeft(acc, 31); 95 | acc *= PRIME64_1; 96 | return acc; 97 | } 98 | 99 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 100 | private static ulong MergeRound(ulong acc, ulong val) 101 | { 102 | val = Round(0, val); 103 | acc ^= val; 104 | acc = (acc * PRIME64_1) + PRIME64_4; 105 | return acc; 106 | } 107 | } -------------------------------------------------------------------------------- /Src/FastHash/XxHash/Xx2Hash64Unsafe.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.XxHash.XxHashConstants; 3 | 4 | namespace Genbox.FastHash.XxHash; 5 | 6 | public static class Xx2Hash64Unsafe 7 | { 8 | public static unsafe ulong ComputeHash(byte* data, int length, uint seed = 0) 9 | { 10 | ulong h64; 11 | 12 | if (length >= 32) 13 | { 14 | byte* bEnd = data + length; 15 | byte* limit = bEnd - 31; 16 | 17 | ulong v1 = seed + PRIME64_1 + PRIME64_2; 18 | ulong v2 = seed + PRIME64_2; 19 | ulong v3 = seed + 0; 20 | ulong v4 = seed - PRIME64_1; 21 | 22 | do 23 | { 24 | v1 = Round(v1, Read64(data)); 25 | data += 8; 26 | v2 = Round(v2, Read64(data)); 27 | data += 8; 28 | v3 = Round(v3, Read64(data)); 29 | data += 8; 30 | v4 = Round(v4, Read64(data)); 31 | data += 8; 32 | } while (data < limit); 33 | 34 | h64 = RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); 35 | h64 = MergeRound(h64, v1); 36 | h64 = MergeRound(h64, v2); 37 | h64 = MergeRound(h64, v3); 38 | h64 = MergeRound(h64, v4); 39 | } 40 | else 41 | h64 = seed + PRIME64_5; 42 | 43 | h64 += (uint)length; 44 | 45 | length &= 31; 46 | while (length >= 8) 47 | { 48 | ulong k1 = Round(0, Read64(data)); 49 | data += 8; 50 | h64 ^= k1; 51 | h64 = (RotateLeft(h64, 27) * PRIME64_1) + PRIME64_4; 52 | length -= 8; 53 | } 54 | 55 | if (length >= 4) 56 | { 57 | h64 ^= Read32(data) * PRIME64_1; 58 | data += 4; 59 | h64 = (RotateLeft(h64, 23) * PRIME64_2) + PRIME64_3; 60 | length -= 4; 61 | } 62 | 63 | while (length > 0) 64 | { 65 | h64 ^= Read8(data) * PRIME64_5; 66 | data++; 67 | h64 = RotateLeft(h64, 11) * PRIME64_1; 68 | length--; 69 | } 70 | 71 | h64 ^= h64 >> 33; 72 | h64 *= PRIME64_2; 73 | h64 ^= h64 >> 29; 74 | h64 *= PRIME64_3; 75 | h64 ^= h64 >> 32; 76 | 77 | return h64; 78 | } 79 | 80 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 81 | private static ulong Round(ulong acc, ulong input) 82 | { 83 | acc += input * PRIME64_2; 84 | acc = RotateLeft(acc, 31); 85 | acc *= PRIME64_1; 86 | return acc; 87 | } 88 | 89 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 90 | private static ulong MergeRound(ulong acc, ulong val) 91 | { 92 | val = Round(0, val); 93 | acc ^= val; 94 | acc = (acc * PRIME64_1) + PRIME64_4; 95 | return acc; 96 | } 97 | } -------------------------------------------------------------------------------- /Src/FastHash/XxHash/XxHashConstants.cs: -------------------------------------------------------------------------------- 1 | namespace Genbox.FastHash.XxHash; 2 | 3 | internal static class XxHashConstants 4 | { 5 | internal const int MIDSIZE_MAX = 240; 6 | internal const int MIDSIZE_STARTOFFSET = 3; 7 | internal const int MIDSIZE_LASTOFFSET = 17; 8 | 9 | internal const int ACC_SIZE = 64; 10 | internal const int ACC_ALIGN = 8; 11 | internal const int ACC_NB = STRIPE_LEN / 8; 12 | internal const int STRIPE_LEN = 64; 13 | 14 | internal const int SECRET_SIZE_MIN = 136; 15 | internal const int SECRET_DEFAULT_SIZE = 192; 16 | internal const int SECRET_CONSUME_RATE = 8; 17 | internal const int SECRET_MERGEACCS_START = 11; 18 | internal const int SECRET_LASTACC_START = 7; 19 | 20 | internal const byte MM_SHUFFLE_0_3_0_1 = 0b0011_0001; 21 | internal const byte MM_SHUFFLE_1_0_3_2 = 0b0100_1110; 22 | 23 | internal const uint PRIME32_1 = 2654435761U; 24 | internal const uint PRIME32_2 = 2246822519U; 25 | internal const uint PRIME32_3 = 3266489917U; 26 | internal const uint PRIME32_4 = 668265263U; 27 | internal const uint PRIME32_5 = 374761393U; 28 | 29 | internal const ulong PRIME64_1 = 11400714785074694791UL; 30 | internal const ulong PRIME64_2 = 14029467366897019727UL; 31 | internal const ulong PRIME64_3 = 1609587929392839161UL; 32 | internal const ulong PRIME64_4 = 9650029242287828579UL; 33 | internal const ulong PRIME64_5 = 2870177450012600261UL; 34 | 35 | // [FixedAddressValueType] 36 | // internal static readonly Vector256 M256i_XXH_PRIME32_1 = Vector256.Create(PRIME32_1); 37 | // 38 | // [FixedAddressValueType] 39 | // internal static readonly Vector128 M128i_XXH_PRIME32_1 = Vector128.Create(PRIME32_1); 40 | 41 | internal static readonly byte[] kSecret = 42 | [ 43 | 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 44 | 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 45 | 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, 46 | 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, 47 | 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, 48 | 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, 49 | 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, 50 | 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, 51 | 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, 52 | 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, 53 | 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, 54 | 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e 55 | ]; 56 | 57 | internal static readonly ulong[] INIT_ACC = 58 | [ 59 | PRIME32_3, PRIME64_1, PRIME64_2, PRIME64_3, 60 | PRIME64_4, PRIME32_2, PRIME64_5, PRIME32_1 61 | ]; 62 | } -------------------------------------------------------------------------------- /Src/FastHash/XxHash/XxHashShared.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using static Genbox.FastHash.XxHash.XxHashConstants; 3 | 4 | namespace Genbox.FastHash.XxHash; 5 | 6 | internal static class XxHashShared 7 | { 8 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 9 | internal static ulong XXH3_avalanche(ulong hash) 10 | { 11 | hash ^= hash >> 37; 12 | hash *= 0x165667919E3779F9UL; 13 | hash ^= hash >> 32; 14 | return hash; 15 | } 16 | 17 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 18 | internal static ulong XXH_mult32to64(ulong x, ulong y) => (uint)x * (ulong)(uint)y; 19 | 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | internal static ulong XXH_xorshift64(ulong v64, int shift) => v64 ^ (v64 >> shift); 22 | 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | internal static UInt128 XXH_mult64to128(ulong lhs, ulong rhs) 25 | { 26 | ulong high = BigMul(lhs, rhs, out ulong low); 27 | return new UInt128(low, high); 28 | } 29 | 30 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 31 | internal static ulong XXH3_mul128_fold64(ulong lhs, ulong rhs) 32 | { 33 | UInt128 product = XXH_mult64to128(lhs, rhs); 34 | return product.Low ^ product.High; 35 | } 36 | 37 | internal static ulong XXH3_mix16B(ReadOnlySpan input, int offset, ReadOnlySpan secret, int secretOffset, ulong seed64) 38 | { 39 | ulong input_lo = Read64(input, offset); 40 | ulong input_hi = Read64(input, offset + 8); 41 | 42 | return XXH3_mul128_fold64( 43 | input_lo ^ (Read64(secret, secretOffset) + seed64), 44 | input_hi ^ (Read64(secret, secretOffset + 8) - seed64) 45 | ); 46 | } 47 | 48 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 49 | internal static void XXH3_hashLong_internal_loop(Span acc, ReadOnlySpan input, int len, ReadOnlySpan secret, int secretSize, XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) 50 | { 51 | int nbStripesPerBlock = (secretSize - STRIPE_LEN) / SECRET_CONSUME_RATE; 52 | int block_len = STRIPE_LEN * nbStripesPerBlock; 53 | int nb_blocks = (len - 1) / block_len; 54 | 55 | for (int n = 0; n < nb_blocks; n++) 56 | { 57 | XXH3_accumulate(acc, input.Slice(n * block_len), secret, nbStripesPerBlock, f_acc512); 58 | f_scramble(acc, secret.Slice( secretSize - STRIPE_LEN)); 59 | } 60 | 61 | /* last partial block */ 62 | // XXH_ASSERT(len > XXH_STRIPE_LEN); 63 | int nbStripes = (len - 1 - (block_len * nb_blocks)) / STRIPE_LEN; 64 | // XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); 65 | XXH3_accumulate(acc, input.Slice(nb_blocks * block_len), secret, nbStripes, f_acc512); 66 | 67 | ReadOnlySpan p = input.Slice(len - STRIPE_LEN); 68 | f_acc512(acc, p, secret.Slice(secretSize - STRIPE_LEN - SECRET_LASTACC_START)); 69 | } 70 | 71 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 72 | internal static ulong XXH3_mergeAccs(Span acc, ReadOnlySpan secret, int secretOffset, ulong start) 73 | { 74 | ulong result64 = start; 75 | 76 | for (int i = 0; i < 4; i++) 77 | result64 += XXH3_mix2Accs(acc, 2 * i, secret, secretOffset + (16 * i)); 78 | 79 | return XXH3_avalanche(result64); 80 | } 81 | 82 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 83 | private static ulong XXH3_mix2Accs(Span acc, int offset, ReadOnlySpan secret, int secretOffset) 84 | { 85 | return XXH3_mul128_fold64(acc[offset + 0] ^ Read64(secret, secretOffset), acc[offset + 1] ^ Read64(secret, secretOffset + 8)); 86 | } 87 | 88 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 89 | private static void XXH3_accumulate(Span acc, ReadOnlySpan input, ReadOnlySpan secret, int nbStripes, XXH3_f_accumulate_512 f_acc512) 90 | { 91 | for (int n = 0; n < nbStripes; n++) 92 | { 93 | ReadOnlySpan inp = input.Slice(n * STRIPE_LEN); 94 | f_acc512(acc, inp, secret.Slice(n * SECRET_CONSUME_RATE)); 95 | } 96 | } 97 | 98 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 99 | internal static void XXH3_accumulate_512_scalar(Span acc, ReadOnlySpan input, ReadOnlySpan secret) 100 | { 101 | for (int i = 0; i < ACC_NB; i++) 102 | XXH3_scalarRound(acc, input, secret, i); 103 | } 104 | 105 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 106 | private static void XXH3_scalarRound(Span acc, ReadOnlySpan input, ReadOnlySpan secret, int lane) 107 | { 108 | Span xacc = acc; 109 | ReadOnlySpan xinput = input; 110 | ReadOnlySpan xsecret = secret; 111 | 112 | ulong data_val = Read64(xinput, lane * 8); 113 | ulong data_key = data_val ^ Read64(xsecret, lane * 8); 114 | xacc[lane ^ 1] += data_val; 115 | xacc[lane] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); 116 | } 117 | 118 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 119 | internal static void XXH3_scrambleAcc_scalar(Span acc, ReadOnlySpan secret) 120 | { 121 | for (int i = 0; i < ACC_NB; i++) 122 | XXH3_scalarScrambleRound(acc, secret, i); 123 | } 124 | 125 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 126 | private static void XXH3_scalarScrambleRound(Span acc, ReadOnlySpan secret, int lane) 127 | { 128 | Span xacc = acc; 129 | ReadOnlySpan xsecret = secret; 130 | 131 | ulong key64 = Read64(xsecret , lane * 8); 132 | ulong acc64 = xacc[lane]; 133 | acc64 = XXH_xorshift64(acc64, 47); 134 | acc64 ^= key64; 135 | acc64 *= PRIME32_1; 136 | xacc[lane] = acc64; 137 | } 138 | 139 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 140 | internal static void XXH3_initCustomSecret_scalar(Span customSecret, ulong seed) 141 | { 142 | int nbRounds = SECRET_DEFAULT_SIZE / 16; 143 | 144 | for (int i = 0; i < nbRounds; i++) 145 | { 146 | ulong lo = Read64(kSecret, 16 * i) + seed; 147 | ulong hi = Read64(kSecret, (16 * i) + 8) - seed; 148 | Write64(customSecret, 16 * i, lo); 149 | Write64(customSecret, (16 * i) + 8, hi); 150 | } 151 | } 152 | 153 | internal delegate ulong XXH3_hashLong64_f(ReadOnlySpan input, int len, ulong seed64, ReadOnlySpan secret, int secretLen); 154 | internal delegate UInt128 XXH3_hashLong128_f(ReadOnlySpan input, int len, ulong seed64, ReadOnlySpan secret, int secretLen); 155 | internal delegate void XXH3_f_scrambleAcc(Span acc, ReadOnlySpan secret); 156 | internal delegate void XXH3_f_initCustomSecret(Span customSecret, ulong seed); 157 | internal delegate void XXH3_f_accumulate_512(Span acc, ReadOnlySpan input, ReadOnlySpan secret); 158 | } 159 | 160 | --------------------------------------------------------------------------------