Make variant's index part of the hash value
authorEric Fiselier <eric@efcs.ca>
Fri, 2 Dec 2016 23:38:31 +0000 (23:38 +0000)
committerEric Fiselier <eric@efcs.ca>
Fri, 2 Dec 2016 23:38:31 +0000 (23:38 +0000)
llvm-svn: 288554

libcxx/include/memory
libcxx/include/variant
libcxx/src/experimental/filesystem/path.cpp
libcxx/test/std/utilities/variant/variant.hash/hash.pass.cpp

index 24361cc..e4cb58b 100644 (file)
@@ -3345,6 +3345,17 @@ struct __scalar_hash<_Tp, 4>
     }
 };
 
+_LIBCPP_INLINE_VISIBILITY
+inline size_t __hash_combine(size_t __lhs, size_t __rhs) _NOEXCEPT {
+    struct _PairT {
+      size_t first;
+      size_t second;
+    };
+    typedef __scalar_hash<_PairT> _HashT;
+    const _PairT __p{__lhs, __rhs};
+    return _HashT()(__p);
+}
+
 template<class _Tp>
 struct _LIBCPP_TYPE_VIS_ONLY hash<_Tp*>
     : public unary_function<_Tp*, size_t>
index 1207b59..45efc78 100644 (file)
@@ -1526,7 +1526,8 @@ struct _LIBCPP_TYPE_VIS_ONLY hash<variant<_Types...>> {
   inline _LIBCPP_INLINE_VISIBILITY
   result_type operator()(const argument_type& __v) const {
     using __variant_detail::__visitation::__variant;
-    return __v.valueless_by_exception()
+    size_t __res =
+        __v.valueless_by_exception()
                ? __v.index()
                : __variant::__visit_alt(
                      [](const auto& __alt) {
@@ -1535,6 +1536,7 @@ struct _LIBCPP_TYPE_VIS_ONLY hash<variant<_Types...>> {
                        return hash<__value_type>{}(__alt.__value);
                      },
                      __v);
+    return __hash_combine(__res, hash<size_t>{}(__v.index()));
   }
 };
 
index 546f3c4..96b81f7 100644 (file)
@@ -6,6 +6,7 @@
 // Source Licenses. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
+#undef NDEBUG
 #include "experimental/filesystem"
 #include "string_view"
 #include "utility"
@@ -390,19 +391,13 @@ int path::__compare(string_view_t __s) const {
 // path.nonmembers
 size_t hash_value(const path& __p) noexcept {
   auto PP = PathParser::CreateBegin(__p.native());
-  struct HashPairT {
-    size_t first;
-    size_t second;
-  };
-  HashPairT hp = {0, 0};
+  size_t hash_value = 0;
   std::hash<string_view> hasher;
-  std::__scalar_hash<decltype(hp)> pair_hasher;
   while (PP) {
-    hp.second = hasher(*PP);
-    hp.first = pair_hasher(hp);
+    hash_value = __hash_combine(hash_value, hasher(*PP));
     ++PP;
   }
-  return hp.first;
+  return hash_value;
 }
 
 ////////////////////////////////////////////////////////////////////////////
index 1745508..d807a7c 100644 (file)
@@ -105,7 +105,20 @@ void test_hash_monostate() {
   }
 }
 
+void test_hash_variant_duplicate_elements() {
+    // Test that the index of the alternative participates in the hash value.
+    using V = std::variant<std::monostate, std::monostate>;
+    using H = std::hash<V>;
+    H h{};
+    const V v1(std::in_place_index<0>);
+    const V v2(std::in_place_index<1>);
+    assert(h(v1) == h(v1));
+    assert(h(v2) == h(v2));
+    LIBCPP_ASSERT(h(v1) != h(v2));
+}
+
 int main() {
   test_hash_variant();
+  test_hash_variant_duplicate_elements();
   test_hash_monostate();
 }