1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14
10 
11 // <variant>
12 
13 // template <class... Types> struct hash<variant<Types...>>;
14 // template <> struct hash<monostate>;
15 
16 #include <cassert>
17 #include <type_traits>
18 #include <variant>
19 
20 #include "test_macros.h"
21 #include "variant_test_helpers.h"
22 #include "poisoned_hash_helper.h"
23 
24 #ifndef TEST_HAS_NO_EXCEPTIONS
25 namespace std {
26 template <> struct hash<::MakeEmptyT> {
operator ()std::hash27   size_t operator()(const ::MakeEmptyT &) const {
28     assert(false);
29     return 0;
30   }
31 };
32 }
33 #endif
34 
test_hash_variant()35 void test_hash_variant() {
36   {
37     using V = std::variant<int, long, int>;
38     using H = std::hash<V>;
39     const V v(std::in_place_index<0>, 42);
40     const V v_copy = v;
41     V v2(std::in_place_index<0>, 100);
42     const H h{};
43     assert(h(v) == h(v));
44     assert(h(v) != h(v2));
45     assert(h(v) == h(v_copy));
46     {
47       ASSERT_SAME_TYPE(decltype(h(v)), std::size_t);
48       static_assert(std::is_copy_constructible<H>::value, "");
49     }
50   }
51   {
52     using V = std::variant<std::monostate, int, long, const char *>;
53     using H = std::hash<V>;
54     const char *str = "hello";
55     const V v0;
56     const V v0_other;
57     const V v1(42);
58     const V v1_other(100);
59     V v2(100l);
60     V v2_other(999l);
61     V v3(str);
62     V v3_other("not hello");
63     const H h{};
64     assert(h(v0) == h(v0));
65     assert(h(v0) == h(v0_other));
66     assert(h(v1) == h(v1));
67     assert(h(v1) != h(v1_other));
68     assert(h(v2) == h(v2));
69     assert(h(v2) != h(v2_other));
70     assert(h(v3) == h(v3));
71     assert(h(v3) != h(v3_other));
72     assert(h(v0) != h(v1));
73     assert(h(v0) != h(v2));
74     assert(h(v0) != h(v3));
75     assert(h(v1) != h(v2));
76     assert(h(v1) != h(v3));
77     assert(h(v2) != h(v3));
78   }
79 #ifndef TEST_HAS_NO_EXCEPTIONS
80   {
81     using V = std::variant<int, MakeEmptyT>;
82     using H = std::hash<V>;
83     V v;
84     makeEmpty(v);
85     V v2;
86     makeEmpty(v2);
87     const H h{};
88     assert(h(v) == h(v2));
89   }
90 #endif
91 }
92 
test_hash_monostate()93 void test_hash_monostate() {
94   using H = std::hash<std::monostate>;
95   const H h{};
96   std::monostate m1{};
97   const std::monostate m2{};
98   assert(h(m1) == h(m1));
99   assert(h(m2) == h(m2));
100   assert(h(m1) == h(m2));
101   {
102     ASSERT_SAME_TYPE(decltype(h(m1)), std::size_t);
103     ASSERT_NOEXCEPT(h(m1));
104     static_assert(std::is_copy_constructible<H>::value, "");
105   }
106   {
107     test_hash_enabled_for_type<std::monostate>();
108   }
109 }
110 
test_hash_variant_duplicate_elements()111 void test_hash_variant_duplicate_elements() {
112     // Test that the index of the alternative participates in the hash value.
113     using V = std::variant<std::monostate, std::monostate>;
114     using H = std::hash<V>;
115     H h{};
116     const V v1(std::in_place_index<0>);
117     const V v2(std::in_place_index<1>);
118     assert(h(v1) == h(v1));
119     assert(h(v2) == h(v2));
120     LIBCPP_ASSERT(h(v1) != h(v2));
121 }
122 
123 struct A {};
124 struct B {};
125 
126 namespace std {
127 
128 template <>
129 struct hash<B> {
operator ()std::hash130   size_t operator()(B const&) const {
131     return 0;
132   }
133 };
134 
135 }
136 
test_hash_variant_enabled()137 void test_hash_variant_enabled() {
138   {
139     test_hash_enabled_for_type<std::variant<int> >();
140     test_hash_enabled_for_type<std::variant<int*, long, double, const int> >();
141   }
142   {
143     test_hash_disabled_for_type<std::variant<int, A>>();
144     test_hash_disabled_for_type<std::variant<const A, void*>>();
145   }
146   {
147     test_hash_enabled_for_type<std::variant<int, B>>();
148     test_hash_enabled_for_type<std::variant<const B, int>>();
149   }
150 }
151 
main(int,char **)152 int main(int, char**) {
153   test_hash_variant();
154   test_hash_variant_duplicate_elements();
155   test_hash_monostate();
156   test_hash_variant_enabled();
157 
158   return 0;
159 }
160