diff --git a/Source/Modules/CMakeBuildUtilities.cmake b/Source/Modules/CMakeBuildUtilities.cmake index 15bc35bc1f..a6578eb95b 100644 --- a/Source/Modules/CMakeBuildUtilities.cmake +++ b/Source/Modules/CMakeBuildUtilities.cmake @@ -102,6 +102,12 @@ else() CMAKE_SET_TARGET_FOLDER(cmlibrhash "Utilities/3rdParty") endif() +#--------------------------------------------------------------------- +# rapidhash is a header-only hashing library used to speed up +# string-keyed hash tables (e.g. cmDefinitions). No system option is +# provided because it has no conventional system package. +add_subdirectory(Utilities/cmrapidhash) + #--------------------------------------------------------------------- # Build zlib library for Curl, CMake, and CTest. if(CMAKE_USE_SYSTEM_ZLIB) diff --git a/Source/cmString.hxx b/Source/cmString.hxx index f7dcb2bf97..16881ac84e 100644 --- a/Source/cmString.hxx +++ b/Source/cmString.hxx @@ -16,6 +16,8 @@ #include #include +#include + namespace cm { class String; @@ -961,8 +963,8 @@ struct hash result_type operator()(argument_type const& s) const noexcept { - result_type const h(std::hash{}(s.view())); - return h; + cm::string_view const v = s.view(); + return static_cast(rapidhash(v.data(), v.size())); } }; } diff --git a/Utilities/Scripts/update-rapidhash.bash b/Utilities/Scripts/update-rapidhash.bash new file mode 100755 index 0000000000..59a4a3a769 --- /dev/null +++ b/Utilities/Scripts/update-rapidhash.bash @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e +set -x +shopt -s dotglob + +readonly name="rapidhash" +readonly ownership="rapidhash upstream " +readonly subtree="Utilities/cmrapidhash" +readonly repo="https://github.com/Nicoshev/rapidhash.git" +readonly tag="rapidhash_v3" +readonly shortlog=false +readonly exact_tree_match=false +readonly paths=" + LICENSE + rapidhash.h +" + +extract_source () { + git_archive + pushd "${extractdir}/${name}-reduced" + echo "* -whitespace" > .gitattributes + fromdos rapidhash.h + chmod a-x rapidhash.h + popd +} + +. "${BASH_SOURCE%/*}/update-third-party.bash" diff --git a/Utilities/cm3p/rapidhash.h b/Utilities/cm3p/rapidhash.h new file mode 100644 index 0000000000..99356d42b2 --- /dev/null +++ b/Utilities/cm3p/rapidhash.h @@ -0,0 +1,6 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file LICENSE.rst or https://cmake.org/licensing for details. */ +#pragma once + +/* Use the rapidhash library bundled with CMake. */ +#include // IWYU pragma: export diff --git a/Utilities/cmrapidhash/.gitattributes b/Utilities/cmrapidhash/.gitattributes new file mode 100644 index 0000000000..562b12e16e --- /dev/null +++ b/Utilities/cmrapidhash/.gitattributes @@ -0,0 +1 @@ +* -whitespace diff --git a/Utilities/cmrapidhash/CMakeLists.txt b/Utilities/cmrapidhash/CMakeLists.txt new file mode 100644 index 0000000000..4c1283155c --- /dev/null +++ b/Utilities/cmrapidhash/CMakeLists.txt @@ -0,0 +1,6 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file LICENSE.rst or https://cmake.org/licensing for details. + +# rapidhash is a header-only library, so there is no library target to build. + +install(FILES LICENSE DESTINATION ${CMake_INSTALL_DOC_DIR}/cmrapidhash) diff --git a/Utilities/cmrapidhash/LICENSE b/Utilities/cmrapidhash/LICENSE new file mode 100644 index 0000000000..67fe15fff3 --- /dev/null +++ b/Utilities/cmrapidhash/LICENSE @@ -0,0 +1,19 @@ +Copyright 2025 Nicolas De Carli + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Utilities/cmrapidhash/rapidhash.h b/Utilities/cmrapidhash/rapidhash.h new file mode 100644 index 0000000000..b71c4e587d --- /dev/null +++ b/Utilities/cmrapidhash/rapidhash.h @@ -0,0 +1,574 @@ +/* + * rapidhash V3 - Very fast, high quality, platform-independent hashing algorithm. + * + * Based on 'wyhash', by Wang Yi + * + * Copyright (C) 2025 Nicolas De Carli + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * You can contact the author at: + * - rapidhash source repository: https://github.com/Nicoshev/rapidhash + */ + +/* + * Includes. + */ + #include + #include + #if defined(_MSC_VER) + # include + # if defined(_M_X64) && !defined(_M_ARM64EC) + # pragma intrinsic(_umul128) + # endif + #endif + + /* + * C/C++ macros. + */ + + #ifdef _MSC_VER + # define RAPIDHASH_ALWAYS_INLINE __forceinline + #elif defined(__GNUC__) + # define RAPIDHASH_ALWAYS_INLINE inline __attribute__((__always_inline__)) + #else + # define RAPIDHASH_ALWAYS_INLINE inline + #endif + + #ifdef __cplusplus + # define RAPIDHASH_NOEXCEPT noexcept + # define RAPIDHASH_CONSTEXPR constexpr + # ifndef RAPIDHASH_INLINE + # define RAPIDHASH_INLINE RAPIDHASH_ALWAYS_INLINE + # endif + # if __cplusplus >= 201402L && ((defined(__GNUC__) && __GNUC__ > 5) || defined(__INTEL_COMPILER) || defined(__clang__)) + # define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_ALWAYS_INLINE constexpr + # else + # define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_ALWAYS_INLINE + # endif + #else + # define RAPIDHASH_NOEXCEPT + # define RAPIDHASH_CONSTEXPR static const + # ifndef RAPIDHASH_INLINE + # define RAPIDHASH_INLINE static RAPIDHASH_ALWAYS_INLINE + # endif + # define RAPIDHASH_INLINE_CONSTEXPR RAPIDHASH_INLINE + #endif + + /* + * Unrolled macro. + * Improves large input speed, but increases code size and worsens small input speed. + * + * RAPIDHASH_COMPACT: Normal behavior. + * RAPIDHASH_UNROLLED: + * + */ + #ifndef RAPIDHASH_UNROLLED + # define RAPIDHASH_COMPACT + #elif defined(RAPIDHASH_COMPACT) + # error "cannot define RAPIDHASH_COMPACT and RAPIDHASH_UNROLLED simultaneously." + #endif + + /* + * Protection macro, alters behaviour of rapid_mum multiplication function. + * + * RAPIDHASH_FAST: Normal behavior, max speed. + * RAPIDHASH_PROTECTED: Extra protection against entropy loss. + */ + #ifndef RAPIDHASH_PROTECTED + # define RAPIDHASH_FAST + #elif defined(RAPIDHASH_FAST) + # error "cannot define RAPIDHASH_PROTECTED and RAPIDHASH_FAST simultaneously." + #endif + + /* + * Likely and unlikely macros. + */ + #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) + # define _likely_(x) __builtin_expect(x,1) + # define _unlikely_(x) __builtin_expect(x,0) + #else + # define _likely_(x) (x) + # define _unlikely_(x) (x) + #endif + + /* + * Endianness macros. + */ + #ifndef RAPIDHASH_LITTLE_ENDIAN + # if defined(_WIN32) || defined(__LITTLE_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + # define RAPIDHASH_LITTLE_ENDIAN + # elif defined(__BIG_ENDIAN__) || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + # define RAPIDHASH_BIG_ENDIAN + # else + # warning "could not determine endianness! Falling back to little endian." + # define RAPIDHASH_LITTLE_ENDIAN + # endif + #endif + + /* + * Default secret parameters. + */ + RAPIDHASH_CONSTEXPR uint64_t rapid_secret[8] = { + 0x2d358dccaa6c78a5ull, + 0x8bb84b93962eacc9ull, + 0x4b33a62ed433d4a3ull, + 0x4d5a2da51de1aa47ull, + 0xa0761d6478bd642full, + 0xe7037ed1a0b428dbull, + 0x90ed1765281c388cull, + 0xaaaaaaaaaaaaaaaaull}; + + /* + * 64*64 -> 128bit multiply function. + * + * @param A Address of 64-bit number. + * @param B Address of 64-bit number. + * + * Calculates 128-bit C = *A * *B. + * + * When RAPIDHASH_FAST is defined: + * Overwrites A contents with C's low 64 bits. + * Overwrites B contents with C's high 64 bits. + * + * When RAPIDHASH_PROTECTED is defined: + * Xors and overwrites A contents with C's low 64 bits. + * Xors and overwrites B contents with C's high 64 bits. + */ + RAPIDHASH_INLINE_CONSTEXPR void rapid_mum(uint64_t *A, uint64_t *B) RAPIDHASH_NOEXCEPT { + #if defined(__SIZEOF_INT128__) + __uint128_t r=*A; r*=*B; + #ifdef RAPIDHASH_PROTECTED + *A^=(uint64_t)r; *B^=(uint64_t)(r>>64); + #else + *A=(uint64_t)r; *B=(uint64_t)(r>>64); + #endif + #elif defined(_MSC_VER) && (defined(_WIN64) || defined(_M_HYBRID_CHPE_ARM64)) + #if defined(_M_X64) + #ifdef RAPIDHASH_PROTECTED + uint64_t a, b; + a=_umul128(*A,*B,&b); + *A^=a; *B^=b; + #else + *A=_umul128(*A,*B,B); + #endif + #else + #ifdef RAPIDHASH_PROTECTED + uint64_t a, b; + b = __umulh(*A, *B); + a = *A * *B; + *A^=a; *B^=b; + #else + uint64_t c = __umulh(*A, *B); + *A = *A * *B; + *B = c; + #endif + #endif + #else + uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B; + uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t>32)+(rm1>>32)+c; + #ifdef RAPIDHASH_PROTECTED + *A^=lo; *B^=hi; + #else + *A=lo; *B=hi; + #endif + #endif + } + + /* + * Multiply and xor mix function. + * + * @param A 64-bit number. + * @param B 64-bit number. + * + * Calculates 128-bit C = A * B. + * Returns 64-bit xor between high and low 64 bits of C. + */ + RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_mix(uint64_t A, uint64_t B) RAPIDHASH_NOEXCEPT { rapid_mum(&A,&B); return A^B; } + + /* + * Read functions. + */ + #ifdef RAPIDHASH_LITTLE_ENDIAN + RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return v;} + RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return v;} + #elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) + RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return __builtin_bswap64(v);} + RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return __builtin_bswap32(v);} + #elif defined(_MSC_VER) + RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return _byteswap_uint64(v);} + RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return _byteswap_ulong(v);} + #else + RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { + uint64_t v; memcpy(&v, p, 8); + return (((v >> 56) & 0xff)| ((v >> 40) & 0xff00)| ((v >> 24) & 0xff0000)| ((v >> 8) & 0xff000000)| ((v << 8) & 0xff00000000)| ((v << 24) & 0xff0000000000)| ((v << 40) & 0xff000000000000)| ((v << 56) & 0xff00000000000000)); + } + RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { + uint32_t v; memcpy(&v, p, 4); + return (((v >> 24) & 0xff)| ((v >> 8) & 0xff00)| ((v << 8) & 0xff0000)| ((v << 24) & 0xff000000)); + } + #endif + + /* + * rapidhash main function. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * @param seed 64-bit seed used to alter the hash result predictably. + * @param secret Triplet of 64-bit secrets used to alter hash result predictably. + * + * Returns a 64-bit hash. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT { + const uint8_t *p=(const uint8_t *)key; + seed ^= rapid_mix(seed ^ secret[2], secret[1]); + uint64_t a=0, b=0; + size_t i = len; + if (_likely_(len <= 16)) { + if (len >= 4) { + seed ^= len; + if (len >= 8) { + const uint8_t* plast = p + len - 8; + a = rapid_read64(p); + b = rapid_read64(plast); + } else { + const uint8_t* plast = p + len - 4; + a = rapid_read32(p); + b = rapid_read32(plast); + } + } else if (len > 0) { + a = (((uint64_t)p[0])<<45)|p[len-1]; + b = p[len>>1]; + } else + a = b = 0; + } else { + uint64_t see1 = seed, see2 = seed; + uint64_t see3 = seed, see4 = seed; + uint64_t see5 = seed, see6 = seed; +#ifdef RAPIDHASH_COMPACT + if (i > 112) { + do { + seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); + see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); + see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); + see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); + see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); + see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5); + see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6); + p += 112; + i -= 112; + } while(i > 112); + seed ^= see1; + see2 ^= see3; + see4 ^= see5; + seed ^= see6; + see2 ^= see4; + seed ^= see2; + } +#else + if (i > 224) { + do { + seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); + see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); + see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); + see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); + see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); + see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5); + see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6); + seed = rapid_mix(rapid_read64(p + 112) ^ secret[0], rapid_read64(p + 120) ^ seed); + see1 = rapid_mix(rapid_read64(p + 128) ^ secret[1], rapid_read64(p + 136) ^ see1); + see2 = rapid_mix(rapid_read64(p + 144) ^ secret[2], rapid_read64(p + 152) ^ see2); + see3 = rapid_mix(rapid_read64(p + 160) ^ secret[3], rapid_read64(p + 168) ^ see3); + see4 = rapid_mix(rapid_read64(p + 176) ^ secret[4], rapid_read64(p + 184) ^ see4); + see5 = rapid_mix(rapid_read64(p + 192) ^ secret[5], rapid_read64(p + 200) ^ see5); + see6 = rapid_mix(rapid_read64(p + 208) ^ secret[6], rapid_read64(p + 216) ^ see6); + p += 224; + i -= 224; + } while (i > 224); + } + if (i > 112) { + seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); + see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); + see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); + see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); + see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); + see5 = rapid_mix(rapid_read64(p + 80) ^ secret[5], rapid_read64(p + 88) ^ see5); + see6 = rapid_mix(rapid_read64(p + 96) ^ secret[6], rapid_read64(p + 104) ^ see6); + p += 112; + i -= 112; + } + seed ^= see1; + see2 ^= see3; + see4 ^= see5; + seed ^= see6; + see2 ^= see4; + seed ^= see2; +#endif + if (i > 16) { + seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed); + if (i > 32) { + seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed); + if (i > 48) { + seed = rapid_mix(rapid_read64(p + 32) ^ secret[1], rapid_read64(p + 40) ^ seed); + if (i > 64) { + seed = rapid_mix(rapid_read64(p + 48) ^ secret[1], rapid_read64(p + 56) ^ seed); + if (i > 80) { + seed = rapid_mix(rapid_read64(p + 64) ^ secret[2], rapid_read64(p + 72) ^ seed); + if (i > 96) { + seed = rapid_mix(rapid_read64(p + 80) ^ secret[1], rapid_read64(p + 88) ^ seed); + } + } + } + } + } + } + a=rapid_read64(p+i-16) ^ i; b=rapid_read64(p+i-8); + } + a ^= secret[1]; + b ^= seed; + rapid_mum(&a, &b); + return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i); +} + + /* + * rapidhashMicro main function. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * @param seed 64-bit seed used to alter the hash result predictably. + * @param secret Triplet of 64-bit secrets used to alter hash result predictably. + * + * Returns a 64-bit hash. + */ + RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT { + const uint8_t *p=(const uint8_t *)key; + seed ^= rapid_mix(seed ^ secret[2], secret[1]); + uint64_t a=0, b=0; + size_t i = len; + if (_likely_(len <= 16)) { + if (len >= 4) { + seed ^= len; + if (len >= 8) { + const uint8_t* plast = p + len - 8; + a = rapid_read64(p); + b = rapid_read64(plast); + } else { + const uint8_t* plast = p + len - 4; + a = rapid_read32(p); + b = rapid_read32(plast); + } + } else if (len > 0) { + a = (((uint64_t)p[0])<<45)|p[len-1]; + b = p[len>>1]; + } else + a = b = 0; + } else { + if (i > 80) { + uint64_t see1 = seed, see2 = seed; + uint64_t see3 = seed, see4 = seed; + do { + seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); + see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); + see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); + see3 = rapid_mix(rapid_read64(p + 48) ^ secret[3], rapid_read64(p + 56) ^ see3); + see4 = rapid_mix(rapid_read64(p + 64) ^ secret[4], rapid_read64(p + 72) ^ see4); + p += 80; + i -= 80; + } while(i > 80); + seed ^= see1; + see2 ^= see3; + seed ^= see4; + seed ^= see2; + } + if (i > 16) { + seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed); + if (i > 32) { + seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed); + if (i > 48) { + seed = rapid_mix(rapid_read64(p + 32) ^ secret[1], rapid_read64(p + 40) ^ seed); + if (i > 64) { + seed = rapid_mix(rapid_read64(p + 48) ^ secret[1], rapid_read64(p + 56) ^ seed); + } + } + } + } + a=rapid_read64(p+i-16) ^ i; b=rapid_read64(p+i-8); + } + a ^= secret[1]; + b ^= seed; + rapid_mum(&a, &b); + return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i); + } + + /* + * rapidhashNano main function. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * @param seed 64-bit seed used to alter the hash result predictably. + * @param secret Triplet of 64-bit secrets used to alter hash result predictably. + * + * Returns a 64-bit hash. + */ + RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano_internal(const void *key, size_t len, uint64_t seed, const uint64_t* secret) RAPIDHASH_NOEXCEPT { + const uint8_t *p=(const uint8_t *)key; + seed ^= rapid_mix(seed ^ secret[2], secret[1]); + uint64_t a=0, b=0; + size_t i = len; + if (_likely_(len <= 16)) { + if (len >= 4) { + seed ^= len; + if (len >= 8) { + const uint8_t* plast = p + len - 8; + a = rapid_read64(p); + b = rapid_read64(plast); + } else { + const uint8_t* plast = p + len - 4; + a = rapid_read32(p); + b = rapid_read32(plast); + } + } else if (len > 0) { + a = (((uint64_t)p[0])<<45)|p[len-1]; + b = p[len>>1]; + } else + a = b = 0; + } else { + if (i > 48) { + uint64_t see1 = seed, see2 = seed; + do { + seed = rapid_mix(rapid_read64(p) ^ secret[0], rapid_read64(p + 8) ^ seed); + see1 = rapid_mix(rapid_read64(p + 16) ^ secret[1], rapid_read64(p + 24) ^ see1); + see2 = rapid_mix(rapid_read64(p + 32) ^ secret[2], rapid_read64(p + 40) ^ see2); + p += 48; + i -= 48; + } while(i > 48); + seed ^= see1; + seed ^= see2; + } + if (i > 16) { + seed = rapid_mix(rapid_read64(p) ^ secret[2], rapid_read64(p + 8) ^ seed); + if (i > 32) { + seed = rapid_mix(rapid_read64(p + 16) ^ secret[2], rapid_read64(p + 24) ^ seed); + } + } + a=rapid_read64(p+i-16) ^ i; b=rapid_read64(p+i-8); + } + a ^= secret[1]; + b ^= seed; + rapid_mum(&a, &b); + return rapid_mix(a ^ secret[7], b ^ secret[1] ^ i); + } + +/* + * rapidhash seeded hash function. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * @param seed 64-bit seed used to alter the hash result predictably. + * + * Calls rapidhash_internal using provided parameters and default secrets. + * + * Returns a 64-bit hash. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT { + return rapidhash_internal(key, len, seed, rapid_secret); +} + +/* + * rapidhash general purpose hash function. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * + * Calls rapidhash_withSeed using provided parameters and the default seed. + * + * Returns a 64-bit hash. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash(const void *key, size_t len) RAPIDHASH_NOEXCEPT { + return rapidhash_withSeed(key, len, 0); +} + +/* + * rapidhashMicro seeded hash function. + * + * Designed for HPC and server applications, where cache misses make a noticeable performance detriment. + * Clang-18+ compiles it to ~140 instructions without stack usage, both on x86-64 and aarch64. + * Faster for sizes up to 512 bytes, just 15%-20% slower for inputs above 1kb. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * @param seed 64-bit seed used to alter the hash result predictably. + * + * Calls rapidhash_internal using provided parameters and default secrets. + * + * Returns a 64-bit hash. + */ + RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT { + return rapidhashMicro_internal(key, len, seed, rapid_secret); +} + +/* + * rapidhashMicro hash function. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * + * Calls rapidhash_withSeed using provided parameters and the default seed. + * + * Returns a 64-bit hash. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashMicro(const void *key, size_t len) RAPIDHASH_NOEXCEPT { + return rapidhashMicro_withSeed(key, len, 0); +} + +/* + * rapidhashNano seeded hash function. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * @param seed 64-bit seed used to alter the hash result predictably. + * + * Calls rapidhash_internal using provided parameters and default secrets. + * + * Returns a 64-bit hash. + */ + RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano_withSeed(const void *key, size_t len, uint64_t seed) RAPIDHASH_NOEXCEPT { + return rapidhashNano_internal(key, len, seed, rapid_secret); +} + +/* + * rapidhashNano hash function. + * + * Designed for Mobile and embedded applications, where keeping a small code size is a top priority. + * Clang-18+ compiles it to less than 100 instructions without stack usage, both on x86-64 and aarch64. + * The fastest for sizes up to 48 bytes, but may be considerably slower for larger inputs. + * + * @param key Buffer to be hashed. + * @param len @key length, in bytes. + * + * Calls rapidhash_withSeed using provided parameters and the default seed. + * + * Returns a 64-bit hash. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano(const void *key, size_t len) RAPIDHASH_NOEXCEPT { + return rapidhashNano_withSeed(key, len, 0); +} diff --git a/Utilities/std/cm/bits/string_view.cxx b/Utilities/std/cm/bits/string_view.cxx index 4a18e2fa14..d89e9646b1 100644 --- a/Utilities/std/cm/bits/string_view.cxx +++ b/Utilities/std/cm/bits/string_view.cxx @@ -9,7 +9,7 @@ # include # include -# include +# include namespace cm { @@ -282,15 +282,7 @@ std::string& operator+=(std::string& s, string_view v) std::hash::result_type std::hash::operator()( argument_type const& s) const noexcept { - // FNV-1a hash. - static KWIML_INT_uint64_t const fnv_offset_basis = 0xcbf29ce484222325; - static KWIML_INT_uint64_t const fnv_prime = 0x100000001b3; - KWIML_INT_uint64_t h = fnv_offset_basis; - for (char const& c : s) { - h = h ^ KWIML_INT_uint64_t(KWIML_INT_uint8_t(c)); - h = h * fnv_prime; - } - return result_type(h); + return result_type(rapidhash(s.data(), s.size())); } #else // Avoid empty translation unit.