Compare commits

...

10 Commits

Author SHA1 Message Date
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 1871 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

292
.gitignore vendored
View File

@@ -1,288 +1,24 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Bb]in/
.bin/
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
nuget/
*[-_]tmp/
# Visual Studio 2015 cache/options directory
# IDE files
.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
.vscode/
.vshistory/
.idea/
*.sln.iml
.editorconfig
*.user
# 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
#backups
.old*/
*[-_]old/

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>12</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;

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace Standart.Hash.xxHash.Test
namespace DTLib.XXHash.Tests
{
using System;
using System.IO;
@@ -15,18 +15,24 @@ namespace Standart.Hash.xxHash.Test
{
// Arrange
byte[] data = {0x60};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert
Assert.Equal(hash1, (ulong) 0xb3e7ca6ca5ba3445);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0xb3e7ca6ca5ba3445);
Assert.Equal(hash3, (ulong) 0xb3e7ca6ca5ba3445);
#endif
}
[Fact]
@@ -34,18 +40,23 @@ namespace Standart.Hash.xxHash.Test
{
// Arrange
byte[] data = {0x60, 0x82, 0x40, 0x77, 0x8a};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert
Assert.Equal(hash1, (ulong) 0x917b11ed024938fc);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x917b11ed024938fc);
Assert.Equal(hash3, (ulong) 0x917b11ed024938fc);
#endif
}
[Fact]
@@ -57,18 +68,24 @@ namespace Standart.Hash.xxHash.Test
0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5,
0x85, 0x1f, 0xa6, 0x86, 0x34,
};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert
Assert.Equal(hash1, (ulong) 0x9d1cb0d181d58bee);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x9d1cb0d181d58bee);
Assert.Equal(hash3, (ulong) 0x9d1cb0d181d58bee);
#endif
}
[Fact]
@@ -82,18 +99,24 @@ namespace Standart.Hash.xxHash.Test
0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03,
0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21,
};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert
Assert.Equal(hash1, (ulong) 0x9233096b7804e12c);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x9233096b7804e12c);
Assert.Equal(hash3, (ulong) 0x9233096b7804e12c);
#endif
}
[Fact]
@@ -111,18 +134,24 @@ namespace Standart.Hash.xxHash.Test
0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0,
0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16,
};
#if NET6_0_OR_GREATER
Span<byte> span = new Span<byte>(data);
ReadOnlySpan<byte> rspan = new ReadOnlySpan<byte>(data);
#endif
// Act
ulong hash1 = xxHash64.ComputeHash(data, data.Length);
#if NET6_0_OR_GREATER
ulong hash2 = xxHash64.ComputeHash(span, span.Length);
ulong hash3 = xxHash64.ComputeHash(rspan, rspan.Length);
#endif
// Assert
Assert.Equal(hash1, (ulong) 0x4c0a65b1ef9ea060);
#if NET6_0_OR_GREATER
Assert.Equal(hash2, (ulong) 0x4c0a65b1ef9ea060);
Assert.Equal(hash3, (ulong) 0x4c0a65b1ef9ea060);
#endif
}
[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,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>DTLib.XXHash</PackageId>
<VersionPrefix>1.0.1</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</TargetFrameworks>
<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.5.1"/>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0"/>
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4"/>
</ItemGroup>
</Project>

View File

@@ -1,11 +1,14 @@
#if NET6_0_OR_GREATER
using System;
#endif
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash
namespace DTLib.XXHash
{
public static class Utils
{
#if NET6_0_OR_GREATER
public static Guid ToGuid(this uint128 value)
{
var a = (Int32) (value.low64);
@@ -32,6 +35,7 @@ namespace Standart.Hash.xxHash
Unsafe.As<byte, ulong>(ref bytes[8]) = value.high64;
return bytes;
}
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Standart.Hash.xxHash
namespace DTLib.XXHash
{
public static partial class xxHash128
{
@@ -20,12 +20,21 @@ namespace Standart.Hash.xxHash
private const uint XXH_PRIME32_5 = 374761393U;
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_MERGEACCS_START = 11;
private const int XXH_SECRET_DEFAULT_SIZE = 192;
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)]
private static uint XXH_rotl32(uint x, int r)
{
@@ -129,3 +138,4 @@ namespace Standart.Hash.xxHash
}
}
}
#endif

View File

@@ -1,15 +1,14 @@
// ReSharper disable InconsistentNaming
#if NET6_0_OR_GREATER
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Standart.Hash.xxHash
namespace DTLib.XXHash
{
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,
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,
};
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_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1
@@ -275,44 +274,31 @@ namespace Standart.Hash.xxHash
if (seed == 0)
return XXH3_hashLong_128b_internal(input, len, secret, secretSize);
int customSecretSize = XXH3_SECRET_DEFAULT_SIZE;
byte* customSecret = stackalloc byte[customSecretSize];
byte* customSecret = stackalloc byte[XXH3_SECRET_DEFAULT_SIZE];
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);
return XXH3_hashLong_128b_internal(input, len, customSecret, customSecretSize);
return XXH3_hashLong_128b_internal(input, len, customSecret, XXH3_SECRET_DEFAULT_SIZE);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe uint128 XXH3_hashLong_128b_internal(byte* input, int len, byte* secret, int secretSize)
{
ulong* acc = stackalloc ulong[8];
fixed (ulong* ptr = &XXH3_INIT_ACC[0])
fixed (ulong* src = &XXH3_INIT_ACC[0])
{
acc[0] = ptr[0];
acc[1] = ptr[1];
acc[2] = ptr[2];
acc[3] = ptr[3];
acc[4] = ptr[4];
acc[5] = ptr[5];
acc[6] = ptr[6];
acc[7] = ptr[7];
}
ulong* acc = stackalloc ulong[8]
{
*(src + 0),
*(src + 1),
*(src + 2),
*(src + 3),
*(src + 4),
*(src + 5),
*(src + 6),
*(src + 7),
};
XXH3_hashLong_internal_loop(acc, input, len, secret, secretSize);
uint128 uint128;
@@ -325,6 +311,7 @@ namespace Standart.Hash.xxHash
return uint128;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_hashLong_internal_loop(ulong* acc, byte* input, int len, byte* secret, int secretSize)
@@ -390,51 +377,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_accumulate_512_avx2(ulong* acc, byte* input, byte* secret)
{
const int m256i_size = 32;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
var acc_vec1 = Unsafe.Read<Vector256<ulong>>(acc + 4);
for (int i = 0; i < XXH_STRIPE_LEN / m256i_size; i++)
{
int uint32_offset = i * 8;
int uint64_offset = i * 4;
var data_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 0).AsUInt32();
var data_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 4).AsUInt32();
var acc_vec = Avx2.LoadVector256(acc + uint64_offset);
var data_vec = Avx2.LoadVector256((uint*)input + uint32_offset);
var key_vec = Avx2.LoadVector256((uint*)secret + uint32_offset);
var data_key = Avx2.Xor(data_vec, key_vec);
var data_key_lo = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var product = Avx2.Multiply(data_key, data_key_lo);
var data_swap = Avx2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum = Avx2.Add(acc_vec, data_swap);
var result = Avx2.Add(product, sum);
Avx2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0).AsUInt32();
var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4).AsUInt32();
var data_key0 = Avx2.Xor(data_vec0, key_vec0);
var data_key1 = Avx2.Xor(data_vec1, key_vec1);
var data_key_lo0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var data_key_lo1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
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)]
private static unsafe void XXH3_accumulate_512_sse2(ulong* acc, byte* input, byte* secret)
{
const int m128i_size = 16;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0);
var acc_vec1 = Unsafe.Read<Vector128<ulong>>(acc + 2);
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++)
{
int uint32_offset = i * 4;
int uint64_offset = i * 2;
var data_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 0).AsUInt32();
var data_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 2).AsUInt32();
var data_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 4).AsUInt32();
var data_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 6).AsUInt32();
var acc_vec = Sse2.LoadVector128(acc + uint64_offset);
var data_vec = Sse2.LoadVector128((uint*) input + uint32_offset);
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset);
var data_key = Sse2.Xor(data_vec, key_vec);
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_swap = Sse2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum = Sse2.Add(acc_vec, data_swap);
var result = Sse2.Add(product, sum);
Sse2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
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_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)]
@@ -473,52 +498,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_scrambleAcc_avx2(ulong* acc, byte* secret)
{
const int m256i_size = 32;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
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++)
{
int uint64_offset = i * 4;
var data_vec0 = Avx2.Xor(acc_vec0, shifted0);
var data_vec1 = Avx2.Xor(acc_vec1, shifted1);
var acc_vec = Avx2.LoadVector256(acc + uint64_offset);
var shifted = Avx2.ShiftRightLogical(acc_vec, 47);
var data_vec = Avx2.Xor(acc_vec, shifted);
var key_vec = Avx2.LoadVector256((ulong*) secret + uint64_offset);
var data_key = Avx2.Xor(data_vec, key_vec).AsUInt32();
var data_key_hi = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var prod_lo = Avx2.Multiply(data_key, prime32);
var prod_hi = Avx2.Multiply(data_key_hi, prime32);
var result = Avx2.Add(prod_lo, Avx2.ShiftLeftLogical(prod_hi, 32));
Avx2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4);
var data_key0 = Avx2.Xor(data_vec0, key_vec0).AsUInt32();
var data_key1 = Avx2.Xor(data_vec1, key_vec1).AsUInt32();
var data_key_hi0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var data_key_hi1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
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)]
private static unsafe void XXH3_scrambleAcc_sse2(ulong* acc, byte* secret)
{
const int m128i_size = 16;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0).AsUInt32();
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++)
{
int uint32_offset = i * 4;
int uint64_offset = i * 2;
var data_vec0 = Sse2.Xor(acc_vec0, shifted0);
var data_vec1 = Sse2.Xor(acc_vec1, shifted1);
var data_vec2 = Sse2.Xor(acc_vec2, shifted2);
var data_vec3 = Sse2.Xor(acc_vec3, shifted3);
var acc_vec = Sse2.LoadVector128(acc + uint64_offset).AsUInt32();
var shifted = Sse2.ShiftRightLogical(acc_vec, 47);
var data_vec = Sse2.Xor(acc_vec, shifted);
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset);
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 prod_lo = Sse2.Multiply(data_key, prime32);
var prod_hi = Sse2.Multiply(data_key_hi, prime32);
var result = Sse2.Add(prod_lo, Sse2.ShiftLeftLogical(prod_hi, 32));
Sse2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
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)]
@@ -558,20 +620,30 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_initCustomSecret_avx2(byte* customSecret, ulong seed64)
{
const int m256i_size = 32;
var seed = Vector256.Create((ulong)seed64, (ulong)(0U - seed64), (ulong)seed64, (ulong)(0U - seed64));
var seed = Vector256.Create(seed64, (0U - seed64), seed64, (0U - seed64));
fixed (byte* secret = &XXH3_SECRET[0])
{
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m256i_size; i++)
{
int uint64_offset = i * 4;
var src0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
var src1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 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 dst32 = Avx2.Add(src32, seed);
Avx2.Store((ulong*) customSecret + uint64_offset, dst32);
}
var dst0 = Avx2.Add(src0, seed);
var dst1 = Avx2.Add(src1, seed);
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)]
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));
fixed (byte* secret = &XXH3_SECRET[0])
{
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m128i_size; i++)
{
int uint64_offset = i * 2;
var src0 = Unsafe.Read<Vector128<long>>((long*)secret + 0);
var src1 = Unsafe.Read<Vector128<long>>((long*)secret + 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 dst16 = Sse2.Add(src16, seed);
Sse2.Store((long*) customSecret + uint64_offset, dst16);
var dst0 = Sse2.Add(src0, seed);
var dst1 = Sse2.Add(src1, seed);
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);
}
}
@@ -615,3 +714,4 @@ namespace Standart.Hash.xxHash
}
}
}
#endif

