Compare commits
10 Commits
9ab0dd4290
...
ea7471d09e
| Author | SHA1 | Date | |
|---|---|---|---|
| ea7471d09e | |||
| bcaa7a9411 | |||
| 676d59bf80 | |||
| bec532f6d9 | |||
| b806cf6e18 | |||
| 90ad0a9f5a | |||
|
|
6b20e7f7b3 | ||
|
|
62d648b6c3 | ||
|
|
f97a238e61 | ||
|
|
91b72f21db |
25
.github/workflows/dotnet.yml
vendored
25
.github/workflows/dotnet.yml
vendored
@@ -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
|
||||
31
.github/workflows/release.yml
vendored
31
.github/workflows/release.yml
vendored
@@ -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
292
.gitignore
vendored
@@ -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/
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -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
|
||||
@@ -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>
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Standart.Hash.xxHash.Perf
|
||||
namespace DTLib.XXHash.PerformanceTest
|
||||
{
|
||||
using BenchmarkDotNet.Running;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Standart.Hash.xxHash.Perf
|
||||
namespace DTLib.XXHash.PerformanceTest
|
||||
{
|
||||
using System;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
@@ -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()
|
||||
24
DTLib.XXHash.Tests/DTLib.XXHash.Tests.csproj
Normal file
24
DTLib.XXHash.Tests/DTLib.XXHash.Tests.csproj
Normal 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>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
116
DTLib.XXHash.Tests/xxHash128Test.cs
Normal file
116
DTLib.XXHash.Tests/xxHash128Test.cs
Normal 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
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -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
28
DTLib.XXHash.sln
Normal 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
|
||||
28
DTLib.XXHash/DTLib.XXHash.csproj
Normal file
28
DTLib.XXHash/DTLib.XXHash.csproj
Normal 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>
|
||||
@@ -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)
|
||||
191
DTLib.XXHash/__inline__xxHash32.cs
Normal file
191
DTLib.XXHash/__inline__xxHash32.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
252
DTLib.XXHash/__inline__xxHash64.cs
Normal file
252
DTLib.XXHash/__inline__xxHash64.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
21
DTLib.XXHash/xxHash32.XXH.cs
Normal file
21
DTLib.XXHash/xxHash32.XXH.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
264
DTLib.XXHash/xxHash32.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
DTLib.XXHash/xxHash64.XXH.cs
Normal file
21
DTLib.XXHash/xxHash64.XXH.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
264
DTLib.XXHash/xxHash64.cs
Normal 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
131
README.md
@@ -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>
|
||||
@@ -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>
|
||||
15
nuget.props
15
nuget.props
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user