![]() |
|
|||
File indexing completed on 2025-09-16 08:52:42
0001 //------------------------------- -*- C++ -*- -------------------------------// 0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details 0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT) 0004 //---------------------------------------------------------------------------// 0005 //! \file corecel/math/detail/FnvHasher.hh 0006 //---------------------------------------------------------------------------// 0007 #pragma once 0008 0009 #include <cstddef> 0010 #include <cstdint> 0011 #include <type_traits> 0012 0013 #include "corecel/Assert.hh" 0014 #include "corecel/cont/Span.hh" 0015 0016 namespace celeritas 0017 { 0018 namespace detail 0019 { 0020 //---------------------------------------------------------------------------// 0021 /*! 0022 * Implementation of the FNV-1a algorithm. 0023 * 0024 * From http://www.isthe.com/chongo/tech/comp/fnv: 0025 * <blockquote> 0026 The basis of the FNV hash algorithm was taken from an idea sent as 0027 reviewer comments to the IEEE POSIX P1003.2 committee by Glenn Fowler and 0028 Phong Vo back in 1991. In a subsequent ballot round: Landon Curt Noll 0029 improved on their algorithm. Some people tried this hash and found that it 0030 worked rather well. In an EMail message to Landon, they named it the 0031 ``Fowler/Noll/Vo'' or FNV hash. 0032 0033 FNV hashes are designed to be fast while maintaining a low collision rate. 0034 The FNV speed allows one to quickly hash lots of data while maintaining a 0035 reasonable collision rate. The high dispersion of the FNV hashes makes 0036 them well suited for hashing nearly identical strings such as URLs, 0037 hostnames, filenames, text, IP addresses, etc. 0038 </blockquote> 0039 * 0040 * High dispersion, quick hashes for similar data is often needed for hash 0041 * tables of pairs of similar values (or strings). 0042 * 0043 * This hashing algorithm is *not* very fast: each byte requires an integer 0044 * addition and multiply! 0045 */ 0046 template<std::size_t S> 0047 struct FnvHashTraits; 0048 0049 // 32-bit specialization 0050 template<> 0051 struct FnvHashTraits<4ul> 0052 { 0053 using value_type = std::uint32_t; 0054 static constexpr value_type initial_basis = 0x811c9dc5u; 0055 static constexpr value_type magic_prime = 0x01000193u; 0056 }; 0057 0058 // 64-bit specialization 0059 template<> 0060 struct FnvHashTraits<8ul> 0061 { 0062 using value_type = std::uint64_t; 0063 static constexpr value_type initial_basis = 0xcbf29ce484222325ull; 0064 static constexpr value_type magic_prime = 0x00000100000001b3ull; 0065 }; 0066 0067 //---------------------------------------------------------------------------// 0068 /*! 0069 * Use a fast algorithm to construct a well-distributed hash. 0070 * 0071 * \tparam T integer type to use for hashing. 0072 * 0073 * This utility class is meant for processing keys in hash tables with native 0074 * integer size. 0075 */ 0076 template<class T> 0077 class FnvHasher 0078 { 0079 static_assert(std::is_unsigned<T>::value, 0080 "Hash type must be an unsigned integer"); 0081 0082 public: 0083 //@{ 0084 //! \name Type aliases 0085 using value_type = T; 0086 //@} 0087 0088 public: 0089 // Construct with a reference to the hashed value which we initialize 0090 explicit inline FnvHasher(value_type* hash_result); 0091 0092 // Hash a byte of data 0093 CELER_FORCEINLINE void operator()(std::byte b) const; 0094 0095 // Hash a size_t (useful for std::hash integration) 0096 inline void operator()(std::size_t value) const; 0097 0098 // Hash a span of bytes 0099 inline void operator()(Span<std::byte const> s) const; 0100 0101 private: 0102 using TraitsT = FnvHashTraits<sizeof(T)>; 0103 0104 // Current hash, starting with a prescribed initial value 0105 value_type* hash_; 0106 }; 0107 0108 //---------------------------------------------------------------------------// 0109 /*! 0110 * Initialize the result on construction. 0111 */ 0112 template<class T> 0113 FnvHasher<T>::FnvHasher(value_type* hash_result) : hash_(hash_result) 0114 { 0115 CELER_EXPECT(hash_); 0116 *hash_ = TraitsT::initial_basis; 0117 } 0118 0119 //---------------------------------------------------------------------------// 0120 /*! 0121 * Hash a byte of data. 0122 * 0123 * The FNV1a algorithm is very simple. 0124 */ 0125 template<class T> 0126 CELER_FORCEINLINE void FnvHasher<T>::operator()(std::byte b) const 0127 { 0128 // XOR hash with the current byte 0129 *hash_ ^= std::to_integer<T>(b); 0130 // Multiply by magic prime 0131 *hash_ *= TraitsT::magic_prime; 0132 } 0133 0134 //---------------------------------------------------------------------------// 0135 /*! 0136 * Hash a size_t. 0137 * 0138 * This is useful for std::hash integration. 0139 */ 0140 template<class T> 0141 void FnvHasher<T>::operator()(std::size_t value) const 0142 { 0143 for (std::size_t i = 0; i < sizeof(std::size_t); ++i) 0144 { 0145 (*this)(static_cast<std::byte>(value & 0xffu)); 0146 value >>= 8; 0147 } 0148 } 0149 0150 //---------------------------------------------------------------------------// 0151 /*! 0152 * Hash a span of bytes. 0153 */ 0154 template<class T> 0155 void FnvHasher<T>::operator()(Span<std::byte const> bytes) const 0156 { 0157 for (auto b : bytes) 0158 { 0159 (*this)(b); 0160 } 0161 } 0162 0163 //---------------------------------------------------------------------------// 0164 // DEDUCTION GUIDES 0165 //---------------------------------------------------------------------------// 0166 0167 template<class T> 0168 FnvHasher(T*) -> FnvHasher<T>; 0169 0170 //---------------------------------------------------------------------------// 0171 } // namespace detail 0172 } // namespace celeritas
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |