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