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