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