From 2ffead76c1f31209e8da265d2e58d9e1f6cb5d12 Mon Sep 17 00:00:00 2001 From: Bronek Kozicki Date: Wed, 13 Mar 2024 21:12:22 +0000 Subject: [PATCH] Upgrade to xxhash 0.8.2 as a Conan requirement, enable SIMD hashing (#4893) We are currently using old version 0.6.2 of `xxhash`, as a verbatim copy and paste of its header file `xxhash.h`. Switch to the more recent version 0.8.2. Since this version is in Conan Center (and properly protects its ABI by keeping the state object incomplete), add it as a Conan requirement. Switch to the SIMD instructions (in the new `XXH3` family) supported by the new version. --- Builds/CMake/RippledCore.cmake | 7 +- CMakeLists.txt | 1 + conanfile.py | 3 + src/ripple/beast/hash/impl/xxhash.cpp | 1004 ------------------------- src/ripple/beast/hash/impl/xxhash.h | 170 ----- src/ripple/beast/hash/xxhasher.h | 39 +- 6 files changed, 37 insertions(+), 1187 deletions(-) delete mode 100644 src/ripple/beast/hash/impl/xxhash.cpp delete mode 100644 src/ripple/beast/hash/impl/xxhash.h diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index b9451e1cfbf..e6720c22b66 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -26,7 +26,6 @@ target_sources (xrpl_core PRIVATE src/ripple/beast/clock/basic_seconds_clock.cpp src/ripple/beast/core/CurrentThreadName.cpp src/ripple/beast/core/SemanticVersion.cpp - src/ripple/beast/hash/impl/xxhash.cpp src/ripple/beast/insight/impl/Collector.cpp src/ripple/beast/insight/impl/Groups.cpp src/ripple/beast/insight/impl/Hook.cpp @@ -153,7 +152,8 @@ target_link_libraries (xrpl_core secp256k1::secp256k1 ed25519::ed25519 date::date - Ripple::opts) + Ripple::opts + xxHash::xxhash) #[=================================[ main/core headers installation #]=================================] @@ -362,9 +362,6 @@ install ( src/ripple/beast/hash/uhash.h src/ripple/beast/hash/xxhasher.h DESTINATION include/ripple/beast/hash) -install ( - FILES src/ripple/beast/hash/impl/xxhash.h - DESTINATION include/ripple/beast/hash/impl) install ( FILES src/ripple/beast/net/IPAddress.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d324008ac40..efe0ebf31ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ endif() find_package(nudb REQUIRED) find_package(date REQUIRED) +find_package(xxHash REQUIRED) target_link_libraries(ripple_libs INTERFACE ed25519::ed25519 diff --git a/conanfile.py b/conanfile.py index d9e2a0ae7c4..d1d24a4876a 100644 --- a/conanfile.py +++ b/conanfile.py @@ -36,6 +36,7 @@ class Xrpl(ConanFile): 'soci/4.0.3', 'sqlite3/3.42.0', 'zlib/1.2.13', + 'xxhash/0.8.2', ] default_options = { @@ -86,6 +87,7 @@ class Xrpl(ConanFile): 'soci:shared': False, 'soci:with_sqlite3': True, 'soci:with_boost': True, + 'xxhash:shared': False, } def set_version(self): @@ -159,4 +161,5 @@ def package_info(self): 'openssl::crypto', 'date::date', 'grpc::grpc++', + 'xxHash::xxhash', ] diff --git a/src/ripple/beast/hash/impl/xxhash.cpp b/src/ripple/beast/hash/impl/xxhash.cpp deleted file mode 100644 index 4a6c85db815..00000000000 --- a/src/ripple/beast/hash/impl/xxhash.cpp +++ /dev/null @@ -1,1004 +0,0 @@ -/* -xxHash - Fast Hash algorithm -Copyright (C) 2012-2014, 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 : http://code.google.com/p/xxhash/ -- public discussion board : https://groups.google.com/forum/#!forum/lz4c -*/ - -#include - -#include - -//************************************** -// 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-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. 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 - -#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 - -//************************************** -// 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 -static void* -XXH_malloc(size_t s) -{ - return malloc(s); -} -static void -XXH_free(void* p) -{ - free(p); -} -// for memcpy() -#include -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 -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 - -namespace beast { -namespace detail { - -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) - { - // Use memcpy to avoid unaligned UB - U64 tmp_aligned; - std::memcpy(&tmp_aligned, ptr, sizeof(U64)); - return endian == XXH_littleEndian ? tmp_aligned - : XXH_swap64(tmp_aligned); - } - 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) -{ - 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)); -} -XXH_errorcode -XXH32_freeState(XXH32_state_t* statePtr) -{ - XXH_free(statePtr); - return XXH_OK; -}; - -XXH64_state_t* -XXH64_createState(void) -{ - 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; - - 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; - - 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); -} - -} // namespace detail -} // namespace beast diff --git a/src/ripple/beast/hash/impl/xxhash.h b/src/ripple/beast/hash/impl/xxhash.h deleted file mode 100644 index 063838a829a..00000000000 --- a/src/ripple/beast/hash/impl/xxhash.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - xxHash - Extremely Fast Hash algorithm - Header File - Copyright (C) 2012-2014, 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 : http://code.google.com/p/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. -*/ - -#ifndef BEAST_HASH_XXHASH_H_INCLUDED -#define BEAST_HASH_XXHASH_H_INCLUDED - -/***************************** - Includes -*****************************/ -#include /* size_t */ - -namespace beast { -namespace detail { - -/***************************** - Type -*****************************/ -typedef enum { XXH_OK = 0, XXH_ERROR } XXH_errorcode; - -/***************************** - Simple Hash Functions -*****************************/ - -unsigned int -XXH32(const void* input, size_t length, unsigned seed); -unsigned long long -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. This function successfully passes all SMHasher tests. 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". -*/ - -/***************************** - Advanced Hash Functions -*****************************/ -typedef struct -{ - long long ll[6]; -} XXH32_state_t; -typedef struct -{ - long long ll[11]; -} XXH64_state_t; - -/* -These structures allow static allocation of XXH states. -States must then be initialized using XXHnn_reset() before first use. - -If you prefer dynamic allocation, please refer to functions below. -*/ - -XXH32_state_t* -XXH32_createState(void); -XXH_errorcode -XXH32_freeState(XXH32_state_t* statePtr); - -XXH64_state_t* -XXH64_createState(void); -XXH_errorcode -XXH64_freeState(XXH64_state_t* statePtr); - -/* -These functions create and release memory for XXH state. -States must then be initialized using XXHnn_reset() before first use. -*/ - -XXH_errorcode -XXH32_reset(XXH32_state_t* statePtr, unsigned seed); -XXH_errorcode -XXH32_update(XXH32_state_t* statePtr, const void* input, size_t length); -unsigned int -XXH32_digest(const XXH32_state_t* statePtr); - -XXH_errorcode -XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed); -XXH_errorcode -XXH64_update(XXH64_state_t* statePtr, const void* input, size_t length); -unsigned long long -XXH64_digest(const XXH64_state_t* statePtr); - -/* -These functions calculate the xxHash of an input provided in multiple smaller -packets, as opposed to an input provided as a single block. - -XXH state space must first be allocated, using either static or dynamic method -provided above. - -Start a new hash by initializing state with a seed, using XXHnn_reset(). - -Then, feed the hash state by calling XXHnn_update() as many times as necessary. -Obviously, input must be valid, meaning allocated and read accessible. -The function returns an error code, with 0 meaning OK, and any other value -meaning there is an error. - -Finally, you can produce a hash anytime, by using XXHnn_digest(). -This function returns the final nn-bits hash. -You can nonetheless continue feeding the hash state with more input, -and therefore get some new hashes, by calling again XXHnn_digest(). - -When you are done, don't forget to free XXH state space, using typically -XXHnn_freeState(). -*/ - -} // namespace detail -} // namespace beast - -#endif diff --git a/src/ripple/beast/hash/xxhasher.h b/src/ripple/beast/hash/xxhasher.h index 512c451a051..1a6fc502321 100644 --- a/src/ripple/beast/hash/xxhasher.h +++ b/src/ripple/beast/hash/xxhasher.h @@ -20,9 +20,11 @@ #ifndef BEAST_HASH_XXHASHER_H_INCLUDED #define BEAST_HASH_XXHASHER_H_INCLUDED -#include #include +#include + #include +#include #include namespace beast { @@ -33,16 +35,35 @@ class xxhasher // requires 64-bit std::size_t static_assert(sizeof(std::size_t) == 8, ""); - detail::XXH64_state_t state_; + XXH3_state_t* state_; + + static XXH3_state_t* + allocState() + { + auto ret = XXH3_createState(); + if (ret == nullptr) + throw std::bad_alloc(); + return ret; + } public: using result_type = std::size_t; static constexpr auto const endian = boost::endian::order::native; - xxhasher() noexcept + xxhasher(xxhasher const&) = delete; + xxhasher& + operator=(xxhasher const&) = delete; + + xxhasher() + { + state_ = allocState(); + XXH3_64bits_reset(state_); + } + + ~xxhasher() noexcept { - detail::XXH64_reset(&state_, 1); + XXH3_freeState(state_); } template < @@ -50,7 +71,8 @@ class xxhasher std::enable_if_t::value>* = nullptr> explicit xxhasher(Seed seed) { - detail::XXH64_reset(&state_, seed); + state_ = allocState(); + XXH3_64bits_reset_withSeed(state_, seed); } template < @@ -58,18 +80,19 @@ class xxhasher std::enable_if_t::value>* = nullptr> xxhasher(Seed seed, Seed) { - detail::XXH64_reset(&state_, seed); + state_ = allocState(); + XXH3_64bits_reset_withSeed(state_, seed); } void operator()(void const* key, std::size_t len) noexcept { - detail::XXH64_update(&state_, key, len); + XXH3_64bits_update(state_, key, len); } explicit operator std::size_t() noexcept { - return detail::XXH64_digest(&state_); + return XXH3_64bits_digest(state_); } };