Back to home page

EIC code displayed by LXR

 
 

    


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