1cc89063bSNico Weber // -*- C++ -*- 2cc89063bSNico Weber //===----------------------------------------------------------------------===// 3cc89063bSNico Weber // 4cc89063bSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5cc89063bSNico Weber // See https://llvm.org/LICENSE.txt for license information. 6cc89063bSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7cc89063bSNico Weber // 8cc89063bSNico Weber //===----------------------------------------------------------------------===// 9480cd780SLouis Dionne 10cc89063bSNico Weber #ifndef SUPPORT_POISONED_HASH_HELPER_H 11cc89063bSNico Weber #define SUPPORT_POISONED_HASH_HELPER_H 12cc89063bSNico Weber 13*33325524SLouis Dionne #include <functional> 14cc89063bSNico Weber #include <cassert> 15fb855eb9SMark de Wever #include <cstddef> 166adbc83eSChristopher Di Bella #include <type_traits> 1769d5a666SChristopher Di Bella #include <utility> 18cc89063bSNico Weber 19cc89063bSNico Weber #include "test_macros.h" 20*33325524SLouis Dionne #include "type_algorithms.h" 21cc89063bSNico Weber 22*33325524SLouis Dionne template <class Hash, class Key, class Res = decltype(std::declval<Hash&>()(std::declval<Key>()))> 23*33325524SLouis Dionne constexpr bool can_hash_impl(int) { 24*33325524SLouis Dionne return std::is_same<Res, std::size_t>::value; 25cc89063bSNico Weber } 26*33325524SLouis Dionne template <class, class> 27*33325524SLouis Dionne constexpr bool can_hash_impl(long) { 28*33325524SLouis Dionne return false; 29*33325524SLouis Dionne } 30cc89063bSNico Weber template <class Hash, class Key> 31*33325524SLouis Dionne constexpr bool can_hash() { 32*33325524SLouis Dionne return can_hash_impl<Hash, Key>(0); 33cc89063bSNico Weber } 34cc89063bSNico Weber 35cc89063bSNico Weber template <class To> 36cc89063bSNico Weber struct ConvertibleToSimple { 37*33325524SLouis Dionne operator To() const { return To{}; } 38cc89063bSNico Weber }; 39cc89063bSNico Weber 40cc89063bSNico Weber template <class To> 41cc89063bSNico Weber struct ConvertibleTo { 42cc89063bSNico Weber To to{}; 43cc89063bSNico Weber operator To&() & { return to; } 44cc89063bSNico Weber operator To const&() const& { return to; } 45cc89063bSNico Weber operator To&&() && { return std::move(to); } 46cc89063bSNico Weber operator To const&&() const&& { return std::move(to); } 47cc89063bSNico Weber }; 48cc89063bSNico Weber 49*33325524SLouis Dionne // Test that the specified Hash meets the requirements of an enabled hash 50*33325524SLouis Dionne template <class Key, class Hash = std::hash<Key>> 51*33325524SLouis Dionne TEST_CONSTEXPR_CXX20 void test_hash_enabled(Key const& key = Key{}) { 52cc89063bSNico Weber static_assert(std::is_destructible<Hash>::value, ""); 53*33325524SLouis Dionne 54cc89063bSNico Weber // Enabled hash requirements 55cc89063bSNico Weber static_assert(std::is_default_constructible<Hash>::value, ""); 56cc89063bSNico Weber static_assert(std::is_copy_constructible<Hash>::value, ""); 57cc89063bSNico Weber static_assert(std::is_move_constructible<Hash>::value, ""); 58cc89063bSNico Weber static_assert(std::is_copy_assignable<Hash>::value, ""); 59cc89063bSNico Weber static_assert(std::is_move_assignable<Hash>::value, ""); 60cc89063bSNico Weber 61cc89063bSNico Weber #if TEST_STD_VER > 14 62cc89063bSNico Weber static_assert(std::is_swappable<Hash>::value, ""); 63cc89063bSNico Weber #elif defined(_LIBCPP_VERSION) 64cb417401SNikolas Klauser static_assert(std::__is_swappable_v<Hash>, ""); 65cc89063bSNico Weber #endif 66cc89063bSNico Weber 67cc89063bSNico Weber // Hashable requirements 682ff5a56eSwmbat static_assert(can_hash<Hash, Key&>(), ""); 692ff5a56eSwmbat static_assert(can_hash<Hash, Key const&>(), ""); 702ff5a56eSwmbat static_assert(can_hash<Hash, Key&&>(), ""); 712ff5a56eSwmbat static_assert(can_hash<Hash const, Key&>(), ""); 722ff5a56eSwmbat static_assert(can_hash<Hash const, Key const&>(), ""); 732ff5a56eSwmbat static_assert(can_hash<Hash const, Key&&>(), ""); 74cc89063bSNico Weber 752ff5a56eSwmbat static_assert(can_hash<Hash, ConvertibleToSimple<Key>&>(), ""); 762ff5a56eSwmbat static_assert(can_hash<Hash, ConvertibleToSimple<Key> const&>(), ""); 772ff5a56eSwmbat static_assert(can_hash<Hash, ConvertibleToSimple<Key>&&>(), ""); 78cc89063bSNico Weber 792ff5a56eSwmbat static_assert(can_hash<Hash, ConvertibleTo<Key>&>(), ""); 802ff5a56eSwmbat static_assert(can_hash<Hash, ConvertibleTo<Key> const&>(), ""); 812ff5a56eSwmbat static_assert(can_hash<Hash, ConvertibleTo<Key>&&>(), ""); 822ff5a56eSwmbat static_assert(can_hash<Hash, ConvertibleTo<Key> const&&>(), ""); 83cc89063bSNico Weber 84cc89063bSNico Weber const Hash h{}; 85cc89063bSNico Weber assert(h(key) == h(key)); 86cc89063bSNico Weber } 87cc89063bSNico Weber 88*33325524SLouis Dionne // Test that the specified Hash meets the requirements of a disabled hash. 89*33325524SLouis Dionne template <class Key, class Hash = std::hash<Key>> 90cc89063bSNico Weber void test_hash_disabled() { 91cc89063bSNico Weber // Disabled hash requirements 92cc89063bSNico Weber static_assert(!std::is_default_constructible<Hash>::value, ""); 93cc89063bSNico Weber static_assert(!std::is_copy_constructible<Hash>::value, ""); 94cc89063bSNico Weber static_assert(!std::is_move_constructible<Hash>::value, ""); 95cc89063bSNico Weber static_assert(!std::is_copy_assignable<Hash>::value, ""); 96cc89063bSNico Weber static_assert(!std::is_move_assignable<Hash>::value, ""); 97cc89063bSNico Weber 98*33325524SLouis Dionne static_assert( 99*33325524SLouis Dionne !std::is_function<typename std::remove_pointer<typename std::remove_reference<Hash>::type>::type>::value, ""); 100cc89063bSNico Weber 101cc89063bSNico Weber // Hashable requirements 1022ff5a56eSwmbat static_assert(!can_hash<Hash, Key&>(), ""); 1032ff5a56eSwmbat static_assert(!can_hash<Hash, Key const&>(), ""); 1042ff5a56eSwmbat static_assert(!can_hash<Hash, Key&&>(), ""); 1052ff5a56eSwmbat static_assert(!can_hash<Hash const, Key&>(), ""); 1062ff5a56eSwmbat static_assert(!can_hash<Hash const, Key const&>(), ""); 1072ff5a56eSwmbat static_assert(!can_hash<Hash const, Key&&>(), ""); 108cc89063bSNico Weber 1092ff5a56eSwmbat static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&>(), ""); 1102ff5a56eSwmbat static_assert(!can_hash<Hash, ConvertibleToSimple<Key> const&>(), ""); 1112ff5a56eSwmbat static_assert(!can_hash<Hash, ConvertibleToSimple<Key>&&>(), ""); 112cc89063bSNico Weber 1132ff5a56eSwmbat static_assert(!can_hash<Hash, ConvertibleTo<Key>&>(), ""); 1142ff5a56eSwmbat static_assert(!can_hash<Hash, ConvertibleTo<Key> const&>(), ""); 1152ff5a56eSwmbat static_assert(!can_hash<Hash, ConvertibleTo<Key>&&>(), ""); 1162ff5a56eSwmbat static_assert(!can_hash<Hash, ConvertibleTo<Key> const&&>(), ""); 117cc89063bSNico Weber } 118cc89063bSNico Weber 119*33325524SLouis Dionne enum Enum {}; 120*33325524SLouis Dionne enum EnumClass : bool {}; 121*33325524SLouis Dionne struct Class {}; 122cc89063bSNico Weber 123*33325524SLouis Dionne // Each header that declares the std::hash template provides enabled 124*33325524SLouis Dionne // specializations of std::hash for std::nullptr_t and all cv-unqualified 125*33325524SLouis Dionne // arithmetic, enumeration, and pointer types. 126*33325524SLouis Dionne #if TEST_STD_VER >= 17 127*33325524SLouis Dionne using MaybeNullptr = types::type_list<std::nullptr_t>; 128*33325524SLouis Dionne #else 129*33325524SLouis Dionne using MaybeNullptr = types::type_list<>; 130*33325524SLouis Dionne #endif 131*33325524SLouis Dionne using LibraryHashTypes = types:: 132*33325524SLouis Dionne concatenate_t<types::arithmetic_types, types::type_list<Enum, EnumClass, void*, void const*, Class*>, MaybeNullptr>; 133cc89063bSNico Weber 134*33325524SLouis Dionne struct TestHashEnabled { 135*33325524SLouis Dionne template <class T> 136*33325524SLouis Dionne void operator()() const { 137*33325524SLouis Dionne test_hash_enabled<T>(); 138cc89063bSNico Weber } 139cc89063bSNico Weber }; 140cc89063bSNico Weber 141*33325524SLouis Dionne // Test that each of the library hash specializations for arithmetic types, 142*33325524SLouis Dionne // enum types, and pointer types are available and enabled. 143*33325524SLouis Dionne template <class Types = LibraryHashTypes> 144*33325524SLouis Dionne void test_library_hash_specializations_available() { 145*33325524SLouis Dionne types::for_each(Types(), TestHashEnabled()); 146cc89063bSNico Weber } 147cc89063bSNico Weber 148cc89063bSNico Weber #endif // SUPPORT_POISONED_HASH_HELPER_H 149