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