145 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef SUPPORT_POISONED_HASH_HELPER_H11#define SUPPORT_POISONED_HASH_HELPER_H12 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 22template <class Hash, class Key, class Res = decltype(std::declval<Hash&>()(std::declval<Key>()))>23constexpr bool can_hash_impl(int) {24 return std::is_same<Res, std::size_t>::value;25}26template <class, class>27constexpr bool can_hash_impl(long) {28 return false;29}30template <class Hash, class Key>31constexpr bool can_hash() {32 return can_hash_impl<Hash, Key>(0);33}34 35template <class To>36struct ConvertibleToSimple {37 operator To() const { return To{}; }38};39 40template <class To>41struct 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 hash50template <class Key, class Hash = std::hash<Key>>51TEST_CONSTEXPR_CXX20 void test_hash_enabled(Key const& key = Key{}) {52 static_assert(std::is_destructible<Hash>::value, "");53 54 // Enabled hash requirements55 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 > 1462 static_assert(std::is_swappable<Hash>::value, "");63#elif defined(_LIBCPP_VERSION)64 static_assert(std::__is_swappable_v<Hash>, "");65#endif66 67 // Hashable requirements68 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.89template <class Key, class Hash = std::hash<Key>>90void test_hash_disabled() {91 // Disabled hash requirements92 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 requirements102 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 119enum Enum {};120enum EnumClass : bool {};121struct Class {};122 123// Each header that declares the std::hash template provides enabled124// specializations of std::hash for std::nullptr_t and all cv-unqualified125// arithmetic, enumeration, and pointer types.126using LibraryHashTypes =127 types::concatenate_t<types::arithmetic_types,128 types::type_list<Enum, EnumClass, void*, void const*, Class*, std::nullptr_t>>;129 130struct TestHashEnabled {131 template <class T>132 void operator()() const {133 test_hash_enabled<T>();134 }135};136 137// Test that each of the library hash specializations for arithmetic types,138// enum types, and pointer types are available and enabled.139template <class Types = LibraryHashTypes>140void test_library_hash_specializations_available() {141 types::for_each(Types(), TestHashEnabled());142}143 144#endif // SUPPORT_POISONED_HASH_HELPER_H145