about summary refs log tree commit diff
path: root/absl/hash
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2019-03-08T22·06-0800
committerDerek Mauro <dmauro@google.com>2019-03-08T22·11-0500
commit88a152ae747c3c42dc9167d46c590929b048d436 (patch)
treee0858f1abd59c78a59b7d8449b7fb7c76904c88c /absl/hash
parentc1cecb25a94c075725e9d2640f6b978a8f61957b (diff)
Export of internal Abseil changes.
--
5dc8d7504b7c11710b19365a6582c288c8992366 by Derek Mauro <dmauro@google.com>:

Fix constexpr Span::last under MSVC and add Span constexpr tests.

PiperOrigin-RevId: 237515952

--
5ea8c146e653bbc49ff7e698699478242df7de35 by Derek Mauro <dmauro@google.com>:

Implement Span::first and Span::last from C++20.
https://github.com/abseil/abseil-cpp/pull/274

PiperOrigin-RevId: 237494399

--
08db3417f1d8fe4556255d57a2f0df51b09bdd9a by Derek Mauro <dmauro@google.com>:

HTTPS in more URLs.

PiperOrigin-RevId: 237486823

--
83ec63a7f8e47b62af619546f9f7b3bf72e74e86 by Derek Mauro <dmauro@google.com>:

Changed HTTP URLs to HTTPS where possible.
https://github.com/abseil/abseil-cpp/pull/270

PiperOrigin-RevId: 237445310

--
220bf279c14cb31efa239500d1a70e0ac0c32e3c by Abseil Team <absl-team@google.com>:

Support parsing decltype(nullptr) as a type.

PiperOrigin-RevId: 237336739

--
ced234bbe78f5d495c3f6f6a9c2e0a95f7c080a5 by Gennadiy Rozental <rogeeff@google.com>:

Introduce internal interface for setting environment variable value in scope

PiperOrigin-RevId: 237275806

--
1f1acb4e294af24d9f7598e85163d5e1d9958ae9 by Samuel Benzaquen <sbenza@google.com>:

Avoid using aliases in the SFINAE expressions to make it more compatible with MSVC.
Turn on the tests in MSVC.

PiperOrigin-RevId: 237261456

--
06cf7de6250a0572ef90fa1176f742ca0451ce71 by Derek Mauro <dmauro@google.com>:

Fix unused variable warning.

PiperOrigin-RevId: 237108006
GitOrigin-RevId: 5dc8d7504b7c11710b19365a6582c288c8992366
Change-Id: Ife5182c80942945c4e8700844c8febb482d6ad82
Diffstat (limited to 'absl/hash')
-rw-r--r--absl/hash/hash_test.cc22
-rw-r--r--absl/hash/internal/hash.h161
2 files changed, 72 insertions, 111 deletions
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index d9ebd30f69c4..a2430e7a653d 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -165,9 +165,6 @@ TEST(HashValueTest, PointerAlignment) {
   }
 }
 
-// TODO(EricWF): MSVC 15 has a bug that causes it to incorrectly evaluate the
-// SFINAE in internal/hash.h, causing this test to fail.
-#if !defined(_MSC_VER)
 TEST(HashValueTest, PairAndTuple) {
   EXPECT_TRUE((is_hashable<std::pair<int, int>>::value));
   EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value));
@@ -196,7 +193,6 @@ TEST(HashValueTest, PairAndTuple) {
       std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9),
       std::forward_as_tuple(0, 0, -42))));
 }
-#endif  // !defined(_MSC_VER)
 
 TEST(HashValueTest, CombineContiguousWorks) {
   std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)};
@@ -304,16 +300,12 @@ TEST(HashValueTest, Strings) {
             SpyHash(absl::string_view("ABC")));
 }
 
-// TODO(EricWF): MSVC 15 has a bug that causes it to incorrectly evaluate the
-// SFINAE in internal/hash.h, causing this test to fail.
-#if !defined(_MSC_VER)
 TEST(HashValueTest, StdArray) {
   EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
 
   EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
       std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}})));
 }