View File

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

View File

@@ -1,11 +1,10 @@
// ReSharper disable InconsistentNaming
#if NET6_0_OR_GREATER
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Standart.Hash.xxHash
namespace DTLib.XXHash
{
public static partial class xxHash128
{
@@ -141,7 +140,6 @@ namespace Standart.Hash.xxHash
return UnsafeComputeHash(ptr, length, seed).ToBytes();
}
}
/// <summary>
/// Compute hash bytes for the string
/// </summary>
@@ -166,10 +164,7 @@ namespace Standart.Hash.xxHash
{
fixed (byte* secret = &XXH3_SECRET[0])
{
// Use inlined version
// 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);
return XXH3_128bits_internal(input, len, seed, secret, XXH3_SECRET_DEFAULT_SIZE);
}
}
}
@@ -181,3 +176,4 @@ namespace Standart.Hash.xxHash
public ulong high64;
}
}
#endif

View File

@@ -1,9 +1,10 @@
// ReSharper disable InconsistentNaming
using System.Runtime.CompilerServices;
#if NET6_0_OR_GREATER
using System.Runtime.Intrinsics;
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
{
@@ -13,11 +14,11 @@ namespace Standart.Hash.xxHash
private const ulong XXH_PRIME64_4 = 9650029242287828579UL;
private const ulong XXH_PRIME64_5 = 2870177450012600261UL;
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;
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;
private const int XXH_STRIPE_LEN = 64;
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_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)]
private static unsafe ulong XXH_readLE64(byte* ptr)
{
@@ -83,11 +92,10 @@ namespace Standart.Hash.xxHash
{
*(ulong*) dst = v64;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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_scalar(lhs, rhs);
@@ -123,3 +131,4 @@ namespace Standart.Hash.xxHash
}
}
}
#endif

