Compare commits

..

15 Commits

Author SHA1 Message Date
3e1a2c00e6 updated dependencies 2025-05-22 20:40:28 +05:00
9360dfe305 v1.0.3 2025-03-22 23:32:35 +05:00
b14ddd8a23 Merge branch 'main' of https://timerix.ddns.net:3322/Timerix/DTLib.XXHash 2025-03-22 23:28:03 +05:00
dc1326ffec TargetFrameworks 2025-03-22 23:27:29 +05:00
895d53d362 TargetFrameworks 2024-09-20 02:38:29 +05:00
ea7471d09e changed repository url 2024-09-20 01:55:11 +05:00
bcaa7a9411 target only netstandard 2.0 and 2.1 2024-09-20 01:42:18 +05:00
676d59bf80 don't pack perf test 2024-01-07 20:55:48 +06:00
bec532f6d9 project file small fix 2024-01-07 20:38:12 +06:00
b806cf6e18 fixed tests 2024-01-07 20:27:18 +06:00
90ad0a9f5a project files added and fixed 2024-01-07 20:09:53 +06:00
Melnik Alexander
6b20e7f7b3 Merge pull request #23 from legigor/master
Add net5.0 support
2022-10-05 20:50:56 +03:00
Igor Tamashchuk
62d648b6c3 Add net5.0 support 2022-10-05 20:31:44 +03:00
Oleksandr Melnyk
f97a238e61 Improve perfomance for XXH128 & XXH3 2022-07-17 17:07:11 +03:00
Oleksandr Melnyk
91b72f21db Improve perfomance for XXH32 and XXH64 2022-07-17 17:03:38 +03:00
49 changed files with 1872 additions and 5302 deletions

View File

@@ -1,25 +0,0 @@
name: .NET
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore ./src
- name: Build
run: dotnet build ./src --no-restore
- name: Test
run: dotnet test ./src --no-build --verbosity normal

View File

@@ -1,31 +0,0 @@
name: Release to NuGet
on:
workflow_dispatch:
inputs:
version:
description: Bump Version
default: v1.0.0
required: true
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.0.x
- name: Build
run: dotnet build ./src -c Release
- name: Test
run: dotnet test ./src -c Release --no-build
- name: Pack nugets
run: dotnet pack ./src/Standart.Hash.xxHash -c Release --no-build --output .
- name: Push to NuGet
run: dotnet nuget push "*.nupkg" --api-key ${{secrets.nuget_api_key}} --source https://api.nuget.org/v3/index.json

312
.gitignore vendored
View File

@@ -1,288 +1,24 @@
## Ignore Visual Studio temporary files, build results, and # Build results
## files generated by popular Visual Studio add-ons. [Bb]in/
## .bin/
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore [Dd]ebug/
[Rr]elease/
# User-specific files [Rr]eleases/
*.suo [Oo]bj/
*.user [Oo]ut/
*.userosscache [Ll]og/
*.sln.docstates [Ll]ogs/
nuget/
# User-specific files (MonoDevelop/Xamarin Studio) *[-_]tmp/
*.userprefs
# IDE files
# Build results .vs/
[Dd]ebug/ .vscode/
[Dd]ebugPublic/ .vshistory/
[Rr]elease/ .idea/
[Rr]eleases/ .editorconfig
x64/ *.user
x86/
bld/ #backups
[Bb]in/ .old*/
[Oo]bj/ *[-_]old/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

View File

@@ -1,16 +0,0 @@
# 2022-06-13
- Added xxHash3
# 2022-06-05
- Added SIMD support for xxHash128
- Inlined all method calls for xxHash128
# 2022-06-03
- Added xxHash128
- Migrated to net6
# 2019-02-16
- Migrated to net core v.3.1
- Added bit operation utils
# 2019-12-15
- Added support for ArraySegment (thanks ksmith3036)
# 2018-03-11
- Added API for ReadOnlySpan
- Added support for the async calls with cancelation tokens

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsPackable>false</IsPackable>
<OutputType>Exe</OutputType>
<TargetFrameworks>net48;net6.0;net8.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<BenchmarkDotNet>0.13.1</BenchmarkDotNet>
<MicrosoftSdk>17.2.0</MicrosoftSdk>
<xUnit>2.4.1</xUnit>
<xUnitRunner>2.4.5</xUnitRunner>
<xUnitTool>2.3.1</xUnitTool>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNet)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DTLib.XXHash\DTLib.XXHash.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
namespace Standart.Hash.xxHash.Perf namespace DTLib.XXHash.PerformanceTest
{ {
using BenchmarkDotNet.Running; using BenchmarkDotNet.Running;

View File

@@ -1,4 +1,4 @@
namespace Standart.Hash.xxHash.Perf namespace DTLib.XXHash.PerformanceTest
{ {
using System; using System;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;

View File

@@ -1,4 +1,4 @@
namespace Standart.Hash.xxHash.Perf namespace DTLib.XXHash.PerformanceTest
{ {
using System; using System;
using System.IO; using System.IO;
@@ -36,7 +36,7 @@
{ {
return xxHash32.ComputeHash(data, data.Length); return xxHash32.ComputeHash(data, data.Length);
} }
#if NET6_0_OR_GREATER
[Benchmark] [Benchmark]
public uint Hash32_Span() public uint Hash32_Span()
{ {
@@ -50,7 +50,7 @@
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(data);
return xxHash32.ComputeHash(span, span.Length); return xxHash32.ComputeHash(span, span.Length);
} }
#endif
[Benchmark] [Benchmark]
public uint Hash32_Stream() public uint Hash32_Stream()
{ {
@@ -70,7 +70,7 @@
{ {
return xxHash64.ComputeHash(data, data.Length); return xxHash64.ComputeHash(data, data.Length);
} }
#if NET6_0_OR_GREATER
[Benchmark] [Benchmark]
public ulong Hash64_Span() public ulong Hash64_Span()
{ {
@@ -84,6 +84,7 @@
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(data);
return xxHash64.ComputeHash(span, span.Length); return xxHash64.ComputeHash(span, span.Length);
} }
#endif
[Benchmark] [Benchmark]
public ulong Hash64_Stream() public ulong Hash64_Stream()

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<IsPackable>false</IsPackable>
<DebugType>full</DebugType>
<TargetFrameworks>net48;net6.0;net8.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<BenchmarkDotNet>0.13.1</BenchmarkDotNet>
<MicrosoftSdk>17.2.0</MicrosoftSdk>
<xUnit>2.4.1</xUnit>
<xUnitRunner>2.4.5</xUnitRunner>
<xUnitTool>2.3.1</xUnitTool>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftSdk)" />
<PackageReference Include="xunit" Version="$(xUnit)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(xUnitRunner)" />
<DotNetCliToolReference Include="dotnet-xunit" Version="$(xUnitTool)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\DTLib.XXHash\DTLib.XXHash.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
namespace Standart.Hash.xxHash.Test namespace DTLib.XXHash.Tests
{ {
using System; using System;
using Xunit; using Xunit;
@@ -35,7 +35,7 @@
} }
} }
} }
#if NET6_0_OR_GREATER
[Fact] [Fact]
public void Should_convert_to_bytes() public void Should_convert_to_bytes()
{ {
@@ -80,5 +80,6 @@
// Assert // Assert
Assert.Equal(guid1, guid2); Assert.Equal(guid1, guid2);
} }
#endif
} }
} }

View File

@@ -0,0 +1,116 @@
#if NET6_0_OR_GREATER
using System;
using System.Text;
using Xunit;
namespace DTLib.XXHash.Tests
{
public class xxHash128Test
{
[Fact]
public void Compute_hash128_for_bytes()
{
// Arrange
var bytes = new byte[]
{
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
0x6c, 0xfb
};
ulong expectedH = 3466251221427321594;
ulong expectedL = 2862260537881727713;
// Act
var hash = xxHash128.ComputeHash(bytes, bytes.Length);
// Assert
Assert.Equal(expectedH, hash.high64);
Assert.Equal(expectedL, hash.low64);
}
[Fact]
public void Compute_hash128_for_span()
{
// Arrange
var bytes = new byte[]
{
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
0x6c, 0xfb
};
var span = bytes.AsSpan();
ulong expectedH = 3466251221427321594;
ulong expectedL = 2862260537881727713;
// Act
var hash = xxHash128.ComputeHash(span, span.Length);
// Assert
Assert.Equal(expectedH, hash.high64);
Assert.Equal(expectedL, hash.low64);
}
[Fact]
public void Compute_hash128_for_string()
{
// Arrange
var str = "veni vidi vici";
var bytes = Encoding.Unicode.GetBytes(str);
// Act
var hash1 = xxHash128.ComputeHash(str);
var hash2 = xxHash128.ComputeHash(bytes, bytes.Length);
// Assert
Assert.Equal(hash1.high64, hash2.high64);
Assert.Equal(hash1.low64, hash2.low64);
}
[Fact]
public void Compute_hash128_bytes_for_bytes()
{
// Arrange
var bytes = new byte[]
{
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
0x6c, 0xfb
};
// ulong expectedH = 3466251221427321594;
// ulong expectedL = 2862260537881727713;
// (hBits * 18446744073709551616) + lBits
// (3466251221427321594 * 18446744073709551616) + 2862260537881727713
// dec: 63941049176852939372872402763456123617
// hex: 301A991EF3707AFA27B8CACB570F12E1
var expected = new byte[]
{
0xe1, 0x12, 0x0F, 0x57, 0xcb, 0xca, 0xb8, 0x27,
0xfa, 0x7a, 0x70, 0xf3, 0x1e, 0x99, 0x1a, 0x30
};
// Act
var hash = xxHash128.ComputeHashBytes(bytes, bytes.Length);
// Assert
for (int i = 0; i < 16; i++)
Assert.Equal(expected[i], hash[i]);
}
}
}
#endif

View File

@@ -1,6 +1,6 @@
using System.Text; using System.Text;
namespace Standart.Hash.xxHash.Test namespace DTLib.XXHash.Tests
{ {
using System; using System;
using System.IO; using System.IO;
@@ -10,23 +10,29 @@ namespace Standart.Hash.xxHash.Test
public class xxHash32Test public class xxHash32Test
{ {
[Fact] [Fact]
public void Compute_hash32_for_the_length_1() public void Compute_hash32_for_the_length_1()
{ {
// Arrange // Arrange
byte[] data = {0xde}; byte[] data = {0xde};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
uint hash1 = xxHash32.ComputeHash(data, data.Length); uint hash1 = xxHash32.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
uint hash2 = xxHash32.ComputeHash(span, span.Length); uint hash2 = xxHash32.ComputeHash(span, span.Length);
uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length); uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (uint) 0x2330eac0); Assert.Equal(hash1, (uint) 0x2330eac0);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (uint) 0x2330eac0); Assert.Equal(hash2, (uint) 0x2330eac0);
Assert.Equal(hash3, (uint) 0x2330eac0); Assert.Equal(hash3, (uint) 0x2330eac0);
#endif
} }
[Fact] [Fact]
@@ -34,18 +40,24 @@ namespace Standart.Hash.xxHash.Test
{ {
// Arrange // Arrange
byte[] data = {0xde, 0x55, 0x47, 0x7f, 0x14}; byte[] data = {0xde, 0x55, 0x47, 0x7f, 0x14};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
uint hash1 = xxHash32.ComputeHash(data, data.Length); uint hash1 = xxHash32.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
uint hash2 = xxHash32.ComputeHash(span, span.Length); uint hash2 = xxHash32.ComputeHash(span, span.Length);
uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length); uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (uint) 0x112348ba); Assert.Equal(hash1, (uint) 0x112348ba);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (uint) 0x112348ba); Assert.Equal(hash2, (uint) 0x112348ba);
Assert.Equal(hash3, (uint) 0x112348ba); Assert.Equal(hash3, (uint) 0x112348ba);
#endif
} }
[Fact] [Fact]
@@ -57,18 +69,24 @@ namespace Standart.Hash.xxHash.Test
0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48, 0xde, 0x55, 0x47, 0x7f, 0x14, 0x8f, 0xf1, 0x48,
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb 0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb
}; };
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
uint hash1 = xxHash32.ComputeHash(data, data.Length); uint hash1 = xxHash32.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
uint hash2 = xxHash32.ComputeHash(span, span.Length); uint hash2 = xxHash32.ComputeHash(span, span.Length);
uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length); uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (uint) 0xcdf89609); Assert.Equal(hash1, (uint) 0xcdf89609);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (uint) 0xcdf89609); Assert.Equal(hash2, (uint) 0xcdf89609);
Assert.Equal(hash3, (uint) 0xcdf89609); Assert.Equal(hash3, (uint) 0xcdf89609);
#endif
} }
[Fact] [Fact]
@@ -81,18 +99,24 @@ namespace Standart.Hash.xxHash.Test
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb, 0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
0x0e 0x0e
}; };
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
uint hash1 = xxHash32.ComputeHash(data, data.Length); uint hash1 = xxHash32.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
uint hash2 = xxHash32.ComputeHash(span, span.Length); uint hash2 = xxHash32.ComputeHash(span, span.Length);
uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length); uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (uint) 0xbca8f924); Assert.Equal(hash1, (uint) 0xbca8f924);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (uint) 0xbca8f924); Assert.Equal(hash2, (uint) 0xbca8f924);
Assert.Equal(hash3, (uint) 0xbca8f924); Assert.Equal(hash3, (uint) 0xbca8f924);
#endif
} }
[Fact] [Fact]
@@ -105,18 +129,24 @@ namespace Standart.Hash.xxHash.Test
0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb, 0x22, 0x3a, 0x40, 0x96, 0x56, 0xc5, 0xdc, 0xbb,
0x0e, 0x59, 0x4d, 0x42, 0xc5 0x0e, 0x59, 0x4d, 0x42, 0xc5
}; };
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
uint hash1 = xxHash32.ComputeHash(data, data.Length); uint hash1 = xxHash32.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
uint hash2 = xxHash32.ComputeHash(span, span.Length); uint hash2 = xxHash32.ComputeHash(span, span.Length);
uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length); uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (uint) 0xf4518e14); Assert.Equal(hash1, (uint) 0xf4518e14);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (uint) 0xf4518e14); Assert.Equal(hash2, (uint) 0xf4518e14);
Assert.Equal(hash3, (uint) 0xf4518e14); Assert.Equal(hash3, (uint) 0xf4518e14);
#endif
} }
[Fact] [Fact]
@@ -130,18 +160,24 @@ namespace Standart.Hash.xxHash.Test
0x0e, 0x59, 0x4d, 0x42, 0xc5, 0x07, 0x21, 0x08, 0x0e, 0x59, 0x4d, 0x42, 0xc5, 0x07, 0x21, 0x08,
0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11, 0x1c, 0x2c, 0xc9, 0x38, 0x7d, 0x43, 0x83, 0x11,
}; };
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
uint hash1 = xxHash32.ComputeHash(data, data.Length); uint hash1 = xxHash32.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
uint hash2 = xxHash32.ComputeHash(span, span.Length); uint hash2 = xxHash32.ComputeHash(span, span.Length);
uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length); uint hash3 = xxHash32.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (uint) 0xf8497daa); Assert.Equal(hash1, (uint) 0xf8497daa);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (uint) 0xf8497daa); Assert.Equal(hash2, (uint) 0xf8497daa);
Assert.Equal(hash3, (uint) 0xf8497daa); Assert.Equal(hash3, (uint) 0xf8497daa);
#endif
} }
[Fact] [Fact]

