|
||||
File indexing completed on 2025-01-18 09:54:49
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/HashUtils.hh 0007 // TODO for v1.0: rename to Hasher.hh 0008 //---------------------------------------------------------------------------// 0009 #pragma once 0010 0011 #include <cstddef> 0012 #include <functional> 0013 #include <initializer_list> 0014 #include <type_traits> 0015 0016 #include "corecel/Macros.hh" 0017 #include "corecel/cont/Span.hh" 0018 0019 #include "detail/FnvHasher.hh" 0020 0021 namespace celeritas 0022 { 0023 //---------------------------------------------------------------------------// 0024 // TODO: add CMake configuration argument so this can be swapped out with e.g. 0025 // xxHash 0026 using Hasher = detail::FnvHasher<std::size_t>; 0027 0028 //---------------------------------------------------------------------------// 0029 /*! 0030 * Hash a span of contiguous data without padding. 0031 * 0032 * This should generally only be used if \c has_unique_object_representations_v 0033 * is \c true, because e.g. structs have padding so this may result in reading 0034 * uninitialized data or giving two equal structs different hashes. 0035 */ 0036 template<class T, std::size_t N> 0037 std::size_t hash_as_bytes(Span<T const, N> s) 0038 { 0039 std::size_t result{}; 0040 Hasher hash{&result}; 0041 hash(Span<std::byte const>{reinterpret_cast<std::byte const*>(s.data()), 0042 s.size() * sizeof(T)}); 0043 return result; 0044 } 0045 0046 //---------------------------------------------------------------------------// 0047 /*! 0048 * Combine hashes of the given arguments using a fast hash algorithm. 0049 * 0050 * See https://florianjw.de/en/variadic_templates.html for why we constructed 0051 * this as such. By making the variadic template use function argument 0052 * expansion rather than recursion, we can unpack the args in a left-to-right 0053 * order. The `(HASH,0)` construction is to give the unpacked expression a 0054 * return type; and putting these in an `initializer_list` constructor 0055 * guarantees the hashes are evaluated from left to right (unlike a typical 0056 * argument expansion where the orders may be arbitrary). 0057 */ 0058 template<class... Args> 0059 std::size_t hash_combine(Args const&... args) 0060 { 0061 // Construct a hasher and initialize 0062 std::size_t result{}; 0063 [[maybe_unused]] Hasher hash{&result}; 0064 0065 // Hash each one of the arguments sequentially by expanding into an unused 0066 // initializer list. 0067 (void)std::initializer_list<int>{(hash(std::hash<Args>()(args)), 0)...}; 0068 0069 return result; 0070 } 0071 //---------------------------------------------------------------------------// 0072 } // namespace celeritas 0073 0074 //---------------------------------------------------------------------------// 0075 //! \cond 0076 namespace std 0077 { 0078 //---------------------------------------------------------------------------// 0079 /*! 0080 * Hash specialization for celeritas span. 0081 * 0082 * This has three distinct cases: 0083 * 1. Unique object representation: use for structs without padding or floats. 0084 * 2. Floating point values: these will hash uniquely if they're not NaN. 0085 * 3. All other types: combine the hash of their individual values. 0086 */ 0087 template<class T, std::size_t Extent> 0088 struct hash<celeritas::Span<T, Extent>> 0089 { 0090 std::size_t operator()(celeritas::Span<T, Extent> const& s) const 0091 { 0092 if constexpr (std::has_unique_object_representations_v<T>) 0093 { 0094 return celeritas::hash_as_bytes(s); 0095 } 0096 else if constexpr (std::is_floating_point_v<T>) 0097 { 0098 CELER_EXPECT(([&s] { 0099 for (auto const& v : s) 0100 { 0101 if (v != v) 0102 return false; 0103 } 0104 return true; 0105 }())); 0106 return celeritas::hash_as_bytes(s); 0107 } 0108 else 0109 { 0110 std::size_t result{}; 0111 celeritas::Hasher hash{&result}; 0112 for (auto const& v : s) 0113 { 0114 hash(std::hash<std::remove_cv_t<T>>{}(v)); 0115 } 0116 return result; 0117 } 0118 } 0119 }; 0120 0121 //---------------------------------------------------------------------------// 0122 } // namespace std 0123 //! \endcond
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |