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