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 TEST_SUPPORT_TYPE_CLASSIFICATION_SWAPPABLE_H 10 #define TEST_SUPPORT_TYPE_CLASSIFICATION_SWAPPABLE_H 11 12 #include <concepts> 13 14 // `adl_swappable` indicates it's been swapped using ADL by maintaining a pointer to itself that 15 // isn't a part of the exchange. This is well-formed since we say that two `adl_swappable` objects 16 // are equal only if their respective `value` subobjects are equal and their respective `this` 17 // subobjects store the addresses of those respective `adl_swappable` objects. 18 class lvalue_adl_swappable { 19 public: 20 lvalue_adl_swappable() = default; 21 lvalue_adl_swappable(int value)22 constexpr lvalue_adl_swappable(int value) noexcept : value_(value) {} 23 lvalue_adl_swappable(lvalue_adl_swappable && other)24 constexpr lvalue_adl_swappable(lvalue_adl_swappable&& other) noexcept 25 : value_(std::move(other.value_)), 26 this_(this) {} 27 lvalue_adl_swappable(lvalue_adl_swappable const & other)28 constexpr lvalue_adl_swappable(lvalue_adl_swappable const& other) noexcept 29 : value_(other.value_), 30 this_(this) {} 31 32 constexpr lvalue_adl_swappable& 33 operator=(lvalue_adl_swappable other) noexcept { 34 value_ = other.value_; 35 return *this; 36 } 37 swap(lvalue_adl_swappable & x,lvalue_adl_swappable & y)38 friend constexpr void swap(lvalue_adl_swappable& x, 39 lvalue_adl_swappable& y) noexcept { 40 std::ranges::swap(x.value_, y.value_); 41 } 42 43 constexpr bool operator==(lvalue_adl_swappable const& other) const noexcept { 44 return value_ == other.value_ && this_ == this && other.this_ == &other; 45 } 46 47 private: 48 int value_{}; 49 lvalue_adl_swappable* this_ = this; 50 }; 51 52 class lvalue_rvalue_adl_swappable { 53 public: 54 lvalue_rvalue_adl_swappable() = default; 55 lvalue_rvalue_adl_swappable(int value)56 constexpr lvalue_rvalue_adl_swappable(int value) noexcept : value_(value) {} 57 58 constexpr lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable && other)59 lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable&& other) noexcept 60 : value_(std::move(other.value_)), 61 this_(this) {} 62 63 constexpr lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable const & other)64 lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable const& other) noexcept 65 : value_(other.value_), 66 this_(this) {} 67 68 constexpr lvalue_rvalue_adl_swappable& 69 operator=(lvalue_rvalue_adl_swappable other) noexcept { 70 value_ = other.value_; 71 return *this; 72 } 73 swap(lvalue_rvalue_adl_swappable & x,lvalue_rvalue_adl_swappable && y)74 friend constexpr void swap(lvalue_rvalue_adl_swappable& x, 75 lvalue_rvalue_adl_swappable&& y) noexcept { 76 std::ranges::swap(x.value_, y.value_); 77 } 78 79 constexpr bool 80 operator==(lvalue_rvalue_adl_swappable const& other) const noexcept { 81 return value_ == other.value_ && this_ == this && other.this_ == &other; 82 } 83 84 private: 85 int value_{}; 86 lvalue_rvalue_adl_swappable* this_ = this; 87 }; 88 89 class rvalue_lvalue_adl_swappable { 90 public: 91 rvalue_lvalue_adl_swappable() = default; 92 rvalue_lvalue_adl_swappable(int value)93 constexpr rvalue_lvalue_adl_swappable(int value) noexcept : value_(value) {} 94 95 constexpr rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable && other)96 rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable&& other) noexcept 97 : value_(std::move(other.value_)), 98 this_(this) {} 99 100 constexpr rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable const & other)101 rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable const& other) noexcept 102 : value_(other.value_), 103 this_(this) {} 104 105 constexpr rvalue_lvalue_adl_swappable& 106 operator=(rvalue_lvalue_adl_swappable other) noexcept { 107 value_ = other.value_; 108 return *this; 109 } 110 swap(rvalue_lvalue_adl_swappable && x,rvalue_lvalue_adl_swappable & y)111 friend constexpr void swap(rvalue_lvalue_adl_swappable&& x, 112 rvalue_lvalue_adl_swappable& y) noexcept { 113 std::ranges::swap(x.value_, y.value_); 114 } 115 116 constexpr bool 117 operator==(rvalue_lvalue_adl_swappable const& other) const noexcept { 118 return value_ == other.value_ && this_ == this && other.this_ == &other; 119 } 120 121 private: 122 int value_{}; 123 rvalue_lvalue_adl_swappable* this_ = this; 124 }; 125 126 class rvalue_adl_swappable { 127 public: 128 rvalue_adl_swappable() = default; 129 rvalue_adl_swappable(int value)130 constexpr rvalue_adl_swappable(int value) noexcept : value_(value) {} 131 rvalue_adl_swappable(rvalue_adl_swappable && other)132 constexpr rvalue_adl_swappable(rvalue_adl_swappable&& other) noexcept 133 : value_(std::move(other.value_)), 134 this_(this) {} 135 rvalue_adl_swappable(rvalue_adl_swappable const & other)136 constexpr rvalue_adl_swappable(rvalue_adl_swappable const& other) noexcept 137 : value_(other.value_), 138 this_(this) {} 139 140 constexpr rvalue_adl_swappable& 141 operator=(rvalue_adl_swappable other) noexcept { 142 value_ = other.value_; 143 return *this; 144 } 145 swap(rvalue_adl_swappable && x,rvalue_adl_swappable && y)146 friend constexpr void swap(rvalue_adl_swappable&& x, 147 rvalue_adl_swappable&& y) noexcept { 148 std::ranges::swap(x.value_, y.value_); 149 } 150 151 constexpr bool operator==(rvalue_adl_swappable const& other) const noexcept { 152 return value_ == other.value_ && this_ == this && other.this_ == &other; 153 } 154 155 private: 156 int value_{}; 157 rvalue_adl_swappable* this_ = this; 158 }; 159 160 class non_move_constructible_adl_swappable { 161 public: 162 non_move_constructible_adl_swappable() = default; 163 non_move_constructible_adl_swappable(int value)164 constexpr non_move_constructible_adl_swappable(int value) noexcept 165 : value_(value) {} 166 non_move_constructible_adl_swappable(non_move_constructible_adl_swappable && other)167 constexpr non_move_constructible_adl_swappable( 168 non_move_constructible_adl_swappable&& other) noexcept 169 : value_(std::move(other.value_)), 170 this_(this) {} 171 non_move_constructible_adl_swappable(non_move_constructible_adl_swappable const & other)172 constexpr non_move_constructible_adl_swappable( 173 non_move_constructible_adl_swappable const& other) noexcept 174 : value_(other.value_), 175 this_(this) {} 176 177 constexpr non_move_constructible_adl_swappable& 178 operator=(non_move_constructible_adl_swappable other) noexcept { 179 value_ = other.value_; 180 return *this; 181 } 182 swap(non_move_constructible_adl_swappable & x,non_move_constructible_adl_swappable & y)183 friend constexpr void swap(non_move_constructible_adl_swappable& x, 184 non_move_constructible_adl_swappable& y) noexcept { 185 std::ranges::swap(x.value_, y.value_); 186 } 187 188 constexpr bool 189 operator==(non_move_constructible_adl_swappable const& other) const noexcept { 190 return value_ == other.value_ && this_ == this && other.this_ == &other; 191 } 192 193 private: 194 int value_{}; 195 non_move_constructible_adl_swappable* this_ = this; 196 }; 197 198 class non_move_assignable_adl_swappable { 199 public: 200 non_move_assignable_adl_swappable() = default; 201 non_move_assignable_adl_swappable(int value)202 constexpr non_move_assignable_adl_swappable(int value) noexcept 203 : value_(value) {} 204 205 non_move_assignable_adl_swappable(non_move_assignable_adl_swappable&& other) = 206 delete; 207 non_move_assignable_adl_swappable(non_move_assignable_adl_swappable const & other)208 constexpr non_move_assignable_adl_swappable( 209 non_move_assignable_adl_swappable const& other) noexcept 210 : value_(other.value_), 211 this_(this) {} 212 213 constexpr non_move_assignable_adl_swappable& 214 operator=(non_move_assignable_adl_swappable&& other) noexcept = delete; 215 swap(non_move_assignable_adl_swappable & x,non_move_assignable_adl_swappable & y)216 friend constexpr void swap(non_move_assignable_adl_swappable& x, 217 non_move_assignable_adl_swappable& y) noexcept { 218 std::ranges::swap(x.value_, y.value_); 219 } 220 221 constexpr bool 222 operator==(non_move_assignable_adl_swappable const& other) const noexcept { 223 return value_ == other.value_ && this_ == this && other.this_ == &other; 224 } 225 226 private: 227 int value_{}; 228 non_move_assignable_adl_swappable* this_ = this; 229 }; 230 231 class throwable_adl_swappable { 232 public: 233 throwable_adl_swappable() = default; 234 throwable_adl_swappable(int value)235 constexpr throwable_adl_swappable(int value) noexcept : value_(value) {} 236 throwable_adl_swappable(throwable_adl_swappable && other)237 constexpr throwable_adl_swappable(throwable_adl_swappable&& other) noexcept 238 : value_(std::move(other.value_)), 239 this_(this) {} 240 241 constexpr throwable_adl_swappable(throwable_adl_swappable const & other)242 throwable_adl_swappable(throwable_adl_swappable const& other) noexcept 243 : value_(other.value_), 244 this_(this) {} 245 246 constexpr throwable_adl_swappable& 247 operator=(throwable_adl_swappable other) noexcept { 248 value_ = other.value_; 249 return *this; 250 } 251 swap(throwable_adl_swappable & X,throwable_adl_swappable & Y)252 friend constexpr void swap(throwable_adl_swappable& X, 253 throwable_adl_swappable& Y) noexcept(false) { 254 std::ranges::swap(X.value_, Y.value_); 255 } 256 257 constexpr bool 258 operator==(throwable_adl_swappable const& other) const noexcept { 259 return value_ == other.value_ && this_ == this && other.this_ == &other; 260 } 261 262 private: 263 int value_{}; 264 throwable_adl_swappable* this_ = this; 265 }; 266 267 #endif // TEST_SUPPORT_TYPE_CLASSIFICATION_SWAPPABLE_H 268