/** * @file a5hash.h * * @version 5.25 * * @brief The header file for the "a5hash" 64-bit hash function, "a5hash32" * 32-bit hash function, "a5hash128" 128-bit hash function, and "a5rand" * 64-bit PRNG. * * The source code is written in ISO C99, with full C++ compliance enabled * conditionally and automatically when compiled with a C++ compiler. * * Description is available at https://github.com/avaneev/a5hash * * Email: aleksey.vaneev@gmail.com or info@voxengo.com * * LICENSE: * * Copyright (c) 2025 Aleksey Vaneev * * 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. */ #ifndef A5HASH_INCLUDED #define A5HASH_INCLUDED #define A5HASH_VER_STR "5.25" ///< A5HASH source code version string. /** * @def A5HASH_NS_CUSTOM * @brief If this macro is defined externally, all symbols will be placed into * the C++ namespace specified by this macro and will not be exported to the * global namespace. WARNING: if the macro's value is empty, the symbols will * be placed into the global namespace anyway. */ /** * @def A5HASH_U64_C( x ) * @brief Macro that defines a numeric value as unsigned 64-bit value. * * @param x Value. */ /** * @def A5HASH_NOEX * @brief Macro that defines the "noexcept" function specifier for C++ * environment. */ /** * @def A5HASH_NULL * @brief Macro that defines "nullptr" value, for C++ guidelines compliance. */ /** * @def A5HASH_NS * @brief Macro that defines the actual implementation namespace in C++ * environment, with export of relevant symbols to the global namespace * (if @ref A5HASH_NS_CUSTOM is undefined). */ #if defined( __cplusplus ) #include #if __cplusplus >= 201103L #include #define A5HASH_U64_C( x ) UINT64_C( x ) #define A5HASH_NOEX noexcept #define A5HASH_NULL nullptr #else // __cplusplus >= 201103L #include #define A5HASH_U64_C( x ) (uint64_t) x #define A5HASH_NOEX throw() #define A5HASH_NULL NULL #endif // __cplusplus >= 201103L #if defined( A5HASH_NS_CUSTOM ) #define A5HASH_NS A5HASH_NS_CUSTOM #else // defined( A5HASH_NS_CUSTOM ) #define A5HASH_NS a5hash_impl #endif // defined( A5HASH_NS_CUSTOM ) #else // defined( __cplusplus ) #include #include #define A5HASH_U64_C( x ) (uint64_t) x #define A5HASH_NOEX #define A5HASH_NULL NULL #endif // defined( __cplusplus ) #if defined( _MSC_VER ) #include #endif // defined( _MSC_VER ) #define A5HASH_VAL10 A5HASH_U64_C( 0xAAAAAAAAAAAAAAAA ) ///< `10` bit-pairs. #define A5HASH_VAL01 A5HASH_U64_C( 0x5555555555555555 ) ///< `01` bit-pairs. /** * @def A5HASH_ICC_GCC * @brief Macro that denotes the use of ICC classic compiler with GCC-style * built-in functions. */ #if defined( __INTEL_COMPILER ) && __INTEL_COMPILER >= 1300 && \ !defined( _MSC_VER ) #define A5HASH_ICC_GCC #endif // ICC check /** * @def A5HASH_GCC_BUILTINS * @brief Macro that denotes availability of GCC-style built-in functions. */ #if defined( __GNUC__ ) || defined( __clang__ ) || \ defined( __IBMC__ ) || defined( __IBMCPP__ ) || defined( A5HASH_ICC_GCC ) #define A5HASH_GCC_BUILTINS #endif // GCC built-ins check /** * @def A5HASH_BMI2 * @brief Macro that denotes availability of the `mulx` intrinsic * (MSVC-compatible compilers only). */ #if defined( _MSC_VER ) #if defined( __BMI2__ ) || ( !defined( A5HASH_GCC_BUILTINS ) && \ defined( _M_AMD64 ) && defined( __AVX2__ ) && \ ( defined( __INTEL_COMPILER ) || _MSC_VER >= 1900 )) #include #define A5HASH_BMI2 #else // BMI2 #include #endif // BMI2 #endif // defined( _MSC_VER ) /** * @def A5HASH_STATIC * @brief Macro that defines a function as "static". */ #if ( defined( __cplusplus ) && __cplusplus >= 201703L ) || \ ( defined( __STDC_VERSION__ ) && __STDC_VERSION__ >= 202311L ) #define A5HASH_STATIC [[maybe_unused]] static #elif defined( A5HASH_GCC_BUILTINS ) #define A5HASH_STATIC static __attribute__((unused)) #else // defined( A5HASH_GCC_BUILTINS ) #define A5HASH_STATIC static #endif // defined( A5HASH_GCC_BUILTINS ) /** * @def A5HASH_INLINE * @brief Macro that defines a function as inlinable at the compiler's * discretion. */ #define A5HASH_INLINE A5HASH_STATIC inline /** * @def A5HASH_INLINE_F * @brief Macro to force code inlining. */ #if defined( __LP64__ ) || defined( _LP64 ) || \ !( SIZE_MAX <= 0xFFFFFFFFU ) || ( defined( UINTPTR_MAX ) && \ !( UINTPTR_MAX <= 0xFFFFFFFFU )) || defined( __x86_64__ ) || \ defined( __aarch64__ ) || defined( _M_AMD64 ) || defined( _M_ARM64 ) #if defined( A5HASH_GCC_BUILTINS ) #define A5HASH_INLINE_F A5HASH_INLINE __attribute__((always_inline)) #elif defined( _MSC_VER ) #define A5HASH_INLINE_F A5HASH_STATIC __forceinline #endif // defined( _MSC_VER ) #endif // 64-bit platform check #if !defined( A5HASH_INLINE_F ) #define A5HASH_INLINE_F A5HASH_INLINE #endif // !defined( A5HASH_INLINE_F ) #if defined( A5HASH_NS ) namespace A5HASH_NS { using std :: memcpy; using std :: size_t; #if __cplusplus >= 201103L using std :: uint32_t; using std :: uint64_t; using uint8_t = unsigned char; ///< For C++ type aliasing compliance. #endif // __cplusplus >= 201103L #endif // defined( A5HASH_NS ) /** * @{ * @brief Load unsigned value of the specific bit size from memory. * * @param p Load address. */ A5HASH_INLINE_F uint32_t a5hash_lu32( const uint8_t* const p ) A5HASH_NOEX { uint32_t v; memcpy( &v, p, 4 ); return( v ); } A5HASH_INLINE_F uint64_t a5hash_lu64( const uint8_t* const p ) A5HASH_NOEX { uint64_t v; memcpy( &v, p, 8 ); return( v ); } /** @} */ /** * @brief 64-bit by 64-bit unsigned multiplication producing a 128-bit result. * * @param u Multiplier 1. * @param v Multiplier 2. * @param[out] rl The lower half of the 128-bit result. * @param[out] rh The upper half of the 128-bit result. */ A5HASH_INLINE_F void a5hash_umul128( const uint64_t u, const uint64_t v, uint64_t* const rl, uint64_t* const rh ) A5HASH_NOEX { #if defined( A5HASH_BMI2 ) *rl = _mulx_u64( u, v, rh ); #elif defined( _MSC_VER ) && ( defined( _M_ARM64 ) || defined( _M_ARM64EC ) || \ ( defined( __INTEL_COMPILER ) && defined( _M_AMD64 ))) *rl = u * v; *rh = __umulh( u, v ); #elif defined( _MSC_VER ) && ( defined( _M_AMD64 ) || defined( _M_IA64 )) *rl = _umul128( u, v, rh ); #elif defined( __SIZEOF_INT128__ ) || \ ( defined( A5HASH_ICC_GCC ) && defined( __x86_64__ )) __uint128_t r = u; r *= v; *rl = (uint64_t) r; *rh = (uint64_t) ( r >> 64 ); #elif ( defined( __IBMC__ ) || defined( __IBMCPP__ )) && defined( __LP64__ ) *rl = u * v; *rh = __mulhdu( u, v ); #else // defined( __IBMC__ ) // _umul128() code for 32-bit systems, adapted from Hacker's Delight, // Henry S. Warren, Jr. *rl = u * v; const uint32_t u0 = (uint32_t) u; const uint32_t v0 = (uint32_t) v; const uint64_t w0 = (uint64_t) u0 * v0; const uint32_t u1 = (uint32_t) ( u >> 32 ); const uint32_t v1 = (uint32_t) ( v >> 32 ); const uint64_t t = (uint64_t) u1 * v0 + (uint32_t) ( w0 >> 32 ); const uint64_t w1 = (uint64_t) u0 * v1 + (uint32_t) t; *rh = (uint64_t) u1 * v1 + (uint32_t) ( w1 >> 32 ) + (uint32_t) ( t >> 32 ); #endif // defined( __IBMC__ ) } /** * @brief A5HASH 64-bit hash function. * * Produces and returns a 64-bit hash value (digest) of the specified message, * string, or binary data block. Designed for string/small key data hash-map * and hash-table uses. * * @param Msg0 The message to produce a hash from. The alignment of this * pointer is unimportant. It is valid to pass 0 when `MsgLen` equals 0. * @param MsgLen Message length, in bytes, can be zero. * @param UseSeed An optional value to use instead of the default seed (0). * This value can have any number of significant bits and any statistical * quality. * @return 64-bit hash of the input data. */ A5HASH_INLINE_F uint64_t a5hash( const void* const Msg0, size_t MsgLen, const uint64_t UseSeed ) A5HASH_NOEX { const uint8_t* Msg = (const uint8_t*) Msg0; uint64_t val01 = A5HASH_VAL01; uint64_t val10 = A5HASH_VAL10; // The seeds are initialized to mantissa bits of PI. uint64_t Seed1 = A5HASH_U64_C( 0x243F6A8885A308D3 ) ^ MsgLen; uint64_t Seed2 = A5HASH_U64_C( 0x452821E638D01377 ) ^ MsgLen; a5hash_umul128( Seed2 ^ ( UseSeed & val10 ), Seed1 ^ ( UseSeed & val01 ), &Seed1, &Seed2 ); if( MsgLen > 16 ) { val01 ^= Seed1; val10 ^= Seed2; do { a5hash_umul128( (uint64_t) a5hash_lu32( Msg ) << 32 ^ a5hash_lu32( Msg + 4 ) ^ Seed1, (uint64_t) a5hash_lu32( Msg + 8 ) << 32 ^ a5hash_lu32( Msg + 12 ) ^ Seed2, &Seed1, &Seed2 ); MsgLen -= 16; Msg += 16; Seed1 += val01; Seed2 += val10; } while( MsgLen > 16 ); } if( MsgLen == 0 ) { goto _fin; } if( MsgLen > 3 ) { const uint8_t* Msg4; size_t mo; Msg4 = Msg + MsgLen - 4; mo = MsgLen >> 3; Seed1 ^= (uint64_t) a5hash_lu32( Msg ) << 32 | a5hash_lu32( Msg4 ); Seed2 ^= (uint64_t) a5hash_lu32( Msg + mo * 4 ) << 32 | a5hash_lu32( Msg4 - mo * 4 ); _fin: a5hash_umul128( Seed1, Seed2, &Seed1, &Seed2 ); a5hash_umul128( val01 ^ Seed1, Seed2, &Seed1, &Seed2 ); return( Seed1 ^ Seed2 ); } else { Seed1 ^= Msg[ 0 ]; if( --MsgLen != 0 ) { Seed1 ^= (uint64_t) Msg[ 1 ] << 8; if( --MsgLen != 0 ) { Seed1 ^= (uint64_t) Msg[ 2 ] << 16; } } goto _fin; } } /** * @brief 32-bit by 32-bit unsigned multiplication producing a 64-bit result. * * @param u Multiplier 1. * @param v Multiplier 2. * @param[out] rl The lower half of the 64-bit result. * @param[out] rh The upper half of the 64-bit result. */ A5HASH_INLINE_F void a5hash_umul64( const uint32_t u, const uint32_t v, uint32_t* const rl, uint32_t* const rh ) A5HASH_NOEX { const uint64_t r = (uint64_t) u * v; *rl = (uint32_t) r; *rh = (uint32_t) ( r >> 32 ); } /** * @brief A5HASH 32-bit hash function. * * Produces and returns a 32-bit hash value (digest) of the specified message, * string, or binary data block. Designed for string/small key data hash-map * and hash-table uses. * * This function works natively on 32-bit platforms and avoids the performance * penalty of 64-bit arithmetic. * * @param Msg0 The message to produce a hash from. The alignment of this * pointer is unimportant. It is valid to pass 0 when `MsgLen` equals 0. * @param MsgLen Message length, in bytes, can be zero. * @param UseSeed An optional value to use instead of the default seed (0). * This value can have any number of significant bits and any statistical * quality. * @return 32-bit hash of the input data. */ A5HASH_INLINE_F uint32_t a5hash32( const void* const Msg0, size_t MsgLen, const uint32_t UseSeed ) A5HASH_NOEX { const uint8_t* Msg = (const uint8_t*) Msg0; uint32_t val01 = (uint32_t) A5HASH_VAL01; uint32_t val10 = (uint32_t) A5HASH_VAL10; // The seeds are initialized to mantissa bits of PI. uint32_t Seed1 = 0x243F6A88 ^ (uint32_t) MsgLen; uint32_t Seed2 = 0x85A308D3 ^ (uint32_t) MsgLen; uint32_t Seed3, Seed4; uint32_t a, b, c, d; #if SIZE_MAX <= 0xFFFFFFFFU Seed3 = 0xFB0BD3EA; Seed4 = 0x0F58FD47; #else // SIZE_MAX <= 0xFFFFFFFFU a5hash_umul64( (uint32_t) ( MsgLen >> 32 ) ^ 0x452821E6, (uint32_t) ( MsgLen >> 32 ) ^ 0x38D01377, &Seed3, &Seed4 ); #endif // SIZE_MAX <= 0xFFFFFFFFU a5hash_umul64( Seed2 ^ ( UseSeed & val10 ), Seed1 ^ ( UseSeed & val01 ), &Seed1, &Seed2 ); if( MsgLen < 17 ) { if( MsgLen > 3 ) { const uint8_t* const Msg4 = Msg + MsgLen - 4; size_t mo; a = a5hash_lu32( Msg ); b = a5hash_lu32( Msg4 ); if( MsgLen < 9 ) { goto _fin; } mo = MsgLen >> 3; c = a5hash_lu32( Msg + mo * 4 ); d = a5hash_lu32( Msg4 - mo * 4 ); } else { a = 0; b = 0; if( MsgLen != 0 ) { a = Msg[ 0 ]; if( MsgLen != 1 ) { a |= (uint32_t) Msg[ 1 ] << 8; if( MsgLen != 2 ) { a |= (uint32_t) Msg[ 2 ] << 16; } } } goto _fin; } } else { val01 ^= Seed1; val10 ^= Seed2; do { const uint32_t s1 = Seed1; const uint32_t s4 = Seed4; a5hash_umul64( a5hash_lu32( Msg ) + Seed1, a5hash_lu32( Msg + 4 ) + Seed2, &Seed1, &Seed2 ); a5hash_umul64( a5hash_lu32( Msg + 8 ) + Seed3, a5hash_lu32( Msg + 12 ) + Seed4, &Seed3, &Seed4 ); MsgLen -= 16; Msg += 16; Seed1 += val01; Seed2 += s4; Seed3 += s1; Seed4 += val10; } while( MsgLen > 16 ); a = a5hash_lu32( Msg + MsgLen - 8 ); b = a5hash_lu32( Msg + MsgLen - 4 ); if( MsgLen < 9 ) { goto _fin; } c = a5hash_lu32( Msg + MsgLen - 16 ); d = a5hash_lu32( Msg + MsgLen - 12 ); } a5hash_umul64( c + Seed3, d + Seed4, &Seed3, &Seed4 ); _fin: Seed1 ^= Seed3; Seed2 ^= Seed4; a5hash_umul64( a + Seed1, b + Seed2, &Seed1, &Seed2 ); a5hash_umul64( val01 ^ Seed1, Seed2, &a, &b ); return( a ^ b ); } /** * @brief A5HASH 128-bit hash function. * * Produces and returns a 128-bit hash value (digest) of the specified * message, string, or binary data block. Designed for string/small key data * hash-map and hash-table uses. * * @param Msg0 The message to produce a hash from. The alignment of this * pointer is unimportant. It is valid to pass 0 when `MsgLen` equals 0. * @param MsgLen Message length, in bytes, can be zero. * @param UseSeed An optional value to use instead of the default seed (0). * This value can have any number of significant bits and any statistical * quality. * @param[out] rh Pointer to 64-bit variable that receives upper 64 bits of * 128-bit hash. The alignment of this pointer is unimportant. Can be 0. * @return Lower 64 bits of 128-bit hash of the input data. */ A5HASH_INLINE uint64_t a5hash128( const void* const Msg0, size_t MsgLen, const uint64_t UseSeed, void* const rh ) A5HASH_NOEX { const uint8_t* Msg = (const uint8_t*) Msg0; uint64_t val01 = A5HASH_VAL01; uint64_t val10 = A5HASH_VAL10; // The seeds are initialized to mantissa bits of PI. uint64_t Seed1 = A5HASH_U64_C( 0x243F6A8885A308D3 ) ^ MsgLen; uint64_t Seed2 = A5HASH_U64_C( 0x452821E638D01377 ) ^ MsgLen; uint64_t Seed3 = A5HASH_U64_C( 0xA4093822299F31D0 ); uint64_t Seed4 = A5HASH_U64_C( 0xC0AC29B7C97C50DD ); uint64_t a, b, c, d; a5hash_umul128( Seed2 ^ ( UseSeed & val10 ), Seed1 ^ ( UseSeed & val01 ), &Seed1, &Seed2 ); if( MsgLen < 17 ) { if( MsgLen > 3 ) { const uint8_t* Msg4; size_t mo; Msg4 = Msg + MsgLen - 4; mo = MsgLen >> 3; a = (uint64_t) a5hash_lu32( Msg ) << 32 | a5hash_lu32( Msg4 ); b = (uint64_t) a5hash_lu32( Msg + mo * 4 ) << 32 | a5hash_lu32( Msg4 - mo * 4 ); _fin16: a5hash_umul128( a + Seed1, b + Seed2, &Seed1, &Seed2 ); a5hash_umul128( val01 ^ Seed1, Seed2, &a, &b ); a ^= b; if( rh != A5HASH_NULL ) { a5hash_umul128( Seed1 ^ Seed3, Seed2 ^ Seed4, &Seed3, &Seed4 ); Seed3 ^= Seed4; memcpy( rh, &Seed3, 8 ); } return( a ); } else { a = 0; b = 0; if( MsgLen != 0 ) { a = Msg[ 0 ]; if( --MsgLen != 0 ) { a |= (uint64_t) Msg[ 1 ] << 8; if( --MsgLen != 0 ) { a |= (uint64_t) Msg[ 2 ] << 16; } } } goto _fin16; } } if( MsgLen < 33 ) { a = (uint64_t) a5hash_lu32( Msg ) << 32 | a5hash_lu32( Msg + 4 ); b = (uint64_t) a5hash_lu32( Msg + 8 ) << 32 | a5hash_lu32( Msg + 12 ); c = (uint64_t) a5hash_lu32( Msg + MsgLen - 16 ) << 32 | a5hash_lu32( Msg + MsgLen - 12 ); d = (uint64_t) a5hash_lu32( Msg + MsgLen - 8 ) << 32 | a5hash_lu32( Msg + MsgLen - 4 ); _fin_m: a5hash_umul128( c + Seed3, d + Seed4, &Seed3, &Seed4 ); _fin: Seed1 ^= Seed3; Seed2 ^= Seed4; a5hash_umul128( a + Seed1, b + Seed2, &Seed1, &Seed2 ); a5hash_umul128( val01 ^ Seed1, Seed2, &a, &b ); a ^= b; if( rh != A5HASH_NULL ) { a5hash_umul128( Seed1 ^ Seed3, Seed2 ^ Seed4, &Seed3, &Seed4 ); Seed3 ^= Seed4; memcpy( rh, &Seed3, 8 ); } return( a ); } else { val01 ^= Seed1; val10 ^= Seed2; if( MsgLen > 64 ) { uint64_t Seed5 = A5HASH_U64_C( 0x082EFA98EC4E6C89 ); uint64_t Seed6 = A5HASH_U64_C( 0x3F84D5B5B5470917 ); uint64_t Seed7 = A5HASH_U64_C( 0x13198A2E03707344 ); uint64_t Seed8 = A5HASH_U64_C( 0xBE5466CF34E90C6C ); do { const uint64_t s1 = Seed1; const uint64_t s3 = Seed3; const uint64_t s5 = Seed5; a5hash_umul128( a5hash_lu64( Msg ) + Seed1, a5hash_lu64( Msg + 32 ) + Seed2, &Seed1, &Seed2 ); Seed1 += val01; Seed2 += Seed8; a5hash_umul128( a5hash_lu64( Msg + 8 ) + Seed3, a5hash_lu64( Msg + 40 ) + Seed4, &Seed3, &Seed4 ); Seed3 += s1; Seed4 += val10; a5hash_umul128( a5hash_lu64( Msg + 16 ) + Seed5, a5hash_lu64( Msg + 48 ) + Seed6, &Seed5, &Seed6 ); a5hash_umul128( a5hash_lu64( Msg + 24 ) + Seed7, a5hash_lu64( Msg + 56 ) + Seed8, &Seed7, &Seed8 ); MsgLen -= 64; Msg += 64; Seed5 += s3; Seed6 += val10; Seed7 += s5; Seed8 += val10; } while( MsgLen > 64 ); Seed1 ^= Seed5; Seed2 ^= Seed6; Seed3 ^= Seed7; Seed4 ^= Seed8; if( MsgLen > 32 ) { goto _tail32; } } else { uint64_t s1; _tail32: s1 = Seed1; a5hash_umul128( a5hash_lu64( Msg ) + Seed1, a5hash_lu64( Msg + 8 ) + Seed2, &Seed1, &Seed2 ); Seed1 += val01; Seed2 += Seed4; a5hash_umul128( a5hash_lu64( Msg + 16 ) + Seed3, a5hash_lu64( Msg + 24 ) + Seed4, &Seed3, &Seed4 ); MsgLen -= 32; Msg += 32; Seed3 += s1; Seed4 += val10; } a = a5hash_lu64( Msg + MsgLen - 16 ); b = a5hash_lu64( Msg + MsgLen - 8 ); if( MsgLen < 17 ) { goto _fin; } c = a5hash_lu64( Msg + MsgLen - 32 ); d = a5hash_lu64( Msg + MsgLen - 24 ); goto _fin_m; } } /** * @brief A5RAND 64-bit pseudo-random number generator. * * A simple, reliable, self-starting, yet efficient PRNG with a 2^64 period. * 0.50 cycles/byte performance. It self-starts in 4 iterations, which is the * suggested "warm-up" period before using its output when seeds are * initialized with an arbitrary value. If initialized with high-quality, * uniformly random value (e.g., from the operating system's entropy or a * hash function's output), the PRNG output is valid from the start. * * @param[in,out] Seed1 Seed value 1. Can be initialized to any value * (even 0). Should not be used as the PRNG value. * @param[in,out] Seed2 Seed value 2. Must be initialized to the same value as * `Seed1`. Should not be used as the PRNG value. * @return The next uniformly random 64-bit value. */ A5HASH_INLINE_F uint64_t a5rand( uint64_t* const Seed1, uint64_t* const Seed2 ) A5HASH_NOEX { uint64_t s1 = *Seed1; uint64_t s2 = *Seed2; a5hash_umul128( s1 + A5HASH_VAL01, s2 + A5HASH_VAL10, &s1, &s2 ); *Seed1 = s1; *Seed2 = s2; return( s1 ^ s2 ); } #if defined( A5HASH_NS ) } // namespace A5HASH_NS #if !defined( A5HASH_NS_CUSTOM ) namespace { using A5HASH_NS :: a5hash_umul128; using A5HASH_NS :: a5hash; using A5HASH_NS :: a5hash32; using A5HASH_NS :: a5hash128; using A5HASH_NS :: a5rand; } // namespace #endif // !defined( A5HASH_NS_CUSTOM ) #endif // defined( A5HASH_NS ) // Defines for Doxygen. #if !defined( A5HASH_NS_CUSTOM ) #define A5HASH_NS_CUSTOM #endif // !defined( A5HASH_NS_CUSTOM ) #undef A5HASH_NS_CUSTOM #undef A5HASH_U64_C #undef A5HASH_NOEX #undef A5HASH_NULL #undef A5HASH_VAL10 #undef A5HASH_VAL01 #undef A5HASH_ICC_GCC #undef A5HASH_GCC_BUILTINS #undef A5HASH_BMI2 #undef A5HASH_STATIC #undef A5HASH_INLINE #undef A5HASH_INLINE_F #endif // A5HASH_INCLUDED