1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef TRANSPARENT_H 10 #define TRANSPARENT_H 11 12 #include "test_macros.h" 13 14 #include <functional> // for std::equal_to 15 16 // testing transparent 17 #if TEST_STD_VER > 11 18 19 struct transparent_less 20 { 21 template <class T, class U> 22 constexpr auto operator()(T&& t, U&& u) const 23 noexcept(noexcept(std::forward<T>(t) < std::forward<U>(u))) 24 -> decltype (std::forward<T>(t) < std::forward<U>(u)) 25 { return std::forward<T>(t) < std::forward<U>(u); } 26 using is_transparent = void; // correct 27 }; 28 29 struct transparent_less_not_referenceable 30 { 31 template <class T, class U> 32 constexpr auto operator()(T&& t, U&& u) const 33 noexcept(noexcept(std::forward<T>(t) < std::forward<U>(u))) 34 -> decltype (std::forward<T>(t) < std::forward<U>(u)) 35 { return std::forward<T>(t) < std::forward<U>(u); } 36 using is_transparent = void () const &; // it's a type; a weird one, but a type 37 }; 38 39 struct transparent_less_no_type 40 { 41 template <class T, class U> 42 constexpr auto operator()(T&& t, U&& u) const 43 noexcept(noexcept(std::forward<T>(t) < std::forward<U>(u))) 44 -> decltype (std::forward<T>(t) < std::forward<U>(u)) 45 { return std::forward<T>(t) < std::forward<U>(u); } 46 private: 47 // using is_transparent = void; // error - should exist 48 }; 49 50 struct transparent_less_private 51 { 52 template <class T, class U> 53 constexpr auto operator()(T&& t, U&& u) const 54 noexcept(noexcept(std::forward<T>(t) < std::forward<U>(u))) 55 -> decltype (std::forward<T>(t) < std::forward<U>(u)) 56 { return std::forward<T>(t) < std::forward<U>(u); } 57 private: 58 using is_transparent = void; // error - should be accessible 59 }; 60 61 struct transparent_less_not_a_type 62 { 63 template <class T, class U> 64 constexpr auto operator()(T&& t, U&& u) const 65 noexcept(noexcept(std::forward<T>(t) < std::forward<U>(u))) 66 -> decltype (std::forward<T>(t) < std::forward<U>(u)) 67 { return std::forward<T>(t) < std::forward<U>(u); } 68 69 int is_transparent; // error - should be a type 70 }; 71 72 struct C2Int { // comparable to int C2IntC2Int73 C2Int() : i_(0) {} C2IntC2Int74 C2Int(int i): i_(i) {} getC2Int75 int get () const { return i_; } 76 private: 77 int i_; 78 }; 79 80 bool operator <(int rhs, const C2Int& lhs) { return rhs < lhs.get(); } 81 bool operator <(const C2Int& rhs, const C2Int& lhs) { return rhs.get() < lhs.get(); } 82 bool operator <(const C2Int& rhs, int lhs) { return rhs.get() < lhs; } 83 84 #endif // TEST_STD_VER > 11 85 86 #if TEST_STD_VER > 17 87 88 template <typename T> 89 struct StoredType; 90 91 template <typename T> 92 struct SearchedType; 93 94 struct hash_impl { 95 template <typename T> operatorhash_impl96 constexpr std::size_t operator()(SearchedType<T> const& t) const { 97 return static_cast<std::size_t>(t.get_value()); 98 } 99 100 template <typename T> operatorhash_impl101 constexpr std::size_t operator()(StoredType<T> const& t) const { 102 return static_cast<std::size_t>(t.get_value()); 103 } 104 }; 105 106 struct non_transparent_hash : hash_impl {}; 107 108 struct transparent_hash : hash_impl { 109 using is_transparent = void; 110 }; 111 112 struct transparent_hash_final final : transparent_hash {}; 113 114 struct transparent_equal_final final : std::equal_to<> {}; 115 116 template <typename T> 117 struct SearchedType { SearchedTypeSearchedType118 SearchedType(T value, int* counter) : value_(value), conversions_(counter) { } 119 120 // Whenever a conversion is performed, increment the counter to keep track 121 // of conversions. 122 operator StoredType<T>() const { 123 ++*conversions_; 124 return StoredType<T>{value_}; 125 } 126 get_valueSearchedType127 int get_value() const { 128 return value_; 129 } 130 131 private: 132 T value_; 133 int* conversions_; 134 }; 135 136 template <typename T> 137 struct StoredType { 138 StoredType() = default; StoredTypeStoredType139 StoredType(T value) : value_(value) { } 140 141 friend bool operator==(StoredType const& lhs, StoredType const& rhs) { 142 return lhs.value_ == rhs.value_; 143 } 144 145 // If we're being passed a SearchedType<T> object, avoid the conversion 146 // to T. This allows testing that the transparent operations are correctly 147 // forwarding the SearchedType all the way to this comparison by checking 148 // that we didn't have a conversion when we search for a SearchedType<T> 149 // in a container full of StoredType<T>. 150 friend bool operator==(StoredType const& lhs, SearchedType<T> const& rhs) { 151 return lhs.value_ == rhs.get_value(); 152 } 153 friend bool operator==(SearchedType<T> const& lhs, StoredType<T> const& rhs) { 154 return lhs.get_value() == rhs.value_; 155 } 156 get_valueStoredType157 int get_value() const { 158 return value_; 159 } 160 161 private: 162 T value_; 163 }; 164 165 #endif // TEST_STD_VER > 17 166 167 #endif // TRANSPARENT_H 168