Back to home page

EIC code displayed by LXR

 
 

    


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