xref: /llvm-project/libcxx/test/std/utilities/variant/variant.hash/hash.pass.cpp (revision 33325524f5e80a898a7ae875e208a54af132001b)
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 template <>
26 struct std::hash<::MakeEmptyT> {
27   std::size_t operator()(const ::MakeEmptyT &) const {
28     assert(false);
29     return 0;
30   }
31 };
32 #endif
33 
34 void test_hash_variant() {
35   {
36     using V = std::variant<int, long, int>;
37     using H = std::hash<V>;
38     const V v(std::in_place_index<0>, 42);
39     const V v_copy = v;
40     V v2(std::in_place_index<0>, 100);
41     const H h{};
42     assert(h(v) == h(v));
43     assert(h(v) != h(v2));
44     assert(h(v) == h(v_copy));
45     {
46       ASSERT_SAME_TYPE(decltype(h(v)), std::size_t);
47       static_assert(std::is_copy_constructible<H>::value, "");
48     }
49   }
50   {
51     using V = std::variant<std::monostate, int, long, const char *>;
52     using H = std::hash<V>;
53     const char *str = "hello";
54     const V v0;
55     const V v0_other;
56     const V v1(42);
57     const V v1_other(100);
58     V v2(100l);
59     V v2_other(999l);
60     V v3(str);
61     V v3_other("not hello");
62     const H h{};
63     assert(h(v0) == h(v0));
64     assert(h(v0) == h(v0_other));
65     assert(h(v1) == h(v1));
66     assert(h(v1) != h(v1_other));
67     assert(h(v2) == h(v2));
68     assert(h(v2) != h(v2_other));
69     assert(h(v3) == h(v3));
70     assert(h(v3) != h(v3_other));
71     assert(h(v0) != h(v1));
72     assert(h(v0) != h(v2));
73     assert(h(v0) != h(v3));
74     assert(h(v1) != h(v2));
75     assert(h(v1) != h(v3));
76     assert(h(v2) != h(v3));
77   }
78 #ifndef TEST_HAS_NO_EXCEPTIONS
79   {
80     using V = std::variant<int, MakeEmptyT>;
81     using H = std::hash<V>;
82     V v;
83     makeEmpty(v);
84     V v2;
85     makeEmpty(v2);
86     const H h{};
87     assert(h(v) == h(v2));
88   }
89 #endif
90 }
91 
92 void test_hash_monostate() {
93   using H = std::hash<std::monostate>;
94   const H h{};
95   std::monostate m1{};
96   const std::monostate m2{};
97   assert(h(m1) == h(m1));
98   assert(h(m2) == h(m2));
99   assert(h(m1) == h(m2));
100   {
101     ASSERT_SAME_TYPE(decltype(h(m1)), std::size_t);
102     ASSERT_NOEXCEPT(h(m1));
103     static_assert(std::is_copy_constructible<H>::value, "");
104   }
105   {
106     test_hash_enabled<std::monostate>();
107   }
108 }
109 
110 void test_hash_variant_duplicate_elements() {
111     // Test that the index of the alternative participates in the hash value.
112     using V = std::variant<std::monostate, std::monostate>;
113     using H = std::hash<V>;
114     H h{};
115     const V v1(std::in_place_index<0>);
116     const V v2(std::in_place_index<1>);
117     assert(h(v1) == h(v1));
118     assert(h(v2) == h(v2));
119     LIBCPP_ASSERT(h(v1) != h(v2));
120 }
121 
122 struct A {};
123 struct B {};
124 
125 template <>
126 struct std::hash<B> {
127   std::size_t operator()(B const&) const {
128     return 0;
129   }
130 };
131 
132 void test_hash_variant_enabled() {
133   {
134     test_hash_enabled<std::variant<int> >();
135     test_hash_enabled<std::variant<int*, long, double, const int> >();
136   }
137   {
138     test_hash_disabled<std::variant<int, A>>();
139     test_hash_disabled<std::variant<const A, void*>>();
140   }
141   {
142     test_hash_enabled<std::variant<int, B>>();
143     test_hash_enabled<std::variant<const B, int>>();
144   }
145 }
146 
147 int main(int, char**) {
148   test_hash_variant();
149   test_hash_variant_duplicate_elements();
150   test_hash_monostate();
151   test_hash_variant_enabled();
152 
153   return 0;
154 }
155