-#endif  // !defined(_MSC_VER)
 
 TEST(HashValueTest, StdBitset) {
   EXPECT_TRUE((is_hashable<std::bitset<257>>::value));
@@ -414,9 +406,6 @@ TEST(HashValueTest, Variant) {
 #endif
 }
 
-// TODO(EricWF): MSVC 15 has a bug that causes it to incorrectly evaluate the
-// SFINAE in internal/hash.h, causing this test to fail.
-#if !defined(_MSC_VER)
 TEST(HashValueTest, Maps) {
   EXPECT_TRUE((is_hashable<std::map<int, std::string>>::value));
 
@@ -433,7 +422,6 @@ TEST(HashValueTest, Maps) {
       MM{{0, "foo"}, {42, "bar"}}, MM{{1, "foo"}, {42, "bar"}},
       MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}})));
 }
-#endif  // !defined(_MSC_VER)
 
 template <typename T, typename = void>
 struct IsHashCallble : std::false_type {};
@@ -511,8 +499,16 @@ struct CombineVariadic {
                              Int(4));
   }
 };
+enum class InvokeTag {
+  kUniquelyRepresented,
+  kHashValue,
+#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+  kLegacyHash,
+#endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+  kStdHash,
+  kNone
+};
 
-using InvokeTag = absl::hash_internal::InvokeHashTag;
 template <InvokeTag T>
 using InvokeTagConstant = std::integral_constant<InvokeTag, T>;
 
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index 2a45bc84ab18..9ab9890143dd 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -535,20 +535,6 @@ hash_range_or_bytes(H hash_state, const T* data, size_t size) {
   return hash_state;
 }
 
-// InvokeHashTag
-//
-// InvokeHash(H, const T&) invokes the appropriate hash implementation for a
-// hasher of type `H` and a value of type `T`. If `T` is not hashable, there
-// will be no matching overload of InvokeHash().
-// Note: Some platforms (eg MSVC) do not support the detect idiom on
-// std::hash. In those platforms the last fallback will be std::hash and
-// InvokeHash() will always have a valid overload even if std::hash<T> is not
-// valid.
-//
-// We try the following options in order:
-//   * If is_uniquely_represented, hash bytes directly.
-//   * ADL AbslHashValue(H, const T&) call.
-//   * std::hash<T>
 #if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \
     ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1
@@ -556,23 +542,15 @@ hash_range_or_bytes(H hash_state, const T* data, size_t size) {
 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0
 #endif
 
-enum class InvokeHashTag {
-  kUniquelyRepresented,
-  kHashValue,
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-  kLegacyHash,
-#endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-  kStdHash,
-  kNone
-};
-
 // HashSelect
 //
 // Type trait to select the appropriate hash implementation to use.
-// HashSelect<T>::value is an instance of InvokeHashTag that indicates the best
-// available hashing mechanism.
-// See `Note` above about MSVC.
-template <typename T>
+// HashSelect::type<T> will give the proper hash implementation, to be invoked
+// as:
+//   HashSelect::type<T>::Invoke(state, value)
+// Also, HashSelect::type<T>::value is a boolean equal to `true` if there is a
+// valid `Invoke` function. Types that are not hashable will have a ::value of
+// `false`.
 struct HashSelect {
  private:
   struct State : HashStateBase<State> {
@@ -581,89 +559,75 @@ struct HashSelect {
     using State::HashStateBase::combine_contiguous;
   };
 
-  // `Probe<V, Tag>::value` evaluates to `V<T>::value` if it is a valid
-  // expression, and `false` otherwise.
-  // `Probe<V, Tag>::tag` always evaluates to `Tag`.
-  template <template <typename> class V, InvokeHashTag Tag>
-  struct Probe {
-   private:
-    template <typename U, typename std::enable_if<V<U>::value, int>::type = 0>
-    static std::true_type Test(int);
-    template <typename U>
-    static std::false_type Test(char);
-
-   public:
-    static constexpr InvokeHashTag kTag = Tag;
-    static constexpr bool value = decltype(
-        Test<absl::remove_const_t<absl::remove_reference_t<T>>>(0))::value;
+  struct UniquelyRepresentedProbe {
+    template <typename H, typename T>
+    static auto Invoke(H state, const T& value)
+        -> absl::enable_if_t<is_uniquely_represented<T>::value, H> {
+      return hash_internal::hash_bytes(std::move(state), value);
+    }
   };
 
-  template <typename U>
-  using ProbeUniquelyRepresented = is_uniquely_represented<U>;
-
-  template <typename U>
-  using ProbeHashValue =
-      std::is_same<State, decltype(AbslHashValue(std::declval<State>(),
-                                                 std::declval<const U&>()))>;
+  struct HashValueProbe {
+    template <typename H, typename T>
+    static auto Invoke(H state, const T& value) -> absl::enable_if_t<
+        std::is_same<H,
+                     decltype(AbslHashValue(std::move(state), value))>::value,
+        H> {
+      return AbslHashValue(std::move(state), value);
+    }
+  };
 
+  struct LegacyHashProbe {
 #if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-  template <typename U>
-  using ProbeLegacyHash =
-      std::is_convertible<decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<
-                                   U>()(std::declval<const U&>())),
-                          size_t>;
+    template <typename H, typename T>
+    static auto Invoke(H state, const T& value) -> absl::enable_if_t<
+        std::is_convertible<
+            decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>()(value)),
+            size_t>::value,
+        H> {
+      return hash_internal::hash_bytes(
+          std::move(state),
+          ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value));
+    }
 #endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+  };
 
-  template <typename U>
-  using ProbeStdHash = absl::type_traits_internal::IsHashable<U>;
+  struct StdHashProbe {
+    template <typename H, typename T>
+    static auto Invoke(H state, const T& value)
+        -> absl::enable_if_t<type_traits_internal::IsHashable<T>::value, H> {
+      return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value));
+    }
+  };
 
-  template <typename U>
-  using ProbeNone = std::true_type;
+  template <typename Hash, typename T>
+  struct Probe : Hash {
+   private:
+    template <typename H, typename = decltype(H::Invoke(
+                              std::declval<State>(), std::declval<const T&>()))>
+    static std::true_type Test(int);
+    template <typename U>
+    static std::false_type Test(char);
+
+   public:
+    static constexpr bool value = decltype(Test<Hash>(0))::value;
+  };
 
  public:
   // Probe each implementation in order.
   // disjunction provides short circuting wrt instantiation.
-  static constexpr InvokeHashTag value = absl::disjunction<
-      Probe<ProbeUniquelyRepresented, InvokeHashTag::kUniquelyRepresented>,
-      Probe<ProbeHashValue, InvokeHashTag::kHashValue>,
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-      Probe<ProbeLegacyHash, InvokeHashTag::kLegacyHash>,
-#endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-      Probe<ProbeStdHash, InvokeHashTag::kStdHash>,
-      Probe<ProbeNone, InvokeHashTag::kNone>>::kTag;
+  template <typename T>
+  using Apply = absl::disjunction<         //
+      Probe<UniquelyRepresentedProbe, T>,  //
+      Probe<HashValueProbe, T>,            //
+      Probe<LegacyHashProbe, T>,           //
+      Probe<StdHashProbe, T>,              //
+      std::false_type>;
 };
 
 template <typename T>
-struct is_hashable : std::integral_constant<bool, HashSelect<T>::value !=
-                                                      InvokeHashTag::kNone> {};
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kUniquelyRepresented,
-                  H>
-InvokeHash(H state, const T& value) {
-  return hash_internal::hash_bytes(std::move(state), value);
-}
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kHashValue, H>
-InvokeHash(H state, const T& value) {
-  return AbslHashValue(std::move(state), value);
-}
-
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kLegacyHash, H>
-InvokeHash(H state, const T& value) {
-  return hash_internal::hash_bytes(
-      std::move(state), ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value));
-}
-#endif  // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kStdHash, H>
-InvokeHash(H state, const T& value) {
-  return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value));
-}
+struct is_hashable
+    : std::integral_constant<bool, HashSelect::template Apply<T>::value> {};
 
 // CityHashState
 class CityHashState : public HashStateBase<CityHashState> {
@@ -873,7 +837,8 @@ struct Hash
 template <typename H>
 template <typename T, typename... Ts>
 H HashStateBase<H>::combine(H state, const T& value, const Ts&... values) {
-  return H::combine(hash_internal::InvokeHash(std::move(state), value),
+  return H::combine(hash_internal::HashSelect::template Apply<T>::Invoke(
+                        std::move(state), value),
                     values...);
 }