View File

@@ -1,8 +1,9 @@
using System; #if NET6_0_OR_GREATER
using System;
using System.Text; using System.Text;
using Xunit; using Xunit;
namespace Standart.Hash.xxHash.Test namespace DTLib.XXHash.Tests
{ {
public class xxHash3Test public class xxHash3Test
{ {
@@ -68,3 +69,4 @@ namespace Standart.Hash.xxHash.Test
} }
} }
} }
#endif

View File

@@ -1,6 +1,6 @@
using System.Text; using System.Text;
namespace Standart.Hash.xxHash.Test namespace DTLib.XXHash.Tests
{ {
using System; using System;
using System.IO; using System.IO;
@@ -15,18 +15,24 @@ namespace Standart.Hash.xxHash.Test
{ {
// Arrange // Arrange
byte[] data = {0x60}; byte[] data = {0x60};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length); ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length); ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length); ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (ulong) 0xb3e7ca6ca5ba3445); Assert.Equal(hash1, (ulong) 0xb3e7ca6ca5ba3445);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0xb3e7ca6ca5ba3445); Assert.Equal(hash2, (ulong) 0xb3e7ca6ca5ba3445);
Assert.Equal(hash3, (ulong) 0xb3e7ca6ca5ba3445); Assert.Equal(hash3, (ulong) 0xb3e7ca6ca5ba3445);
#endif
} }
[Fact] [Fact]
@@ -34,18 +40,23 @@ namespace Standart.Hash.xxHash.Test
{ {
// Arrange // Arrange
byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a}; byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length); ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length); ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length); ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (ulong) 0x917b11ed024938fc); Assert.Equal(hash1, (ulong) 0x917b11ed024938fc);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x917b11ed024938fc); Assert.Equal(hash2, (ulong) 0x917b11ed024938fc);
Assert.Equal(hash3, (ulong) 0x917b11ed024938fc); Assert.Equal(hash3, (ulong) 0x917b11ed024938fc);
#endif
} }
[Fact] [Fact]
@@ -57,18 +68,24 @@ namespace Standart.Hash.xxHash.Test
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5, 0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
0x85, 0x1f, 0xa6, 0x86, 0x34, 0x85, 0x1f, 0xa6, 0x86, 0x34,
}; };
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length); ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length); ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length); ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (ulong) 0x9d1cb0d181d58bee); Assert.Equal(hash1, (ulong) 0x9d1cb0d181d58bee);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x9d1cb0d181d58bee); Assert.Equal(hash2, (ulong) 0x9d1cb0d181d58bee);
Assert.Equal(hash3, (ulong) 0x9d1cb0d181d58bee); Assert.Equal(hash3, (ulong) 0x9d1cb0d181d58bee);
#endif
} }
[Fact] [Fact]
@@ -82,18 +99,24 @@ namespace Standart.Hash.xxHash.Test
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03, 0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21, 0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
}; };
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length); ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length); ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length); ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (ulong) 0x9233096b7804e12c); Assert.Equal(hash1, (ulong) 0x9233096b7804e12c);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x9233096b7804e12c); Assert.Equal(hash2, (ulong) 0x9233096b7804e12c);
Assert.Equal(hash3, (ulong) 0x9233096b7804e12c); Assert.Equal(hash3, (ulong) 0x9233096b7804e12c);
#endif
} }
[Fact] [Fact]
@@ -111,18 +134,24 @@ namespace Standart.Hash.xxHash.Test
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0, 0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16, 0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
}; };
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data); Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data); ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act // Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length); ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length); ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length); ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert // Assert
Assert.Equal(hash1, (ulong) 0x4c0a65b1ef9ea060); Assert.Equal(hash1, (ulong) 0x4c0a65b1ef9ea060);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x4c0a65b1ef9ea060); Assert.Equal(hash2, (ulong) 0x4c0a65b1ef9ea060);
Assert.Equal(hash3, (ulong) 0x4c0a65b1ef9ea060); Assert.Equal(hash3, (ulong) 0x4c0a65b1ef9ea060);
#endif
} }
[Fact] [Fact]

28
DTLib.XXHash.sln Normal file
View File

@@ -0,0 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTLib.XXHash", "DTLib.XXHash\DTLib.XXHash.csproj", "{7462108E-0FAE-49B1-9DDE-2996E09DFFD2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTLib.XXHash.PerformanceTest", "DTLib.XXHash.PerformanceTest\DTLib.XXHash.PerformanceTest.csproj", "{E5EFBB2E-ABC7-4FE8-AA2E-B62B4D6B9B5D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTLib.XXHash.Tests", "DTLib.XXHash.Tests\DTLib.XXHash.Tests.csproj", "{F3CC0F6B-D5BC-40FD-94EC-AF1A9534177F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7462108E-0FAE-49B1-9DDE-2996E09DFFD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7462108E-0FAE-49B1-9DDE-2996E09DFFD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7462108E-0FAE-49B1-9DDE-2996E09DFFD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7462108E-0FAE-49B1-9DDE-2996E09DFFD2}.Release|Any CPU.Build.0 = Release|Any CPU
{E5EFBB2E-ABC7-4FE8-AA2E-B62B4D6B9B5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5EFBB2E-ABC7-4FE8-AA2E-B62B4D6B9B5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5EFBB2E-ABC7-4FE8-AA2E-B62B4D6B9B5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5EFBB2E-ABC7-4FE8-AA2E-B62B4D6B9B5D}.Release|Any CPU.Build.0 = Release|Any CPU
{F3CC0F6B-D5BC-40FD-94EC-AF1A9534177F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3CC0F6B-D5BC-40FD-94EC-AF1A9534177F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3CC0F6B-D5BC-40FD-94EC-AF1A9534177F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F3CC0F6B-D5BC-40FD-94EC-AF1A9534177F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>DTLib.XXHash</PackageId>
<VersionPrefix>1.0.4</VersionPrefix>
<Authors>Oleksandr Melnyk</Authors>
<PackageTags>hash;xxHash;DTLib</PackageTags>
<Description>XXHash implementation in C# using intrinsics</Description>
<RepositoryType>GIT</RepositoryType>
<RepositoryUrl>https://timerix.ddns.net:3322/Timerix/DTLib.XXHash</RepositoryUrl>
<PackageProjectUrl>https://timerix.ddns.net:3322/Timerix/DTLib.XXHash</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0;net8.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="DTLib.XXHash.Tests" />
<InternalsVisibleTo Include="DTLib.XXHash.PerformanceTest" />
</ItemGroup>
<ItemGroup >
<PackageReference Include="System.Buffers" Version="4.6.1" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
</ItemGroup>
</Project>

View File

@@ -1,11 +1,14 @@
#if NET6_0_OR_GREATER
using System; using System;
#endif
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static class Utils public static class Utils
{ {
#if NET6_0_OR_GREATER
public static Guid ToGuid(this uint128 value) public static Guid ToGuid(this uint128 value)
{ {
var a = (Int32) (value.low64); var a = (Int32) (value.low64);
@@ -32,6 +35,7 @@ namespace Standart.Hash.xxHash
Unsafe.As<byte, ulong>(ref bytes[8]) = value.high64; Unsafe.As<byte, ulong>(ref bytes[8]) = value.high64;
return bytes; return bytes;
} }
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void BlockCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) internal static unsafe void BlockCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)

View File

@@ -0,0 +1,191 @@
/*
* This is the auto generated code.
* All function calls are inlined in XXH32
* Please don't try to analyze it.
*/
using System.Runtime.CompilerServices;
namespace DTLib.XXHash
{
public partial class xxHash32
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint __inline__XXH32(byte* input, int len, uint seed)
{
uint h32;
if (len >= 16)
{
byte* end = input + len;
byte* limit = end - 15;
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
uint v2 = seed + XXH_PRIME32_2;
uint v3 = seed + 0;
uint v4 = seed - XXH_PRIME32_1;
do
{
var reg1 = *((uint*)(input + 0));
var reg2 = *((uint*)(input + 4));
var reg3 = *((uint*)(input + 8));
var reg4 = *((uint*)(input + 12));
// XXH32_round
v1 += reg1 * XXH_PRIME32_2;
v1 = (v1 << 13) | (v1 >> (32 - 13));
v1 *= XXH_PRIME32_1;
// XXH32_round
v2 += reg2 * XXH_PRIME32_2;
v2 = (v2 << 13) | (v2 >> (32 - 13));
v2 *= XXH_PRIME32_1;
// XXH32_round
v3 += reg3 * XXH_PRIME32_2;
v3 = (v3 << 13) | (v3 >> (32 - 13));
v3 *= XXH_PRIME32_1;
// XXH32_round
v4 += reg4 * XXH_PRIME32_2;
v4 = (v4 << 13) | (v4 >> (32 - 13));
v4 *= XXH_PRIME32_1;
input += 16;
} while (input < limit);
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
((v2 << 7) | (v2 >> (32 - 7))) +
((v3 << 12) | (v3 >> (32 - 12))) +
((v4 << 18) | (v4 >> (32 - 18)));
}
else
{
h32 = seed + XXH_PRIME32_5;
}
h32 += (uint) len;
// XXH32_finalize
len &= 15;
while (len >= 4)
{
h32 += *((uint*) input) * XXH_PRIME32_3;
input += 4;
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
len -= 4;
}
while (len > 0)
{
h32 += *((byte*) input) * XXH_PRIME32_5;
++input;
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
--len;
}
// XXH32_avalanche
h32 ^= h32 >> 15;
h32 *= XXH_PRIME32_2;
h32 ^= h32 >> 13;
h32 *= XXH_PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void __inline__XXH32_stream_process(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
byte* limit = ptr + len;
do
{
var reg1 = *((uint*)(ptr + 0));
var reg2 = *((uint*)(ptr + 4));
var reg3 = *((uint*)(ptr + 8));
var reg4 = *((uint*)(ptr + 12));
// XXH32_round
v1 += reg1 * XXH_PRIME32_2;
v1 = (v1 << 13) | (v1 >> (32 - 13));
v1 *= XXH_PRIME32_1;
// XXH32_round
v2 += reg2 * XXH_PRIME32_2;
v2 = (v2 << 13) | (v2 >> (32 - 13));
v2 *= XXH_PRIME32_1;
// XXH32_round
v3 += reg3 * XXH_PRIME32_2;
v3 = (v3 << 13) | (v3 >> (32 - 13));
v3 *= XXH_PRIME32_1;
// XXH32_round
v4 += reg4 * XXH_PRIME32_2;
v4 = (v4 << 13) | (v4 >> (32 - 13));
v4 *= XXH_PRIME32_1;
ptr += 16;
} while (ptr < limit);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint __inline__XXH32_stream_finalize(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4, long length, uint seed)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
uint h32;
if (length >= 16)
{
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
((v2 << 7) | (v2 >> (32 - 7))) +
((v3 << 12) | (v3 >> (32 - 12))) +
((v4 << 18) | (v4 >> (32 - 18)));
}
else
{
h32 = seed + XXH_PRIME32_5;
}
h32 += (uint)length;
// XXH32_finalize
len &= 15;
while (len >= 4)
{
h32 += *((uint*)ptr) * XXH_PRIME32_3;
ptr += 4;
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
len -= 4;
}
while (len > 0)
{
h32 += *((byte*)ptr) * XXH_PRIME32_5;
ptr++;
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
len--;
}
// XXH32_avalanche
h32 ^= h32 >> 15;
h32 *= XXH_PRIME32_2;
h32 ^= h32 >> 13;
h32 *= XXH_PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
}
}
}

View File

@@ -0,0 +1,252 @@
/*
* This is the auto generated code.
* All function calls are inlined in XXH64
* Please don't try to analyze it.
*/
using System.Runtime.CompilerServices;
namespace DTLib.XXHash
{
public partial class xxHash64
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong __inline__XXH64(byte* input, int len, ulong seed)
{
ulong h64;
if (len >= 32)
{
byte* end = input + len;
byte* limit = end - 31;
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
ulong v2 = seed + XXH_PRIME64_2;
ulong v3 = seed + 0;
ulong v4 = seed - XXH_PRIME64_1;
do
{
var reg1 = *((ulong*)(input + 0));
var reg2 = *((ulong*)(input + 8));
var reg3 = *((ulong*)(input + 16));
var reg4 = *((ulong*)(input + 24));
// XXH64_round
v1 += reg1 * XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
// XXH64_round
v2 += reg2 * XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
// XXH64_round
v3 += reg3 * XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
// XXH64_round
v4 += reg4 * XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
input += 32;
} while (input < limit);
h64 = ((v1 << 1) | (v1 >> (64 - 1))) +
((v2 << 7) | (v2 >> (64 - 7))) +
((v3 << 12) | (v3 >> (64 - 12))) +
((v4 << 18) | (v4 >> (64 - 18)));
// XXH64_mergeRound
v1 *= XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
h64 ^= v1;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v2 *= XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
h64 ^= v2;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v3 *= XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
h64 ^= v3;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v4 *= XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
h64 ^= v4;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
}
else
{
h64 = seed + XXH_PRIME64_5;
}
h64 += (ulong) len;
// XXH64_finalize
len &= 31;
while (len >= 8) {
ulong k1 = XXH64_round(0, *(ulong*)input);
input += 8;
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
len -= 8;
}
if (len >= 4) {
h64 ^= *(uint*)input * XXH_PRIME64_1;
input += 4;
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
len -= 4;
}
while (len > 0) {
h64 ^= (*input++) * XXH_PRIME64_5;
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
--len;
}
// XXH64_avalanche
h64 ^= h64 >> 33;
h64 *= XXH_PRIME64_2;
h64 ^= h64 >> 29;
h64 *= XXH_PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void __inline__XXH64_stream_process(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3,
ref ulong v4)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
byte* limit = ptr + len;
do
{
var reg1 = *((ulong*)(ptr + 0));
var reg2 = *((ulong*)(ptr + 8));
var reg3 = *((ulong*)(ptr + 16));
var reg4 = *((ulong*)(ptr + 24));
// XXH64_round
v1 += reg1 * XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
// XXH64_round
v2 += reg2 * XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
// XXH64_round
v3 += reg3 * XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
// XXH64_round
v4 += reg4 * XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
ptr += 32;
} while (ptr < limit);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong __inline__XXH64_stream_finalize(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3,
ref ulong v4, long length, ulong seed)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
byte* end = pData + len;
ulong h64;
if (length >= 32)
{
h64 = ((v1 << 1) | (v1 >> (64 - 1))) +
((v2 << 7) | (v2 >> (64 - 7))) +
((v3 << 12) | (v3 >> (64 - 12))) +
((v4 << 18) | (v4 >> (64 - 18)));
// XXH64_mergeRound
v1 *= XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
h64 ^= v1;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v2 *= XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
h64 ^= v2;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v3 *= XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
h64 ^= v3;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v4 *= XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
h64 ^= v4;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
}
else
{
h64 = seed + XXH_PRIME64_5;
}
h64 += (ulong) length;
// XXH64_finalize
len &= 31;
while (len >= 8) {
ulong k1 = XXH64_round(0, *(ulong*)ptr);
ptr += 8;
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
len -= 8;
}
if (len >= 4) {
h64 ^= *(uint*)ptr * XXH_PRIME64_1;
ptr += 4;
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
len -= 4;
}
while (len > 0) {
h64 ^= (*ptr++) * XXH_PRIME64_5;
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
--len;
}
// XXH64_avalanche
h64 ^= h64 >> 33;
h64 *= XXH_PRIME64_2;
h64 ^= h64 >> 29;
h64 *= XXH_PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
}
}
}

View File

@@ -1,9 +1,9 @@
// ReSharper disable InconsistentNaming #if NET6_0_OR_GREATER
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash128 public static partial class xxHash128
{ {
@@ -12,7 +12,7 @@ namespace Standart.Hash.xxHash
private const ulong XXH_PRIME64_3 = 1609587929392839161UL; private const ulong XXH_PRIME64_3 = 1609587929392839161UL;
private const ulong XXH_PRIME64_4 = 9650029242287828579UL; private const ulong XXH_PRIME64_4 = 9650029242287828579UL;
private const ulong XXH_PRIME64_5 = 2870177450012600261UL; private const ulong XXH_PRIME64_5 = 2870177450012600261UL;
private const uint XXH_PRIME32_1 = 2654435761U; private const uint XXH_PRIME32_1 = 2654435761U;
private const uint XXH_PRIME32_2 = 2246822519U; private const uint XXH_PRIME32_2 = 2246822519U;
private const uint XXH_PRIME32_3 = 3266489917U; private const uint XXH_PRIME32_3 = 3266489917U;
@@ -20,12 +20,21 @@ namespace Standart.Hash.xxHash
private const uint XXH_PRIME32_5 = 374761393U; private const uint XXH_PRIME32_5 = 374761393U;
private const int XXH_STRIPE_LEN = 64; private const int XXH_STRIPE_LEN = 64;
private const int XXH_ACC_NB = XXH_STRIPE_LEN / 8; private const int XXH_ACC_NB = 8;
private const int XXH_SECRET_CONSUME_RATE = 8; private const int XXH_SECRET_CONSUME_RATE = 8;
private const int XXH_SECRET_MERGEACCS_START = 11; private const int XXH_SECRET_MERGEACCS_START = 11;
private const int XXH_SECRET_DEFAULT_SIZE = 192; private const int XXH_SECRET_DEFAULT_SIZE = 192;
private const int XXH_SECRET_LASTACC_START = 7; private const int XXH_SECRET_LASTACC_START = 7;
private const byte MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
private const byte MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
[FixedAddressValueType]
private static readonly Vector256<uint> M256i_XXH_PRIME32_1 = Vector256.Create(XXH_PRIME32_1);
[FixedAddressValueType]
private static readonly Vector128<uint> M128i_XXH_PRIME32_1 = Vector128.Create(XXH_PRIME32_1);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint XXH_rotl32(uint x, int r) private static uint XXH_rotl32(uint x, int r)
{ {
@@ -128,4 +137,5 @@ namespace Standart.Hash.xxHash
*(ulong*) dst = v64; *(ulong*) dst = v64;
} }
} }
} }
#endif

