xref: /llvm-project/libcxx/test/support/type_classification/swappable.h (revision 480cd780d63fd9c658cc2f51d0c54416b8b1a5c3)
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