@@ -24,7 +24,7 @@ | |||
| snowball | ? | BSD-3-Clause | NO | | | |||
| t1ha | ? | Zlib | NO | | | |||
| uthash | 1.9.8 | BSD | YES | | | |||
| xxhash | ? | BSD | NO | | | |||
| xxhash | 0.8.1 | BSD | NO | | | |||
| zstd | 1.4.5 | BSD | NO | | | |||
| google-ced | 37529e6 | Apache 2 | YES | build fixes | | |||
| kann | ? | MIT | YES | blas/lapack changes| |
@@ -1,4 +1,4 @@ | |||
SET(XXHASHSRC xxhash.c) | |||
SET(XXHASHSRC xxhash.c xxh_x86dispatch.c) | |||
ADD_LIBRARY(xxhash STATIC ${XXHASHSRC}) | |||
@@ -0,0 +1,55 @@ | |||
/* | |||
* xxHash - Extremely Fast Hash algorithm | |||
* Development source file for `xxh3` | |||
* Copyright (C) 2019-2020 Yann Collet | |||
* | |||
* BSD 2-Clause License (https://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: https://www.xxhash.com | |||
* - xxHash source repository: https://github.com/Cyan4973/xxHash | |||
*/ | |||
/* | |||
* Note: This file used to host the source code of XXH3_* variants. | |||
* during the development period. | |||
* The source code is now properly integrated within xxhash.h. | |||
* | |||
* xxh3.h is no longer useful, | |||
* but it is still provided for compatibility with source code | |||
* which used to include it directly. | |||
* | |||
* Programs are now highly discouraged to include xxh3.h. | |||
* Include `xxhash.h` instead, which is the officially supported interface. | |||
* | |||
* In the future, xxh3.h will start to generate warnings, then errors, | |||
* then it will be removed from source package and from include directory. | |||
*/ | |||
/* Simulate the same impact as including the old xxh3.h source file */ | |||
#define XXH_INLINE_ALL | |||
#include "xxhash.h" |
@@ -0,0 +1,770 @@ | |||
/* | |||
* xxHash - Extremely Fast Hash algorithm | |||
* Copyright (C) 2020 Yann Collet | |||
* | |||
* BSD 2-Clause License (https://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: https://www.xxhash.com | |||
* - xxHash source repository: https://github.com/Cyan4973/xxHash | |||
*/ | |||
/*! | |||
* @file xxh_x86dispatch.c | |||
* | |||
* Automatic dispatcher code for the @ref xxh3_family on x86-based targets. | |||
* | |||
* Optional add-on. | |||
* | |||
* **Compile this file with the default flags for your target.** Do not compile | |||
* with flags like `-mavx*`, `-march=native`, or `/arch:AVX*`, there will be | |||
* an error. See @ref XXH_X86DISPATCH_ALLOW_AVX for details. | |||
* | |||
* @defgroup dispatch x86 Dispatcher | |||
* @{ | |||
*/ | |||
#if defined (__cplusplus) | |||
extern "C" { | |||
#endif | |||
#if !(defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || defined(_M_X64)) | |||
# error "Dispatching is currently only supported on x86 and x86_64." | |||
#endif | |||
/*! | |||
* @def XXH_X86DISPATCH_ALLOW_AVX | |||
* @brief Disables the AVX sanity check. | |||
* | |||
* Don't compile xxh_x86dispatch.c with options like `-mavx*`, `-march=native`, | |||
* or `/arch:AVX*`. It is intended to be compiled for the minimum target, and | |||
* it selectively enables SSE2, AVX2, and AVX512 when it is needed. | |||
* | |||
* Using this option _globally_ allows this feature, and therefore makes it | |||
* undefined behavior to execute on any CPU without said feature. | |||
* | |||
* Even if the source code isn't directly using AVX intrinsics in a function, | |||
* the compiler can still generate AVX code from autovectorization and by | |||
* "upgrading" SSE2 intrinsics to use the VEX prefixes (a.k.a. AVX128). | |||
* | |||
* Use the same flags that you use to compile the rest of the program; this | |||
* file will safely generate SSE2, AVX2, and AVX512 without these flags. | |||
* | |||
* Define XXH_X86DISPATCH_ALLOW_AVX to ignore this check, and feel free to open | |||
* an issue if there is a target in the future where AVX is a default feature. | |||
*/ | |||
#ifdef XXH_DOXYGEN | |||
# define XXH_X86DISPATCH_ALLOW_AVX | |||
#endif | |||
#if defined(__AVX__) && !defined(XXH_X86DISPATCH_ALLOW_AVX) | |||
# error "Do not compile xxh_x86dispatch.c with AVX enabled! See the comment above." | |||
#endif | |||
#ifdef __has_include | |||
# define XXH_HAS_INCLUDE(header) __has_include(header) | |||
#else | |||
# define XXH_HAS_INCLUDE(header) 0 | |||
#endif | |||
/*! | |||
* @def XXH_DISPATCH_SCALAR | |||
* @brief Enables/dispatching the scalar code path. | |||
* | |||
* If this is defined to 0, SSE2 support is assumed. This reduces code size | |||
* when the scalar path is not needed. | |||
* | |||
* This is automatically defined to 0 when... | |||
* - SSE2 support is enabled in the compiler | |||
* - Targeting x86_64 | |||
* - Targeting Android x86 | |||
* - Targeting macOS | |||
*/ | |||
#ifndef XXH_DISPATCH_SCALAR | |||
# if defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) /* SSE2 on by default */ \ | |||
|| defined(__x86_64__) || defined(_M_X64) /* x86_64 */ \ | |||
|| defined(__ANDROID__) || defined(__APPLEv__) /* Android or macOS */ | |||
# define XXH_DISPATCH_SCALAR 0 /* disable */ | |||
# else | |||
# define XXH_DISPATCH_SCALAR 1 | |||
# endif | |||
#endif | |||
/*! | |||
* @def XXH_DISPATCH_AVX2 | |||
* @brief Enables/disables dispatching for AVX2. | |||
* | |||
* This is automatically detected if it is not defined. | |||
* - GCC 4.7 and later are known to support AVX2, but >4.9 is required for | |||
* to get the AVX2 intrinsics and typedefs without -mavx -mavx2. | |||
* - Visual Studio 2013 Update 2 and later are known to support AVX2. | |||
* - The GCC/Clang internal header `<avx2intrin.h>` is detected. While this is | |||
* not allowed to be included directly, it still appears in the builtin | |||
* include path and is detectable with `__has_include`. | |||
* | |||
* @see XXH_AVX2 | |||
*/ | |||
#ifndef XXH_DISPATCH_AVX2 | |||
# if (defined(__GNUC__) && (__GNUC__ > 4)) /* GCC 5.0+ */ \ | |||
|| (defined(_MSC_VER) && _MSC_VER >= 1900) /* VS 2015+ */ \ | |||
|| (defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 180030501) /* VS 2013 Update 2 */ \ | |||
|| XXH_HAS_INCLUDE(<avx2intrin.h>) /* GCC/Clang internal header */ | |||
# define XXH_DISPATCH_AVX2 1 /* enable dispatch towards AVX2 */ | |||
# else | |||
# define XXH_DISPATCH_AVX2 0 | |||
# endif | |||
#endif /* XXH_DISPATCH_AVX2 */ | |||
/*! | |||
* @def XXH_DISPATCH_AVX512 | |||
* @brief Enables/disables dispatching for AVX512. | |||
* | |||
* Automatically detected if one of the following conditions is met: | |||
* - GCC 4.9 and later are known to support AVX512. | |||
* - Visual Studio 2017 and later are known to support AVX2. | |||
* - The GCC/Clang internal header `<avx512fintrin.h>` is detected. While this | |||
* is not allowed to be included directly, it still appears in the builtin | |||
* include path and is detectable with `__has_include`. | |||
* | |||
* @see XXH_AVX512 | |||
*/ | |||
#ifndef XXH_DISPATCH_AVX512 | |||
# if (defined(__GNUC__) \ | |||
&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))) /* GCC 4.9+ */ \ | |||
|| (defined(_MSC_VER) && _MSC_VER >= 1910) /* VS 2017+ */ \ | |||
|| XXH_HAS_INCLUDE(<avx512fintrin.h>) /* GCC/Clang internal header */ | |||
# define XXH_DISPATCH_AVX512 1 /* enable dispatch towards AVX512 */ | |||
# else | |||
# define XXH_DISPATCH_AVX512 0 | |||
# endif | |||
#endif /* XXH_DISPATCH_AVX512 */ | |||
/*! | |||
* @def XXH_TARGET_SSE2 | |||
* @brief Allows a function to be compiled with SSE2 intrinsics. | |||
* | |||
* Uses `__attribute__((__target__("sse2")))` on GCC to allow SSE2 to be used | |||
* even with `-mno-sse2`. | |||
* | |||
* @def XXH_TARGET_AVX2 | |||
* @brief Like @ref XXH_TARGET_SSE2, but for AVX2. | |||
* | |||
* @def XXH_TARGET_AVX512 | |||
* @brief Like @ref XXH_TARGET_SSE2, but for AVX512. | |||
*/ | |||
#if defined(__GNUC__) | |||
# include <emmintrin.h> /* SSE2 */ | |||
# if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512 | |||
# include <immintrin.h> /* AVX2, AVX512F */ | |||
# endif | |||
# define XXH_TARGET_SSE2 __attribute__((__target__("sse2"))) | |||
# define XXH_TARGET_AVX2 __attribute__((__target__("avx2"))) | |||
# define XXH_TARGET_AVX512 __attribute__((__target__("avx512f"))) | |||
#elif defined(_MSC_VER) | |||
# include <intrin.h> | |||
# define XXH_TARGET_SSE2 | |||
# define XXH_TARGET_AVX2 | |||
# define XXH_TARGET_AVX512 | |||
#else | |||
# error "Dispatching is currently not supported for your compiler." | |||
#endif | |||
#ifdef XXH_DISPATCH_DEBUG | |||
/* debug logging */ | |||
# include <stdio.h> | |||
# define XXH_debugPrint(str) { fprintf(stderr, "DEBUG: xxHash dispatch: %s \n", str); fflush(NULL); } | |||
#else | |||
# define XXH_debugPrint(str) ((void)0) | |||
# undef NDEBUG /* avoid redefinition */ | |||
# define NDEBUG | |||
#endif | |||
#include <assert.h> | |||
#define XXH_INLINE_ALL | |||
#define XXH_X86DISPATCH | |||
#include "xxhash.h" | |||
/* | |||
* Support both AT&T and Intel dialects | |||
* | |||
* GCC doesn't convert AT&T syntax to Intel syntax, and will error out if | |||
* compiled with -masm=intel. Instead, it supports dialect switching with | |||
* curly braces: { AT&T syntax | Intel syntax } | |||
* | |||
* Clang's integrated assembler automatically converts AT&T syntax to Intel if | |||
* needed, making the dialect switching useless (it isn't even supported). | |||
* | |||
* Note: Comments are written in the inline assembly itself. | |||
*/ | |||
#ifdef __clang__ | |||
# define XXH_I_ATT(intel, att) att "\n\t" | |||
#else | |||
# define XXH_I_ATT(intel, att) "{" att "|" intel "}\n\t" | |||
#endif | |||
/*! | |||
* @internal | |||
* @brief Runs CPUID. | |||
* | |||
* @param eax , ecx The parameters to pass to CPUID, %eax and %ecx respectively. | |||
* @param abcd The array to store the result in, `{ eax, ebx, ecx, edx }` | |||
*/ | |||
static void XXH_cpuid(xxh_u32 eax, xxh_u32 ecx, xxh_u32* abcd) | |||
{ | |||
#if defined(_MSC_VER) | |||
__cpuidex(abcd, eax, ecx); | |||
#else | |||
xxh_u32 ebx, edx; | |||
# if defined(__i386__) && defined(__PIC__) | |||
__asm__( | |||
"# Call CPUID\n\t" | |||
"#\n\t" | |||
"# On 32-bit x86 with PIC enabled, we are not allowed to overwrite\n\t" | |||
"# EBX, so we use EDI instead.\n\t" | |||
XXH_I_ATT("mov edi, ebx", "movl %%ebx, %%edi") | |||
XXH_I_ATT("cpuid", "cpuid" ) | |||
XXH_I_ATT("xchg edi, ebx", "xchgl %%ebx, %%edi") | |||
: "=D" (ebx), | |||
# else | |||
__asm__( | |||
"# Call CPUID\n\t" | |||
XXH_I_ATT("cpuid", "cpuid") | |||
: "=b" (ebx), | |||
# endif | |||
"+a" (eax), "+c" (ecx), "=d" (edx)); | |||
abcd[0] = eax; | |||
abcd[1] = ebx; | |||
abcd[2] = ecx; | |||
abcd[3] = edx; | |||
#endif | |||
} | |||
/* | |||
* Modified version of Intel's guide | |||
* https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family | |||
*/ | |||
#if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512 | |||
/*! | |||
* @internal | |||
* @brief Runs `XGETBV`. | |||
* | |||
* While the CPU may support AVX2, the operating system might not properly save | |||
* the full YMM/ZMM registers. | |||
* | |||
* xgetbv is used for detecting this: Any compliant operating system will define | |||
* a set of flags in the xcr0 register indicating how it saves the AVX registers. | |||
* | |||
* You can manually disable this flag on Windows by running, as admin: | |||
* | |||
* bcdedit.exe /set xsavedisable 1 | |||
* | |||
* and rebooting. Run the same command with 0 to re-enable it. | |||
*/ | |||
static xxh_u64 XXH_xgetbv(void) | |||
{ | |||
#if defined(_MSC_VER) | |||
return _xgetbv(0); /* min VS2010 SP1 compiler is required */ | |||
#else | |||
xxh_u32 xcr0_lo, xcr0_hi; | |||
__asm__( | |||
"# Call XGETBV\n\t" | |||
"#\n\t" | |||
"# Older assemblers (e.g. macOS's ancient GAS version) don't support\n\t" | |||
"# the XGETBV opcode, so we encode it by hand instead.\n\t" | |||
"# See <https://github.com/asmjit/asmjit/issues/78> for details.\n\t" | |||
".byte 0x0f, 0x01, 0xd0\n\t" | |||
: "=a" (xcr0_lo), "=d" (xcr0_hi) : "c" (0)); | |||
return xcr0_lo | ((xxh_u64)xcr0_hi << 32); | |||
#endif | |||
} | |||
#endif | |||
#define XXH_SSE2_CPUID_MASK (1 << 26) | |||
#define XXH_OSXSAVE_CPUID_MASK ((1 << 26) | (1 << 27)) | |||
#define XXH_AVX2_CPUID_MASK (1 << 5) | |||
#define XXH_AVX2_XGETBV_MASK ((1 << 2) | (1 << 1)) | |||
#define XXH_AVX512F_CPUID_MASK (1 << 16) | |||
#define XXH_AVX512F_XGETBV_MASK ((7 << 5) | (1 << 2) | (1 << 1)) | |||
/*! | |||
* @internal | |||
* @brief Returns the best XXH3 implementation. | |||
* | |||
* Runs various CPUID/XGETBV tests to try and determine the best implementation. | |||
* | |||
* @ret The best @ref XXH_VECTOR implementation. | |||
* @see XXH_VECTOR_TYPES | |||
*/ | |||
static int XXH_featureTest(void) | |||
{ | |||
xxh_u32 abcd[4]; | |||
xxh_u32 max_leaves; | |||
int best = XXH_SCALAR; | |||
#if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512 | |||
xxh_u64 xgetbv_val; | |||
#endif | |||
#if defined(__GNUC__) && defined(__i386__) | |||
xxh_u32 cpuid_supported; | |||
__asm__( | |||
"# For the sake of ruthless backwards compatibility, check if CPUID\n\t" | |||
"# is supported in the EFLAGS on i386.\n\t" | |||
"# This is not necessary on x86_64 - CPUID is mandatory.\n\t" | |||
"# The ID flag (bit 21) in the EFLAGS register indicates support\n\t" | |||
"# for the CPUID instruction. If a software procedure can set and\n\t" | |||
"# clear this flag, the processor executing the procedure supports\n\t" | |||
"# the CPUID instruction.\n\t" | |||
"# <https://c9x.me/x86/html/file_module_x86_id_45.html>\n\t" | |||
"#\n\t" | |||
"# Routine is from <https://wiki.osdev.org/CPUID>.\n\t" | |||
"# Save EFLAGS\n\t" | |||
XXH_I_ATT("pushfd", "pushfl" ) | |||
"# Store EFLAGS\n\t" | |||
XXH_I_ATT("pushfd", "pushfl" ) | |||
"# Invert the ID bit in stored EFLAGS\n\t" | |||
XXH_I_ATT("xor dword ptr[esp], 0x200000", "xorl $0x200000, (%%esp)") | |||
"# Load stored EFLAGS (with ID bit inverted)\n\t" | |||
XXH_I_ATT("popfd", "popfl" ) | |||
"# Store EFLAGS again (ID bit may or not be inverted)\n\t" | |||
XXH_I_ATT("pushfd", "pushfl" ) | |||
"# eax = modified EFLAGS (ID bit may or may not be inverted)\n\t" | |||
XXH_I_ATT("pop eax", "popl %%eax" ) | |||
"# eax = whichever bits were changed\n\t" | |||
XXH_I_ATT("xor eax, dword ptr[esp]", "xorl (%%esp), %%eax" ) | |||
"# Restore original EFLAGS\n\t" | |||
XXH_I_ATT("popfd", "popfl" ) | |||
"# eax = zero if ID bit can't be changed, else non-zero\n\t" | |||
XXH_I_ATT("and eax, 0x200000", "andl $0x200000, %%eax" ) | |||
: "=a" (cpuid_supported) :: "cc"); | |||
if (XXH_unlikely(!cpuid_supported)) { | |||
XXH_debugPrint("CPUID support is not detected!"); | |||
return best; | |||
} | |||
#endif | |||
/* Check how many CPUID pages we have */ | |||
XXH_cpuid(0, 0, abcd); | |||
max_leaves = abcd[0]; | |||
/* Shouldn't happen on hardware, but happens on some QEMU configs. */ | |||
if (XXH_unlikely(max_leaves == 0)) { | |||
XXH_debugPrint("Max CPUID leaves == 0!"); | |||
return best; | |||
} | |||
/* Check for SSE2, OSXSAVE and xgetbv */ | |||
XXH_cpuid(1, 0, abcd); | |||
/* | |||
* Test for SSE2. The check is redundant on x86_64, but it doesn't hurt. | |||
*/ | |||
if (XXH_unlikely((abcd[3] & XXH_SSE2_CPUID_MASK) != XXH_SSE2_CPUID_MASK)) | |||
return best; | |||
XXH_debugPrint("SSE2 support detected."); | |||
best = XXH_SSE2; | |||
#if XXH_DISPATCH_AVX2 || XXH_DISPATCH_AVX512 | |||
/* Make sure we have enough leaves */ | |||
if (XXH_unlikely(max_leaves < 7)) | |||
return best; | |||
/* Test for OSXSAVE and XGETBV */ | |||
if ((abcd[2] & XXH_OSXSAVE_CPUID_MASK) != XXH_OSXSAVE_CPUID_MASK) | |||
return best; | |||
/* CPUID check for AVX features */ | |||
XXH_cpuid(7, 0, abcd); | |||
xgetbv_val = XXH_xgetbv(); | |||
#if XXH_DISPATCH_AVX2 | |||
/* Validate that AVX2 is supported by the CPU */ | |||
if ((abcd[1] & XXH_AVX2_CPUID_MASK) != XXH_AVX2_CPUID_MASK) | |||
return best; | |||
/* Validate that the OS supports YMM registers */ | |||
if ((xgetbv_val & XXH_AVX2_XGETBV_MASK) != XXH_AVX2_XGETBV_MASK) { | |||
XXH_debugPrint("AVX2 supported by the CPU, but not the OS."); | |||
return best; | |||
} | |||
/* AVX2 supported */ | |||
XXH_debugPrint("AVX2 support detected."); | |||
best = XXH_AVX2; | |||
#endif | |||
#if XXH_DISPATCH_AVX512 | |||
/* Check if AVX512F is supported by the CPU */ | |||
if ((abcd[1] & XXH_AVX512F_CPUID_MASK) != XXH_AVX512F_CPUID_MASK) { | |||
XXH_debugPrint("AVX512F not supported by CPU"); | |||
return best; | |||
} | |||
/* Validate that the OS supports ZMM registers */ | |||
if ((xgetbv_val & XXH_AVX512F_XGETBV_MASK) != XXH_AVX512F_XGETBV_MASK) { | |||
XXH_debugPrint("AVX512F supported by the CPU, but not the OS."); | |||
return best; | |||
} | |||
/* AVX512F supported */ | |||
XXH_debugPrint("AVX512F support detected."); | |||
best = XXH_AVX512; | |||
#endif | |||
#endif | |||
return best; | |||
} | |||
/* === Vector implementations === */ | |||
/*! | |||
* @internal | |||
* @brief Defines the various dispatch functions. | |||
* | |||
* TODO: Consolidate? | |||
* | |||
* @param suffix The suffix for the functions, e.g. sse2 or scalar | |||
* @param target XXH_TARGET_* or empty. | |||
*/ | |||
#define XXH_DEFINE_DISPATCH_FUNCS(suffix, target) \ | |||
\ | |||
/* === XXH3, default variants === */ \ | |||
\ | |||
XXH_NO_INLINE target XXH64_hash_t \ | |||
XXHL64_default_##suffix(const void* XXH_RESTRICT input, size_t len) \ | |||
{ \ | |||
return XXH3_hashLong_64b_internal( \ | |||
input, len, XXH3_kSecret, sizeof(XXH3_kSecret), \ | |||
XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix \ | |||
); \ | |||
} \ | |||
\ | |||
/* === XXH3, Seeded variants === */ \ | |||
\ | |||
XXH_NO_INLINE target XXH64_hash_t \ | |||
XXHL64_seed_##suffix(const void* XXH_RESTRICT input, size_t len, \ | |||
XXH64_hash_t seed) \ | |||
{ \ | |||
return XXH3_hashLong_64b_withSeed_internal( \ | |||
input, len, seed, XXH3_accumulate_512_##suffix, \ | |||
XXH3_scrambleAcc_##suffix, XXH3_initCustomSecret_##suffix \ | |||
); \ | |||
} \ | |||
\ | |||
/* === XXH3, Secret variants === */ \ | |||
\ | |||
XXH_NO_INLINE target XXH64_hash_t \ | |||
XXHL64_secret_##suffix(const void* XXH_RESTRICT input, size_t len, \ | |||
const void* secret, size_t secretLen) \ | |||
{ \ | |||
return XXH3_hashLong_64b_internal( \ | |||
input, len, secret, secretLen, \ | |||
XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix \ | |||
); \ | |||
} \ | |||
\ | |||
/* === XXH3 update variants === */ \ | |||
\ | |||
XXH_NO_INLINE target XXH_errorcode \ | |||
XXH3_update_##suffix(XXH3_state_t* state, const void* input, size_t len) \ | |||
{ \ | |||
return XXH3_update(state, (const xxh_u8*)input, len, \ | |||
XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix); \ | |||
} \ | |||
\ | |||
/* === XXH128 default variants === */ \ | |||
\ | |||
XXH_NO_INLINE target XXH128_hash_t \ | |||
XXHL128_default_##suffix(const void* XXH_RESTRICT input, size_t len) \ | |||
{ \ | |||
return XXH3_hashLong_128b_internal( \ | |||
input, len, XXH3_kSecret, sizeof(XXH3_kSecret), \ | |||
XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix \ | |||
); \ | |||
} \ | |||
\ | |||
/* === XXH128 Secret variants === */ \ | |||
\ | |||
XXH_NO_INLINE target XXH128_hash_t \ | |||
XXHL128_secret_##suffix(const void* XXH_RESTRICT input, size_t len, \ | |||
const void* XXH_RESTRICT secret, size_t secretLen) \ | |||
{ \ | |||
return XXH3_hashLong_128b_internal( \ | |||
input, len, (const xxh_u8*)secret, secretLen, \ | |||
XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix); \ | |||
} \ | |||
\ | |||
/* === XXH128 Seeded variants === */ \ | |||
\ | |||
XXH_NO_INLINE target XXH128_hash_t \ | |||
XXHL128_seed_##suffix(const void* XXH_RESTRICT input, size_t len, \ | |||
XXH64_hash_t seed) \ | |||
{ \ | |||
return XXH3_hashLong_128b_withSeed_internal(input, len, seed, \ | |||
XXH3_accumulate_512_##suffix, XXH3_scrambleAcc_##suffix, \ | |||
XXH3_initCustomSecret_##suffix); \ | |||
} | |||
/* End XXH_DEFINE_DISPATCH_FUNCS */ | |||
#if XXH_DISPATCH_SCALAR | |||
XXH_DEFINE_DISPATCH_FUNCS(scalar, /* nothing */) | |||
#endif | |||
XXH_DEFINE_DISPATCH_FUNCS(sse2, XXH_TARGET_SSE2) | |||
#if XXH_DISPATCH_AVX2 | |||
XXH_DEFINE_DISPATCH_FUNCS(avx2, XXH_TARGET_AVX2) | |||
#endif | |||
#if XXH_DISPATCH_AVX512 | |||
XXH_DEFINE_DISPATCH_FUNCS(avx512, XXH_TARGET_AVX512) | |||
#endif | |||
#undef XXH_DEFINE_DISPATCH_FUNCS | |||
/* ==== Dispatchers ==== */ | |||
typedef XXH64_hash_t (*XXH3_dispatchx86_hashLong64_default)(const void* XXH_RESTRICT, size_t); | |||
typedef XXH64_hash_t (*XXH3_dispatchx86_hashLong64_withSeed)(const void* XXH_RESTRICT, size_t, XXH64_hash_t); | |||
typedef XXH64_hash_t (*XXH3_dispatchx86_hashLong64_withSecret)(const void* XXH_RESTRICT, size_t, const void* XXH_RESTRICT, size_t); | |||
typedef XXH_errorcode (*XXH3_dispatchx86_update)(XXH3_state_t*, const void*, size_t); | |||
typedef struct { | |||
XXH3_dispatchx86_hashLong64_default hashLong64_default; | |||
XXH3_dispatchx86_hashLong64_withSeed hashLong64_seed; | |||
XXH3_dispatchx86_hashLong64_withSecret hashLong64_secret; | |||
XXH3_dispatchx86_update update; | |||
} XXH_dispatchFunctions_s; | |||
#define XXH_NB_DISPATCHES 4 | |||
/*! | |||
* @internal | |||
* @brief Table of dispatchers for @ref XXH3_64bits(). | |||
* | |||
* @pre The indices must match @ref XXH_VECTOR_TYPE. | |||
*/ | |||
static const XXH_dispatchFunctions_s XXH_kDispatch[XXH_NB_DISPATCHES] = { | |||
#if XXH_DISPATCH_SCALAR | |||
/* Scalar */ { XXHL64_default_scalar, XXHL64_seed_scalar, XXHL64_secret_scalar, XXH3_update_scalar }, | |||
#else | |||
/* Scalar */ { NULL, NULL, NULL, NULL }, | |||
#endif | |||
/* SSE2 */ { XXHL64_default_sse2, XXHL64_seed_sse2, XXHL64_secret_sse2, XXH3_update_sse2 }, | |||
#if XXH_DISPATCH_AVX2 | |||
/* AVX2 */ { XXHL64_default_avx2, XXHL64_seed_avx2, XXHL64_secret_avx2, XXH3_update_avx2 }, | |||
#else | |||
/* AVX2 */ { NULL, NULL, NULL, NULL }, | |||
#endif | |||
#if XXH_DISPATCH_AVX512 | |||
/* AVX512 */ { XXHL64_default_avx512, XXHL64_seed_avx512, XXHL64_secret_avx512, XXH3_update_avx512 } | |||
#else | |||
/* AVX512 */ { NULL, NULL, NULL, NULL } | |||
#endif | |||
}; | |||
/*! | |||
* @internal | |||
* @brief The selected dispatch table for @ref XXH3_64bits(). | |||
*/ | |||
static XXH_dispatchFunctions_s XXH_g_dispatch = { NULL, NULL, NULL, NULL }; | |||
typedef XXH128_hash_t (*XXH3_dispatchx86_hashLong128_default)(const void* XXH_RESTRICT, size_t); | |||
typedef XXH128_hash_t (*XXH3_dispatchx86_hashLong128_withSeed)(const void* XXH_RESTRICT, size_t, XXH64_hash_t); | |||
typedef XXH128_hash_t (*XXH3_dispatchx86_hashLong128_withSecret)(const void* XXH_RESTRICT, size_t, const void* XXH_RESTRICT, size_t); | |||
typedef struct { | |||
XXH3_dispatchx86_hashLong128_default hashLong128_default; | |||
XXH3_dispatchx86_hashLong128_withSeed hashLong128_seed; | |||
XXH3_dispatchx86_hashLong128_withSecret hashLong128_secret; | |||
XXH3_dispatchx86_update update; | |||
} XXH_dispatch128Functions_s; | |||
/*! | |||
* @internal | |||
* @brief Table of dispatchers for @ref XXH3_128bits(). | |||
* | |||
* @pre The indices must match @ref XXH_VECTOR_TYPE. | |||
*/ | |||
static const XXH_dispatch128Functions_s XXH_kDispatch128[XXH_NB_DISPATCHES] = { | |||
#if XXH_DISPATCH_SCALAR | |||
/* Scalar */ { XXHL128_default_scalar, XXHL128_seed_scalar, XXHL128_secret_scalar, XXH3_update_scalar }, | |||
#else | |||
/* Scalar */ { NULL, NULL, NULL, NULL }, | |||
#endif | |||
/* SSE2 */ { XXHL128_default_sse2, XXHL128_seed_sse2, XXHL128_secret_sse2, XXH3_update_sse2 }, | |||
#if XXH_DISPATCH_AVX2 | |||
/* AVX2 */ { XXHL128_default_avx2, XXHL128_seed_avx2, XXHL128_secret_avx2, XXH3_update_avx2 }, | |||
#else | |||
/* AVX2 */ { NULL, NULL, NULL, NULL }, | |||
#endif | |||
#if XXH_DISPATCH_AVX512 | |||
/* AVX512 */ { XXHL128_default_avx512, XXHL128_seed_avx512, XXHL128_secret_avx512, XXH3_update_avx512 } | |||
#else | |||
/* AVX512 */ { NULL, NULL, NULL, NULL } | |||
#endif | |||
}; | |||
/*! | |||
* @internal | |||
* @brief The selected dispatch table for @ref XXH3_64bits(). | |||
*/ | |||
static XXH_dispatch128Functions_s XXH_g_dispatch128 = { NULL, NULL, NULL, NULL }; | |||
/*! | |||
* @internal | |||
* @brief Runs a CPUID check and sets the correct dispatch tables. | |||
*/ | |||
static void XXH_setDispatch(void) | |||
{ | |||
int vecID = XXH_featureTest(); | |||
XXH_STATIC_ASSERT(XXH_AVX512 == XXH_NB_DISPATCHES-1); | |||
assert(XXH_SCALAR <= vecID && vecID <= XXH_AVX512); | |||
#if !XXH_DISPATCH_SCALAR | |||
assert(vecID != XXH_SCALAR); | |||
#endif | |||
#if !XXH_DISPATCH_AVX512 | |||
assert(vecID != XXH_AVX512); | |||
#endif | |||
#if !XXH_DISPATCH_AVX2 | |||
assert(vecID != XXH_AVX2); | |||
#endif | |||
XXH_g_dispatch = XXH_kDispatch[vecID]; | |||
XXH_g_dispatch128 = XXH_kDispatch128[vecID]; | |||
} | |||
/* ==== XXH3 public functions ==== */ | |||
static XXH64_hash_t | |||
XXH3_hashLong_64b_defaultSecret_selection(const void* input, size_t len, | |||
XXH64_hash_t seed64, const xxh_u8* secret, size_t secretLen) | |||
{ | |||
(void)seed64; (void)secret; (void)secretLen; | |||
if (XXH_g_dispatch.hashLong64_default == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch.hashLong64_default(input, len); | |||
} | |||
XXH64_hash_t XXH3_64bits_dispatch(const void* input, size_t len) | |||
{ | |||
return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_defaultSecret_selection); | |||
} | |||
static XXH64_hash_t | |||
XXH3_hashLong_64b_withSeed_selection(const void* input, size_t len, | |||
XXH64_hash_t seed64, const xxh_u8* secret, size_t secretLen) | |||
{ | |||
(void)secret; (void)secretLen; | |||
if (XXH_g_dispatch.hashLong64_seed == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch.hashLong64_seed(input, len, seed64); | |||
} | |||
XXH64_hash_t XXH3_64bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed) | |||
{ | |||
return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed_selection); | |||
} | |||
static XXH64_hash_t | |||
XXH3_hashLong_64b_withSecret_selection(const void* input, size_t len, | |||
XXH64_hash_t seed64, const xxh_u8* secret, size_t secretLen) | |||
{ | |||
(void)seed64; | |||
if (XXH_g_dispatch.hashLong64_secret == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch.hashLong64_secret(input, len, secret, secretLen); | |||
} | |||
XXH64_hash_t XXH3_64bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen) | |||
{ | |||
return XXH3_64bits_internal(input, len, 0, secret, secretLen, XXH3_hashLong_64b_withSecret_selection); | |||
} | |||
XXH_errorcode | |||
XXH3_64bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len) | |||
{ | |||
if (XXH_g_dispatch.update == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch.update(state, (const xxh_u8*)input, len); | |||
} | |||
/* ==== XXH128 public functions ==== */ | |||
static XXH128_hash_t | |||
XXH3_hashLong_128b_defaultSecret_selection(const void* input, size_t len, | |||
XXH64_hash_t seed64, const void* secret, size_t secretLen) | |||
{ | |||
(void)seed64; (void)secret; (void)secretLen; | |||
if (XXH_g_dispatch128.hashLong128_default == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch128.hashLong128_default(input, len); | |||
} | |||
XXH128_hash_t XXH3_128bits_dispatch(const void* input, size_t len) | |||
{ | |||
return XXH3_128bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_defaultSecret_selection); | |||
} | |||
static XXH128_hash_t | |||
XXH3_hashLong_128b_withSeed_selection(const void* input, size_t len, | |||
XXH64_hash_t seed64, const void* secret, size_t secretLen) | |||
{ | |||
(void)secret; (void)secretLen; | |||
if (XXH_g_dispatch128.hashLong128_seed == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch128.hashLong128_seed(input, len, seed64); | |||
} | |||
XXH128_hash_t XXH3_128bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed) | |||
{ | |||
return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_128b_withSeed_selection); | |||
} | |||
static XXH128_hash_t | |||
XXH3_hashLong_128b_withSecret_selection(const void* input, size_t len, | |||
XXH64_hash_t seed64, const void* secret, size_t secretLen) | |||
{ | |||
(void)seed64; | |||
if (XXH_g_dispatch128.hashLong128_secret == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch128.hashLong128_secret(input, len, secret, secretLen); | |||
} | |||
XXH128_hash_t XXH3_128bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen) | |||
{ | |||
return XXH3_128bits_internal(input, len, 0, secret, secretLen, XXH3_hashLong_128b_withSecret_selection); | |||
} | |||
XXH_errorcode | |||
XXH3_128bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len) | |||
{ | |||
if (XXH_g_dispatch128.update == NULL) XXH_setDispatch(); | |||
return XXH_g_dispatch128.update(state, (const xxh_u8*)input, len); | |||
} | |||
#if defined (__cplusplus) | |||
} | |||
#endif | |||
/*! @} */ |
@@ -0,0 +1,86 @@ | |||
/* | |||
* xxHash - XXH3 Dispatcher for x86-based targets | |||
* Copyright (C) 2020 Yann Collet | |||
* | |||
* BSD 2-Clause License (https://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: https://www.xxhash.com | |||
* - xxHash source repository: https://github.com/Cyan4973/xxHash | |||
*/ | |||
#ifndef XXH_X86DISPATCH_H_13563687684 | |||
#define XXH_X86DISPATCH_H_13563687684 | |||
#include "xxhash.h" /* XXH64_hash_t, XXH3_state_t */ | |||
#if defined (__cplusplus) | |||
extern "C" { | |||
#endif | |||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_dispatch(const void* input, size_t len); | |||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed); | |||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen); | |||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len); | |||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_dispatch(const void* input, size_t len); | |||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed_dispatch(const void* input, size_t len, XXH64_hash_t seed); | |||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret_dispatch(const void* input, size_t len, const void* secret, size_t secretLen); | |||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update_dispatch(XXH3_state_t* state, const void* input, size_t len); | |||
#if defined (__cplusplus) | |||
} | |||
#endif | |||
/* automatic replacement of XXH3 functions. | |||
* can be disabled by setting XXH_DISPATCH_DISABLE_REPLACE */ | |||
#ifndef XXH_DISPATCH_DISABLE_REPLACE | |||
# undef XXH3_64bits | |||
# define XXH3_64bits XXH3_64bits_dispatch | |||
# undef XXH3_64bits_withSeed | |||
# define XXH3_64bits_withSeed XXH3_64bits_withSeed_dispatch | |||
# undef XXH3_64bits_withSecret | |||
# define XXH3_64bits_withSecret XXH3_64bits_withSecret_dispatch | |||
# undef XXH3_64bits_update | |||
# define XXH3_64bits_update XXH3_64bits_update_dispatch | |||
# undef XXH128 | |||
# define XXH128 XXH3_128bits_withSeed_dispatch | |||
# define XXH3_128bits XXH3_128bits_dispatch | |||
# undef XXH3_128bits | |||
# define XXH3_128bits XXH3_128bits_dispatch | |||
# undef XXH3_128bits_withSeed | |||
# define XXH3_128bits_withSeed XXH3_128bits_withSeed_dispatch | |||
# undef XXH3_128bits_withSecret | |||
# define XXH3_128bits_withSecret XXH3_128bits_withSecret_dispatch | |||
# undef XXH3_128bits_update | |||
# define XXH3_128bits_update XXH3_128bits_update_dispatch | |||
#endif /* XXH_DISPATCH_DISABLE_REPLACE */ | |||
#endif /* XXH_X86DISPATCH_H_13563687684 */ |
@@ -1,941 +1,43 @@ | |||
/* | |||
xxHash - Fast Hash algorithm | |||
Copyright (C) 2012-2014, Yann Collet. | |||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) | |||
* xxHash - Extremely Fast Hash algorithm | |||
* Copyright (C) 2012-2020 Yann Collet | |||
* | |||
* BSD 2-Clause License (https://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: https://www.xxhash.com | |||
* - xxHash source repository: https://github.com/Cyan4973/xxHash | |||
*/ | |||
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 : http://code.google.com/p/xxhash/ | |||
- public discussion board : https://groups.google.com/forum/#!forum/lz4c | |||
*/ | |||
//************************************** | |||
// Tuning parameters | |||
//************************************** | |||
// Unaligned memory access is automatically enabled for "common" CPU, such as x86. | |||
// For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected. | |||
// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance. | |||
// You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32). | |||
#if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) | |||
# define XXH_USE_UNALIGNED_ACCESS 1 | |||
#endif | |||
// 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. | |||
// This option has a very small performance cost (only measurable on small inputs). | |||
// 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-independent 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-independence be of no importance for your application, you may set the #define below to 1. | |||
// It will improve speed for Big-endian CPU. | |||
// This option has no impact on Little_Endian CPU. | |||
#define XXH_FORCE_NATIVE_FORMAT 0 | |||
//************************************** | |||
// Compiler Specific Options | |||
//************************************** | |||
// Disable some Visual warning messages | |||
#ifdef _MSC_VER // Visual Studio | |||
# pragma warning(disable : 4127) // disable: C4127: conditional expression is constant | |||
#endif | |||
/* | |||
* xxhash.c instantiates functions defined in xxhash.h | |||
*/ | |||
#ifdef _MSC_VER // Visual Studio | |||
# define FORCE_INLINE static __forceinline | |||
#else | |||
# ifdef __GNUC__ | |||
# define FORCE_INLINE static inline __attribute__((always_inline)) | |||
# else | |||
# define FORCE_INLINE static inline | |||
# endif | |||
#endif | |||
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ | |||
#define XXH_IMPLEMENTATION /* access definitions */ | |||
//************************************** | |||
// Includes & Memory related functions | |||
//************************************** | |||
#include "xxhash.h" | |||
// Modify the local functions below should you wish to use some other memory routines | |||
// for malloc(), free() | |||
#include <stdlib.h> | |||
static void* XXH_malloc(size_t s) { return malloc(s); } | |||
static void XXH_free (void* p) { free(p); } | |||
// for memcpy() | |||
#include <string.h> | |||
static void* XXH_memcpy(void* dest, const void* src, size_t size) | |||
{ | |||
return memcpy(dest,src,size); | |||
} | |||
//************************************** | |||
// Basic Types | |||
//************************************** | |||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99 | |||
# include <stdint.h> | |||
typedef uint8_t BYTE; | |||
typedef uint16_t U16; | |||
typedef uint32_t U32; | |||
typedef int32_t S32; | |||
typedef uint64_t U64; | |||
#else | |||
typedef unsigned char BYTE; | |||
typedef unsigned short U16; | |||
typedef unsigned int U32; | |||
typedef signed int S32; | |||
typedef unsigned long long U64; | |||
#endif | |||
#if defined(__GNUC__) && !defined(XXH_USE_UNALIGNED_ACCESS) | |||
# define _PACKED __attribute__ ((packed)) | |||
#else | |||
# define _PACKED | |||
#endif | |||
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__) | |||
# ifdef __IBMC__ | |||
# pragma pack(1) | |||
# else | |||
# pragma pack(push, 1) | |||
# endif | |||
#endif | |||
typedef struct _U32_S | |||
{ | |||
U32 v; | |||
} _PACKED U32_S; | |||
typedef struct _U64_S | |||
{ | |||
U64 v; | |||
} _PACKED U64_S; | |||
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__) | |||
# pragma pack(pop) | |||
#endif | |||
#define A32(x) (((U32_S *)(x))->v) | |||
#define A64(x) (((U64_S *)(x))->v) | |||
//*************************************** | |||
// Compiler-specific Functions and Macros | |||
//*************************************** | |||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) | |||
// Note : although _rotl exists for minGW (GCC under windows), performance seems poor | |||
#if defined(_MSC_VER) | |||
# define XXH_rotl32(x,r) _rotl(x,r) | |||
# define XXH_rotl64(x,r) _rotl64(x,r) | |||
#else | |||
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) | |||
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) | |||
#endif | |||
#if defined(_MSC_VER) // Visual Studio | |||
# define XXH_swap32 _byteswap_ulong | |||
# define XXH_swap64 _byteswap_uint64 | |||
#elif GCC_VERSION >= 403 | |||
# define XXH_swap32 __builtin_bswap32 | |||
# define XXH_swap64 __builtin_bswap64 | |||
#else | |||
static inline U32 XXH_swap32 (U32 x) | |||
{ | |||
return ((x << 24) & 0xff000000 ) | | |||
((x << 8) & 0x00ff0000 ) | | |||
((x >> 8) & 0x0000ff00 ) | | |||
((x >> 24) & 0x000000ff ); | |||
} | |||
static inline U64 XXH_swap64 (U64 x) | |||
{ | |||
return ((x << 56) & 0xff00000000000000ULL) | | |||
((x << 40) & 0x00ff000000000000ULL) | | |||
((x << 24) & 0x0000ff0000000000ULL) | | |||
((x << 8) & 0x000000ff00000000ULL) | | |||
((x >> 8) & 0x00000000ff000000ULL) | | |||
((x >> 24) & 0x0000000000ff0000ULL) | | |||
((x >> 40) & 0x000000000000ff00ULL) | | |||
((x >> 56) & 0x00000000000000ffULL); | |||
} | |||
#endif | |||
//************************************** | |||
// Constants | |||
//************************************** | |||
#define PRIME32_1 2654435761U | |||
#define PRIME32_2 2246822519U | |||
#define PRIME32_3 3266489917U | |||
#define PRIME32_4 668265263U | |||
#define PRIME32_5 374761393U | |||
#define PRIME64_1 11400714785074694791ULL | |||
#define PRIME64_2 14029467366897019727ULL | |||
#define PRIME64_3 1609587929392839161ULL | |||
#define PRIME64_4 9650029242287828579ULL | |||
#define PRIME64_5 2870177450012600261ULL | |||
//************************************** | |||
// Architecture Macros | |||
//************************************** | |||
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; | |||
#ifndef XXH_CPU_LITTLE_ENDIAN // It is possible to define XXH_CPU_LITTLE_ENDIAN externally, for example using a compiler switch | |||
static const int one = 1; | |||
# define XXH_CPU_LITTLE_ENDIAN (*(char*)(&one)) | |||
#endif | |||
//************************************** | |||
// Macros | |||
//************************************** | |||
#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } // use only *after* variable declarations | |||
//**************************** | |||
// 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) | |||
{ | |||
if (align==XXH_unaligned) | |||
return endian==XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr)); | |||
else | |||
return endian==XXH_littleEndian ? *(U32*)ptr : XXH_swap32(*(U32*)ptr); | |||
} | |||
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) | |||
{ | |||
return XXH_readLE32_align(ptr, endian, XXH_unaligned); | |||
} | |||
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) | |||
{ | |||
if (align==XXH_unaligned) | |||
return endian==XXH_littleEndian ? A64(ptr) : XXH_swap64(A64(ptr)); | |||
else | |||
return endian==XXH_littleEndian ? *(U64*)ptr : XXH_swap64(*(U64*)ptr); | |||
} | |||
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) | |||
{ | |||
return XXH_readLE64_align(ptr, endian, XXH_unaligned); | |||
} | |||
//**************************** | |||
// Simple Hash Functions | |||
//**************************** | |||
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 += XXH_get32bits(p) * PRIME32_2; | |||
v1 = XXH_rotl32(v1, 13); | |||
v1 *= PRIME32_1; | |||
p+=4; | |||
v2 += XXH_get32bits(p) * PRIME32_2; | |||
v2 = XXH_rotl32(v2, 13); | |||
v2 *= PRIME32_1; | |||
p+=4; | |||
v3 += XXH_get32bits(p) * PRIME32_2; | |||
v3 = XXH_rotl32(v3, 13); | |||
v3 *= PRIME32_1; | |||
p+=4; | |||
v4 += XXH_get32bits(p) * PRIME32_2; | |||
v4 = XXH_rotl32(v4, 13); | |||
v4 *= PRIME32_1; | |||
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; | |||
} | |||
unsigned int XXH32 (const void* input, size_t len, unsigned seed) | |||
{ | |||
#if 0 | |||
// Simple version, good for code maintenance, but unfortunately slow for small inputs | |||
XXH32_state_t 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 !defined(XXH_USE_UNALIGNED_ACCESS) | |||
if ((((size_t)input) & 3) == 0) // Input is aligned, let's leverage the speed advantage | |||
{ | |||
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); | |||
} | |||
# endif | |||
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 | |||
} | |||
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* 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 += XXH_get64bits(p) * PRIME64_2; | |||
p+=8; | |||
v1 = XXH_rotl64(v1, 31); | |||
v1 *= PRIME64_1; | |||
v2 += XXH_get64bits(p) * PRIME64_2; | |||
p+=8; | |||
v2 = XXH_rotl64(v2, 31); | |||
v2 *= PRIME64_1; | |||
v3 += XXH_get64bits(p) * PRIME64_2; | |||
p+=8; | |||
v3 = XXH_rotl64(v3, 31); | |||
v3 *= PRIME64_1; | |||
v4 += XXH_get64bits(p) * PRIME64_2; | |||
p+=8; | |||
v4 = XXH_rotl64(v4, 31); | |||
v4 *= PRIME64_1; | |||
} | |||
while (p<=limit); | |||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); | |||
v1 *= PRIME64_2; | |||
v1 = XXH_rotl64(v1, 31); | |||
v1 *= PRIME64_1; | |||
h64 ^= v1; | |||
h64 = h64 * PRIME64_1 + PRIME64_4; | |||
v2 *= PRIME64_2; | |||
v2 = XXH_rotl64(v2, 31); | |||
v2 *= PRIME64_1; | |||
h64 ^= v2; | |||
h64 = h64 * PRIME64_1 + PRIME64_4; | |||
v3 *= PRIME64_2; | |||
v3 = XXH_rotl64(v3, 31); | |||
v3 *= PRIME64_1; | |||
h64 ^= v3; | |||
h64 = h64 * PRIME64_1 + PRIME64_4; | |||
v4 *= PRIME64_2; | |||
v4 = XXH_rotl64(v4, 31); | |||
v4 *= PRIME64_1; | |||
h64 ^= v4; | |||
h64 = h64 * PRIME64_1 + PRIME64_4; | |||
} | |||
else | |||
{ | |||
h64 = seed + PRIME64_5; | |||
} | |||
h64 += (U64) len; | |||
while (p+8<=bEnd) | |||
{ | |||
U64 k1 = XXH_get64bits(p); | |||
k1 *= PRIME64_2; | |||
k1 = XXH_rotl64(k1,31); | |||
k1 *= PRIME64_1; | |||
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; | |||
} | |||
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_state_t 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 !defined(XXH_USE_UNALIGNED_ACCESS) | |||
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); | |||
} | |||
# endif | |||
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 | |||
****************************************************/ | |||
/*** Allocation ***/ | |||
typedef struct | |||
{ | |||
U64 total_len; | |||
U32 seed; | |||
U32 v1; | |||
U32 v2; | |||
U32 v3; | |||
U32 v4; | |||
U32 mem32[4]; /* defined as U32 for alignment */ | |||
U32 memsize; | |||
} XXH_istate32_t; | |||
typedef struct | |||
{ | |||
U64 total_len; | |||
U64 seed; | |||
U64 v1; | |||
U64 v2; | |||
U64 v3; | |||
U64 v4; | |||
U64 mem64[4]; /* defined as U64 for alignment */ | |||
U32 memsize; | |||
} XXH_istate64_t; | |||
XXH32_state_t* XXH32_createState(void) | |||
{ | |||
XXH_STATIC_ASSERT(sizeof(XXH32_state_t) >= sizeof(XXH_istate32_t)); // A compilation error here means XXH32_state_t is not large enough | |||
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); | |||
} | |||
void* XXH32_init (unsigned seed) | |||
{ | |||
XXH32_state_t *st = XXH32_createState(); | |||
XXH32_reset(st, seed); | |||
return st; | |||
} | |||
XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) | |||
{ | |||
XXH_free(statePtr); | |||
return XXH_OK; | |||
} | |||
XXH64_state_t* XXH64_createState(void) | |||
{ | |||
XXH_STATIC_ASSERT(sizeof(XXH64_state_t) >= sizeof(XXH_istate64_t)); // A compilation error here means XXH64_state_t is not large enough | |||
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); | |||
} | |||
XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) | |||
{ | |||
XXH_free(statePtr); | |||
return XXH_OK; | |||
} | |||
/*** Hash feed ***/ | |||
XXH_errorcode XXH32_reset(XXH32_state_t* state_in, U32 seed) | |||
{ | |||
XXH_istate32_t* state = (XXH_istate32_t*) state_in; | |||
state->seed = seed; | |||
state->v1 = seed + PRIME32_1 + PRIME32_2; | |||
state->v2 = seed + PRIME32_2; | |||
state->v3 = seed + 0; | |||
state->v4 = seed - PRIME32_1; | |||
state->total_len = 0; | |||
state->memsize = 0; | |||
return XXH_OK; | |||
} | |||
XXH_errorcode XXH64_reset(XXH64_state_t* state_in, unsigned long long seed) | |||
{ | |||
XXH_istate64_t* state = (XXH_istate64_t*) state_in; | |||
state->seed = seed; | |||
state->v1 = seed + PRIME64_1 + PRIME64_2; | |||
state->v2 = seed + PRIME64_2; | |||
state->v3 = seed + 0; | |||
state->v4 = seed - PRIME64_1; | |||
state->total_len = 0; | |||
state->memsize = 0; | |||
return XXH_OK; | |||
} | |||
FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state_in, const void* input, size_t len, XXH_endianess endian) | |||
{ | |||
XXH_istate32_t* state = (XXH_istate32_t *) state_in; | |||
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 < 16) // fill in tmp buffer | |||
{ | |||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len); | |||
state->memsize += (U32)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 += XXH_readLE32(p32, endian) * PRIME32_2; | |||
state->v1 = XXH_rotl32(state->v1, 13); | |||
state->v1 *= PRIME32_1; | |||
p32++; | |||
state->v2 += XXH_readLE32(p32, endian) * PRIME32_2; | |||
state->v2 = XXH_rotl32(state->v2, 13); | |||
state->v2 *= PRIME32_1; | |||
p32++; | |||
state->v3 += XXH_readLE32(p32, endian) * PRIME32_2; | |||
state->v3 = XXH_rotl32(state->v3, 13); | |||
state->v3 *= PRIME32_1; | |||
p32++; | |||
state->v4 += XXH_readLE32(p32, endian) * PRIME32_2; | |||
state->v4 = XXH_rotl32(state->v4, 13); | |||
state->v4 *= PRIME32_1; | |||
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 += XXH_readLE32(p, endian) * PRIME32_2; | |||
v1 = XXH_rotl32(v1, 13); | |||
v1 *= PRIME32_1; | |||
p+=4; | |||
v2 += XXH_readLE32(p, endian) * PRIME32_2; | |||
v2 = XXH_rotl32(v2, 13); | |||
v2 *= PRIME32_1; | |||
p+=4; | |||
v3 += XXH_readLE32(p, endian) * PRIME32_2; | |||
v3 = XXH_rotl32(v3, 13); | |||
v3 *= PRIME32_1; | |||
p+=4; | |||
v4 += XXH_readLE32(p, endian) * PRIME32_2; | |||
v4 = XXH_rotl32(v4, 13); | |||
v4 *= PRIME32_1; | |||
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, bEnd-p); | |||
state->memsize = (int)(bEnd-p); | |||
} | |||
return XXH_OK; | |||
} | |||
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_in, XXH_endianess endian) | |||
{ | |||
XXH_istate32_t* state = (XXH_istate32_t*) state_in; | |||
const BYTE * p = (const BYTE*)state->mem32; | |||
BYTE* bEnd = (BYTE*)(state->mem32) + state->memsize; | |||
U32 h32; | |||
if (state->total_len >= 16) | |||
{ | |||
h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18); | |||
} | |||
else | |||
{ | |||
h32 = state->seed + PRIME32_5; | |||
} | |||
h32 += (U32) state->total_len; | |||
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; | |||
#if 0 | |||
XXH32_freeState((XXH32_state_t *)state_in); | |||
#endif | |||
return h32; | |||
} | |||
U32 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); | |||
} | |||
FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state_in, const void* input, size_t len, XXH_endianess endian) | |||
{ | |||
XXH_istate64_t * state = (XXH_istate64_t *) state_in; | |||
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) // some data left from previous update | |||
{ | |||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize); | |||
{ | |||
const U64* p64 = state->mem64; | |||
state->v1 += XXH_readLE64(p64, endian) * PRIME64_2; | |||
state->v1 = XXH_rotl64(state->v1, 31); | |||
state->v1 *= PRIME64_1; | |||
p64++; | |||
state->v2 += XXH_readLE64(p64, endian) * PRIME64_2; | |||
state->v2 = XXH_rotl64(state->v2, 31); | |||
state->v2 *= PRIME64_1; | |||
p64++; | |||
state->v3 += XXH_readLE64(p64, endian) * PRIME64_2; | |||
state->v3 = XXH_rotl64(state->v3, 31); | |||
state->v3 *= PRIME64_1; | |||
p64++; | |||
state->v4 += XXH_readLE64(p64, endian) * PRIME64_2; | |||
state->v4 = XXH_rotl64(state->v4, 31); | |||
state->v4 *= PRIME64_1; | |||
p64++; | |||
} | |||
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 += XXH_readLE64(p, endian) * PRIME64_2; | |||
v1 = XXH_rotl64(v1, 31); | |||
v1 *= PRIME64_1; | |||
p+=8; | |||
v2 += XXH_readLE64(p, endian) * PRIME64_2; | |||
v2 = XXH_rotl64(v2, 31); | |||
v2 *= PRIME64_1; | |||
p+=8; | |||
v3 += XXH_readLE64(p, endian) * PRIME64_2; | |||
v3 = XXH_rotl64(v3, 31); | |||
v3 *= PRIME64_1; | |||
p+=8; | |||
v4 += XXH_readLE64(p, endian) * PRIME64_2; | |||
v4 = XXH_rotl64(v4, 31); | |||
v4 *= PRIME64_1; | |||
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, bEnd-p); | |||
state->memsize = (int)(bEnd-p); | |||
} | |||
return XXH_OK; | |||
} | |||
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_in, XXH_endianess endian) | |||
{ | |||
XXH_istate64_t * state = (XXH_istate64_t *) state_in; | |||
const BYTE * p = (const BYTE*)state->mem64; | |||
BYTE* bEnd = (BYTE*)state->mem64 + state->memsize; | |||
U64 h64; | |||
if (state->total_len >= 32) | |||
{ | |||
U64 v1 = state->v1; | |||
U64 v2 = state->v2; | |||
U64 v3 = state->v3; | |||
U64 v4 = state->v4; | |||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); | |||
v1 *= PRIME64_2; | |||
v1 = XXH_rotl64(v1, 31); | |||
v1 *= PRIME64_1; | |||
h64 ^= v1; | |||
h64 = h64*PRIME64_1 + PRIME64_4; | |||
v2 *= PRIME64_2; | |||
v2 = XXH_rotl64(v2, 31); | |||
v2 *= PRIME64_1; | |||
h64 ^= v2; | |||
h64 = h64*PRIME64_1 + PRIME64_4; | |||
v3 *= PRIME64_2; | |||
v3 = XXH_rotl64(v3, 31); | |||
v3 *= PRIME64_1; | |||
h64 ^= v3; | |||
h64 = h64*PRIME64_1 + PRIME64_4; | |||
v4 *= PRIME64_2; | |||
v4 = XXH_rotl64(v4, 31); | |||
v4 *= PRIME64_1; | |||
h64 ^= v4; | |||
h64 = h64*PRIME64_1 + PRIME64_4; | |||
} | |||
else | |||
{ | |||
h64 = state->seed + PRIME64_5; | |||
} | |||
h64 += (U64) state->total_len; | |||
while (p+8<=bEnd) | |||
{ | |||
U64 k1 = XXH_readLE64(p, endian); | |||
k1 *= PRIME64_2; | |||
k1 = XXH_rotl64(k1,31); | |||
k1 *= PRIME64_1; | |||
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; | |||
#if 0 | |||
XXH64_freeState((XXH64_state_t *)state_in); | |||
#endif | |||
return h64; | |||
} | |||
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); | |||
} | |||
@@ -1480,8 +1480,6 @@ void rspamd_cryptobox_hash (guchar *out, | |||
G_STATIC_ASSERT (sizeof (t1ha_context_t) <= | |||
sizeof (((rspamd_cryptobox_fast_hash_state_t *)NULL)->opaque)); | |||
G_STATIC_ASSERT (sizeof (XXH64_state_t) <= | |||
sizeof (((rspamd_cryptobox_fast_hash_state_t *)NULL)->opaque)); | |||
struct RSPAMD_ALIGNED(16) _mum_iuf { |