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 #ifndef SUPPORT_POISONED_HASH_HELPER_H 11 #define SUPPORT_POISONED_HASH_HELPER_H 12 13 #include <functional> 14 #include <cassert> 15 #include <cstddef> 16 #include <type_traits> 17 #include <utility> 18 19 #include "test_macros.h" 20 #include "type_algorithms.h" 21 22 template <class Hash, class Key, class Res = decltype(std::declval<Hash&>()(std::declval<Key>()))> 23 constexpr bool can_hash_impl(int) { 24 return std::is_same<Res, std::size_t>::value; 25 } 26 template <class, class> 27 constexpr bool can_hash_impl(long) { 28 return false; 29 } 30 template <class Hash, class Key> 31 constexpr bool can_hash() { 32 return can_hash_impl<Hash, Key>(0); 33 } 34 35 template <class To> 36 struct ConvertibleToSimple { 37 operator To() const { return To{}; } 38 }; 39 40 template <class To> 41 struct ConvertibleTo { 42 To to{}; 43 operator To&() & { return to; } 44 operator To const&() const& { return to; } 45 operator To&&() && { return std::move(to); } 46 operator To const&&() const&& { return std::move(to); } 47 }; 48 49 // Test that the specified Hash meets the requirements of an enabled hash 50 template <class Key, class Hash = std::hash<Key>> 51 TEST_CONSTEXPR_CXX20 void test_hash_enabled(Key const& key = Key{}) { 52 static_assert(std::is_destructible<Hash>::value, ""); 53 54 // Enabled hash requirements 55 static_assert(std::is_default_constructible<Hash>::value, ""); 56 static_assert(std::is_copy_constructible<Hash>::value, ""); 57 static_assert(std::is_move_constructible<Hash>::value, ""); 58 static_assert(std::is_copy_assignable<Hash>::value, ""); 59 static_assert(std::is_move_assignable<Hash>::value, ""); 60 61 #if TEST_STD_VER > 14 62 static_assert(std::is_swappable<Hash>::value, ""); 63 #elif defined(_LIBCPP_VERSION) 64 static_assert(std::__is_swappable_v<Hash>, ""); 65 #endif 66 67 // Hashable requirements 68 static_assert(can_hash<Hash, Key&>(), ""); 69 static_assert(can_hash<Hash, Key const&>(), ""); 70 static_assert(can_hash<Hash, Key&&>(), ""); 71 static_assert(can_hash<Hash const, Key&>(), ""); 72 static_assert(can_hash<Hash const, Key const&>(), ""); 73 static_assert(can_hash<Hash const, Key&&>(), ""); 74 75 static_assert(can_hash<Hash, ConvertibleToSimple<Key>&>(), ""); 76 static_assert(can_hash<Hash, ConvertibleToSimple<Key> const&>(), ""); 77 static_assert(can_hash<Hash, ConvertibleToSimple<Key>&&>(), ""); 78 79 static_assert(can_hash<Hash, ConvertibleTo<Key>&>(), ""); 80 static_assert(can_hash<Hash, ConvertibleTo<Key> const&>(), ""); 81 static_assert(can_hash<Hash, ConvertibleTo<Key>&&>(), ""); 82 static_assert(can_hash<Hash, ConvertibleTo<Key> const&&>(), ""); 83 84 const Hash h{}; 85 assert(h(key) == h(key)); 86 } 87 88 // Test that the specified Hash meets the requirements of a disabled hash. 89 template <class Key, class Hash = std::hash<Key>> 90 void test_hash_disabled() { 91 // Disabled hash requirements 92 static_assert(!std::is_default_constructible<Hash>::value, ""); 93 static_assert(!std::is_copy_constructible<Hash>::value, ""); 94 static_assert(!std::is_move_constructible<Hash>::value, ""); 95 static_assert(!std::is_copy_assignable<Hash>::value, ""); 96 static_assert(!std::is_move_assignable<Hash>::value, ""); 97 98 static_assert( 99 !std::is_function<typename std::remove_pointer<typename std::remove_reference<Hash>::type>::type>::value, ""); 100 101 // Hashable requirements 102 static_assert(!can_hash<Hash, Key&>(), ""); 103 static_assert(!can_hash<Hash, Key const&>(), ""); 104 static_assert(!can_hash<Hash, Key&&>(), ""); 105 static_assert(!can_hash<Hash const, Key&>(), ""); 106 static_assert(!can_hash<Hash const, Key const&>(), ""); 107 static_assert(!can_hash<Hash const, Key&&>(), ""); 108 109 static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&>(), ""); 110 static_assert(!can_hash<Hash, ConvertibleToSimple<Key> const&>(), ""); 111 static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&&>(), ""); 112 113 static_assert(!can_hash<Hash, ConvertibleTo<Key>&>(), ""); 114 static_assert(!can_hash<Hash, ConvertibleTo<Key> const&>(), ""); 115 static_assert(!can_hash<Hash, ConvertibleTo<Key>&&>(), ""); 116 static_assert(!can_hash<Hash, ConvertibleTo<Key> const&&>(), ""); 117 } 118 119 enum Enum {}; 120 enum EnumClass : bool {}; 121 struct Class {}; 122 123 // Each header that declares the std::hash template provides enabled 124 // specializations of std::hash for std::nullptr_t and all cv-unqualified 125 // arithmetic, enumeration, and pointer types. 126 #if TEST_STD_VER >= 17 127 using MaybeNullptr = types::type_list<std::nullptr_t>; 128 #else 129 using MaybeNullptr = types::type_list<>; 130 #endif 131 using LibraryHashTypes = types:: 132 concatenate_t<types::arithmetic_types, types::type_list<Enum, EnumClass, void*, void const*, Class*>, MaybeNullptr>; 133 134 struct TestHashEnabled { 135 template <class T> 136 void operator()() const { 137 test_hash_enabled<T>(); 138 } 139 }; 140 141 // Test that each of the library hash specializations for arithmetic types, 142 // enum types, and pointer types are available and enabled. 143 template <class Types = LibraryHashTypes> 144 void test_library_hash_specializations_available() { 145 types::for_each(Types(), TestHashEnabled()); 146 } 147 148 #endif // SUPPORT_POISONED_HASH_HELPER_H 149