mirror of
https://github.com/facebook/zstd.git
synced 2024-12-05 04:36:47 +08:00
Merge pull request #701 from terrelln/lk-xxh
[linux-kernel] Separate xxhash into its own module
This commit is contained in:
commit
ac4b4d0c44
@ -1,21 +1,33 @@
|
||||
# Linux Kernel Patch
|
||||
|
||||
There are three pieces, the `zstd_compress` and `zstd_decompress` kernel modules, the BtrFS patch, and the SquashFS patch.
|
||||
There are four pieces, the `xxhash` kernel module, the `zstd_compress` and `zstd_decompress` kernel modules, the BtrFS patch, and the SquashFS patch.
|
||||
The patches are based off of the linux kernel master branch (version 4.10).
|
||||
|
||||
## xxHash kernel module
|
||||
|
||||
* The patch is locaed in `xxhash.diff`.
|
||||
* The header is in `include/linux/xxhash.h`.
|
||||
* The source is in `lib/xxhash.c`.
|
||||
* `test/XXHashUserLandTest.cpp` contains tests for the patch in userland by mocking the kernel headers.
|
||||
I tested the tests by commenting a line of of each branch in `xxhash.c` one line at a time, and made sure the tests failed.
|
||||
It can be run with the following commands:
|
||||
```
|
||||
cd test && make googletest && make XXHashUserLandTest && ./XXHashUserLandTest
|
||||
```
|
||||
* I also benchmarked the `xxhash` module against upstream xxHash, and made sure that they ran at the same speed.
|
||||
|
||||
## Zstd Kernel modules
|
||||
|
||||
* The (large) patch is locaed in `zstd.diff`, which depends on `xxhash.diff`.
|
||||
* The header is in `include/linux/zstd.h`.
|
||||
* It is split up into `zstd_compress` and `zstd_decompress`, which can be loaded independently.
|
||||
* Source files are in `lib/zstd/`.
|
||||
* `lib/Kconfig` and `lib/Makefile` need to be modified by applying `lib/Kconfig.diff` and `lib/Makefile.diff` respectively.
|
||||
These changes are also included in the `zstd.diff`.
|
||||
* `test/UserlandTest.cpp` contains tests for the patch in userland by mocking the kernel headers.
|
||||
It can be run with the following commands:
|
||||
```
|
||||
cd test
|
||||
make googletest
|
||||
make UserlandTest
|
||||
./UserlandTest
|
||||
cd test && make googletest && make UserlandTest && ./UserlandTest
|
||||
```
|
||||
|
||||
## BtrFS
|
||||
|
230
contrib/linux-kernel/include/linux/xxhash.h
Normal file
230
contrib/linux-kernel/include/linux/xxhash.h
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet.
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: http://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/*
|
||||
* Notice extracted from xxHash homepage:
|
||||
*
|
||||
* xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
* It also successfully passes all tests from the SMHasher suite.
|
||||
*
|
||||
* Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2
|
||||
* Duo @3GHz)
|
||||
*
|
||||
* Name Speed Q.Score Author
|
||||
* xxHash 5.4 GB/s 10
|
||||
* CrapWow 3.2 GB/s 2 Andrew
|
||||
* MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
* SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
* SBox 1.4 GB/s 9 Bret Mulvey
|
||||
* Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
* SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
* CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
* FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
* CRC32 0.43 GB/s 9
|
||||
* MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
* SHA1-32 0.28 GB/s 10
|
||||
*
|
||||
* Q.Score is a measure of quality of the hash function.
|
||||
* It depends on successfully passing SMHasher test set.
|
||||
* 10 is a perfect score.
|
||||
*
|
||||
* A 64-bits version, named xxh64 offers much better speed,
|
||||
* but for 64-bits applications only.
|
||||
* Name Speed on 64 bits Speed on 32 bits
|
||||
* xxh64 13.8 GB/s 1.9 GB/s
|
||||
* xxh32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#ifndef XXHASH_H
|
||||
#define XXHASH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*-****************************
|
||||
* Simple Hash Functions
|
||||
*****************************/
|
||||
|
||||
/**
|
||||
* xxh32() - calculate the 32-bit hash of the input with a given seed.
|
||||
*
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||
*
|
||||
* Return: The 32-bit hash of the data.
|
||||
*/
|
||||
uint32_t xxh32(const void *input, size_t length, uint32_t seed);
|
||||
|
||||
/**
|
||||
* xxh64() - calculate the 64-bit hash of the input with a given seed.
|
||||
*
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
* @seed: The seed can be used to alter the result predictably.
|
||||
*
|
||||
* This function runs 2x faster on 64-bit systems, but slower on 32-bit systems.
|
||||
*
|
||||
* Return: The 64-bit hash of the data.
|
||||
*/
|
||||
uint64_t xxh64(const void *input, size_t length, uint64_t seed);
|
||||
|
||||
/*-****************************
|
||||
* Streaming Hash Functions
|
||||
*****************************/
|
||||
|
||||
/*
|
||||
* These definitions are only meant to allow allocation of XXH state
|
||||
* statically, on stack, or in a struct for example.
|
||||
* Do not use members directly.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct xxh32_state - private xxh32 state, do not use members directly
|
||||
*/
|
||||
struct xxh32_state {
|
||||
uint32_t total_len_32;
|
||||
uint32_t large_len;
|
||||
uint32_t v1;
|
||||
uint32_t v2;
|
||||
uint32_t v3;
|
||||
uint32_t v4;
|
||||
uint32_t mem32[4];
|
||||
uint32_t memsize;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xxh32_state - private xxh64 state, do not use members directly
|
||||
*/
|
||||
struct xxh64_state {
|
||||
uint64_t total_len;
|
||||
uint64_t v1;
|
||||
uint64_t v2;
|
||||
uint64_t v3;
|
||||
uint64_t v4;
|
||||
uint64_t mem64[4];
|
||||
uint32_t memsize;
|
||||
};
|
||||
|
||||
/**
|
||||
* xxh32_reset() - reset the xxh32 state to start a new hashing operation
|
||||
*
|
||||
* @state: The xxh32 state to reset.
|
||||
* @seed: Initialize the hash state with this seed.
|
||||
*
|
||||
* Call this function on any xxh32_state to prepare for a new hashing operation.
|
||||
*/
|
||||
void xxh32_reset(struct xxh32_state *state, uint32_t seed);
|
||||
|
||||
/**
|
||||
* xxh32_update() - hash the data given and update the xxh32 state
|
||||
*
|
||||
* @state: The xxh32 state to update.
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
*
|
||||
* After calling xxh32_reset() call xxh32_update() as many times as necessary.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error code.
|
||||
*/
|
||||
int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
|
||||
|
||||
/**
|
||||
* xxh32_digest() - produce the current xxh32 hash
|
||||
*
|
||||
* @state: Produce the current xxh32 hash of this state.
|
||||
*
|
||||
* A hash value can be produced at any time. It is still possible to continue
|
||||
* inserting input into the hash state after a call to xxh32_digest(), and
|
||||
* generate new hashes later on, by calling xxh32_digest() again.
|
||||
*
|
||||
* Return: The xxh32 hash stored in the state.
|
||||
*/
|
||||
uint32_t xxh32_digest(const struct xxh32_state *state);
|
||||
|
||||
/**
|
||||
* xxh64_reset() - reset the xxh64 state to start a new hashing operation
|
||||
*
|
||||
* @state: The xxh64 state to reset.
|
||||
* @seed: Initialize the hash state with this seed.
|
||||
*/
|
||||
void xxh64_reset(struct xxh64_state *state, uint64_t seed);
|
||||
|
||||
/**
|
||||
* xxh64_update() - hash the data given and update the xxh64 state
|
||||
* @state: The xxh64 state to update.
|
||||
* @input: The data to hash.
|
||||
* @length: The length of the data to hash.
|
||||
*
|
||||
* After calling xxh64_reset() call xxh64_update() as many times as necessary.
|
||||
*
|
||||
* Return: Zero on success, otherwise an error code.
|
||||
*/
|
||||
int xxh64_update(struct xxh64_state *state, const void *input, size_t length);
|
||||
|
||||
/**
|
||||
* xxh64_digest() - produce the current xxh64 hash
|
||||
*
|
||||
* @state: Produce the current xxh64 hash of this state.
|
||||
*
|
||||
* A hash value can be produced at any time. It is still possible to continue
|
||||
* inserting input into the hash state after a call to xxh64_digest(), and
|
||||
* generate new hashes later on, by calling xxh64_digest() again.
|
||||
*
|
||||
* Return: The xxh64 hash stored in the state.
|
||||
*/
|
||||
uint64_t xxh64_digest(const struct xxh64_state *state);
|
||||
|
||||
/*-**************************
|
||||
* Utils
|
||||
***************************/
|
||||
|
||||
/**
|
||||
* xxh32_copy_state() - copy the source state into the destination state
|
||||
*
|
||||
* @src: The source xxh32 state.
|
||||
* @dst: The destination xxh32 state.
|
||||
*/
|
||||
void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src);
|
||||
|
||||
/**
|
||||
* xxh64_copy_state() - copy the source state into the destination state
|
||||
*
|
||||
* @src: The source xxh64 state.
|
||||
* @dst: The destination xxh64 state.
|
||||
*/
|
||||
void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src);
|
||||
|
||||
#endif /* XXHASH_H */
|
@ -1,15 +1,17 @@
|
||||
diff --git a/lib/Kconfig b/lib/Kconfig
|
||||
index 260a80e..39d9347 100644
|
||||
index b6009d7..f00ddab 100644
|
||||
--- a/lib/Kconfig
|
||||
+++ b/lib/Kconfig
|
||||
@@ -239,6 +239,12 @@ config LZ4HC_COMPRESS
|
||||
@@ -241,6 +241,14 @@ config LZ4HC_COMPRESS
|
||||
config LZ4_DECOMPRESS
|
||||
tristate
|
||||
|
||||
+config ZSTD_COMPRESS
|
||||
+ select XXHASH
|
||||
+ tristate
|
||||
+
|
||||
+config ZSTD_DECOMPRESS
|
||||
+ select XXHASH
|
||||
+ tristate
|
||||
+
|
||||
source "lib/xz/Kconfig"
|
||||
|
@ -1,8 +1,8 @@
|
||||
diff --git a/lib/Makefile b/lib/Makefile
|
||||
index 50144a3..b30a998 100644
|
||||
index e16f94a..0cfd529 100644
|
||||
--- a/lib/Makefile
|
||||
+++ b/lib/Makefile
|
||||
@@ -106,6 +106,8 @@ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
|
||||
@@ -115,6 +115,8 @@ obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
|
||||
obj-$(CONFIG_LZ4_COMPRESS) += lz4/
|
||||
obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/
|
||||
obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/
|
||||
|
494
contrib/linux-kernel/lib/xxhash.c
Normal file
494
contrib/linux-kernel/lib/xxhash.c
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet.
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You can contact the author at:
|
||||
* - xxHash homepage: http://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/xxhash.h>
|
||||
|
||||
/*-*************************************
|
||||
* Macros
|
||||
**************************************/
|
||||
#define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
|
||||
#define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
# define XXH_CPU_LITTLE_ENDIAN 1
|
||||
#else
|
||||
# define XXH_CPU_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/*-*************************************
|
||||
* Constants
|
||||
**************************************/
|
||||
static const uint32_t PRIME32_1 = 2654435761U;
|
||||
static const uint32_t PRIME32_2 = 2246822519U;
|
||||
static const uint32_t PRIME32_3 = 3266489917U;
|
||||
static const uint32_t PRIME32_4 = 668265263U;
|
||||
static const uint32_t PRIME32_5 = 374761393U;
|
||||
|
||||
static const uint64_t PRIME64_1 = 11400714785074694791ULL;
|
||||
static const uint64_t PRIME64_2 = 14029467366897019727ULL;
|
||||
static const uint64_t PRIME64_3 = 1609587929392839161ULL;
|
||||
static const uint64_t PRIME64_4 = 9650029242287828579ULL;
|
||||
static const uint64_t PRIME64_5 = 2870177450012600261ULL;
|
||||
|
||||
/*-**************************
|
||||
* Utils
|
||||
***************************/
|
||||
void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
EXPORT_SYMBOL(xxh32_copy_state);
|
||||
|
||||
void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
EXPORT_SYMBOL(xxh64_copy_state);
|
||||
|
||||
/*-***************************
|
||||
* Simple Hash Functions
|
||||
****************************/
|
||||
static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
|
||||
{
|
||||
seed += input * PRIME32_2;
|
||||
seed = xxh_rotl32(seed, 13);
|
||||
seed *= PRIME32_1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *b_end = p + len;
|
||||
uint32_t h32;
|
||||
|
||||
if (len >= 16) {
|
||||
const uint8_t *const limit = b_end - 16;
|
||||
uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
uint32_t v2 = seed + PRIME32_2;
|
||||
uint32_t v3 = seed + 0;
|
||||
uint32_t v4 = seed - PRIME32_1;
|
||||
|
||||
do {
|
||||
v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
} while (p <= limit);
|
||||
|
||||
h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
|
||||
xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
|
||||
} else {
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (uint32_t)len;
|
||||
|
||||
while (p + 4 <= b_end) {
|
||||
h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
EXPORT_SYMBOL(xxh32);
|
||||
|
||||
static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
|
||||
{
|
||||
acc += input * PRIME64_2;
|
||||
acc = xxh_rotl64(acc, 31);
|
||||
acc *= PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
|
||||
{
|
||||
val = xxh64_round(0, val);
|
||||
acc ^= val;
|
||||
acc = acc * PRIME64_1 + PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
uint64_t h64;
|
||||
|
||||
if (len >= 32) {
|
||||
const uint8_t *const limit = b_end - 32;
|
||||
uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
uint64_t v2 = seed + PRIME64_2;
|
||||
uint64_t v3 = seed + 0;
|
||||
uint64_t v4 = seed - PRIME64_1;
|
||||
|
||||
do {
|
||||
v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
} while (p <= limit);
|
||||
|
||||
h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
h64 = xxh64_merge_round(h64, v1);
|
||||
h64 = xxh64_merge_round(h64, v2);
|
||||
h64 = xxh64_merge_round(h64, v3);
|
||||
h64 = xxh64_merge_round(h64, v4);
|
||||
|
||||
} else {
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (uint64_t)len;
|
||||
|
||||
while (p + 8 <= b_end) {
|
||||
const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
|
||||
h64 ^= k1;
|
||||
h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (p + 4 <= b_end) {
|
||||
h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
EXPORT_SYMBOL(xxh64);
|
||||
|
||||
/*-**************************************************
|
||||
* Advanced Hash Functions
|
||||
***************************************************/
|
||||
void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
|
||||
{
|
||||
/* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
struct xxh32_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state.v2 = seed + PRIME32_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME32_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
}
|
||||
EXPORT_SYMBOL(xxh32_reset);
|
||||
|
||||
void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
|
||||
{
|
||||
/* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
struct xxh64_state state;
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state.v2 = seed + PRIME64_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME64_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
}
|
||||
EXPORT_SYMBOL(xxh64_reset);
|
||||
|
||||
int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
|
||||
if (input == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
state->total_len_32 += (uint32_t)len;
|
||||
state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
|
||||
|
||||
if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||
memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* some data left from previous update */
|
||||
const uint32_t *p32 = state->mem32;
|
||||
|
||||
memcpy((uint8_t *)(state->mem32) + state->memsize, input,
|
||||
16 - state->memsize);
|
||||
|
||||
state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
|
||||
p32++;
|
||||
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= b_end - 16) {
|
||||
const uint8_t *const limit = b_end - 16;
|
||||
uint32_t v1 = state->v1;
|
||||
uint32_t v2 = state->v2;
|
||||
uint32_t v3 = state->v3;
|
||||
uint32_t v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
p += 4;
|
||||
} while (p <= limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < b_end) {
|
||||
memcpy(state->mem32, p, (size_t)(b_end-p));
|
||||
state->memsize = (uint32_t)(b_end-p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(xxh32_update);
|
||||
|
||||
uint32_t xxh32_digest(const struct xxh32_state *state)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)state->mem32;
|
||||
const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
|
||||
state->memsize;
|
||||
uint32_t h32;
|
||||
|
||||
if (state->large_len) {
|
||||
h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
|
||||
xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
|
||||
} else {
|
||||
h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += state->total_len_32;
|
||||
|
||||
while (p + 4 <= b_end) {
|
||||
h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
EXPORT_SYMBOL(xxh32_digest);
|
||||
|
||||
int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)input;
|
||||
const uint8_t *const b_end = p + len;
|
||||
|
||||
if (input == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* tmp buffer is full */
|
||||
const uint64_t *p64 = state->mem64;
|
||||
|
||||
memcpy(((uint8_t *)p64) + state->memsize, input,
|
||||
32 - state->memsize);
|
||||
|
||||
state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
|
||||
p64++;
|
||||
state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
|
||||
|
||||
p += 32 - state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p + 32 <= b_end) {
|
||||
const uint8_t *const limit = b_end - 32;
|
||||
uint64_t v1 = state->v1;
|
||||
uint64_t v2 = state->v2;
|
||||
uint64_t v3 = state->v3;
|
||||
uint64_t v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
p += 8;
|
||||
} while (p <= limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < b_end) {
|
||||
memcpy(state->mem64, p, (size_t)(b_end-p));
|
||||
state->memsize = (uint32_t)(b_end - p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(xxh64_update);
|
||||
|
||||
uint64_t xxh64_digest(const struct xxh64_state *state)
|
||||
{
|
||||
const uint8_t *p = (const uint8_t *)state->mem64;
|
||||
const uint8_t *const b_end = (const uint8_t *)state->mem64 +
|
||||
state->memsize;
|
||||
uint64_t h64;
|
||||
|
||||
if (state->total_len >= 32) {
|
||||
const uint64_t v1 = state->v1;
|
||||
const uint64_t v2 = state->v2;
|
||||
const uint64_t v3 = state->v3;
|
||||
const uint64_t v4 = state->v4;
|
||||
|
||||
h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
h64 = xxh64_merge_round(h64, v1);
|
||||
h64 = xxh64_merge_round(h64, v2);
|
||||
h64 = xxh64_merge_round(h64, v3);
|
||||
h64 = xxh64_merge_round(h64, v4);
|
||||
} else {
|
||||
h64 = state->v3 + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (uint64_t)state->total_len;
|
||||
|
||||
while (p + 8 <= b_end) {
|
||||
const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
|
||||
h64 ^= k1;
|
||||
h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (p + 4 <= b_end) {
|
||||
h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
while (p < b_end) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
EXPORT_SYMBOL(xxh64_digest);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("xxHash");
|
@ -3,7 +3,7 @@ obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd_decompress.o
|
||||
|
||||
ccflags-y += -O3
|
||||
|
||||
zstd_compress-y := entropy_common.o fse_decompress.o xxhash.o zstd_common.o \
|
||||
zstd_compress-y := entropy_common.o fse_decompress.o zstd_common.o \
|
||||
fse_compress.o huf_compress.o compress.o
|
||||
zstd_decompress-y := entropy_common.o fse_decompress.o xxhash.o zstd_common.o \
|
||||
zstd_decompress-y := entropy_common.o fse_decompress.o zstd_common.o \
|
||||
huf_decompress.o decompress.o
|
||||
|
@ -73,7 +73,7 @@ struct ZSTD_CCtx_s {
|
||||
size_t workSpaceSize;
|
||||
size_t blockSize;
|
||||
U64 frameContentSize;
|
||||
XXH64_state_t xxhState;
|
||||
struct xxh64_state xxhState;
|
||||
ZSTD_customMem customMem;
|
||||
|
||||
seqStore_t seqStore; /* sequences storage ptrs */
|
||||
@ -221,7 +221,7 @@ static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 fra
|
||||
cctx->loadedDictEnd = 0;
|
||||
{ int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
|
||||
cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
|
||||
XXH64_reset(&cctx->xxhState, 0);
|
||||
xxh64_reset(&cctx->xxhState, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -264,7 +264,7 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
|
||||
} }
|
||||
|
||||
if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
|
||||
XXH64_reset(&zc->xxhState, 0);
|
||||
xxh64_reset(&zc->xxhState, 0);
|
||||
zc->hashLog3 = hashLog3;
|
||||
zc->hashTable = (U32*)(zc->workSpace);
|
||||
zc->chainTable = zc->hashTable + hSize;
|
||||
@ -2322,7 +2322,7 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
|
||||
U32 const maxDist = 1 << cctx->params.cParams.windowLog;
|
||||
|
||||
if (cctx->params.fParams.checksumFlag && srcSize)
|
||||
XXH64_update(&cctx->xxhState, src, srcSize);
|
||||
xxh64_update(&cctx->xxhState, src, srcSize);
|
||||
|
||||
while (remaining) {
|
||||
U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
|
||||
@ -2720,7 +2720,7 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
|
||||
}
|
||||
|
||||
if (cctx->params.fParams.checksumFlag) {
|
||||
U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
|
||||
U32 const checksum = (U32) xxh64_digest(&cctx->xxhState);
|
||||
if (dstCapacity<4) return ERROR(dstSize_tooSmall);
|
||||
MEM_writeLE32(op, checksum);
|
||||
op += 4;
|
||||
|
@ -81,7 +81,7 @@ struct ZSTD_DCtx_s
|
||||
ZSTD_dStage stage;
|
||||
U32 litEntropy;
|
||||
U32 fseEntropy;
|
||||
XXH64_state_t xxhState;
|
||||
struct xxh64_state xxhState;
|
||||
size_t headerSize;
|
||||
U32 dictID;
|
||||
const BYTE* litPtr;
|
||||
@ -366,7 +366,7 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t he
|
||||
if (ZSTD_isError(result)) return result; /* invalid header */
|
||||
if (result>0) return ERROR(srcSize_wrong); /* headerSize too small */
|
||||
if (dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID)) return ERROR(dictionary_wrong);
|
||||
if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
|
||||
if (dctx->fParams.checksumFlag) xxh64_reset(&dctx->xxhState, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1517,7 +1517,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
}
|
||||
|
||||
if (ZSTD_isError(decodedSize)) return decodedSize;
|
||||
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, op, decodedSize);
|
||||
if (dctx->fParams.checksumFlag) xxh64_update(&dctx->xxhState, op, decodedSize);
|
||||
op += decodedSize;
|
||||
ip += cBlockSize;
|
||||
remainingSize -= cBlockSize;
|
||||
@ -1525,7 +1525,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
}
|
||||
|
||||
if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
|
||||
U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
|
||||
U32 const checkCalc = (U32)xxh64_digest(&dctx->xxhState);
|
||||
U32 checkRead;
|
||||
if (remainingSize<4) return ERROR(checksum_wrong);
|
||||
checkRead = MEM_readLE32(ip);
|
||||
@ -1731,7 +1731,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
return ERROR(corruption_detected);
|
||||
}
|
||||
if (ZSTD_isError(rSize)) return rSize;
|
||||
if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
|
||||
if (dctx->fParams.checksumFlag) xxh64_update(&dctx->xxhState, dst, rSize);
|
||||
|
||||
if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
|
||||
if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
|
||||
@ -1749,7 +1749,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, c
|
||||
return rSize;
|
||||
}
|
||||
case ZSTDds_checkChecksum:
|
||||
{ U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
|
||||
{ U32 const h32 = (U32)xxh64_digest(&dctx->xxhState);
|
||||
U32 const check32 = MEM_readLE32(src); /* srcSize == 4, guaranteed by dctx->expected */
|
||||
if (check32 != h32) return ERROR(checksum_wrong);
|
||||
dctx->expected = 0;
|
||||
|
@ -1,700 +0,0 @@
|
||||
/*
|
||||
* xxHash - Fast Hash algorithm
|
||||
* Copyright (C) 2012-2016, Yann Collet
|
||||
*
|
||||
* BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You can contact the author at :
|
||||
* - xxHash homepage: http://www.xxhash.com
|
||||
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
/*!XXH_ACCEPT_NULL_INPUT_POINTER :
|
||||
* If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
|
||||
* When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
|
||||
* By default, this option is disabled. To enable it, uncomment below define :
|
||||
*/
|
||||
/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
|
||||
|
||||
/*!XXH_FORCE_NATIVE_FORMAT :
|
||||
* By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
|
||||
* Results are therefore identical for little-endian and big-endian CPU.
|
||||
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
|
||||
* Should endian-independance be of no importance for your application, you may set the #define below to 1,
|
||||
* to improve speed for Big-endian CPU.
|
||||
* This option has no impact on Little_Endian CPU.
|
||||
*/
|
||||
#define XXH_FORCE_NATIVE_FORMAT 0
|
||||
|
||||
/*!XXH_FORCE_ALIGN_CHECK :
|
||||
* This is a minor performance trick, only useful with lots of very small keys.
|
||||
* It means : check for aligned/unaligned input.
|
||||
* The check costs one initial branch per hash; set to 0 when the input data
|
||||
* is guaranteed to be aligned.
|
||||
*/
|
||||
#define XXH_FORCE_ALIGN_CHECK 0
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Includes & Memory related functions
|
||||
***************************************/
|
||||
/* Modify the local functions below should you wish to use some other memory routines */
|
||||
/* for memcpy() */
|
||||
#include <linux/string.h>
|
||||
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }
|
||||
|
||||
#include "xxhash.h"
|
||||
#include "mem.h"
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Compiler Specific Options
|
||||
***************************************/
|
||||
#include <linux/compiler.h>
|
||||
#define FORCE_INLINE static __always_inline
|
||||
|
||||
|
||||
/* ****************************************
|
||||
* Compiler-specific Functions and Macros
|
||||
******************************************/
|
||||
#define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
#define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
||||
|
||||
/* *************************************
|
||||
* Architecture Macros
|
||||
***************************************/
|
||||
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
|
||||
|
||||
/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */
|
||||
#ifndef XXH_CPU_LITTLE_ENDIAN
|
||||
# define XXH_CPU_LITTLE_ENDIAN MEM_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
|
||||
/* ***************************
|
||||
* Memory reads
|
||||
*****************************/
|
||||
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
(void)endian;
|
||||
(void)align;
|
||||
return MEM_readLE32(ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
static U32 XXH_readBE32(const void* ptr)
|
||||
{
|
||||
return MEM_readBE32(ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
(void)endian;
|
||||
(void)align;
|
||||
return MEM_readLE64(ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
static U64 XXH_readBE64(const void* ptr)
|
||||
{
|
||||
return MEM_readBE64(ptr);
|
||||
}
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
static const U32 PRIME32_1 = 2654435761U;
|
||||
static const U32 PRIME32_2 = 2246822519U;
|
||||
static const U32 PRIME32_3 = 3266489917U;
|
||||
static const U32 PRIME32_4 = 668265263U;
|
||||
static const U32 PRIME32_5 = 374761393U;
|
||||
|
||||
static const U64 PRIME64_1 = 11400714785074694791ULL;
|
||||
static const U64 PRIME64_2 = 14029467366897019727ULL;
|
||||
static const U64 PRIME64_3 = 1609587929392839161ULL;
|
||||
static const U64 PRIME64_4 = 9650029242287828579ULL;
|
||||
static const U64 PRIME64_5 = 2870177450012600261ULL;
|
||||
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
|
||||
|
||||
|
||||
/* **************************
|
||||
* Utils
|
||||
****************************/
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
|
||||
{
|
||||
memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
|
||||
{
|
||||
memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
|
||||
/* ***************************
|
||||
* Simple Hash Functions
|
||||
*****************************/
|
||||
|
||||
static U32 XXH32_round(U32 seed, U32 input)
|
||||
{
|
||||
seed += input * PRIME32_2;
|
||||
seed = XXH_rotl32(seed, 13);
|
||||
seed *= PRIME32_1;
|
||||
return seed;
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U32 h32;
|
||||
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL) {
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)16;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=16) {
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
U32 v2 = seed + PRIME32_2;
|
||||
U32 v3 = seed + 0;
|
||||
U32 v4 = seed - PRIME32_1;
|
||||
|
||||
do {
|
||||
v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;
|
||||
v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;
|
||||
v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;
|
||||
v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;
|
||||
} while (p<=limit);
|
||||
|
||||
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
|
||||
} else {
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (U32) len;
|
||||
|
||||
while (p+4<=bEnd) {
|
||||
h32 += XXH_get32bits(p) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH32_CREATESTATE_STATIC(state);
|
||||
XXH32_reset(state, seed);
|
||||
XXH32_update(state, input, len);
|
||||
return XXH32_digest(state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if (XXH_FORCE_ALIGN_CHECK) {
|
||||
if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
} }
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static U64 XXH64_round(U64 acc, U64 input)
|
||||
{
|
||||
acc += input * PRIME64_2;
|
||||
acc = XXH_rotl64(acc, 31);
|
||||
acc *= PRIME64_1;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static U64 XXH64_mergeRound(U64 acc, U64 val)
|
||||
{
|
||||
val = XXH64_round(0, val);
|
||||
acc ^= val;
|
||||
acc = acc * PRIME64_1 + PRIME64_4;
|
||||
return acc;
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
U64 h64;
|
||||
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL) {
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)32;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=32) {
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
U64 v2 = seed + PRIME64_2;
|
||||
U64 v3 = seed + 0;
|
||||
U64 v4 = seed - PRIME64_1;
|
||||
|
||||
do {
|
||||
v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;
|
||||
v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;
|
||||
v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;
|
||||
v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;
|
||||
} while (p<=limit);
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
h64 = XXH64_mergeRound(h64, v1);
|
||||
h64 = XXH64_mergeRound(h64, v2);
|
||||
h64 = XXH64_mergeRound(h64, v3);
|
||||
h64 = XXH64_mergeRound(h64, v4);
|
||||
|
||||
} else {
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) len;
|
||||
|
||||
while (p+8<=bEnd) {
|
||||
U64 const k1 = XXH64_round(0, XXH_get64bits(p));
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd) {
|
||||
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH64_CREATESTATE_STATIC(state);
|
||||
XXH64_reset(state, seed);
|
||||
XXH64_update(state, input, len);
|
||||
return XXH64_digest(state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if (XXH_FORCE_ALIGN_CHECK) {
|
||||
if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
} }
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* **************************************************
|
||||
* Advanced Hash Functions
|
||||
****************************************************/
|
||||
|
||||
|
||||
/*** Hash feed ***/
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)
|
||||
{
|
||||
XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||
memset(&state, 0, sizeof(state)-4); /* do not write into reserved, for future removal */
|
||||
state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state.v2 = seed + PRIME32_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME32_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)
|
||||
{
|
||||
XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */
|
||||
memset(&state, 0, sizeof(state)-8); /* do not write into reserved, for future removal */
|
||||
state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state.v2 = seed + PRIME64_2;
|
||||
state.v3 = seed + 0;
|
||||
state.v4 = seed - PRIME64_1;
|
||||
memcpy(statePtr, &state, sizeof(state));
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len_32 += (unsigned)len;
|
||||
state->large_len |= (len>=16) | (state->total_len_32>=16);
|
||||
|
||||
if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (unsigned)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* some data left from previous update */
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
|
||||
{ const U32* p32 = state->mem32;
|
||||
state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;
|
||||
state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); p32++;
|
||||
}
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= bEnd-16) {
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = state->v1;
|
||||
U32 v2 = state->v2;
|
||||
U32 v3 = state->v3;
|
||||
U32 v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;
|
||||
v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;
|
||||
v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;
|
||||
v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;
|
||||
} while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd) {
|
||||
XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));
|
||||
state->memsize = (unsigned)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)
|
||||
{
|
||||
const BYTE * p = (const BYTE*)state->mem32;
|
||||
const BYTE* const bEnd = (const BYTE*)(state->mem32) + state->memsize;
|
||||
U32 h32;
|
||||
|
||||
if (state->large_len) {
|
||||
h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
|
||||
} else {
|
||||
h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += state->total_len_32;
|
||||
|
||||
while (p+4<=bEnd) {
|
||||
h32 += XXH_readLE32(p, endian) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* **** XXH64 **** */
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) { /* tmp buffer is full */
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
|
||||
state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));
|
||||
state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));
|
||||
state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));
|
||||
state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));
|
||||
p += 32-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p+32 <= bEnd) {
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = state->v1;
|
||||
U64 v2 = state->v2;
|
||||
U64 v3 = state->v3;
|
||||
U64 v4 = state->v4;
|
||||
|
||||
do {
|
||||
v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;
|
||||
v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;
|
||||
v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;
|
||||
v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;
|
||||
} while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd) {
|
||||
XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));
|
||||
state->memsize = (unsigned)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)
|
||||
{
|
||||
const BYTE * p = (const BYTE*)state->mem64;
|
||||
const BYTE* const bEnd = (const BYTE*)state->mem64 + state->memsize;
|
||||
U64 h64;
|
||||
|
||||
if (state->total_len >= 32) {
|
||||
U64 const v1 = state->v1;
|
||||
U64 const v2 = state->v2;
|
||||
U64 const v3 = state->v3;
|
||||
U64 const v4 = state->v4;
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
h64 = XXH64_mergeRound(h64, v1);
|
||||
h64 = XXH64_mergeRound(h64, v2);
|
||||
h64 = XXH64_mergeRound(h64, v3);
|
||||
h64 = XXH64_mergeRound(h64, v4);
|
||||
} else {
|
||||
h64 = state->v3 + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) state->total_len;
|
||||
|
||||
while (p+8<=bEnd) {
|
||||
U64 const k1 = XXH64_round(0, XXH_readLE64(p, endian));
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd) {
|
||||
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd) {
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
/* **************************
|
||||
* Canonical representation
|
||||
****************************/
|
||||
|
||||
/*! Default XXH result types are basic unsigned 32 and 64 bits.
|
||||
* The canonical representation follows human-readable write convention, aka big-endian (large digits first).
|
||||
* These functions allow transformation of hash result into and from its canonical format.
|
||||
* This way, hash values can be written into a file or buffer, and remain comparable across different systems and programs.
|
||||
*/
|
||||
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
|
||||
MEM_writeBE32(dst, hash);
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
|
||||
MEM_writeBE64(dst, hash);
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE32(src);
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE64(src);
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
/*
|
||||
xxHash - Extremely Fast Hash algorithm
|
||||
Header File
|
||||
Copyright (C) 2012-2016, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
*/
|
||||
|
||||
/* Notice extracted from xxHash homepage :
|
||||
|
||||
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
It also successfully passes all tests from the SMHasher suite.
|
||||
|
||||
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||
|
||||
Name Speed Q.Score Author
|
||||
xxHash 5.4 GB/s 10
|
||||
CrapWow 3.2 GB/s 2 Andrew
|
||||
MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
SBox 1.4 GB/s 9 Bret Mulvey
|
||||
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
CRC32 0.43 GB/s 9
|
||||
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
SHA1-32 0.28 GB/s 10
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
|
||||
A 64-bits version, named XXH64, is available since r35.
|
||||
It offers much better speed, but for 64-bits applications only.
|
||||
Name Speed on 64 bits Speed on 32 bits
|
||||
XXH64 13.8 GB/s 1.9 GB/s
|
||||
XXH32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#ifndef XXHASH_H_5627135585666179
|
||||
#define XXHASH_H_5627135585666179 1
|
||||
|
||||
|
||||
/* ****************************
|
||||
* Definitions
|
||||
******************************/
|
||||
#include <linux/types.h> /* size_t */
|
||||
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||
|
||||
|
||||
/* ****************************
|
||||
* API modifier
|
||||
******************************/
|
||||
/** XXH_PRIVATE_API
|
||||
* This is useful if you want to include xxhash functions in `static` mode
|
||||
* in order to inline them, and remove their symbol from the public list.
|
||||
* Methodology :
|
||||
* #define XXH_PRIVATE_API
|
||||
* #include "xxhash.h"
|
||||
* `xxhash.c` is automatically included.
|
||||
* It's not useful to compile and link it as a separate module anymore.
|
||||
*/
|
||||
#define XXH_PUBLIC_API /* do nothing */
|
||||
|
||||
/*!XXH_NAMESPACE, aka Namespace Emulation :
|
||||
|
||||
If you want to include _and expose_ xxHash functions from within your own library,
|
||||
but also want to avoid symbol collisions with another library which also includes xxHash,
|
||||
|
||||
you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library
|
||||
with the value of XXH_NAMESPACE (so avoid to keep it NULL and avoid numeric values).
|
||||
|
||||
Note that no change is required within the calling program as long as it includes `xxhash.h` :
|
||||
regular symbol name will be automatically translated by this header.
|
||||
*/
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Version
|
||||
***************************************/
|
||||
#define XXH_VERSION_MAJOR 0
|
||||
#define XXH_VERSION_MINOR 6
|
||||
#define XXH_VERSION_RELEASE 2
|
||||
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||
|
||||
|
||||
/* ****************************
|
||||
* Simple Hash Functions
|
||||
******************************/
|
||||
typedef unsigned int XXH32_hash_t;
|
||||
typedef unsigned long long XXH64_hash_t;
|
||||
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);
|
||||
|
||||
/*!
|
||||
XXH32() :
|
||||
Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
|
||||
The memory between input & input+length must be valid (allocated and read-accessible).
|
||||
"seed" can be used to alter the result predictably.
|
||||
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||
XXH64() :
|
||||
Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
|
||||
"seed" can be used to alter the result predictably.
|
||||
This function runs 2x faster on 64-bits systems, but slower on 32-bits systems (see benchmark).
|
||||
*/
|
||||
|
||||
|
||||
/* ****************************
|
||||
* Streaming Hash Functions
|
||||
******************************/
|
||||
typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */
|
||||
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
|
||||
|
||||
|
||||
/* hash streaming */
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
|
||||
|
||||
/*
|
||||
These functions generate the xxHash of an input provided in multiple segments.
|
||||
Note that, for small input, they are slower than single-call functions, due to state management.
|
||||
For small input, prefer `XXH32()` and `XXH64()` .
|
||||
|
||||
XXH state must first be allocated, using XXH*_createState() .
|
||||
|
||||
Start a new hash by initializing state with a seed, using XXH*_reset().
|
||||
|
||||
Then, feed the hash state by calling XXH*_update() as many times as necessary.
|
||||
Obviously, input must be allocated and read accessible.
|
||||
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
||||
|
||||
Finally, a hash value can be produced anytime, by using XXH*_digest().
|
||||
This function returns the nn-bits hash as an int or long long.
|
||||
|
||||
It's still possible to continue inserting input into the hash state after a digest,
|
||||
and generate some new hashes later on, by calling again XXH*_digest().
|
||||
|
||||
When done, free XXH state space if it was allocated dynamically.
|
||||
*/
|
||||
|
||||
|
||||
/* **************************
|
||||
* Utils
|
||||
****************************/
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
|
||||
|
||||
|
||||
/* **************************
|
||||
* Canonical representation
|
||||
****************************/
|
||||
/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.
|
||||
* The canonical representation uses human-readable write convention, aka big-endian (large digits first).
|
||||
* These functions allow transformation of hash result into and from its canonical format.
|
||||
* This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.
|
||||
*/
|
||||
typedef struct { unsigned char digest[4]; } XXH32_canonical_t;
|
||||
typedef struct { unsigned char digest[8]; } XXH64_canonical_t;
|
||||
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
|
||||
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
|
||||
|
||||
|
||||
/* ================================================================================================
|
||||
This section contains definitions which are not guaranteed to remain stable.
|
||||
They may change in future versions, becoming incompatible with a different version of the library.
|
||||
They shall only be used with static linking.
|
||||
Never use these definitions in association with dynamic linking !
|
||||
=================================================================================================== */
|
||||
/* These definitions are only meant to allow allocation of XXH state
|
||||
statically, on stack, or in a struct for example.
|
||||
Do not use members directly. */
|
||||
|
||||
struct XXH32_state_s {
|
||||
unsigned total_len_32;
|
||||
unsigned large_len;
|
||||
unsigned v1;
|
||||
unsigned v2;
|
||||
unsigned v3;
|
||||
unsigned v4;
|
||||
unsigned mem32[4]; /* buffer defined as U32 for alignment */
|
||||
unsigned memsize;
|
||||
unsigned reserved; /* never read nor write, will be removed in a future version */
|
||||
}; /* typedef'd to XXH32_state_t */
|
||||
|
||||
struct XXH64_state_s {
|
||||
unsigned long long total_len;
|
||||
unsigned long long v1;
|
||||
unsigned long long v2;
|
||||
unsigned long long v3;
|
||||
unsigned long long v4;
|
||||
unsigned long long mem64[4]; /* buffer defined as U64 for alignment */
|
||||
unsigned memsize;
|
||||
unsigned reserved[2]; /* never read nor write, will be removed in a future version */
|
||||
}; /* typedef'd to XXH64_state_t */
|
||||
|
||||
#endif /* XXHASH_H_5627135585666179 */
|
@ -22,10 +22,10 @@
|
||||
***************************************/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/xxhash.h>
|
||||
#include <linux/zstd.h>
|
||||
#include "mem.h"
|
||||
#include "error_private.h"
|
||||
#include "xxhash.h" /* XXH_reset, update, digest */
|
||||
|
||||
|
||||
/*-*************************************
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
IFLAGS := -isystem include/ -I ../include/ -I ../lib/zstd/ -isystem googletest/googletest/include
|
||||
IFLAGS := -isystem include/ -I ../include/ -I ../lib/zstd/ -isystem googletest/googletest/include -isystem ../../../lib/common/
|
||||
|
||||
SOURCES := $(wildcard ../lib/zstd/*.c)
|
||||
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))
|
||||
@ -15,6 +15,15 @@ CPPFLAGS += $(IFLAGS)
|
||||
UserlandTest: UserlandTest.cpp ../lib/zstd/libzstd.a
|
||||
$(CXX) $(CXXFLAGS) $(CFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
|
||||
|
||||
../lib/zstd/xxhash.o: ../lib/zstd/xxhash.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
../../../lib/common/xxhash.o: ../../../lib/common/xxhash.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
XXHashUserlandTest: XXHashUserlandTest.cpp ../lib/xxhash.o ../../../lib/common/xxhash.o
|
||||
$(CXX) $(CXXFLAGS) $(CFLAGS) $(CPPFLAGS) $^ googletest/build/googlemock/gtest/libgtest.a googletest/build/googlemock/gtest/libgtest_main.a -o $@
|
||||
|
||||
# Install googletest
|
||||
.PHONY: googletest
|
||||
googletest:
|
||||
|
166
contrib/linux-kernel/test/XXHashUserlandTest.cpp
Normal file
166
contrib/linux-kernel/test/XXHashUserlandTest.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
extern "C" {
|
||||
#include <linux/errno.h>
|
||||
#include <linux/xxhash.h>
|
||||
}
|
||||
#include <gtest/gtest.h>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#define XXH_STATIC_LINKING_ONLY
|
||||
#include <xxhash.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
const std::array<std::string, 11> kTestInputs = {
|
||||
"",
|
||||
"0",
|
||||
"01234",
|
||||
"0123456789abcde",
|
||||
"0123456789abcdef",
|
||||
"0123456789abcdef0",
|
||||
"0123456789abcdef0123",
|
||||
"0123456789abcdef0123456789abcde",
|
||||
"0123456789abcdef0123456789abcdef",
|
||||
"0123456789abcdef0123456789abcdef0",
|
||||
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
||||
};
|
||||
|
||||
bool testXXH32(const void *input, const size_t length, uint32_t seed) {
|
||||
return XXH32(input, length, seed) == xxh32(input, length, seed);
|
||||
}
|
||||
|
||||
bool testXXH64(const void *input, const size_t length, uint32_t seed) {
|
||||
return XXH64(input, length, seed) == xxh64(input, length, seed);
|
||||
}
|
||||
|
||||
class XXH32State {
|
||||
struct xxh32_state kernelState;
|
||||
XXH32_state_t state;
|
||||
|
||||
public:
|
||||
explicit XXH32State(const uint32_t seed) { reset(seed); }
|
||||
XXH32State(XXH32State const& other) noexcept {
|
||||
xxh32_copy_state(&kernelState, &other.kernelState);
|
||||
XXH32_copyState(&state, &other.state);
|
||||
}
|
||||
XXH32State& operator=(XXH32State const& other) noexcept {
|
||||
xxh32_copy_state(&kernelState, &other.kernelState);
|
||||
XXH32_copyState(&state, &other.state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset(const uint32_t seed) {
|
||||
xxh32_reset(&kernelState, seed);
|
||||
EXPECT_EQ(0, XXH32_reset(&state, seed));
|
||||
}
|
||||
|
||||
void update(const void *input, const size_t length) {
|
||||
EXPECT_EQ(0, xxh32_update(&kernelState, input, length));
|
||||
EXPECT_EQ(0, (int)XXH32_update(&state, input, length));
|
||||
}
|
||||
|
||||
bool testDigest() const {
|
||||
return xxh32_digest(&kernelState) == XXH32_digest(&state);
|
||||
}
|
||||
};
|
||||
|
||||
class XXH64State {
|
||||
struct xxh64_state kernelState;
|
||||
XXH64_state_t state;
|
||||
|
||||
public:
|
||||
explicit XXH64State(const uint64_t seed) { reset(seed); }
|
||||
XXH64State(XXH64State const& other) noexcept {
|
||||
xxh64_copy_state(&kernelState, &other.kernelState);
|
||||
XXH64_copyState(&state, &other.state);
|
||||
}
|
||||
XXH64State& operator=(XXH64State const& other) noexcept {
|
||||
xxh64_copy_state(&kernelState, &other.kernelState);
|
||||
XXH64_copyState(&state, &other.state);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset(const uint64_t seed) {
|
||||
xxh64_reset(&kernelState, seed);
|
||||
EXPECT_EQ(0, XXH64_reset(&state, seed));
|
||||
}
|
||||
|
||||
void update(const void *input, const size_t length) {
|
||||
EXPECT_EQ(0, xxh64_update(&kernelState, input, length));
|
||||
EXPECT_EQ(0, (int)XXH64_update(&state, input, length));
|
||||
}
|
||||
|
||||
bool testDigest() const {
|
||||
return xxh64_digest(&kernelState) == XXH64_digest(&state);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TEST(Simple, Null) {
|
||||
EXPECT_TRUE(testXXH32(NULL, 0, 0));
|
||||
EXPECT_TRUE(testXXH64(NULL, 0, 0));
|
||||
}
|
||||
|
||||
TEST(Stream, Null) {
|
||||
struct xxh32_state state32;
|
||||
xxh32_reset(&state32, 0);
|
||||
EXPECT_EQ(-EINVAL, xxh32_update(&state32, NULL, 0));
|
||||
|
||||
struct xxh64_state state64;
|
||||
xxh64_reset(&state64, 0);
|
||||
EXPECT_EQ(-EINVAL, xxh64_update(&state64, NULL, 0));
|
||||
}
|
||||
|
||||
TEST(Simple, TestInputs) {
|
||||
for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
|
||||
for (auto const input : kTestInputs) {
|
||||
EXPECT_TRUE(testXXH32(input.data(), input.size(), seed));
|
||||
EXPECT_TRUE(testXXH64(input.data(), input.size(), (uint64_t)seed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Stream, TestInputs) {
|
||||
for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
|
||||
for (auto const input : kTestInputs) {
|
||||
XXH32State s32(seed);
|
||||
XXH64State s64(seed);
|
||||
s32.update(input.data(), input.size());
|
||||
s64.update(input.data(), input.size());
|
||||
EXPECT_TRUE(s32.testDigest());
|
||||
EXPECT_TRUE(s64.testDigest());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Stream, MultipleTestInputs) {
|
||||
for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
|
||||
XXH32State s32(seed);
|
||||
XXH64State s64(seed);
|
||||
for (auto const input : kTestInputs) {
|
||||
s32.update(input.data(), input.size());
|
||||
s64.update(input.data(), input.size());
|
||||
}
|
||||
EXPECT_TRUE(s32.testDigest());
|
||||
EXPECT_TRUE(s64.testDigest());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Stream, CopyState) {
|
||||
for (uint32_t seed = 0; seed < 100000; seed = (seed + 1) * 3) {
|
||||
XXH32State s32(seed);
|
||||
XXH64State s64(seed);
|
||||
for (auto const input : kTestInputs) {
|
||||
auto t32(s32);
|
||||
t32.update(input.data(), input.size());
|
||||
s32 = t32;
|
||||
auto t64(s64);
|
||||
t64.update(input.data(), input.size());
|
||||
s64 = t64;
|
||||
}
|
||||
EXPECT_TRUE(s32.testDigest());
|
||||
EXPECT_TRUE(s64.testDigest());
|
||||
}
|
||||
}
|
6
contrib/linux-kernel/test/include/linux/errno.h
Normal file
6
contrib/linux-kernel/test/include/linux/errno.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef LINUX_ERRNO_H_
|
||||
#define LINUX_ERRNO_H_
|
||||
|
||||
#define EINVAL 22
|
||||
|
||||
#endif // LINUX_ERRNO_H_
|
762
contrib/linux-kernel/xxhash.diff
Normal file
762
contrib/linux-kernel/xxhash.diff
Normal file
@ -0,0 +1,762 @@
|
||||
diff --git a/include/linux/xxhash.h b/include/linux/xxhash.h
|
||||
new file mode 100644
|
||||
index 0000000..c77b12b
|
||||
--- /dev/null
|
||||
+++ b/include/linux/xxhash.h
|
||||
@@ -0,0 +1,230 @@
|
||||
+/*
|
||||
+ * xxHash - Extremely Fast Hash algorithm
|
||||
+ * Copyright (C) 2012-2016, Yann Collet.
|
||||
+ *
|
||||
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are
|
||||
+ * met:
|
||||
+ *
|
||||
+ * * Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * * Redistributions in binary form must reproduce the above
|
||||
+ * copyright notice, this list of conditions and the following disclaimer
|
||||
+ * in the documentation and/or other materials provided with the
|
||||
+ * distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+ *
|
||||
+ * You can contact the author at:
|
||||
+ * - xxHash homepage: http://cyan4973.github.io/xxHash/
|
||||
+ * - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * Notice extracted from xxHash homepage:
|
||||
+ *
|
||||
+ * xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
+ * It also successfully passes all tests from the SMHasher suite.
|
||||
+ *
|
||||
+ * Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2
|
||||
+ * Duo @3GHz)
|
||||
+ *
|
||||
+ * Name Speed Q.Score Author
|
||||
+ * xxHash 5.4 GB/s 10
|
||||
+ * CrapWow 3.2 GB/s 2 Andrew
|
||||
+ * MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
+ * SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
+ * SBox 1.4 GB/s 9 Bret Mulvey
|
||||
+ * Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
+ * SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
+ * CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
+ * FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
+ * CRC32 0.43 GB/s 9
|
||||
+ * MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
+ * SHA1-32 0.28 GB/s 10
|
||||
+ *
|
||||
+ * Q.Score is a measure of quality of the hash function.
|
||||
+ * It depends on successfully passing SMHasher test set.
|
||||
+ * 10 is a perfect score.
|
||||
+ *
|
||||
+ * A 64-bits version, named xxh64 offers much better speed,
|
||||
+ * but for 64-bits applications only.
|
||||
+ * Name Speed on 64 bits Speed on 32 bits
|
||||
+ * xxh64 13.8 GB/s 1.9 GB/s
|
||||
+ * xxh32 6.8 GB/s 6.0 GB/s
|
||||
+ */
|
||||
+
|
||||
+#ifndef XXHASH_H
|
||||
+#define XXHASH_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+/*-****************************
|
||||
+ * Simple Hash Functions
|
||||
+ *****************************/
|
||||
+
|
||||
+/**
|
||||
+ * xxh32() - calculate the 32-bit hash of the input with a given seed.
|
||||
+ *
|
||||
+ * @input: The data to hash.
|
||||
+ * @length: The length of the data to hash.
|
||||
+ * @seed: The seed can be used to alter the result predictably.
|
||||
+ *
|
||||
+ * Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||
+ *
|
||||
+ * Return: The 32-bit hash of the data.
|
||||
+ */
|
||||
+uint32_t xxh32(const void *input, size_t length, uint32_t seed);
|
||||
+
|
||||
+/**
|
||||
+ * xxh64() - calculate the 64-bit hash of the input with a given seed.
|
||||
+ *
|
||||
+ * @input: The data to hash.
|
||||
+ * @length: The length of the data to hash.
|
||||
+ * @seed: The seed can be used to alter the result predictably.
|
||||
+ *
|
||||
+ * This function runs 2x faster on 64-bit systems, but slower on 32-bit systems.
|
||||
+ *
|
||||
+ * Return: The 64-bit hash of the data.
|
||||
+ */
|
||||
+uint64_t xxh64(const void *input, size_t length, uint64_t seed);
|
||||
+
|
||||
+/*-****************************
|
||||
+ * Streaming Hash Functions
|
||||
+ *****************************/
|
||||
+
|
||||
+/*
|
||||
+ * These definitions are only meant to allow allocation of XXH state
|
||||
+ * statically, on stack, or in a struct for example.
|
||||
+ * Do not use members directly.
|
||||
+ */
|
||||
+
|
||||
+/**
|
||||
+ * struct xxh32_state - private xxh32 state, do not use members directly
|
||||
+ */
|
||||
+struct xxh32_state {
|
||||
+ uint32_t total_len_32;
|
||||
+ uint32_t large_len;
|
||||
+ uint32_t v1;
|
||||
+ uint32_t v2;
|
||||
+ uint32_t v3;
|
||||
+ uint32_t v4;
|
||||
+ uint32_t mem32[4];
|
||||
+ uint32_t memsize;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct xxh32_state - private xxh64 state, do not use members directly
|
||||
+ */
|
||||
+struct xxh64_state {
|
||||
+ uint64_t total_len;
|
||||
+ uint64_t v1;
|
||||
+ uint64_t v2;
|
||||
+ uint64_t v3;
|
||||
+ uint64_t v4;
|
||||
+ uint64_t mem64[4];
|
||||
+ uint32_t memsize;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * xxh32_reset() - reset the xxh32 state to start a new hashing operation
|
||||
+ *
|
||||
+ * @state: The xxh32 state to reset.
|
||||
+ * @seed: Initialize the hash state with this seed.
|
||||
+ *
|
||||
+ * Call this function on any xxh32_state to prepare for a new hashing operation.
|
||||
+ */
|
||||
+void xxh32_reset(struct xxh32_state *state, uint32_t seed);
|
||||
+
|
||||
+/**
|
||||
+ * xxh32_update() - hash the data given and update the xxh32 state
|
||||
+ *
|
||||
+ * @state: The xxh32 state to update.
|
||||
+ * @input: The data to hash.
|
||||
+ * @length: The length of the data to hash.
|
||||
+ *
|
||||
+ * After calling xxh32_reset() call xxh32_update() as many times as necessary.
|
||||
+ *
|
||||
+ * Return: Zero on success, otherwise an error code.
|
||||
+ */
|
||||
+int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
|
||||
+
|
||||
+/**
|
||||
+ * xxh32_digest() - produce the current xxh32 hash
|
||||
+ *
|
||||
+ * @state: Produce the current xxh32 hash of this state.
|
||||
+ *
|
||||
+ * A hash value can be produced at any time. It is still possible to continue
|
||||
+ * inserting input into the hash state after a call to xxh32_digest(), and
|
||||
+ * generate new hashes later on, by calling xxh32_digest() again.
|
||||
+ *
|
||||
+ * Return: The xxh32 hash stored in the state.
|
||||
+ */
|
||||
+uint32_t xxh32_digest(const struct xxh32_state *state);
|
||||
+
|
||||
+/**
|
||||
+ * xxh64_reset() - reset the xxh64 state to start a new hashing operation
|
||||
+ *
|
||||
+ * @state: The xxh64 state to reset.
|
||||
+ * @seed: Initialize the hash state with this seed.
|
||||
+ */
|
||||
+void xxh64_reset(struct xxh64_state *state, uint64_t seed);
|
||||
+
|
||||
+/**
|
||||
+ * xxh64_update() - hash the data given and update the xxh64 state
|
||||
+ * @state: The xxh64 state to update.
|
||||
+ * @input: The data to hash.
|
||||
+ * @length: The length of the data to hash.
|
||||
+ *
|
||||
+ * After calling xxh64_reset() call xxh64_update() as many times as necessary.
|
||||
+ *
|
||||
+ * Return: Zero on success, otherwise an error code.
|
||||
+ */
|
||||
+int xxh64_update(struct xxh64_state *state, const void *input, size_t length);
|
||||
+
|
||||
+/**
|
||||
+ * xxh64_digest() - produce the current xxh64 hash
|
||||
+ *
|
||||
+ * @state: Produce the current xxh64 hash of this state.
|
||||
+ *
|
||||
+ * A hash value can be produced at any time. It is still possible to continue
|
||||
+ * inserting input into the hash state after a call to xxh64_digest(), and
|
||||
+ * generate new hashes later on, by calling xxh64_digest() again.
|
||||
+ *
|
||||
+ * Return: The xxh64 hash stored in the state.
|
||||
+ */
|
||||
+uint64_t xxh64_digest(const struct xxh64_state *state);
|
||||
+
|
||||
+/*-**************************
|
||||
+ * Utils
|
||||
+ ***************************/
|
||||
+
|
||||
+/**
|
||||
+ * xxh32_copy_state() - copy the source state into the destination state
|
||||
+ *
|
||||
+ * @src: The source xxh32 state.
|
||||
+ * @dst: The destination xxh32 state.
|
||||
+ */
|
||||
+void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src);
|
||||
+
|
||||
+/**
|
||||
+ * xxh64_copy_state() - copy the source state into the destination state
|
||||
+ *
|
||||
+ * @src: The source xxh64 state.
|
||||
+ * @dst: The destination xxh64 state.
|
||||
+ */
|
||||
+void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src);
|
||||
+
|
||||
+#endif /* XXHASH_H */
|
||||
diff --git a/lib/Kconfig b/lib/Kconfig
|
||||
index 0c8b78a..b6009d7 100644
|
||||
--- a/lib/Kconfig
|
||||
+++ b/lib/Kconfig
|
||||
@@ -184,6 +184,9 @@ config CRC8
|
||||
when they need to do cyclic redundancy check according CRC8
|
||||
algorithm. Module will be called crc8.
|
||||
|
||||
+config XXHASH
|
||||
+ tristate
|
||||
+
|
||||
config AUDIT_GENERIC
|
||||
bool
|
||||
depends on AUDIT && !AUDIT_ARCH
|
||||
diff --git a/lib/Makefile b/lib/Makefile
|
||||
index 320ac46..e16f94a 100644
|
||||
--- a/lib/Makefile
|
||||
+++ b/lib/Makefile
|
||||
@@ -101,6 +101,7 @@ obj-$(CONFIG_CRC32_SELFTEST) += crc32test.o
|
||||
obj-$(CONFIG_CRC7) += crc7.o
|
||||
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
|
||||
obj-$(CONFIG_CRC8) += crc8.o
|
||||
+obj-$(CONFIG_XXHASH) += xxhash.o
|
||||
obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
|
||||
|
||||
obj-$(CONFIG_842_COMPRESS) += 842/
|
||||
diff --git a/lib/xxhash.c b/lib/xxhash.c
|
||||
new file mode 100644
|
||||
index 0000000..f367222
|
||||
--- /dev/null
|
||||
+++ b/lib/xxhash.c
|
||||
@@ -0,0 +1,494 @@
|
||||
+/*
|
||||
+ * xxHash - Extremely Fast Hash algorithm
|
||||
+ * Copyright (C) 2012-2016, Yann Collet.
|
||||
+ *
|
||||
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are
|
||||
+ * met:
|
||||
+ *
|
||||
+ * * Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * * Redistributions in binary form must reproduce the above
|
||||
+ * copyright notice, this list of conditions and the following disclaimer
|
||||
+ * in the documentation and/or other materials provided with the
|
||||
+ * distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+ *
|
||||
+ * You can contact the author at:
|
||||
+ * - xxHash homepage: http://cyan4973.github.io/xxHash/
|
||||
+ * - xxHash source repository: https://github.com/Cyan4973/xxHash
|
||||
+ */
|
||||
+
|
||||
+#include <asm/unaligned.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/compiler.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/string.h>
|
||||
+#include <linux/xxhash.h>
|
||||
+
|
||||
+/*-*************************************
|
||||
+ * Macros
|
||||
+ **************************************/
|
||||
+#define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
|
||||
+#define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
|
||||
+
|
||||
+#ifdef __LITTLE_ENDIAN
|
||||
+# define XXH_CPU_LITTLE_ENDIAN 1
|
||||
+#else
|
||||
+# define XXH_CPU_LITTLE_ENDIAN 0
|
||||
+#endif
|
||||
+
|
||||
+/*-*************************************
|
||||
+ * Constants
|
||||
+ **************************************/
|
||||
+static const uint32_t PRIME32_1 = 2654435761U;
|
||||
+static const uint32_t PRIME32_2 = 2246822519U;
|
||||
+static const uint32_t PRIME32_3 = 3266489917U;
|
||||
+static const uint32_t PRIME32_4 = 668265263U;
|
||||
+static const uint32_t PRIME32_5 = 374761393U;
|
||||
+
|
||||
+static const uint64_t PRIME64_1 = 11400714785074694791ULL;
|
||||
+static const uint64_t PRIME64_2 = 14029467366897019727ULL;
|
||||
+static const uint64_t PRIME64_3 = 1609587929392839161ULL;
|
||||
+static const uint64_t PRIME64_4 = 9650029242287828579ULL;
|
||||
+static const uint64_t PRIME64_5 = 2870177450012600261ULL;
|
||||
+
|
||||
+/*-**************************
|
||||
+ * Utils
|
||||
+ ***************************/
|
||||
+void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
|
||||
+{
|
||||
+ memcpy(dst, src, sizeof(*dst));
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh32_copy_state);
|
||||
+
|
||||
+void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
|
||||
+{
|
||||
+ memcpy(dst, src, sizeof(*dst));
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh64_copy_state);
|
||||
+
|
||||
+/*-***************************
|
||||
+ * Simple Hash Functions
|
||||
+ ****************************/
|
||||
+static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
|
||||
+{
|
||||
+ seed += input * PRIME32_2;
|
||||
+ seed = xxh_rotl32(seed, 13);
|
||||
+ seed *= PRIME32_1;
|
||||
+ return seed;
|
||||
+}
|
||||
+
|
||||
+uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
|
||||
+{
|
||||
+ const uint8_t *p = (const uint8_t *)input;
|
||||
+ const uint8_t *b_end = p + len;
|
||||
+ uint32_t h32;
|
||||
+
|
||||
+ if (len >= 16) {
|
||||
+ const uint8_t *const limit = b_end - 16;
|
||||
+ uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
+ uint32_t v2 = seed + PRIME32_2;
|
||||
+ uint32_t v3 = seed + 0;
|
||||
+ uint32_t v4 = seed - PRIME32_1;
|
||||
+
|
||||
+ do {
|
||||
+ v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ } while (p <= limit);
|
||||
+
|
||||
+ h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
|
||||
+ xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
|
||||
+ } else {
|
||||
+ h32 = seed + PRIME32_5;
|
||||
+ }
|
||||
+
|
||||
+ h32 += (uint32_t)len;
|
||||
+
|
||||
+ while (p + 4 <= b_end) {
|
||||
+ h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
+ h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
+ p += 4;
|
||||
+ }
|
||||
+
|
||||
+ while (p < b_end) {
|
||||
+ h32 += (*p) * PRIME32_5;
|
||||
+ h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
+ h32 ^= h32 >> 15;
|
||||
+ h32 *= PRIME32_2;
|
||||
+ h32 ^= h32 >> 13;
|
||||
+ h32 *= PRIME32_3;
|
||||
+ h32 ^= h32 >> 16;
|
||||
+
|
||||
+ return h32;
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh32);
|
||||
+
|
||||
+static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
|
||||
+{
|
||||
+ acc += input * PRIME64_2;
|
||||
+ acc = xxh_rotl64(acc, 31);
|
||||
+ acc *= PRIME64_1;
|
||||
+ return acc;
|
||||
+}
|
||||
+
|
||||
+static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
|
||||
+{
|
||||
+ val = xxh64_round(0, val);
|
||||
+ acc ^= val;
|
||||
+ acc = acc * PRIME64_1 + PRIME64_4;
|
||||
+ return acc;
|
||||
+}
|
||||
+
|
||||
+uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
|
||||
+{
|
||||
+ const uint8_t *p = (const uint8_t *)input;
|
||||
+ const uint8_t *const b_end = p + len;
|
||||
+ uint64_t h64;
|
||||
+
|
||||
+ if (len >= 32) {
|
||||
+ const uint8_t *const limit = b_end - 32;
|
||||
+ uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
+ uint64_t v2 = seed + PRIME64_2;
|
||||
+ uint64_t v3 = seed + 0;
|
||||
+ uint64_t v4 = seed - PRIME64_1;
|
||||
+
|
||||
+ do {
|
||||
+ v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ } while (p <= limit);
|
||||
+
|
||||
+ h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
+ xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
+ h64 = xxh64_merge_round(h64, v1);
|
||||
+ h64 = xxh64_merge_round(h64, v2);
|
||||
+ h64 = xxh64_merge_round(h64, v3);
|
||||
+ h64 = xxh64_merge_round(h64, v4);
|
||||
+
|
||||
+ } else {
|
||||
+ h64 = seed + PRIME64_5;
|
||||
+ }
|
||||
+
|
||||
+ h64 += (uint64_t)len;
|
||||
+
|
||||
+ while (p + 8 <= b_end) {
|
||||
+ const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
+
|
||||
+ h64 ^= k1;
|
||||
+ h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
+ p += 8;
|
||||
+ }
|
||||
+
|
||||
+ if (p + 4 <= b_end) {
|
||||
+ h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
+ h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
+ p += 4;
|
||||
+ }
|
||||
+
|
||||
+ while (p < b_end) {
|
||||
+ h64 ^= (*p) * PRIME64_5;
|
||||
+ h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
+ h64 ^= h64 >> 33;
|
||||
+ h64 *= PRIME64_2;
|
||||
+ h64 ^= h64 >> 29;
|
||||
+ h64 *= PRIME64_3;
|
||||
+ h64 ^= h64 >> 32;
|
||||
+
|
||||
+ return h64;
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh64);
|
||||
+
|
||||
+/*-**************************************************
|
||||
+ * Advanced Hash Functions
|
||||
+ ***************************************************/
|
||||
+void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
|
||||
+{
|
||||
+ /* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
+ struct xxh32_state state;
|
||||
+
|
||||
+ memset(&state, 0, sizeof(state));
|
||||
+ state.v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
+ state.v2 = seed + PRIME32_2;
|
||||
+ state.v3 = seed + 0;
|
||||
+ state.v4 = seed - PRIME32_1;
|
||||
+ memcpy(statePtr, &state, sizeof(state));
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh32_reset);
|
||||
+
|
||||
+void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
|
||||
+{
|
||||
+ /* use a local state for memcpy() to avoid strict-aliasing warnings */
|
||||
+ struct xxh64_state state;
|
||||
+
|
||||
+ memset(&state, 0, sizeof(state));
|
||||
+ state.v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
+ state.v2 = seed + PRIME64_2;
|
||||
+ state.v3 = seed + 0;
|
||||
+ state.v4 = seed - PRIME64_1;
|
||||
+ memcpy(statePtr, &state, sizeof(state));
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh64_reset);
|
||||
+
|
||||
+int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
|
||||
+{
|
||||
+ const uint8_t *p = (const uint8_t *)input;
|
||||
+ const uint8_t *const b_end = p + len;
|
||||
+
|
||||
+ if (input == NULL)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ state->total_len_32 += (uint32_t)len;
|
||||
+ state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
|
||||
+
|
||||
+ if (state->memsize + len < 16) { /* fill in tmp buffer */
|
||||
+ memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
|
||||
+ state->memsize += (uint32_t)len;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (state->memsize) { /* some data left from previous update */
|
||||
+ const uint32_t *p32 = state->mem32;
|
||||
+
|
||||
+ memcpy((uint8_t *)(state->mem32) + state->memsize, input,
|
||||
+ 16 - state->memsize);
|
||||
+
|
||||
+ state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
|
||||
+ p32++;
|
||||
+ state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
|
||||
+ p32++;
|
||||
+ state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
|
||||
+ p32++;
|
||||
+ state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
|
||||
+ p32++;
|
||||
+
|
||||
+ p += 16-state->memsize;
|
||||
+ state->memsize = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (p <= b_end - 16) {
|
||||
+ const uint8_t *const limit = b_end - 16;
|
||||
+ uint32_t v1 = state->v1;
|
||||
+ uint32_t v2 = state->v2;
|
||||
+ uint32_t v3 = state->v3;
|
||||
+ uint32_t v4 = state->v4;
|
||||
+
|
||||
+ do {
|
||||
+ v1 = xxh32_round(v1, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ v2 = xxh32_round(v2, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ v3 = xxh32_round(v3, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ v4 = xxh32_round(v4, get_unaligned_le32(p));
|
||||
+ p += 4;
|
||||
+ } while (p <= limit);
|
||||
+
|
||||
+ state->v1 = v1;
|
||||
+ state->v2 = v2;
|
||||
+ state->v3 = v3;
|
||||
+ state->v4 = v4;
|
||||
+ }
|
||||
+
|
||||
+ if (p < b_end) {
|
||||
+ memcpy(state->mem32, p, (size_t)(b_end-p));
|
||||
+ state->memsize = (uint32_t)(b_end-p);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh32_update);
|
||||
+
|
||||
+uint32_t xxh32_digest(const struct xxh32_state *state)
|
||||
+{
|
||||
+ const uint8_t *p = (const uint8_t *)state->mem32;
|
||||
+ const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
|
||||
+ state->memsize;
|
||||
+ uint32_t h32;
|
||||
+
|
||||
+ if (state->large_len) {
|
||||
+ h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
|
||||
+ xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
|
||||
+ } else {
|
||||
+ h32 = state->v3 /* == seed */ + PRIME32_5;
|
||||
+ }
|
||||
+
|
||||
+ h32 += state->total_len_32;
|
||||
+
|
||||
+ while (p + 4 <= b_end) {
|
||||
+ h32 += get_unaligned_le32(p) * PRIME32_3;
|
||||
+ h32 = xxh_rotl32(h32, 17) * PRIME32_4;
|
||||
+ p += 4;
|
||||
+ }
|
||||
+
|
||||
+ while (p < b_end) {
|
||||
+ h32 += (*p) * PRIME32_5;
|
||||
+ h32 = xxh_rotl32(h32, 11) * PRIME32_1;
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
+ h32 ^= h32 >> 15;
|
||||
+ h32 *= PRIME32_2;
|
||||
+ h32 ^= h32 >> 13;
|
||||
+ h32 *= PRIME32_3;
|
||||
+ h32 ^= h32 >> 16;
|
||||
+
|
||||
+ return h32;
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh32_digest);
|
||||
+
|
||||
+int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
|
||||
+{
|
||||
+ const uint8_t *p = (const uint8_t *)input;
|
||||
+ const uint8_t *const b_end = p + len;
|
||||
+
|
||||
+ if (input == NULL)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ state->total_len += len;
|
||||
+
|
||||
+ if (state->memsize + len < 32) { /* fill in tmp buffer */
|
||||
+ memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
|
||||
+ state->memsize += (uint32_t)len;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (state->memsize) { /* tmp buffer is full */
|
||||
+ const uint64_t *p64 = state->mem64;
|
||||
+
|
||||
+ memcpy(((uint8_t *)p64) + state->memsize, input,
|
||||
+ 32 - state->memsize);
|
||||
+
|
||||
+ state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
|
||||
+ p64++;
|
||||
+ state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
|
||||
+ p64++;
|
||||
+ state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
|
||||
+ p64++;
|
||||
+ state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
|
||||
+
|
||||
+ p += 32 - state->memsize;
|
||||
+ state->memsize = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (p + 32 <= b_end) {
|
||||
+ const uint8_t *const limit = b_end - 32;
|
||||
+ uint64_t v1 = state->v1;
|
||||
+ uint64_t v2 = state->v2;
|
||||
+ uint64_t v3 = state->v3;
|
||||
+ uint64_t v4 = state->v4;
|
||||
+
|
||||
+ do {
|
||||
+ v1 = xxh64_round(v1, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ v2 = xxh64_round(v2, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ v3 = xxh64_round(v3, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ v4 = xxh64_round(v4, get_unaligned_le64(p));
|
||||
+ p += 8;
|
||||
+ } while (p <= limit);
|
||||
+
|
||||
+ state->v1 = v1;
|
||||
+ state->v2 = v2;
|
||||
+ state->v3 = v3;
|
||||
+ state->v4 = v4;
|
||||
+ }
|
||||
+
|
||||
+ if (p < b_end) {
|
||||
+ memcpy(state->mem64, p, (size_t)(b_end-p));
|
||||
+ state->memsize = (uint32_t)(b_end - p);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh64_update);
|
||||
+
|
||||
+uint64_t xxh64_digest(const struct xxh64_state *state)
|
||||
+{
|
||||
+ const uint8_t *p = (const uint8_t *)state->mem64;
|
||||
+ const uint8_t *const b_end = (const uint8_t *)state->mem64 +
|
||||
+ state->memsize;
|
||||
+ uint64_t h64;
|
||||
+
|
||||
+ if (state->total_len >= 32) {
|
||||
+ const uint64_t v1 = state->v1;
|
||||
+ const uint64_t v2 = state->v2;
|
||||
+ const uint64_t v3 = state->v3;
|
||||
+ const uint64_t v4 = state->v4;
|
||||
+
|
||||
+ h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
|
||||
+ xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
|
||||
+ h64 = xxh64_merge_round(h64, v1);
|
||||
+ h64 = xxh64_merge_round(h64, v2);
|
||||
+ h64 = xxh64_merge_round(h64, v3);
|
||||
+ h64 = xxh64_merge_round(h64, v4);
|
||||
+ } else {
|
||||
+ h64 = state->v3 + PRIME64_5;
|
||||
+ }
|
||||
+
|
||||
+ h64 += (uint64_t)state->total_len;
|
||||
+
|
||||
+ while (p + 8 <= b_end) {
|
||||
+ const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
|
||||
+
|
||||
+ h64 ^= k1;
|
||||
+ h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
|
||||
+ p += 8;
|
||||
+ }
|
||||
+
|
||||
+ if (p + 4 <= b_end) {
|
||||
+ h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
|
||||
+ h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
+ p += 4;
|
||||
+ }
|
||||
+
|
||||
+ while (p < b_end) {
|
||||
+ h64 ^= (*p) * PRIME64_5;
|
||||
+ h64 = xxh_rotl64(h64, 11) * PRIME64_1;
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
+ h64 ^= h64 >> 33;
|
||||
+ h64 *= PRIME64_2;
|
||||
+ h64 ^= h64 >> 29;
|
||||
+ h64 *= PRIME64_3;
|
||||
+ h64 ^= h64 >> 32;
|
||||
+
|
||||
+ return h64;
|
||||
+}
|
||||
+EXPORT_SYMBOL(xxh64_digest);
|
||||
+
|
||||
+MODULE_LICENSE("Dual BSD/GPL");
|
||||
+MODULE_DESCRIPTION("xxHash");
|
12547
contrib/linux-kernel/zstd.diff
Normal file
12547
contrib/linux-kernel/zstd.diff
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user