View File

@@ -1,15 +1,14 @@
// ReSharper disable InconsistentNaming #if NET6_0_OR_GREATER
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash128 public static partial class xxHash128
{ {
private static byte[] XXH3_SECRET = private static readonly byte[] XXH3_SECRET =
{ {
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
@@ -25,7 +24,7 @@ namespace Standart.Hash.xxHash
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
}; };
private static ulong[] XXH3_INIT_ACC = private static readonly ulong[] XXH3_INIT_ACC =
{ {
XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3,
XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1
@@ -268,62 +267,50 @@ namespace Standart.Hash.xxHash
uint128 product = XXH_mult64to128(lhs, rhs); uint128 product = XXH_mult64to128(lhs, rhs);
return product.low64 ^ product.high64; return product.low64 ^ product.high64;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint128 XXH3_hashLong_128b_withSeed(byte* input, int len, byte* secret, int secretSize, ulong seed) private static unsafe uint128 XXH3_hashLong_128b_withSeed(byte* input, int len, byte* secret, int secretSize, ulong seed)
{ {
if (seed == 0) if (seed == 0)
return XXH3_hashLong_128b_internal(input, len, secret, secretSize); return XXH3_hashLong_128b_internal(input, len, secret, secretSize);
int customSecretSize = XXH3_SECRET_DEFAULT_SIZE; byte* customSecret = stackalloc byte[XXH3_SECRET_DEFAULT_SIZE];
byte* customSecret = stackalloc byte[customSecretSize];
fixed (byte* ptr = &XXH3_SECRET[0])
{
for (int i = 0; i < customSecretSize; i += 8)
{
customSecret[i] = ptr[i];
customSecret[i+1] = ptr[i+1];
customSecret[i+2] = ptr[i+2];
customSecret[i+3] = ptr[i+3];
customSecret[i+4] = ptr[i+4];
customSecret[i+5] = ptr[i+5];
customSecret[i+6] = ptr[i+6];
customSecret[i+7] = ptr[i+7];
}
}
XXH3_initCustomSecret(customSecret, seed); XXH3_initCustomSecret(customSecret, seed);
return XXH3_hashLong_128b_internal(input, len, customSecret, customSecretSize); return XXH3_hashLong_128b_internal(input, len, customSecret, XXH3_SECRET_DEFAULT_SIZE);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint128 XXH3_hashLong_128b_internal(byte* input, int len, byte* secret, int secretSize) private static unsafe uint128 XXH3_hashLong_128b_internal(byte* input, int len, byte* secret, int secretSize)
{ {
ulong* acc = stackalloc ulong[8]; fixed (ulong* src = &XXH3_INIT_ACC[0])
fixed (ulong* ptr = &XXH3_INIT_ACC[0])
{ {
acc[0] = ptr[0]; ulong* acc = stackalloc ulong[8]
acc[1] = ptr[1]; {
acc[2] = ptr[2]; *(src + 0),
acc[3] = ptr[3]; *(src + 1),
acc[4] = ptr[4]; *(src + 2),
acc[5] = ptr[5]; *(src + 3),
acc[6] = ptr[6]; *(src + 4),
acc[7] = ptr[7]; *(src + 5),
*(src + 6),
*(src + 7),
};
XXH3_hashLong_internal_loop(acc, input, len, secret, secretSize);
uint128 uint128;
uint128.low64 = XXH3_mergeAccs(acc,
secret + XXH_SECRET_MERGEACCS_START,
(ulong)len * XXH_PRIME64_1);
uint128.high64 = XXH3_mergeAccs(acc,
secret + secretSize - XXH3_ACC_SIZE - XXH_SECRET_MERGEACCS_START,
~((ulong)len * XXH_PRIME64_2));
return uint128;
} }
XXH3_hashLong_internal_loop(acc, input, len, secret, secretSize);
uint128 uint128;
uint128.low64 = XXH3_mergeAccs(acc,
secret + XXH_SECRET_MERGEACCS_START,
(ulong)len * XXH_PRIME64_1);
uint128.high64 = XXH3_mergeAccs(acc,
secret + secretSize - XXH3_ACC_SIZE - XXH_SECRET_MERGEACCS_START,
~((ulong)len * XXH_PRIME64_2));
return uint128;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -390,51 +377,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_accumulate_512_avx2(ulong* acc, byte* input, byte* secret) private static unsafe void XXH3_accumulate_512_avx2(ulong* acc, byte* input, byte* secret)
{ {
const int m256i_size = 32; var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector256<ulong>>(acc + 4);
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
for (int i = 0; i < XXH_STRIPE_LEN / m256i_size; i++) var data_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 0).AsUInt32();
{ var data_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 4).AsUInt32();
int uint32_offset = i * 8;
int uint64_offset = i * 4;
var acc_vec = Avx2.LoadVector256(acc + uint64_offset); var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0).AsUInt32();
var data_vec = Avx2.LoadVector256((uint*)input + uint32_offset); var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4).AsUInt32();
var key_vec = Avx2.LoadVector256((uint*)secret + uint32_offset);
var data_key = Avx2.Xor(data_vec, key_vec); var data_key0 = Avx2.Xor(data_vec0, key_vec0);
var data_key_lo = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1); var data_key1 = Avx2.Xor(data_vec1, key_vec1);
var product = Avx2.Multiply(data_key, data_key_lo);
var data_swap = Avx2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64(); var data_key_lo0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var sum = Avx2.Add(acc_vec, data_swap); var data_key_lo1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
var result = Avx2.Add(product, sum);
Avx2.Store(acc + uint64_offset, result); var product0 = Avx2.Multiply(data_key0, data_key_lo0);
} var product1 = Avx2.Multiply(data_key1, data_key_lo1);
var data_swap0 = Avx2.Shuffle(data_vec0, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap1 = Avx2.Shuffle(data_vec1, MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum0 = Avx2.Add(acc_vec0, data_swap0);
var sum1 = Avx2.Add(acc_vec1, data_swap1);
var result0 = Avx2.Add(product0, sum0);
var result1 = Avx2.Add(product1, sum1);
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 4, result1);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_accumulate_512_sse2(ulong* acc, byte* input, byte* secret) private static unsafe void XXH3_accumulate_512_sse2(ulong* acc, byte* input, byte* secret)
{ {
const int m128i_size = 16; var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0);
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector128<ulong>>(acc + 2);
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110; var acc_vec2 = Unsafe.Read<Vector128<ulong>>(acc + 4);
var acc_vec3 = Unsafe.Read<Vector128<ulong>>(acc + 6);
for (int i = 0; i < XXH_STRIPE_LEN / m128i_size; i++) var data_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 0).AsUInt32();
{ var data_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 2).AsUInt32();
int uint32_offset = i * 4; var data_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 4).AsUInt32();
int uint64_offset = i * 2; var data_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 6).AsUInt32();
var acc_vec = Sse2.LoadVector128(acc + uint64_offset); var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var data_vec = Sse2.LoadVector128((uint*) input + uint32_offset); var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset); var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var data_key = Sse2.Xor(data_vec, key_vec); var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
var data_key_lo = Sse2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var product = Sse2.Multiply(data_key, data_key_lo); var data_key0 = Sse2.Xor(data_vec0, key_vec0);
var data_swap = Sse2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64(); var data_key1 = Sse2.Xor(data_vec1, key_vec1);
var sum = Sse2.Add(acc_vec, data_swap); var data_key2 = Sse2.Xor(data_vec2, key_vec2);
var result = Sse2.Add(product, sum); var data_key3 = Sse2.Xor(data_vec3, key_vec3);
Sse2.Store(acc + uint64_offset, result);
} var data_key_lo0 = Sse2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var data_key_lo1 = Sse2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
var data_key_lo2 = Sse2.Shuffle(data_key2, MM_SHUFFLE_0_3_0_1);
var data_key_lo3 = Sse2.Shuffle(data_key3, MM_SHUFFLE_0_3_0_1);
var product0 = Sse2.Multiply(data_key0, data_key_lo0);
var product1 = Sse2.Multiply(data_key1, data_key_lo1);
var product2 = Sse2.Multiply(data_key2, data_key_lo2);
var product3 = Sse2.Multiply(data_key3, data_key_lo3);
var data_swap0 = Sse2.Shuffle(data_vec0, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap1 = Sse2.Shuffle(data_vec1, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap2 = Sse2.Shuffle(data_vec2, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap3 = Sse2.Shuffle(data_vec3, MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum0 = Sse2.Add(acc_vec0, data_swap0);
var sum1 = Sse2.Add(acc_vec1, data_swap1);
var sum2 = Sse2.Add(acc_vec2, data_swap2);
var sum3 = Sse2.Add(acc_vec3, data_swap3);
var result0 = Sse2.Add(product0, sum0);
var result1 = Sse2.Add(product1, sum1);
var result2 = Sse2.Add(product2, sum2);
var result3 = Sse2.Add(product3, sum3);
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 2, result1);
Unsafe.Write(acc + 4, result2);
Unsafe.Write(acc + 6, result3);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -473,52 +498,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_scrambleAcc_avx2(ulong* acc, byte* secret) private static unsafe void XXH3_scrambleAcc_avx2(ulong* acc, byte* secret)
{ {
const int m256i_size = 32; var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector256<ulong>>(acc + 4);
var prime32 = Vector256.Create(XXH_PRIME32_1); var shifted0 = Avx2.ShiftRightLogical(acc_vec0, 47);
var shifted1 = Avx2.ShiftRightLogical(acc_vec1, 47);
for (int i = 0; i < XXH_STRIPE_LEN / m256i_size; i++) var data_vec0 = Avx2.Xor(acc_vec0, shifted0);
{ var data_vec1 = Avx2.Xor(acc_vec1, shifted1);
int uint64_offset = i * 4;
var acc_vec = Avx2.LoadVector256(acc + uint64_offset); var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
var shifted = Avx2.ShiftRightLogical(acc_vec, 47); var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4);
var data_vec = Avx2.Xor(acc_vec, shifted);
var key_vec = Avx2.LoadVector256((ulong*) secret + uint64_offset); var data_key0 = Avx2.Xor(data_vec0, key_vec0).AsUInt32();
var data_key = Avx2.Xor(data_vec, key_vec).AsUInt32(); var data_key1 = Avx2.Xor(data_vec1, key_vec1).AsUInt32();
var data_key_hi = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var prod_lo = Avx2.Multiply(data_key, prime32); var data_key_hi0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var prod_hi = Avx2.Multiply(data_key_hi, prime32); var data_key_hi1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
var result = Avx2.Add(prod_lo, Avx2.ShiftLeftLogical(prod_hi, 32));
Avx2.Store(acc + uint64_offset, result); var prod_lo0 = Avx2.Multiply(data_key0, M256i_XXH_PRIME32_1);
} var prod_lo1 = Avx2.Multiply(data_key1, M256i_XXH_PRIME32_1);
var prod_hi0 = Avx2.Multiply(data_key_hi0, M256i_XXH_PRIME32_1);
var prod_hi1 = Avx2.Multiply(data_key_hi1, M256i_XXH_PRIME32_1);
var result0 = Avx2.Add(prod_lo0, Avx2.ShiftLeftLogical(prod_hi0, 32));
var result1 = Avx2.Add(prod_lo1, Avx2.ShiftLeftLogical(prod_hi1, 32));
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 4, result1);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_scrambleAcc_sse2(ulong* acc, byte* secret) private static unsafe void XXH3_scrambleAcc_sse2(ulong* acc, byte* secret)
{ {
const int m128i_size = 16; var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0).AsUInt32();
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector128<ulong>>(acc + 2).AsUInt32();
var acc_vec2 = Unsafe.Read<Vector128<ulong>>(acc + 4).AsUInt32();
var acc_vec3 = Unsafe.Read<Vector128<ulong>>(acc + 6).AsUInt32();
var prime32 = Vector128.Create(XXH_PRIME32_1); var shifted0 = Sse2.ShiftRightLogical(acc_vec0, 47);
var shifted1 = Sse2.ShiftRightLogical(acc_vec1, 47);
for (int i = 0; i < XXH_STRIPE_LEN / m128i_size; i++) var shifted2 = Sse2.ShiftRightLogical(acc_vec2, 47);
{ var shifted3 = Sse2.ShiftRightLogical(acc_vec3, 47);
int uint32_offset = i * 4;
int uint64_offset = i * 2;
var acc_vec = Sse2.LoadVector128(acc + uint64_offset).AsUInt32(); var data_vec0 = Sse2.Xor(acc_vec0, shifted0);
var shifted = Sse2.ShiftRightLogical(acc_vec, 47); var data_vec1 = Sse2.Xor(acc_vec1, shifted1);
var data_vec = Sse2.Xor(acc_vec, shifted); var data_vec2 = Sse2.Xor(acc_vec2, shifted2);
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset); var data_vec3 = Sse2.Xor(acc_vec3, shifted3);
var data_key = Sse2.Xor(data_vec, key_vec);
var data_key_hi = Sse2.Shuffle(data_key.AsUInt32(), _MM_SHUFFLE_0_3_0_1); var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var prod_lo = Sse2.Multiply(data_key, prime32); var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var prod_hi = Sse2.Multiply(data_key_hi, prime32); var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var result = Sse2.Add(prod_lo, Sse2.ShiftLeftLogical(prod_hi, 32)); var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
Sse2.Store(acc + uint64_offset, result);
} var data_key0= Sse2.Xor(data_vec0, key_vec0);
var data_key1= Sse2.Xor(data_vec1, key_vec1);
var data_key2= Sse2.Xor(data_vec2, key_vec2);
var data_key3= Sse2.Xor(data_vec3, key_vec3);
var data_key_hi0 = Sse2.Shuffle(data_key0.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var data_key_hi1 = Sse2.Shuffle(data_key1.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var data_key_hi2 = Sse2.Shuffle(data_key2.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var data_key_hi3 = Sse2.Shuffle(data_key3.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var prod_lo0 = Sse2.Multiply(data_key0, M128i_XXH_PRIME32_1);
var prod_lo1 = Sse2.Multiply(data_key1, M128i_XXH_PRIME32_1);
var prod_lo2 = Sse2.Multiply(data_key2, M128i_XXH_PRIME32_1);
var prod_lo3 = Sse2.Multiply(data_key3, M128i_XXH_PRIME32_1);
var prod_hi0 = Sse2.Multiply(data_key_hi0, M128i_XXH_PRIME32_1);
var prod_hi1 = Sse2.Multiply(data_key_hi1, M128i_XXH_PRIME32_1);
var prod_hi2 = Sse2.Multiply(data_key_hi2, M128i_XXH_PRIME32_1);
var prod_hi3 = Sse2.Multiply(data_key_hi3, M128i_XXH_PRIME32_1);
var result0 = Sse2.Add(prod_lo0, Sse2.ShiftLeftLogical(prod_hi0, 32));
var result1 = Sse2.Add(prod_lo1, Sse2.ShiftLeftLogical(prod_hi1, 32));
var result2 = Sse2.Add(prod_lo2, Sse2.ShiftLeftLogical(prod_hi2, 32));
var result3 = Sse2.Add(prod_lo3, Sse2.ShiftLeftLogical(prod_hi3, 32));
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 2, result1);
Unsafe.Write(acc + 4, result2);
Unsafe.Write(acc + 6, result3);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -558,20 +620,30 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_initCustomSecret_avx2(byte* customSecret, ulong seed64) private static unsafe void XXH3_initCustomSecret_avx2(byte* customSecret, ulong seed64)
{ {
const int m256i_size = 32; var seed = Vector256.Create(seed64, (0U - seed64), seed64, (0U - seed64));
var seed = Vector256.Create((ulong)seed64, (ulong)(0U - seed64), (ulong)seed64, (ulong)(0U - seed64));
fixed (byte* secret = &XXH3_SECRET[0]) fixed (byte* secret = &XXH3_SECRET[0])
{ {
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m256i_size; i++) var src0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
{ var src1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4);
int uint64_offset = i * 4; var src2 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 8);
var src3 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 12);
var src4 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 16);
var src5 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 20);
var src32 = Avx2.LoadVector256(((ulong*)secret) + uint64_offset); var dst0 = Avx2.Add(src0, seed);
var dst32 = Avx2.Add(src32, seed); var dst1 = Avx2.Add(src1, seed);
Avx2.Store((ulong*) customSecret + uint64_offset, dst32); var dst2 = Avx2.Add(src2, seed);
} var dst3 = Avx2.Add(src3, seed);
var dst4 = Avx2.Add(src4, seed);
var dst5 = Avx2.Add(src5, seed);
Unsafe.Write((ulong*)customSecret + 0, dst0);
Unsafe.Write((ulong*)customSecret + 4, dst1);
Unsafe.Write((ulong*)customSecret + 8, dst2);
Unsafe.Write((ulong*)customSecret + 12, dst3);
Unsafe.Write((ulong*)customSecret + 16, dst4);
Unsafe.Write((ulong*)customSecret + 20, dst5);
} }
} }
@@ -579,21 +651,48 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_initCustomSecret_sse2(byte* customSecret, ulong seed64) private static unsafe void XXH3_initCustomSecret_sse2(byte* customSecret, ulong seed64)
{ {
const int m128i_size = 16;
var seed = Vector128.Create((long)seed64, (long)(0U - seed64)); var seed = Vector128.Create((long)seed64, (long)(0U - seed64));
fixed (byte* secret = &XXH3_SECRET[0]) fixed (byte* secret = &XXH3_SECRET[0])
{ {
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m128i_size; i++) var src0 = Unsafe.Read<Vector128<long>>((long*)secret + 0);
{ var src1 = Unsafe.Read<Vector128<long>>((long*)secret + 2);
int uint64_offset = i * 2; var src2 = Unsafe.Read<Vector128<long>>((long*)secret + 4);
var src3 = Unsafe.Read<Vector128<long>>((long*)secret + 6);
var src4 = Unsafe.Read<Vector128<long>>((long*)secret + 8);
var src5 = Unsafe.Read<Vector128<long>>((long*)secret + 10);
var src6 = Unsafe.Read<Vector128<long>>((long*)secret + 12);
var src7 = Unsafe.Read<Vector128<long>>((long*)secret + 14);
var src8 = Unsafe.Read<Vector128<long>>((long*)secret + 16);
var src9 = Unsafe.Read<Vector128<long>>((long*)secret + 18);
var src10 = Unsafe.Read<Vector128<long>>((long*)secret + 20);
var src11 = Unsafe.Read<Vector128<long>>((long*)secret + 22);
var src16 = Sse2.LoadVector128(((long*) secret) + uint64_offset); var dst0 = Sse2.Add(src0, seed);
var dst16 = Sse2.Add(src16, seed); var dst1 = Sse2.Add(src1, seed);
Sse2.Store((long*) customSecret + uint64_offset, dst16); var dst2 = Sse2.Add(src2, seed);
var dst3 = Sse2.Add(src3, seed);
} var dst4 = Sse2.Add(src4, seed);
var dst5 = Sse2.Add(src5, seed);
var dst6 = Sse2.Add(src6, seed);
var dst7 = Sse2.Add(src7, seed);
var dst8 = Sse2.Add(src8, seed);
var dst9 = Sse2.Add(src9, seed);
var dst10 = Sse2.Add(src10, seed);
var dst11 = Sse2.Add(src11, seed);
Unsafe.Write((long*)customSecret + 0, dst0);
Unsafe.Write((long*)customSecret + 2, dst1);
Unsafe.Write((long*)customSecret + 4, dst2);
Unsafe.Write((long*)customSecret + 6, dst3);
Unsafe.Write((long*)customSecret + 8, dst4);
Unsafe.Write((long*)customSecret + 10, dst5);
Unsafe.Write((long*)customSecret + 12, dst6);
Unsafe.Write((long*)customSecret + 14, dst7);
Unsafe.Write((long*)customSecret + 16, dst8);
Unsafe.Write((long*)customSecret + 18, dst9);
Unsafe.Write((long*)customSecret + 20, dst10);
Unsafe.Write((long*)customSecret + 22, dst11);
} }
} }
@@ -614,4 +713,5 @@ namespace Standart.Hash.xxHash
} }
} }
} }
} }
#endif

