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
|