Home | History | Annotate | Download | only in variant.hash
      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
     27 namespace std {
     28 template <> struct hash<::MakeEmptyT> {
     29   size_t operator()(const ::MakeEmptyT &) const {
     30     assert(false);
     31     return 0;
     32   }
     33 };
     34 }
     35 #endif
     36 
     37 void 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 
     95 void 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     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 template <>
    128 struct std::hash<B> {
    129   size_t operator()(B const&) const {
    130     return 0;
    131   }
    132 };
    133 
    134 void test_hash_variant_enabled() {
    135   {
    136     test_hash_enabled_for_type<std::variant<int> >();
    137     test_hash_enabled_for_type<std::variant<int*, long, double, const int> >();
    138   }
    139   {
    140     test_hash_disabled_for_type<std::variant<int, A>>();
    141     test_hash_disabled_for_type<std::variant<const A, void*>>();
    142   }
    143   {
    144     test_hash_enabled_for_type<std::variant<int, B>>();
    145     test_hash_enabled_for_type<std::variant<const B, int>>();
    146   }
    147 }
    148 
    149 int main() {
    150   test_hash_variant();
    151   test_hash_variant_duplicate_elements();
    152   test_hash_monostate();
    153   test_hash_variant_enabled();
    154 }
    155