xref: /llvm-project/libcxx/test/support/poisoned_hash_helper.h (revision 33325524f5e80a898a7ae875e208a54af132001b)
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