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