View File

@@ -1,8 +1,7 @@
// ReSharper disable InconsistentNaming #if NET6_0_OR_GREATER
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash128 public static partial class xxHash128
{ {
@@ -17,4 +16,5 @@ namespace Standart.Hash.xxHash
return hash; return hash;
} }
} }
} }
#endif

View File

@@ -1,11 +1,10 @@
// ReSharper disable InconsistentNaming #if NET6_0_OR_GREATER
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash128 public static partial class xxHash128
{ {
@@ -27,7 +26,7 @@ namespace Standart.Hash.xxHash
return UnsafeComputeHash(ptr, length, seed); return UnsafeComputeHash(ptr, length, seed);
} }
} }
/// <summary> /// <summary>
/// Compute xxHash for the data byte span /// Compute xxHash for the data byte span
/// </summary> /// </summary>
@@ -65,7 +64,7 @@ namespace Standart.Hash.xxHash
return UnsafeComputeHash(ptr, length, seed); return UnsafeComputeHash(ptr, length, seed);
} }
} }
/// <summary> /// <summary>
/// Compute xxHash for the string /// Compute xxHash for the string
/// </summary> /// </summary>
@@ -103,7 +102,7 @@ namespace Standart.Hash.xxHash
return UnsafeComputeHash(ptr, length, seed).ToBytes(); return UnsafeComputeHash(ptr, length, seed).ToBytes();
} }
} }
/// <summary> /// <summary>
/// Compute hash bytes for the span /// Compute hash bytes for the span
/// </summary> /// </summary>
@@ -141,7 +140,6 @@ namespace Standart.Hash.xxHash
return UnsafeComputeHash(ptr, length, seed).ToBytes(); return UnsafeComputeHash(ptr, length, seed).ToBytes();
} }
} }
/// <summary> /// <summary>
/// Compute hash bytes for the string /// Compute hash bytes for the string
/// </summary> /// </summary>
@@ -166,10 +164,7 @@ namespace Standart.Hash.xxHash
{ {
fixed (byte* secret = &XXH3_SECRET[0]) fixed (byte* secret = &XXH3_SECRET[0])
{ {
// Use inlined version return XXH3_128bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE);
// return XXH3_128bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE);
return __inline__XXH3_128bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE);
} }
} }
} }
@@ -180,4 +175,5 @@ namespace Standart.Hash.xxHash
public ulong low64; public ulong low64;
public ulong high64; public ulong high64;
} }
} }
#endif

View File

