aboutsummaryrefslogtreecommitdiff
path: root/absl/hash/internal/hash.h
diff options
context:
space:
mode:
authorGravatar Milad Fa <46688537+miladfarca@users.noreply.github.com>2021-10-06 17:20:14 -0400
committerGravatar GitHub <noreply@github.com>2021-10-06 17:20:14 -0400
commitae0f4c266095c9003786cd571bc1fb72544104a1 (patch)
tree471d3ba0b4adca43f55507101f3101575706b466 /absl/hash/internal/hash.h
parentb9b925341f9e90f5e7aa0cf23f036c29c7e454eb (diff)
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.h52
1 files changed, 47 insertions, 5 deletions
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index e5af0ac..b1e33ca 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
// -----------------------------------------------------------------------------