diff options
author | Milad Fa <46688537+miladfarca@users.noreply.github.com> | 2021-10-06 17:20:14 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-06 17:20:14 -0400 |
commit | ae0f4c266095c9003786cd571bc1fb72544104a1 (patch) | |
tree | 471d3ba0b4adca43f55507101f3101575706b466 /absl/hash/internal/hash.h | |
parent | b9b925341f9e90f5e7aa0cf23f036c29c7e454eb (diff) | |
download | abseil-ae0f4c266095c9003786cd571bc1fb72544104a1.tar.gz abseil-ae0f4c266095c9003786cd571bc1fb72544104a1.tar.bz2 abseil-ae0f4c266095c9003786cd571bc1fb72544104a1.zip |
Fix hashing on big endian platforms (#1028)
Avoid using libstdc++'s implementation of std::hash<std::bitset> and
std::hash<std::vector> on big endian platforms in the implementation
of absl::Hash.
This is a workaround for a buggy implementation that results in many
collisions.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102531
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98731
Diffstat (limited to 'absl/hash/internal/hash.h')
-rw-r--r-- | absl/hash/internal/hash.h | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index e5af0ac0..b1e33caf 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h @@ -21,6 +21,7 @@ #include <algorithm> #include <array> +#include <bitset> #include <cmath> #include <cstring> #include <deque> @@ -489,8 +490,9 @@ typename std::enable_if<is_hashable<T>::value, H>::type AbslHashValue( // AbslHashValue for hashing std::vector // -// Do not use this for vector<bool>. It does not have a .data(), and a fallback -// for std::hash<> is most likely faster. +// Do not use this for vector<bool> on platforms that have a working +// implementation of std::hash. It does not have a .data(), and a fallback for +// std::hash<> is most likely faster. template <typename H, typename T, typename Allocator> typename std::enable_if<is_hashable<T>::value && !std::is_same<T, bool>::value, H>::type @@ -500,6 +502,27 @@ AbslHashValue(H hash_state, const std::vector<T, Allocator>& vector) { vector.size()); } +#if defined(ABSL_IS_BIG_ENDIAN) && \ + (defined(__GLIBCXX__) || defined(__GLIBCPP__)) +// AbslHashValue for hashing std::vector<bool> +// +// std::hash in libstdc++ does not work correctly with vector<bool> on Big +// Endian platforms therefore we need to implement a custom AbslHashValue for +// it. More details on the bug: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102531 +template <typename H, typename T, typename Allocator> +typename std::enable_if<is_hashable<T>::value && std::is_same<T, bool>::value, + H>::type +AbslHashValue(H hash_state, const std::vector<T, Allocator>& vector) { + typename H::AbslInternalPiecewiseCombiner combiner; + for (const auto& i : vector) { + unsigned char c = static_cast<unsigned char>(i); + hash_state = combiner.add_buffer(std::move(hash_state), &c, sizeof(c)); + } + return H::combine(combiner.finalize(std::move(hash_state)), vector.size()); +} +#endif + // ----------------------------------------------------------------------------- // AbslHashValue for Ordered Associative Containers // ----------------------------------------------------------------------------- @@ -592,9 +615,28 @@ AbslHashValue(H hash_state, const absl::variant<T...>& v) { // AbslHashValue for Other Types // ----------------------------------------------------------------------------- -// AbslHashValue for hashing std::bitset is not defined, for the same reason as -// for vector<bool> (see std::vector above): It does not expose the raw bytes, -// and a fallback to std::hash<> is most likely faster. +// AbslHashValue for hashing std::bitset is not defined on Little Endian +// platforms, for the same reason as for vector<bool> (see std::vector above): +// It does not expose the raw bytes, and a fallback to std::hash<> is most +// likely faster. + +#if defined(ABSL_IS_BIG_ENDIAN) && \ + (defined(__GLIBCXX__) || defined(__GLIBCPP__)) +// AbslHashValue for hashing std::bitset +// +// std::hash in libstdc++ does not work correctly with std::bitset on Big Endian +// platforms therefore we need to implement a custom AbslHashValue for it. More +// details on the bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102531 +template <typename H, size_t N> +H AbslHashValue(H hash_state, const std::bitset<N>& set) { + typename H::AbslInternalPiecewiseCombiner combiner; + for (int i = 0; i < N; i++) { + unsigned char c = static_cast<unsigned char>(set[i]); + hash_state = combiner.add_buffer(std::move(hash_state), &c, sizeof(c)); + } + return H::combine(combiner.finalize(std::move(hash_state)), N); +} +#endif // ----------------------------------------------------------------------------- |