@@ -1,9 +1,10 @@
// ReSharper disable InconsistentNaming #if NET6_0_OR_GREATER
using System.Runtime.Intrinsics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
using System.Runtime.CompilerServices;
#pragma warning disable CS0414 // Field is assigned but its value is never used
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash3 public static partial class xxHash3
{ {
@@ -13,11 +14,11 @@ namespace Standart.Hash.xxHash
private const ulong XXH_PRIME64_4 = 9650029242287828579UL; private const ulong XXH_PRIME64_4 = 9650029242287828579UL;
private const ulong XXH_PRIME64_5 = 2870177450012600261UL; private const ulong XXH_PRIME64_5 = 2870177450012600261UL;
private const uint XXH_PRIME32_1 = 2654435761U; private static readonly uint XXH_PRIME32_1 = 2654435761U;
private const uint XXH_PRIME32_2 = 2246822519U; private static readonly uint XXH_PRIME32_2 = 2246822519U;
private const uint XXH_PRIME32_3 = 3266489917U; private static readonly uint XXH_PRIME32_3 = 3266489917U;
private const uint XXH_PRIME32_4 = 668265263U; private static readonly uint XXH_PRIME32_4 = 668265263U;
private const uint XXH_PRIME32_5 = 374761393U; private static readonly uint XXH_PRIME32_5 = 374761393U;
private const int XXH_STRIPE_LEN = 64; private const int XXH_STRIPE_LEN = 64;
private const int XXH_ACC_NB = XXH_STRIPE_LEN / 8; private const int XXH_ACC_NB = XXH_STRIPE_LEN / 8;
@@ -26,6 +27,14 @@ namespace Standart.Hash.xxHash
private const int XXH_SECRET_MERGEACCS_START = 11; private const int XXH_SECRET_MERGEACCS_START = 11;
private const int XXH_SECRET_LASTACC_START = 7; private const int XXH_SECRET_LASTACC_START = 7;
private const byte MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
private const byte MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
[FixedAddressValueType]
private static readonly Vector256<uint> M256i_XXH_PRIME32_1 = Vector256.Create(XXH_PRIME32_1);
[FixedAddressValueType]
private static readonly Vector128<uint> M128i_XXH_PRIME32_1 = Vector128.Create(XXH_PRIME32_1);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong XXH_readLE64(byte* ptr) private static unsafe ulong XXH_readLE64(byte* ptr)
{ {
@@ -83,11 +92,10 @@ namespace Standart.Hash.xxHash
{ {
*(ulong*) dst = v64; *(ulong*) dst = v64;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint128 XXH_mult64to128(ulong lhs, ulong rhs) private static uint128 XXH_mult64to128(ulong lhs, ulong rhs)
{ {
if (Bmi2.IsSupported) if (Bmi2.X64.IsSupported)
return XXH_mult64to128_bmi2(lhs, rhs); return XXH_mult64to128_bmi2(lhs, rhs);
return XXH_mult64to128_scalar(lhs, rhs); return XXH_mult64to128_scalar(lhs, rhs);
@@ -122,4 +130,5 @@ namespace Standart.Hash.xxHash
return r128; return r128;
} }
} }
} }
#endif

View File

@@ -1,14 +1,13 @@
// ReSharper disable InconsistentNaming
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
#if NET6_0_OR_GREATER
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash3 public static partial class xxHash3
{ {
private static byte[] XXH3_SECRET = private static readonly byte[] XXH3_SECRET =
{ {
0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c,
0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f,
@@ -24,7 +23,7 @@ namespace Standart.Hash.xxHash
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
}; };
private static ulong[] XXH3_INIT_ACC = private static readonly ulong[] XXH3_INIT_ACC =
{ {
XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3,
XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1
@@ -75,14 +74,12 @@ namespace Standart.Hash.xxHash
+ XXH3_mul128_fold64(input_lo, input_hi); + XXH3_mul128_fold64(input_lo, input_hi);
return XXH3_avalanche(acc); return XXH3_avalanche(acc);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XXH3_mul128_fold64(ulong lhs, ulong rhs) private static ulong XXH3_mul128_fold64(ulong lhs, ulong rhs)
{ {
uint128 product = XXH_mult64to128(lhs, rhs); uint128 product = XXH_mult64to128(lhs, rhs);
return product.low64 ^ product.high64; return product.low64 ^ product.high64;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XXH3_avalanche(ulong h64) private static ulong XXH3_avalanche(ulong h64)
{ {
@@ -201,27 +198,11 @@ namespace Standart.Hash.xxHash
if (seed == 0) if (seed == 0)
return XXH3_hashLong_64b_internal(input, len, secret, secretSize); return XXH3_hashLong_64b_internal(input, len, secret, secretSize);
int customSecretSize = XXH3_SECRET_DEFAULT_SIZE; byte* customSecret = stackalloc byte[XXH3_SECRET_DEFAULT_SIZE];
byte* customSecret = stackalloc byte[customSecretSize];
fixed (byte* ptr = &XXH3_SECRET[0])
{
for (int i = 0; i < customSecretSize; i += 8)
{
customSecret[i] = ptr[i];
customSecret[i + 1] = ptr[i + 1];
customSecret[i + 2] = ptr[i + 2];
customSecret[i + 3] = ptr[i + 3];
customSecret[i + 4] = ptr[i + 4];
customSecret[i + 5] = ptr[i + 5];
customSecret[i + 6] = ptr[i + 6];
customSecret[i + 7] = ptr[i + 7];
}
}
XXH3_initCustomSecret(customSecret, seed); XXH3_initCustomSecret(customSecret, seed);
return XXH3_hashLong_64b_internal(input, len, customSecret, customSecretSize); return XXH3_hashLong_64b_internal(input, len, customSecret, XXH3_SECRET_DEFAULT_SIZE);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -238,40 +219,78 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_initCustomSecret_avx2(byte* customSecret, ulong seed64) private static unsafe void XXH3_initCustomSecret_avx2(byte* customSecret, ulong seed64)
{ {
const int m256i_size = 32; var seed = Vector256.Create(seed64, (0U - seed64), seed64, (0U - seed64));
var seed = Vector256.Create(seed64, 0U - seed64, seed64, 0U - seed64);
fixed (byte* secret = &XXH3_SECRET[0]) fixed (byte* secret = &XXH3_SECRET[0])
{ {
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m256i_size; i++) var src0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
{ var src1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4);
int uint64_offset = i * 4; var src2 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 8);
var src3 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 12);
var src4 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 16);
var src5 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 20);
var src32 = Avx2.LoadVector256(((ulong*) secret) + uint64_offset); var dst0 = Avx2.Add(src0, seed);
var dst32 = Avx2.Add(src32, seed); var dst1 = Avx2.Add(src1, seed);
Avx2.Store((ulong*) customSecret + uint64_offset, dst32); var dst2 = Avx2.Add(src2, seed);
} var dst3 = Avx2.Add(src3, seed);
var dst4 = Avx2.Add(src4, seed);
var dst5 = Avx2.Add(src5, seed);
Unsafe.Write((ulong*)customSecret + 0, dst0);
Unsafe.Write((ulong*)customSecret + 4, dst1);
Unsafe.Write((ulong*)customSecret + 8, dst2);
Unsafe.Write((ulong*)customSecret + 12, dst3);
Unsafe.Write((ulong*)customSecret + 16, dst4);
Unsafe.Write((ulong*)customSecret + 20, dst5);
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_initCustomSecret_sse2(byte* customSecret, ulong seed64) private static unsafe void XXH3_initCustomSecret_sse2(byte* customSecret, ulong seed64)
{ {
const int m128i_size = 16; var seed = Vector128.Create((long)seed64, (long)(0U - seed64));
var seed = Vector128.Create((long) seed64, (long) (0U - seed64));
fixed (byte* secret = &XXH3_SECRET[0]) fixed (byte* secret = &XXH3_SECRET[0])
{ {
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m128i_size; i++) var src0 = Unsafe.Read<Vector128<long>>((long*)secret + 0);
{ var src1 = Unsafe.Read<Vector128<long>>((long*)secret + 2);
int uint64_offset = i * 2; var src2 = Unsafe.Read<Vector128<long>>((long*)secret + 4);
var src3 = Unsafe.Read<Vector128<long>>((long*)secret + 6);
var src4 = Unsafe.Read<Vector128<long>>((long*)secret + 8);
var src5 = Unsafe.Read<Vector128<long>>((long*)secret + 10);
var src6 = Unsafe.Read<Vector128<long>>((long*)secret + 12);
var src7 = Unsafe.Read<Vector128<long>>((long*)secret + 14);
var src8 = Unsafe.Read<Vector128<long>>((long*)secret + 16);
var src9 = Unsafe.Read<Vector128<long>>((long*)secret + 18);
var src10 = Unsafe.Read<Vector128<long>>((long*)secret + 20);
var src11 = Unsafe.Read<Vector128<long>>((long*)secret + 22);
var src16 = Sse2.LoadVector128(((long*) secret) + uint64_offset); var dst0 = Sse2.Add(src0, seed);
var dst16 = Sse2.Add(src16, seed); var dst1 = Sse2.Add(src1, seed);
Sse2.Store((long*) customSecret + uint64_offset, dst16); var dst2 = Sse2.Add(src2, seed);
} var dst3 = Sse2.Add(src3, seed);
var dst4 = Sse2.Add(src4, seed);
var dst5 = Sse2.Add(src5, seed);
var dst6 = Sse2.Add(src6, seed);
var dst7 = Sse2.Add(src7, seed);
var dst8 = Sse2.Add(src8, seed);
var dst9 = Sse2.Add(src9, seed);
var dst10 = Sse2.Add(src10, seed);
var dst11 = Sse2.Add(src11, seed);
Unsafe.Write((long*)customSecret + 0, dst0);
Unsafe.Write((long*)customSecret + 2, dst1);
Unsafe.Write((long*)customSecret + 4, dst2);
Unsafe.Write((long*)customSecret + 6, dst3);
Unsafe.Write((long*)customSecret + 8, dst4);
Unsafe.Write((long*)customSecret + 10, dst5);
Unsafe.Write((long*)customSecret + 12, dst6);
Unsafe.Write((long*)customSecret + 14, dst7);
Unsafe.Write((long*)customSecret + 16, dst8);
Unsafe.Write((long*)customSecret + 18, dst9);
Unsafe.Write((long*)customSecret + 20, dst10);
Unsafe.Write((long*)customSecret + 22, dst11);
} }
} }
@@ -295,23 +314,24 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong XXH3_hashLong_64b_internal(byte* input, int len, byte* secret, int secretSize) private static unsafe ulong XXH3_hashLong_64b_internal(byte* input, int len, byte* secret, int secretSize)
{ {
ulong* acc = stackalloc ulong[8]; fixed (ulong* src = &XXH3_INIT_ACC[0])
fixed (ulong* ptr = &XXH3_INIT_ACC[0])
{ {
acc[0] = ptr[0]; ulong* acc = stackalloc ulong[8]
acc[1] = ptr[1]; {
acc[2] = ptr[2]; *(src + 0),
acc[3] = ptr[3]; *(src + 1),
acc[4] = ptr[4]; *(src + 2),
acc[5] = ptr[5]; *(src + 3),
acc[6] = ptr[6]; *(src + 4),
acc[7] = ptr[7]; *(src + 5),
*(src + 6),
*(src + 7),
};
XXH3_hashLong_internal_loop(acc, input, len, secret, secretSize);
return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, ((ulong)len) * XXH_PRIME64_1);
} }
XXH3_hashLong_internal_loop(acc, input, len, secret, secretSize);
return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, ((ulong) len) * XXH_PRIME64_1);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -378,51 +398,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_accumulate_512_avx2(ulong* acc, byte* input, byte* secret) private static unsafe void XXH3_accumulate_512_avx2(ulong* acc, byte* input, byte* secret)
{ {
const int m256i_size = 32; var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector256<ulong>>(acc + 4);
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
for (int i = 0; i < XXH_STRIPE_LEN / m256i_size; i++) var data_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 0).AsUInt32();
{ var data_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 4).AsUInt32();
int uint32_offset = i * 8;
int uint64_offset = i * 4;
var acc_vec = Avx2.LoadVector256(acc + uint64_offset); var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0).AsUInt32();
var data_vec = Avx2.LoadVector256((uint*) input + uint32_offset); var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4).AsUInt32();
var key_vec = Avx2.LoadVector256((uint*) secret + uint32_offset);
var data_key = Avx2.Xor(data_vec, key_vec); var data_key0 = Avx2.Xor(data_vec0, key_vec0);
var data_key_lo = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1); var data_key1 = Avx2.Xor(data_vec1, key_vec1);
var product = Avx2.Multiply(data_key, data_key_lo);
var data_swap = Avx2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64(); var data_key_lo0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var sum = Avx2.Add(acc_vec, data_swap); var data_key_lo1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
var result = Avx2.Add(product, sum);
Avx2.Store(acc + uint64_offset, result); var product0 = Avx2.Multiply(data_key0, data_key_lo0);
} var product1 = Avx2.Multiply(data_key1, data_key_lo1);
var data_swap0 = Avx2.Shuffle(data_vec0, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap1 = Avx2.Shuffle(data_vec1, MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum0 = Avx2.Add(acc_vec0, data_swap0);
var sum1 = Avx2.Add(acc_vec1, data_swap1);
var result0 = Avx2.Add(product0, sum0);
var result1 = Avx2.Add(product1, sum1);
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 4, result1);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_accumulate_512_sse2(ulong* acc, byte* input, byte* secret) private static unsafe void XXH3_accumulate_512_sse2(ulong* acc, byte* input, byte* secret)
{ {
const int m128i_size = 16; var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0);
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector128<ulong>>(acc + 2);
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110; var acc_vec2 = Unsafe.Read<Vector128<ulong>>(acc + 4);
var acc_vec3 = Unsafe.Read<Vector128<ulong>>(acc + 6);
for (int i = 0; i < XXH_STRIPE_LEN / m128i_size; i++) var data_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 0).AsUInt32();
{ var data_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 2).AsUInt32();
int uint32_offset = i * 4; var data_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 4).AsUInt32();
int uint64_offset = i * 2; var data_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 6).AsUInt32();
var acc_vec = Sse2.LoadVector128(acc + uint64_offset); var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var data_vec = Sse2.LoadVector128((uint*) input + uint32_offset); var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset); var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var data_key = Sse2.Xor(data_vec, key_vec); var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
var data_key_lo = Sse2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var product = Sse2.Multiply(data_key, data_key_lo); var data_key0 = Sse2.Xor(data_vec0, key_vec0);
var data_swap = Sse2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64(); var data_key1 = Sse2.Xor(data_vec1, key_vec1);
var sum = Sse2.Add(acc_vec, data_swap); var data_key2 = Sse2.Xor(data_vec2, key_vec2);
var result = Sse2.Add(product, sum); var data_key3 = Sse2.Xor(data_vec3, key_vec3);
Sse2.Store(acc + uint64_offset, result);
} var data_key_lo0 = Sse2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var data_key_lo1 = Sse2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
var data_key_lo2 = Sse2.Shuffle(data_key2, MM_SHUFFLE_0_3_0_1);
var data_key_lo3 = Sse2.Shuffle(data_key3, MM_SHUFFLE_0_3_0_1);
var product0 = Sse2.Multiply(data_key0, data_key_lo0);
var product1 = Sse2.Multiply(data_key1, data_key_lo1);
var product2 = Sse2.Multiply(data_key2, data_key_lo2);
var product3 = Sse2.Multiply(data_key3, data_key_lo3);
var data_swap0 = Sse2.Shuffle(data_vec0, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap1 = Sse2.Shuffle(data_vec1, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap2 = Sse2.Shuffle(data_vec2, MM_SHUFFLE_1_0_3_2).AsUInt64();
var data_swap3 = Sse2.Shuffle(data_vec3, MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum0 = Sse2.Add(acc_vec0, data_swap0);
var sum1 = Sse2.Add(acc_vec1, data_swap1);
var sum2 = Sse2.Add(acc_vec2, data_swap2);
var sum3 = Sse2.Add(acc_vec3, data_swap3);
var result0 = Sse2.Add(product0, sum0);
var result1 = Sse2.Add(product1, sum1);
var result2 = Sse2.Add(product2, sum2);
var result3 = Sse2.Add(product3, sum3);
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 2, result1);
Unsafe.Write(acc + 4, result2);
Unsafe.Write(acc + 6, result3);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -459,52 +517,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_scrambleAcc_avx2(ulong* acc, byte* secret) private static unsafe void XXH3_scrambleAcc_avx2(ulong* acc, byte* secret)
{ {
const int m256i_size = 32; var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector256<ulong>>(acc + 4);
var prime32 = Vector256.Create(XXH_PRIME32_1); var shifted0 = Avx2.ShiftRightLogical(acc_vec0, 47);
var shifted1 = Avx2.ShiftRightLogical(acc_vec1, 47);
for (int i = 0; i < XXH_STRIPE_LEN / m256i_size; i++) var data_vec0 = Avx2.Xor(acc_vec0, shifted0);
{ var data_vec1 = Avx2.Xor(acc_vec1, shifted1);
int uint64_offset = i * 4;
var acc_vec = Avx2.LoadVector256(acc + uint64_offset); var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
var shifted = Avx2.ShiftRightLogical(acc_vec, 47); var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4);
var data_vec = Avx2.Xor(acc_vec, shifted);
var key_vec = Avx2.LoadVector256((ulong*) secret + uint64_offset); var data_key0 = Avx2.Xor(data_vec0, key_vec0).AsUInt32();
var data_key = Avx2.Xor(data_vec, key_vec).AsUInt32(); var data_key1 = Avx2.Xor(data_vec1, key_vec1).AsUInt32();
var data_key_hi = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var prod_lo = Avx2.Multiply(data_key, prime32); var data_key_hi0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var prod_hi = Avx2.Multiply(data_key_hi, prime32); var data_key_hi1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
var result = Avx2.Add(prod_lo, Avx2.ShiftLeftLogical(prod_hi, 32));
Avx2.Store(acc + uint64_offset, result); var prod_lo0 = Avx2.Multiply(data_key0, M256i_XXH_PRIME32_1);
} var prod_lo1 = Avx2.Multiply(data_key1, M256i_XXH_PRIME32_1);
var prod_hi0 = Avx2.Multiply(data_key_hi0, M256i_XXH_PRIME32_1);
var prod_hi1 = Avx2.Multiply(data_key_hi1, M256i_XXH_PRIME32_1);
var result0 = Avx2.Add(prod_lo0, Avx2.ShiftLeftLogical(prod_hi0, 32));
var result1 = Avx2.Add(prod_lo1, Avx2.ShiftLeftLogical(prod_hi1, 32));
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 4, result1);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_scrambleAcc_sse2(ulong* acc, byte* secret) private static unsafe void XXH3_scrambleAcc_sse2(ulong* acc, byte* secret)
{ {
const int m128i_size = 16; var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0).AsUInt32();
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001; var acc_vec1 = Unsafe.Read<Vector128<ulong>>(acc + 2).AsUInt32();
var acc_vec2 = Unsafe.Read<Vector128<ulong>>(acc + 4).AsUInt32();
var acc_vec3 = Unsafe.Read<Vector128<ulong>>(acc + 6).AsUInt32();
var prime32 = Vector128.Create(XXH_PRIME32_1); var shifted0 = Sse2.ShiftRightLogical(acc_vec0, 47);
var shifted1 = Sse2.ShiftRightLogical(acc_vec1, 47);
var shifted2 = Sse2.ShiftRightLogical(acc_vec2, 47);
var shifted3 = Sse2.ShiftRightLogical(acc_vec3, 47);
for (int i = 0; i < XXH_STRIPE_LEN / m128i_size; i++) var data_vec0 = Sse2.Xor(acc_vec0, shifted0);
{ var data_vec1 = Sse2.Xor(acc_vec1, shifted1);
int uint32_offset = i * 4; var data_vec2 = Sse2.Xor(acc_vec2, shifted2);
int uint64_offset = i * 2; var data_vec3 = Sse2.Xor(acc_vec3, shifted3);
var acc_vec = Sse2.LoadVector128(acc + uint64_offset).AsUInt32(); var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var shifted = Sse2.ShiftRightLogical(acc_vec, 47); var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var data_vec = Sse2.Xor(acc_vec, shifted); var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset); var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
var data_key = Sse2.Xor(data_vec, key_vec);
var data_key_hi = Sse2.Shuffle(data_key.AsUInt32(), _MM_SHUFFLE_0_3_0_1); var data_key0 = Sse2.Xor(data_vec0, key_vec0);
var prod_lo = Sse2.Multiply(data_key, prime32); var data_key1 = Sse2.Xor(data_vec1, key_vec1);
var prod_hi = Sse2.Multiply(data_key_hi, prime32); var data_key2 = Sse2.Xor(data_vec2, key_vec2);
var result = Sse2.Add(prod_lo, Sse2.ShiftLeftLogical(prod_hi, 32)); var data_key3 = Sse2.Xor(data_vec3, key_vec3);
Sse2.Store(acc + uint64_offset, result);
} var data_key_hi0 = Sse2.Shuffle(data_key0.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var data_key_hi1 = Sse2.Shuffle(data_key1.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var data_key_hi2 = Sse2.Shuffle(data_key2.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var data_key_hi3 = Sse2.Shuffle(data_key3.AsUInt32(), MM_SHUFFLE_0_3_0_1);
var prod_lo0 = Sse2.Multiply(data_key0, M128i_XXH_PRIME32_1);
var prod_lo1 = Sse2.Multiply(data_key1, M128i_XXH_PRIME32_1);
var prod_lo2 = Sse2.Multiply(data_key2, M128i_XXH_PRIME32_1);
var prod_lo3 = Sse2.Multiply(data_key3, M128i_XXH_PRIME32_1);
var prod_hi0 = Sse2.Multiply(data_key_hi0, M128i_XXH_PRIME32_1);
var prod_hi1 = Sse2.Multiply(data_key_hi1, M128i_XXH_PRIME32_1);
var prod_hi2 = Sse2.Multiply(data_key_hi2, M128i_XXH_PRIME32_1);
var prod_hi3 = Sse2.Multiply(data_key_hi3, M128i_XXH_PRIME32_1);
var result0 = Sse2.Add(prod_lo0, Sse2.ShiftLeftLogical(prod_hi0, 32));
var result1 = Sse2.Add(prod_lo1, Sse2.ShiftLeftLogical(prod_hi1, 32));
var result2 = Sse2.Add(prod_lo2, Sse2.ShiftLeftLogical(prod_hi2, 32));
var result3 = Sse2.Add(prod_lo3, Sse2.ShiftLeftLogical(prod_hi3, 32));
Unsafe.Write(acc + 0, result0);
Unsafe.Write(acc + 2, result1);
Unsafe.Write(acc + 4, result2);
Unsafe.Write(acc + 6, result3);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -528,4 +623,5 @@ namespace Standart.Hash.xxHash
xacc[lane] = acc64; xacc[lane] = acc64;
} }
} }
} }
#endif

View File

@@ -1,8 +1,7 @@
// ReSharper disable InconsistentNaming #if NET6_0_OR_GREATER
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash3 public static partial class xxHash3
{ {
@@ -17,4 +16,5 @@ namespace Standart.Hash.xxHash
return hash; return hash;
} }
} }
} }
#endif

View File

@@ -1,10 +1,9 @@
// ReSharper disable InconsistentNaming #if NET6_0_OR_GREATER
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
public static partial class xxHash3 public static partial class xxHash3
{ {
@@ -89,11 +88,9 @@ namespace Standart.Hash.xxHash
{ {
fixed (byte* secret = &XXH3_SECRET[0]) fixed (byte* secret = &XXH3_SECRET[0])
{ {
// Use inlined version return XXH3_64bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE);
// return XXH3_64bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE);
return __inline__XXH3_64bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE);
} }
} }
} }
} }
#endif

View File

@@ -0,0 +1,21 @@
using System.Runtime.CompilerServices;
namespace DTLib.XXHash
{
public static partial class xxHash32
{
private static readonly uint XXH_PRIME32_1 = 2654435761U;
private static readonly uint XXH_PRIME32_2 = 2246822519U;
private static readonly uint XXH_PRIME32_3 = 3266489917U;
private static readonly uint XXH_PRIME32_4 = 668265263U;
private static readonly uint XXH_PRIME32_5 = 374761393U;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint XXH_rotl32(uint x, int r)
{
return (x << r) | (x >> (32 - r));
}
}
}

View File

@@ -1,6 +1,6 @@
// ReSharper disable InconsistentNaming 
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;

264
DTLib.XXHash/xxHash32.cs Normal file
View File

@@ -0,0 +1,264 @@
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
#if NET6_0_OR_GREATER
using System.Runtime.InteropServices;
#endif
using System.Threading;
using System.Threading.Tasks;
namespace DTLib.XXHash
{
public static partial class xxHash32
{
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &data[0])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="offset">The offset of the data for hashing</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(byte[] data, int offset, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(offset < data.Length);
Debug.Assert(length <= data.Length - offset);
fixed (byte* pData = &data[0 + offset])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static ulong ComputeHash(ArraySegment<byte> data, uint seed = 0)
{
return ComputeHash(data.Array, data.Offset, data.Count, seed);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
{
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns>The hash</returns>
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 16);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
uint v2 = seed + XXH_PRIME32_2;
uint v3 = seed + 0;
uint v4 = seed - XXH_PRIME32_1;
try
{
// Read flow of bytes
while ((readBytes =
await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 16) continue;
int r = offset % 16; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the final chunk
uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h32;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
#if NET6_0_OR_GREATER
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(Span<byte> data, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(ReadOnlySpan<byte> data, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
#endif
/// <summary>
/// Compute xxHash for the stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static uint ComputeHash(Stream stream, int bufferSize = 4096, uint seed = 0)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 16);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
uint v2 = seed + XXH_PRIME32_2;
uint v3 = seed + 0;
uint v4 = seed - XXH_PRIME32_1;
try
{
// Read flow of bytes
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 16) continue;
int r = offset % 16; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the last chunk
uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h32;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
/// <summary>
/// Compute xxHash for the string
/// </summary>
/// <param name="str">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(string str, uint seed = 0)
{
Debug.Assert(str != null);
fixed (char* c = str)
{
byte* ptr = (byte*) c;
int length = str.Length * 2;
return UnsafeComputeHash(ptr, length, seed);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed)
{
// Use inlined version
// return XXH32(ptr, length, seed);
return __inline__XXH32(ptr, length, seed);
}
}
}

View File

@@ -0,0 +1,21 @@
using System.Runtime.CompilerServices;
namespace DTLib.XXHash
{
public static partial class xxHash64
{
private const ulong XXH_PRIME64_1 = 11400714785074694791UL;
private const ulong XXH_PRIME64_2 = 14029467366897019727UL;
private const ulong XXH_PRIME64_3 = 1609587929392839161UL;
private const ulong XXH_PRIME64_4 = 9650029242287828579UL;
private const ulong XXH_PRIME64_5 = 2870177450012600261UL;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XXH_rotl64(ulong x, int r)
{
return (x << r) | (x >> (64 - r));
}
}
}

View File

@@ -1,6 +1,6 @@
// ReSharper disable InconsistentNaming 
namespace Standart.Hash.xxHash namespace DTLib.XXHash
{ {
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;

264
DTLib.XXHash/xxHash64.cs Normal file
View File

@@ -0,0 +1,264 @@
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
#if NET6_0_OR_GREATER
using System;
using System.Runtime.InteropServices;
#endif
using System.Threading;
using System.Threading.Tasks;
namespace DTLib.XXHash
{
public static partial class xxHash64
{
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &data[0])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(byte[] data, int offset, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(offset < data.Length);
Debug.Assert(length <= data.Length - offset);
fixed (byte* pData = &data[0 + offset])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static ulong ComputeHash(System.ArraySegment<byte> data, ulong seed = 0)
{
return ComputeHash(data.Array, data.Offset, data.Count, seed);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
{
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <param name="cancellationToken">The cancelation token</param>
/// <returns>The hash</returns>
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize, ulong seed,
CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 32);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
ulong v2 = seed + XXH_PRIME64_2;
ulong v3 = seed + 0;
ulong v4 = seed - XXH_PRIME64_1;
try
{
// Read flow of bytes
while ((readBytes =
await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 32) continue;
int r = offset % 32; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the final chunk
ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h64;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
#if NET6_0_OR_GREATER
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(Span<byte> data, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(ReadOnlySpan<byte> data, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
#endif
/// <summary>
/// Compute xxHash for the stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static ulong ComputeHash(Stream stream, int bufferSize = 8192, ulong seed = 0)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 32);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
ulong v2 = seed + XXH_PRIME64_2;
ulong v3 = seed + 0;
ulong v4 = seed - XXH_PRIME64_1;
try
{
// Read flow of bytes
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 32) continue;
int r = offset % 32; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the final chunk
ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h64;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
/// <summary>
/// Compute xxHash for the string
/// </summary>
/// <param name="str">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(string str, uint seed = 0)
{
Debug.Assert(str != null);
fixed (char* c = str)
{
byte* ptr = (byte*) c;
int length = str.Length * 2;
return UnsafeComputeHash(ptr, length, seed);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed)
{
// Use inlined version
// return XXH64(ptr, length, seed);
return __inline__XXH64(ptr, length, seed);
}
}
}

131
README.md
View File

@@ -1,131 +0,0 @@
<p align="center">
<a href="#" target="_blank" rel="noopener noreferrer">
<img width="550" src="https://user-images.githubusercontent.com/1567570/39971158-5b213cca-56ff-11e8-9a1e-6c717e95d092.png" alt="xxHash.st">
</a>
</p>
<p align="center">
Extremely fast non-cryptographic hash algorithm <a href="http://www.xxhash.com/" target="_blank">xxhash</a>
</p>
<br>
<p align="center">
<a href="https://www.nuget.org/packages/Standart.Hash.xxHash">
<img src="https://img.shields.io/badge/platform-x64-blue.svg?longCache=true" alt="platform"/>
</a>
<a href="https://github.com/uranium62/xxHash/blob/master/LICENSE">
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="license" />
</a>
</p>
xxHash is an Extremely fast Hash algorithm, running at RAM speed limits. It successfully completes the **SMHasher** test suite which evaluates collision, dispersion and randomness qualities of hash functions.
## Instalation
```
PM> Install-Package Standart.Hash.xxHash
```
## Benchmarks
This benchmark was launched on a **Windows 10.0.19044.1706 (21H2)**. The reference system uses a **AMD Ryzen 7 2700, 1 CPU, 16 logical and 8 physical cores**
```
BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19044.1706 (21H2)
AMD Ryzen 7 2700, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.300
[Host] : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
Job-HQVLOG : .NET 6.0.5 (6.0.522.21309), X64 RyuJIT
Runtime=.NET 6.0
```
| Method | x64 |
|:---------------|-----------:|
| Hash32 Array | 5.87 GB/s |
| Hash64 Array | 9.07 GB/s |
| Hash128 Array | 12.04 GB/s |
| Hash3 Array | 12.08 GB/s |
| Hash32 Span | 5.87 GB/s |
| Hash64 Span | 9.07 GB/s |
| Hash128 Span | 12.04 GB/s |
| Hash3 Span | 12.08 GB/s |
| Hash32 Stream | 3.22 GB/s |
| Hash64 Stream | 4.81 GB/s |
## Comparison between С# and C implementation
| Method | Platform | Language | 1KB Time | 1MB Time | 1GB Time | Speed |
|:-------------------|---------:|---------:|----------:|----------:|----------:|-----------:|
| Hash32 | x64 | C# | 151.5 ns | 143.4 us | 170.3 ms | 5.87 GB/s |
| Hash32 | x64 | C | 138.5 ns | 129.5 us | 152.4 ms | 6.56 GB/s |
| Hash64 | x64 | C# | 84.6 ns | 77.9 us | 110.2 ms | 9.07 GB/s |
| Hash64 | x64 | C | 74.2 ns | 64.8 us | 83.0 ms | 12.04 GB/s |
| Hash128 (SSE2/AVX2)| x64 | C# | 151.6 ns | 64.5 us | 80.5 ms | 12.04 GB/s |
| Hash128 (SSE2/AVX2)| x64 | C | 84.4 ns | 38.3 us | 57.4 ms | 17.42 GB/s |
| Hash3 (SSE2/AVX2)| x64 | C# | 77.6 ns | 62.1 us | 78.5 ms | 12.08 GB/s |
| Hash3 (SSE2/AVX2)| x64 | C | 73.7 ns | 42.2 us | 59.8 ms | 16.72 GB/s |
## Api
```cs
public static uint ComputeHash(byte[] data, int length, uint seed = 0) { throw null; }
public static uint ComputeHash(Span<byte> data, int length, uint seed = 0) { throw null; }
public static uint ComputeHash(Stream stream, int bufferSize = 4096, uint seed = 0) { throw null; }
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0) { throw null; }
public static uint ComputeHash(string str, uint seed = 0) { throw null; }
public static ulong ComputeHash(byte[] data, int length, ulong seed = 0) { throw null; }
public static ulong ComputeHash(Span<byte> data, int length, ulong seed = 0) { throw null; }
public static ulong ComputeHash(Stream stream, int bufferSize = 8192, ulong seed = 0) { throw null; }
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0) { throw null; }
public static ulong ComputeHash(string str, uint seed = 0) { throw null; }
public static uint128 ComputeHash(byte[] data, int length, uint seed = 0) { throw null; }
public static uint128 ComputeHash(Span<byte> data, int length, uint seed = 0) { throw null; }
public static uint128 ComputeHash(string str, uint seed = 0) { throw null; }
// allocations
public static byte[] ComputeHashBytes(byte[] data, int length, uint seed = 0) { throw null; }
public static byte[] ComputeHashBytes(Span<byte> data, int length, uint seed = 0) { throw null; }
public static byte[] ComputeHashBytes(string str, uint seed = 0) { throw null; }
```
## Examples
A few examples of how to use api
```cs
byte[] data = Encoding.UTF8.GetBytes("veni vidi vici");
ulong h64_1 = xxHash64.ComputeHash(data, data.Length);
ulong h64_2 = xxHash64.ComputeHash(new Span<byte>(data), data.Length);
ulong h64_3 = xxHash64.ComputeHash(new ReadOnlySpan<byte>(data), data.Length);
ulong h64_4 = xxHash64.ComputeHash(new MemoryStream(data));
ulong h64_5 = await xxHash64.ComputeHashAsync(new MemoryStream(data));
ulong h64_6 = xxHash64.ComputeHash("veni vidi vici");
uint h32_1 = xxHash32.ComputeHash(data, data.Length);
uint h32_2 = xxHash32.ComputeHash(new Span<byte>(data), data.Length);
uint h32_3 = xxHash32.ComputeHash(new ReadOnlySpan<byte>(data), data.Length);
uint h32_4 = xxHash32.ComputeHash(new MemoryStream(data));
uint h32_5 = await xxHash32.ComputeHashAsync(new MemoryStream(data));
uint h32_6 = xxHash32.ComputeHash("veni vidi vici");
ulong h3_1 = xxHash3.ComputeHash(data, data.Length);
ulong h3_2 = xxHash3.ComputeHash(new Span<byte>(data), data.Length);
ulong h3_3 = xxHash3.ComputeHash(new ReadOnlySpan<byte>(data), data.Length);
ulong h3_4 = xxHash3.ComputeHash("veni vidi vici");
uint128 h128_1 = xxHash128.ComputeHash(data, data.Length);
uint128 h128_2 = xxHash128.ComputeHash(new Span<byte>(data), data.Length);
uint128 h128_3 = xxHash128.ComputeHash(new ReadOnlySpan<byte>(data), data.Length);
uint128 h128_4 = xxHash128.ComputeHash("veni vidi vici");
Guid guid = h128_1.ToGuid();
byte[] bytes = h128_1.ToBytes();
byte[] hash_bytes_1 = xxHash128.ComputeHashBytes(data, data.Length);
byte[] hash_bytes_2 = xxHash128.ComputeHashBytes(new Span<byte>(data), data.Length);
byte[] hash_bytes_3 = xxHash128.ComputeHashBytes(new ReadOnlySpan<byte>(data), data.Length);
byte[] hash_bytes_4 = xxHash128.ComputeHashBytes("veni vidi vici");
```
---
<p align="center">
Made in :beginner: Ukraine with :heart:
</p>

View File

@@ -1,9 +0,0 @@
<Project>
<PropertyGroup>
<BenchmarkDotNet>0.13.1</BenchmarkDotNet>
<MicrosoftSdk>17.2.0</MicrosoftSdk>
<xUnit>2.4.1</xUnit>
<xUnitRunner>2.4.5</xUnitRunner>
<xUnitTool>2.3.1</xUnitTool>
</PropertyGroup>
</Project>

View File

@@ -1,15 +0,0 @@
<Project>
<Import Project="deps.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<PackageId>Standart.Hash.xxHash</PackageId>
<VersionPrefix>4.0.3</VersionPrefix>
<AssemblyName>Standart.Hash.xxHash</AssemblyName>
<AssemblyTitle>Standart.Hash.xxHash</AssemblyTitle>
<Authors>Oleksandr Melnyk</Authors>
<PackageTags>hash;xxHash</PackageTags>
<Description>Standart.Hash.xxHash</Description>
<PackageProjectUrl>https://github.com/uranium62/xxHash</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
</Project>

View File

@@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\deps.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<Optimize>false</Optimize>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNet)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\deps.props" />
<PropertyGroup>
<IsPackable>false</IsPackable>
<TargetFramework>net6.0</TargetFramework>
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<Optimize>false</Optimize>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftSdk)" />
<PackageReference Include="xunit" Version="$(xUnit)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(xUnitRunner)" />
<DotNetCliToolReference Include="dotnet-xunit" Version="$(xUnitTool)" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Standart.Hash.xxHash\Standart.Hash.xxHash.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,113 +0,0 @@
using System;
using System.Text;
using Xunit;
namespace Standart.Hash.xxHash.Test;
public class xxHash128Test
{
[Fact]
public void Compute_hash128_for_bytes()
{
// Arrange
var bytes = new byte[]
{
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
0x6c, 0xfb
};
ulong expectedH = 3466251221427321594;
ulong expectedL = 2862260537881727713;
// Act
var hash = xxHash128.ComputeHash(bytes, bytes.Length);
// Assert
Assert.Equal(expectedH, hash.high64);
Assert.Equal(expectedL, hash.low64);
}
[Fact]
public void Compute_hash128_for_span()
{
// Arrange
var bytes = new byte[]
{
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
0x6c, 0xfb
};
var span = bytes.AsSpan();
ulong expectedH = 3466251221427321594;
ulong expectedL = 2862260537881727713;
// Act
var hash = xxHash128.ComputeHash(span, span.Length);
// Assert
Assert.Equal(expectedH, hash.high64);
Assert.Equal(expectedL, hash.low64);
}
[Fact]
public void Compute_hash128_for_string()
{
// Arrange
var str = "veni vidi vici";
var bytes = Encoding.Unicode.GetBytes(str);
// Act
var hash1 = xxHash128.ComputeHash(str);
var hash2 = xxHash128.ComputeHash(bytes, bytes.Length);
// Assert
Assert.Equal(hash1.high64, hash2.high64);
Assert.Equal(hash1.low64, hash2.low64);
}
[Fact]
public void Compute_hash128_bytes_for_bytes()
{
// Arrange
var bytes = new byte[]
{
0xd2, 0x94, 0x29, 0xc9, 0x4c, 0xc5, 0x0f, 0xbb,
0xaa, 0xf4, 0x7c, 0xd5, 0x69, 0x5a, 0xa9, 0xbd,
0xaf, 0xd8, 0x3f, 0xfb, 0xca, 0x6a, 0xd4, 0x2c,
0x6c, 0x69, 0x7a, 0x5b, 0x0d, 0xe8, 0xd2, 0xb1,
0x41, 0xb3, 0x1b, 0x23, 0xdb, 0x8c, 0x25, 0xb4,
0x6c, 0xfb
};
// ulong expectedH = 3466251221427321594;
// ulong expectedL = 2862260537881727713;
// (hBits * 18446744073709551616) + lBits
// (3466251221427321594 * 18446744073709551616) + 2862260537881727713
// dec: 63941049176852939372872402763456123617
// hex: 301A991EF3707AFA27B8CACB570F12E1
var expected = new byte[]
{
0xe1, 0x12, 0x0F, 0x57, 0xcb, 0xca, 0xb8, 0x27,
0xfa, 0x7a, 0x70, 0xf3, 0x1e, 0x99, 0x1a, 0x30
};
// Act
var hash = xxHash128.ComputeHashBytes(bytes, bytes.Length);
// Assert
for (int i = 0; i < 16; i++)
Assert.Equal(expected[i], hash[i]);
}
}

View File

@@ -1,28 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Standart.Hash.xxHash", "Standart.Hash.xxHash\Standart.Hash.xxHash.csproj", "{E468CD00-D581-46DD-ADE6-71EFA74AD62E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Standart.Hash.xxHash.Perf", "Standart.Hash.xxHash.Perf\Standart.Hash.xxHash.Perf.csproj", "{7B80269B-1EC4-40B5-8E19-F0A68C4404E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Standart.Hash.xxHash.Test", "Standart.Hash.xxHash.Test\Standart.Hash.xxHash.Test.csproj", "{0D9506CC-A6A1-4C0C-8827-9AB958942895}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E468CD00-D581-46DD-ADE6-71EFA74AD62E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E468CD00-D581-46DD-ADE6-71EFA74AD62E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E468CD00-D581-46DD-ADE6-71EFA74AD62E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E468CD00-D581-46DD-ADE6-71EFA74AD62E}.Release|Any CPU.Build.0 = Release|Any CPU
{7B80269B-1EC4-40B5-8E19-F0A68C4404E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7B80269B-1EC4-40B5-8E19-F0A68C4404E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7B80269B-1EC4-40B5-8E19-F0A68C4404E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7B80269B-1EC4-40B5-8E19-F0A68C4404E5}.Release|Any CPU.Build.0 = Release|Any CPU
{0D9506CC-A6A1-4C0C-8827-9AB958942895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D9506CC-A6A1-4C0C-8827-9AB958942895}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D9506CC-A6A1-4C0C-8827-9AB958942895}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D9506CC-A6A1-4C0C-8827-9AB958942895}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -1,15 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\nuget.props" />
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="$(AssemblyName).Test" />
<InternalsVisibleTo Include="$(AssemblyName).Perf" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,179 +0,0 @@
/*
* This is the auto generated code.
* All function calls are inlined in XXH32
* Please don't try to analyze it.
*/
using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash;
public partial class xxHash32
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint __inline__XXH32(byte* input, int len, uint seed)
{
uint h32;
if (len >= 16)
{
byte* end = input + len;
byte* limit = end - 15;
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
uint v2 = seed + XXH_PRIME32_2;
uint v3 = seed + 0;
uint v4 = seed - XXH_PRIME32_1;
do
{
// XXH32_round
v1 += *((uint*) (input+0)) * XXH_PRIME32_2;
v1 = (v1 << 13) | (v1 >> (32 - 13));
v1 *= XXH_PRIME32_1;
// XXH32_round
v2 += *((uint*) (input+4)) * XXH_PRIME32_2;
v2 = (v2 << 13) | (v2 >> (32 - 13));
v2 *= XXH_PRIME32_1;
// XXH32_round
v3 += *((uint*) (input+8)) * XXH_PRIME32_2;
v3 = (v3 << 13) | (v3 >> (32 - 13));
v3 *= XXH_PRIME32_1;
// XXH32_round
v4 += *((uint*) (input+12)) * XXH_PRIME32_2;
v4 = (v4 << 13) | (v4 >> (32 - 13));
v4 *= XXH_PRIME32_1;
input += 16;
} while (input < limit);
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
((v2 << 7) | (v2 >> (32 - 7))) +
((v3 << 12) | (v3 >> (32 - 12))) +
((v4 << 18) | (v4 >> (32 - 18)));
}
else
{
h32 = seed + XXH_PRIME32_5;
}
h32 += (uint) len;
// XXH32_finalize
len &= 15;
while (len >= 4)
{
h32 += *((uint*) input) * XXH_PRIME32_3;
input += 4;
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
len -= 4;
}
while (len > 0)
{
h32 += *((byte*) input) * XXH_PRIME32_5;
++input;
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
--len;
}
// XXH32_avalanche
h32 ^= h32 >> 15;
h32 *= XXH_PRIME32_2;
h32 ^= h32 >> 13;
h32 *= XXH_PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void __inline__XXH32_stream_process(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
byte* limit = ptr + len;
do
{
// XXH32_round
v1 += *((uint*)(ptr + 0)) * XXH_PRIME32_2;
v1 = (v1 << 13) | (v1 >> (32 - 13));
v1 *= XXH_PRIME32_1;
// XXH32_round
v2 += *((uint*)(ptr + 4)) * XXH_PRIME32_2;
v2 = (v2 << 13) | (v2 >> (32 - 13));
v2 *= XXH_PRIME32_1;
// XXH32_round
v3 += *((uint*)(ptr + 8)) * XXH_PRIME32_2;
v3 = (v3 << 13) | (v3 >> (32 - 13));
v3 *= XXH_PRIME32_1;
// XXH32_round
v4 += *((uint*)(ptr + 12)) * XXH_PRIME32_2;
v4 = (v4 << 13) | (v4 >> (32 - 13));
v4 *= XXH_PRIME32_1;
ptr += 16;
} while (ptr < limit);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint __inline__XXH32_stream_finalize(byte[] input, int len, ref uint v1, ref uint v2, ref uint v3, ref uint v4, long length, uint seed)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
uint h32;
if (length >= 16)
{
h32 = ((v1 << 1) | (v1 >> (32 - 1))) +
((v2 << 7) | (v2 >> (32 - 7))) +
((v3 << 12) | (v3 >> (32 - 12))) +
((v4 << 18) | (v4 >> (32 - 18)));
}
else
{
h32 = seed + XXH_PRIME32_5;
}
h32 += (uint)length;
// XXH32_finalize
len &= 15;
while (len >= 4)
{
h32 += *((uint*)ptr) * XXH_PRIME32_3;
ptr += 4;
h32 = ((h32 << 17) | (h32 >> (32 - 17))) * XXH_PRIME32_4;
len -= 4;
}
while (len > 0)
{
h32 += *((byte*)ptr) * XXH_PRIME32_5;
ptr++;
h32 = ((h32 << 11) | (h32 >> (32 - 11))) * XXH_PRIME32_1;
len--;
}
// XXH32_avalanche
h32 ^= h32 >> 15;
h32 *= XXH_PRIME32_2;
h32 ^= h32 >> 13;
h32 *= XXH_PRIME32_3;
h32 ^= h32 >> 16;
return h32;
}
}
}

View File

@@ -1,247 +0,0 @@
/*
* This is the auto generated code.
* All function calls are inlined in XXH64
* Please don't try to analyze it.
*/
using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash;
public partial class xxHash64
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong __inline__XXH64(byte* input, int len, ulong seed)
{
ulong h64;
if (len >= 32)
{
byte* end = input + len;
byte* limit = end - 31;
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
ulong v2 = seed + XXH_PRIME64_2;
ulong v3 = seed + 0;
ulong v4 = seed - XXH_PRIME64_1;
do
{
// XXH64_round
v1 += *((ulong*) input) * XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
input += 8;
// XXH64_round
v2 += *((ulong*) input) * XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
input += 8;
// XXH64_round
v3 += *((ulong*) input) * XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
input += 8;
// XXH64_round
v4 += *((ulong*) input) * XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
input += 8;
} while (input < limit);
h64 = ((v1 << 1) | (v1 >> (64 - 1))) +
((v2 << 7) | (v2 >> (64 - 7))) +
((v3 << 12) | (v3 >> (64 - 12))) +
((v4 << 18) | (v4 >> (64 - 18)));
// XXH64_mergeRound
v1 *= XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
h64 ^= v1;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v2 *= XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
h64 ^= v2;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v3 *= XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
h64 ^= v3;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v4 *= XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
h64 ^= v4;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
}
else
{
h64 = seed + XXH_PRIME64_5;
}
h64 += (ulong) len;
// XXH64_finalize
len &= 31;
while (len >= 8) {
ulong k1 = XXH64_round(0, *(ulong*)input);
input += 8;
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
len -= 8;
}
if (len >= 4) {
h64 ^= *(uint*)input * XXH_PRIME64_1;
input += 4;
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
len -= 4;
}
while (len > 0) {
h64 ^= (*input++) * XXH_PRIME64_5;
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
--len;
}
// XXH64_avalanche
h64 ^= h64 >> 33;
h64 *= XXH_PRIME64_2;
h64 ^= h64 >> 29;
h64 *= XXH_PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void __inline__XXH64_stream_process(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3,
ref ulong v4)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
byte* limit = ptr + len;
do
{
// XXH64_round
v1 += *((ulong*) ptr) * XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
ptr += 8;
// XXH64_round
v2 += *((ulong*) ptr) * XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
ptr += 8;
// XXH64_round
v3 += *((ulong*) ptr) * XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
ptr += 8;
// XXH64_round
v4 += *((ulong*) ptr) * XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
ptr += 8;
} while (ptr < limit);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong __inline__XXH64_stream_finalize(byte[] input, int len, ref ulong v1, ref ulong v2, ref ulong v3,
ref ulong v4, long length, ulong seed)
{
fixed (byte* pData = &input[0])
{
byte* ptr = pData;
byte* end = pData + len;
ulong h64;
if (length >= 32)
{
h64 = ((v1 << 1) | (v1 >> (64 - 1))) +
((v2 << 7) | (v2 >> (64 - 7))) +
((v3 << 12) | (v3 >> (64 - 12))) +
((v4 << 18) | (v4 >> (64 - 18)));
// XXH64_mergeRound
v1 *= XXH_PRIME64_2;
v1 = (v1 << 31) | (v1 >> (64 - 31));
v1 *= XXH_PRIME64_1;
h64 ^= v1;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v2 *= XXH_PRIME64_2;
v2 = (v2 << 31) | (v2 >> (64 - 31));
v2 *= XXH_PRIME64_1;
h64 ^= v2;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v3 *= XXH_PRIME64_2;
v3 = (v3 << 31) | (v3 >> (64 - 31));
v3 *= XXH_PRIME64_1;
h64 ^= v3;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
// XXH64_mergeRound
v4 *= XXH_PRIME64_2;
v4 = (v4 << 31) | (v4 >> (64 - 31));
v4 *= XXH_PRIME64_1;
h64 ^= v4;
h64 = h64 * XXH_PRIME64_1 + XXH_PRIME64_4;
}
else
{
h64 = seed + XXH_PRIME64_5;
}
h64 += (ulong) length;
// XXH64_finalize
len &= 31;
while (len >= 8) {
ulong k1 = XXH64_round(0, *(ulong*)ptr);
ptr += 8;
h64 ^= k1;
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
len -= 8;
}
if (len >= 4) {
h64 ^= *(uint*)ptr * XXH_PRIME64_1;
ptr += 4;
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
len -= 4;
}
while (len > 0) {
h64 ^= (*ptr++) * XXH_PRIME64_5;
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
--len;
}
// XXH64_avalanche
h64 ^= h64 >> 33;
h64 *= XXH_PRIME64_2;
h64 ^= h64 >> 29;
h64 *= XXH_PRIME64_3;
h64 ^= h64 >> 32;
return h64;
}
}
}

View File

@@ -1,20 +0,0 @@
// ReSharper disable InconsistentNaming
using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash;
public static partial class xxHash32
{
private const uint XXH_PRIME32_1 = 2654435761U;
private const uint XXH_PRIME32_2 = 2246822519U;
private const uint XXH_PRIME32_3 = 3266489917U;
private const uint XXH_PRIME32_4 = 668265263U;
private const uint XXH_PRIME32_5 = 374761393U;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint XXH_rotl32(uint x, int r)
{
return (x << r) | (x >> (32 - r));
}
}

View File

@@ -1,264 +0,0 @@
// ReSharper disable InconsistentNaming
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Standart.Hash.xxHash;
public static partial class xxHash32
{
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(byte[] data, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &data[0])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="offset">The offset of the data for hashing</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(byte[] data, int offset, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(offset < data.Length);
Debug.Assert(length <= data.Length - offset);
fixed (byte* pData = &data[0 + offset])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static ulong ComputeHash(ArraySegment<byte> data, uint seed = 0)
{
Debug.Assert(data != null);
return ComputeHash(data.Array, data.Offset, data.Count, seed);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize = 4096, uint seed = 0)
{
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <param name="cancellationToken">The cancellation token</param>
/// <returns>The hash</returns>
public static async ValueTask<uint> ComputeHashAsync(Stream stream, int bufferSize, uint seed, CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 16);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
uint v2 = seed + XXH_PRIME32_2;
uint v3 = seed + 0;
uint v4 = seed - XXH_PRIME32_1;
try
{
// Read flow of bytes
while ((readBytes =
await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 16) continue;
int r = offset % 16; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the final chunk
uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h32;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(Span<byte> data, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(ReadOnlySpan<byte> data, int length, uint seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static uint ComputeHash(Stream stream, int bufferSize = 4096, uint seed = 0)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 16);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 16);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
uint v1 = seed + XXH_PRIME32_1 + XXH_PRIME32_2;
uint v2 = seed + XXH_PRIME32_2;
uint v3 = seed + 0;
uint v4 = seed - XXH_PRIME32_1;
try
{
// Read flow of bytes
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 16) continue;
int r = offset % 16; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH32_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the last chunk
uint h32 = __inline__XXH32_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h32;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
/// <summary>
/// Compute xxHash for the string
/// </summary>
/// <param name="str">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe uint ComputeHash(string str, uint seed = 0)
{
Debug.Assert(str != null);
fixed (char* c = str)
{
byte* ptr = (byte*) c;
int length = str.Length * 2;
return UnsafeComputeHash(ptr, length, seed);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint UnsafeComputeHash(byte* ptr, int length, uint seed)
{
// Use inlined version
// return XXH32(ptr, length, seed);
return __inline__XXH32(ptr, length, seed);
}
}

View File

@@ -1,20 +0,0 @@
// ReSharper disable InconsistentNaming
using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash;
public static partial class xxHash64
{
private const ulong XXH_PRIME64_1 = 11400714785074694791UL;
private const ulong XXH_PRIME64_2 = 14029467366897019727UL;
private const ulong XXH_PRIME64_3 = 1609587929392839161UL;
private const ulong XXH_PRIME64_4 = 9650029242287828579UL;
private const ulong XXH_PRIME64_5 = 2870177450012600261UL;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XXH_rotl64(ulong x, int r)
{
return (x << r) | (x >> (64 - r));
}
}

View File

@@ -1,264 +0,0 @@
// ReSharper disable InconsistentNaming
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Standart.Hash.xxHash;
public static partial class xxHash64
{
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(byte[] data, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &data[0])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(byte[] data, int offset, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(offset < data.Length);
Debug.Assert(length <= data.Length - offset);
fixed (byte* pData = &data[0 + offset])
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte array
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(System.ArraySegment<byte> data, ulong seed = 0)
{
Debug.Assert(data != null);
return ComputeHash(data.Array, data.Offset, data.Count, seed);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize = 8192, ulong seed = 0)
{
return await ComputeHashAsync(stream, bufferSize, seed, CancellationToken.None);
}
/// <summary>
/// Compute xxHash for the async stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <param name="cancellationToken">The cancelation token</param>
/// <returns>The hash</returns>
public static async ValueTask<ulong> ComputeHashAsync(Stream stream, int bufferSize, ulong seed,
CancellationToken cancellationToken)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 32);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
ulong v2 = seed + XXH_PRIME64_2;
ulong v3 = seed + 0;
ulong v4 = seed - XXH_PRIME64_1;
try
{
// Read flow of bytes
while ((readBytes =
await stream.ReadAsync(buffer, offset, bufferSize, cancellationToken).ConfigureAwait(false)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 32) continue;
int r = offset % 32; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the final chunk
ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h64;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(Span<byte> data, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the data byte span
/// </summary>
/// <param name="data">The source of data</param>
/// <param name="length">The length of the data for hashing</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(ReadOnlySpan<byte> data, int length, ulong seed = 0)
{
Debug.Assert(data != null);
Debug.Assert(length >= 0);
Debug.Assert(length <= data.Length);
fixed (byte* pData = &MemoryMarshal.GetReference(data))
{
return UnsafeComputeHash(pData, length, seed);
}
}
/// <summary>
/// Compute xxHash for the stream
/// </summary>
/// <param name="stream">The stream of data</param>
/// <param name="bufferSize">The buffer size</param>
/// <param name="seed">The seed number</param>
/// <returns>The hash</returns>
public static ulong ComputeHash(Stream stream, int bufferSize = 8192, ulong seed = 0)
{
Debug.Assert(stream != null);
Debug.Assert(bufferSize > 32);
// Optimizing memory allocation
byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize + 32);
int readBytes;
int offset = 0;
long length = 0;
// Prepare the seed vector
ulong v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
ulong v2 = seed + XXH_PRIME64_2;
ulong v3 = seed + 0;
ulong v4 = seed - XXH_PRIME64_1;
try
{
// Read flow of bytes
while ((readBytes = stream.Read(buffer, offset, bufferSize)) > 0)
{
length = length + readBytes;
offset = offset + readBytes;
if (offset < 32) continue;
int r = offset % 32; // remain
int l = offset - r; // length
// Process the next chunk
__inline__XXH64_stream_process(buffer, l, ref v1, ref v2, ref v3, ref v4);
// Put remaining bytes to buffer
Utils.BlockCopy(buffer, l, buffer, 0, r);
offset = r;
}
// Process the final chunk
ulong h64 = __inline__XXH64_stream_finalize(buffer, offset, ref v1, ref v2, ref v3, ref v4, length, seed);
return h64;
}
finally
{
// Free memory
ArrayPool<byte>.Shared.Return(buffer);
}
}
/// <summary>
/// Compute xxHash for the string
/// </summary>
/// <param name="str">The source of data</param>
/// <param name="seed">The seed number</param>
/// <returns>hash</returns>
public static unsafe ulong ComputeHash(string str, uint seed = 0)
{
Debug.Assert(str != null);
fixed (char* c = str)
{
byte* ptr = (byte*) c;
int length = str.Length * 2;
return UnsafeComputeHash(ptr, length, seed);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe ulong UnsafeComputeHash(byte* ptr, int length, ulong seed)
{
// Use inlined version
// return XXH64(ptr, length, seed);
return __inline__XXH64(ptr, length, seed);
}
}