View File

@@ -1,14 +1,13 @@
// ReSharper disable InconsistentNaming
using System.Runtime.CompilerServices;
#if NET6_0_OR_GREATER
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace Standart.Hash.xxHash
namespace DTLib.XXHash
{
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,
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,
};
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_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);
return XXH3_avalanche(acc);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XXH3_mul128_fold64(ulong lhs, ulong rhs)
{
uint128 product = XXH_mult64to128(lhs, rhs);
return product.low64 ^ product.high64;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong XXH3_avalanche(ulong h64)
{
@@ -201,27 +198,11 @@ namespace Standart.Hash.xxHash
if (seed == 0)
return XXH3_hashLong_64b_internal(input, len, secret, secretSize);
int customSecretSize = 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];
}
}
byte* customSecret = stackalloc byte[XXH3_SECRET_DEFAULT_SIZE];
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)]
@@ -238,40 +219,78 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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])
{
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m256i_size; i++)
{
int uint64_offset = i * 4;
var src0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
var src1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 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 dst32 = Avx2.Add(src32, seed);
Avx2.Store((ulong*) customSecret + uint64_offset, dst32);
}
var dst0 = Avx2.Add(src0, seed);
var dst1 = Avx2.Add(src1, seed);
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)]
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])
{
for (int i = 0; i < XXH_SECRET_DEFAULT_SIZE / m128i_size; i++)
{
int uint64_offset = i * 2;
var src0 = Unsafe.Read<Vector128<long>>((long*)secret + 0);
var src1 = Unsafe.Read<Vector128<long>>((long*)secret + 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 dst16 = Sse2.Add(src16, seed);
Sse2.Store((long*) customSecret + uint64_offset, dst16);
}
var dst0 = Sse2.Add(src0, seed);
var dst1 = Sse2.Add(src1, seed);
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)]
private static unsafe ulong XXH3_hashLong_64b_internal(byte* input, int len, byte* secret, int secretSize)
{
ulong* acc = stackalloc ulong[8];
fixed (ulong* ptr = &XXH3_INIT_ACC[0])
fixed (ulong* src = &XXH3_INIT_ACC[0])
{
acc[0] = ptr[0];
acc[1] = ptr[1];
acc[2] = ptr[2];
acc[3] = ptr[3];
acc[4] = ptr[4];
acc[5] = ptr[5];
acc[6] = ptr[6];
acc[7] = ptr[7];
}
ulong* acc = stackalloc ulong[8]
{
*(src + 0),
*(src + 1),
*(src + 2),
*(src + 3),
*(src + 4),
*(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);
return XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, ((ulong)len) * XXH_PRIME64_1);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -378,51 +398,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_accumulate_512_avx2(ulong* acc, byte* input, byte* secret)
{
const int m256i_size = 32;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
var acc_vec1 = Unsafe.Read<Vector256<ulong>>(acc + 4);
for (int i = 0; i < XXH_STRIPE_LEN / m256i_size; i++)
{
int uint32_offset = i * 8;
int uint64_offset = i * 4;
var data_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 0).AsUInt32();
var data_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)input + 4).AsUInt32();
var acc_vec = Avx2.LoadVector256(acc + uint64_offset);
var data_vec = Avx2.LoadVector256((uint*) input + uint32_offset);
var key_vec = Avx2.LoadVector256((uint*) secret + uint32_offset);
var data_key = Avx2.Xor(data_vec, key_vec);
var data_key_lo = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var product = Avx2.Multiply(data_key, data_key_lo);
var data_swap = Avx2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum = Avx2.Add(acc_vec, data_swap);
var result = Avx2.Add(product, sum);
Avx2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0).AsUInt32();
var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4).AsUInt32();
var data_key0 = Avx2.Xor(data_vec0, key_vec0);
var data_key1 = Avx2.Xor(data_vec1, key_vec1);
var data_key_lo0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var data_key_lo1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
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)]
private static unsafe void XXH3_accumulate_512_sse2(ulong* acc, byte* input, byte* secret)
{
const int m128i_size = 16;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
const byte _MM_SHUFFLE_1_0_3_2 = 0b0100_1110;
var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0);
var acc_vec1 = Unsafe.Read<Vector128<ulong>>(acc + 2);
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++)
{
int uint32_offset = i * 4;
int uint64_offset = i * 2;
var data_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 0).AsUInt32();
var data_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 2).AsUInt32();
var data_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 4).AsUInt32();
var data_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)input + 6).AsUInt32();
var acc_vec = Sse2.LoadVector128(acc + uint64_offset);
var data_vec = Sse2.LoadVector128((uint*) input + uint32_offset);
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset);
var data_key = Sse2.Xor(data_vec, key_vec);
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_swap = Sse2.Shuffle(data_vec, _MM_SHUFFLE_1_0_3_2).AsUInt64();
var sum = Sse2.Add(acc_vec, data_swap);
var result = Sse2.Add(product, sum);
Sse2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
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_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)]
@@ -459,52 +517,89 @@ namespace Standart.Hash.xxHash
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void XXH3_scrambleAcc_avx2(ulong* acc, byte* secret)
{
const int m256i_size = 32;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
var acc_vec0 = Unsafe.Read<Vector256<ulong>>(acc + 0);
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++)
{
int uint64_offset = i * 4;
var data_vec0 = Avx2.Xor(acc_vec0, shifted0);
var data_vec1 = Avx2.Xor(acc_vec1, shifted1);
var acc_vec = Avx2.LoadVector256(acc + uint64_offset);
var shifted = Avx2.ShiftRightLogical(acc_vec, 47);
var data_vec = Avx2.Xor(acc_vec, shifted);
var key_vec = Avx2.LoadVector256((ulong*) secret + uint64_offset);
var data_key = Avx2.Xor(data_vec, key_vec).AsUInt32();
var data_key_hi = Avx2.Shuffle(data_key, _MM_SHUFFLE_0_3_0_1);
var prod_lo = Avx2.Multiply(data_key, prime32);
var prod_hi = Avx2.Multiply(data_key_hi, prime32);
var result = Avx2.Add(prod_lo, Avx2.ShiftLeftLogical(prod_hi, 32));
Avx2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 0);
var key_vec1 = Unsafe.Read<Vector256<ulong>>((ulong*)secret + 4);
var data_key0 = Avx2.Xor(data_vec0, key_vec0).AsUInt32();
var data_key1 = Avx2.Xor(data_vec1, key_vec1).AsUInt32();
var data_key_hi0 = Avx2.Shuffle(data_key0, MM_SHUFFLE_0_3_0_1);
var data_key_hi1 = Avx2.Shuffle(data_key1, MM_SHUFFLE_0_3_0_1);
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)]
private static unsafe void XXH3_scrambleAcc_sse2(ulong* acc, byte* secret)
{
const int m128i_size = 16;
const byte _MM_SHUFFLE_0_3_0_1 = 0b0011_0001;
var acc_vec0 = Unsafe.Read<Vector128<ulong>>(acc + 0).AsUInt32();
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++)
{
int uint32_offset = i * 4;
int uint64_offset = i * 2;
var data_vec0 = Sse2.Xor(acc_vec0, shifted0);
var data_vec1 = Sse2.Xor(acc_vec1, shifted1);
var data_vec2 = Sse2.Xor(acc_vec2, shifted2);
var data_vec3 = Sse2.Xor(acc_vec3, shifted3);
var acc_vec = Sse2.LoadVector128(acc + uint64_offset).AsUInt32();
var shifted = Sse2.ShiftRightLogical(acc_vec, 47);
var data_vec = Sse2.Xor(acc_vec, shifted);
var key_vec = Sse2.LoadVector128((uint*) secret + uint32_offset);
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 prod_lo = Sse2.Multiply(data_key, prime32);
var prod_hi = Sse2.Multiply(data_key_hi, prime32);
var result = Sse2.Add(prod_lo, Sse2.ShiftLeftLogical(prod_hi, 32));
Sse2.Store(acc + uint64_offset, result);
}
var key_vec0 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 0).AsUInt32();
var key_vec1 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 2).AsUInt32();
var key_vec2 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 4).AsUInt32();
var key_vec3 = Unsafe.Read<Vector128<ulong>>((ulong*)secret + 6).AsUInt32();
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)]
@@ -529,3 +624,4 @@ namespace Standart.Hash.xxHash
}
}
}
#endif

View File

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

View File

@@ -1,10 +1,9 @@
// ReSharper disable InconsistentNaming
#if NET6_0_OR_GREATER
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Standart.Hash.xxHash
namespace DTLib.XXHash
{
public static partial class xxHash3
{
@@ -89,11 +88,9 @@ namespace Standart.Hash.xxHash
{
fixed (byte* secret = &XXH3_SECRET[0])
{
// Use inlined version
// 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);
return 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;

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;

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);
}
}