xref: /llvm-project/libcxx/test/support/copy_move_types.h (revision f5832bab6f5024cabe32a9f668b7f44e6b7cfef5)
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 LIBCXX_TEST_STD_UTILITIES_TUPLE_CNSTR_TYPES_H
10 #define LIBCXX_TEST_STD_UTILITIES_TUPLE_CNSTR_TYPES_H
11 
12 #include "test_allocator.h"
13 #include <type_traits>
14 #include <tuple>
15 
16 // Types that can be used to test copy/move operations
17 
18 struct MutableCopy {
19   int val;
20   bool alloc_constructed{false};
21 
22   constexpr MutableCopy() = default;
MutableCopyMutableCopy23   constexpr MutableCopy(int _val) : val(_val) {}
24   constexpr MutableCopy(MutableCopy&) = default;
25   constexpr MutableCopy(const MutableCopy&) = delete;
26 
MutableCopyMutableCopy27   constexpr MutableCopy(std::allocator_arg_t, const test_allocator<int>&, MutableCopy& o)
28       : val(o.val), alloc_constructed(true) {}
29 };
30 
31 template <>
32 struct std::uses_allocator<MutableCopy, test_allocator<int>> : std::true_type {};
33 
34 struct ConstCopy {
35   int val;
36   bool alloc_constructed{false};
37 
38   constexpr ConstCopy() = default;
39   constexpr ConstCopy(int _val) : val(_val) {}
40   constexpr ConstCopy(const ConstCopy&) = default;
41   constexpr ConstCopy(ConstCopy&) = delete;
42 
43   constexpr ConstCopy(std::allocator_arg_t, const test_allocator<int>&, const ConstCopy& o)
44       : val(o.val), alloc_constructed(true) {}
45 };
46 
47 template <>
48 struct std::uses_allocator<ConstCopy, test_allocator<int>> : std::true_type {};
49 
50 struct MutableMove {
51   int val;
52   bool alloc_constructed{false};
53 
54   constexpr MutableMove() = default;
55   constexpr MutableMove(int _val) : val(_val) {}
56   constexpr MutableMove(MutableMove&&) = default;
57   constexpr MutableMove(const MutableMove&&) = delete;
58 
59   constexpr MutableMove(std::allocator_arg_t, const test_allocator<int>&, MutableMove&& o)
60       : val(o.val), alloc_constructed(true) {}
61 };
62 
63 template <>
64 struct std::uses_allocator<MutableMove, test_allocator<int>> : std::true_type {};
65 
66 struct ConstMove {
67   int val;
68   bool alloc_constructed{false};
69 
70   constexpr ConstMove() = default;
71   constexpr ConstMove(int _val) : val(_val) {}
72   constexpr ConstMove(const ConstMove&& o) : val(o.val) {}
73   constexpr ConstMove(ConstMove&&) = delete;
74 
75   constexpr ConstMove(std::allocator_arg_t, const test_allocator<int>&, const ConstMove&& o)
76       : val(o.val), alloc_constructed(true) {}
77 };
78 
79 template <>
80 struct std::uses_allocator<ConstMove, test_allocator<int>> : std::true_type {};
81 
82 template <class T>
83 struct ConvertibleFrom {
84   T v;
85   bool alloc_constructed{false};
86 
87   constexpr ConvertibleFrom() = default;
88   constexpr ConvertibleFrom(T& _v)
89     requires(std::is_constructible_v<T, T&>)
90   : v(_v) {}
91   constexpr ConvertibleFrom(const T& _v)
92     requires(std::is_constructible_v<T, const T&> && !std::is_const_v<T>)
93   : v(_v) {}
94   constexpr ConvertibleFrom(T&& _v)
95     requires(std::is_constructible_v<T, T &&>)
96   : v(std::move(_v)) {}
97   constexpr ConvertibleFrom(const T&& _v)
98     requires(std::is_constructible_v<T, const T &&> && !std::is_const_v<T>)
99   : v(std::move(_v)) {}
100 
101   template <class U>
102     requires std::is_constructible_v<ConvertibleFrom, U&&>
103   constexpr ConvertibleFrom(std::allocator_arg_t, const test_allocator<int>&, U&& _u)
104       : ConvertibleFrom{std::forward<U>(_u)} {
105     alloc_constructed = true;
106   }
107 };
108 
109 template <class T>
110 struct std::uses_allocator<ConvertibleFrom<T>, test_allocator<int>> : std::true_type {};
111 
112 template <class T>
113 struct ExplicitConstructibleFrom {
114   T v;
115   bool alloc_constructed{false};
116 
117   constexpr explicit ExplicitConstructibleFrom() = default;
118   constexpr explicit ExplicitConstructibleFrom(T& _v)
119     requires(std::is_constructible_v<T, T&>)
120   : v(_v) {}
121   constexpr explicit ExplicitConstructibleFrom(const T& _v)
122     requires(std::is_constructible_v<T, const T&> && !std::is_const_v<T>)
123   : v(_v) {}
124   constexpr explicit ExplicitConstructibleFrom(T&& _v)
125     requires(std::is_constructible_v<T, T &&>)
126   : v(std::move(_v)) {}
127   constexpr explicit ExplicitConstructibleFrom(const T&& _v)
128     requires(std::is_constructible_v<T, const T &&> && !std::is_const_v<T>)
129   : v(std::move(_v)) {}
130 
131   template <class U>
132     requires std::is_constructible_v<ExplicitConstructibleFrom, U&&>
133   constexpr ExplicitConstructibleFrom(std::allocator_arg_t, const test_allocator<int>&, U&& _u)
134       : ExplicitConstructibleFrom{std::forward<U>(_u)} {
135     alloc_constructed = true;
136   }
137 };
138 
139 template <class T>
140 struct std::uses_allocator<ExplicitConstructibleFrom<T>, test_allocator<int>> : std::true_type {};
141 
142 struct TracedCopyMove {
143   int nonConstCopy = 0;
144   int constCopy = 0;
145   int nonConstMove = 0;
146   int constMove = 0;
147   bool alloc_constructed = false;
148 
149   constexpr TracedCopyMove() = default;
150   constexpr TracedCopyMove(const TracedCopyMove& other)
151       : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy + 1), nonConstMove(other.nonConstMove),
152         constMove(other.constMove) {}
153   constexpr TracedCopyMove(TracedCopyMove& other)
154       : nonConstCopy(other.nonConstCopy + 1), constCopy(other.constCopy), nonConstMove(other.nonConstMove),
155         constMove(other.constMove) {}
156 
157   constexpr TracedCopyMove(TracedCopyMove&& other)
158       : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove + 1),
159         constMove(other.constMove) {}
160 
161   constexpr TracedCopyMove(const TracedCopyMove&& other)
162       : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove),
163         constMove(other.constMove + 1) {}
164 
165   template <class U>
166     requires std::is_constructible_v<TracedCopyMove, U&&>
167   constexpr TracedCopyMove(std::allocator_arg_t, const test_allocator<int>&, U&& _u)
168       : TracedCopyMove{std::forward<U>(_u)} {
169     alloc_constructed = true;
170   }
171 };
172 
173 template <>
174 struct std::uses_allocator<TracedCopyMove, test_allocator<int>> : std::true_type {};
175 
176 // If the constructor tuple(tuple<UTypes...>&) is not available,
177 // the fallback call to `tuple(const tuple&) = default;` or any other
178 // constructor that takes const ref would increment the constCopy.
179 inline constexpr bool nonConstCopyCtrCalled(const TracedCopyMove& obj) {
180   return obj.nonConstCopy == 1 && obj.constCopy == 0 && obj.constMove == 0 && obj.nonConstMove == 0;
181 }
182 
183 // If the constructor tuple(const tuple<UTypes...>&&) is not available,
184 // the fallback call to `tuple(const tuple&) = default;` or any other
185 // constructor that takes const ref would increment the constCopy.
186 inline constexpr bool constMoveCtrCalled(const TracedCopyMove& obj) {
187   return obj.nonConstMove == 0 && obj.constMove == 1 && obj.constCopy == 0 && obj.nonConstCopy == 0;
188 }
189 
190 struct NoConstructorFromInt {};
191 
192 struct CvtFromTupleRef : TracedCopyMove {
193   constexpr CvtFromTupleRef() = default;
194   constexpr CvtFromTupleRef(std::tuple<CvtFromTupleRef>& other)
195       : TracedCopyMove(static_cast<TracedCopyMove&>(std::get<0>(other))) {}
196 };
197 
198 struct ExplicitCtrFromTupleRef : TracedCopyMove {
199   constexpr explicit ExplicitCtrFromTupleRef() = default;
200   constexpr explicit ExplicitCtrFromTupleRef(std::tuple<ExplicitCtrFromTupleRef>& other)
201       : TracedCopyMove(static_cast<TracedCopyMove&>(std::get<0>(other))) {}
202 };
203 
204 struct CvtFromConstTupleRefRef : TracedCopyMove {
205   constexpr CvtFromConstTupleRefRef() = default;
206   constexpr CvtFromConstTupleRefRef(const std::tuple<CvtFromConstTupleRefRef>&& other)
207       : TracedCopyMove(static_cast<const TracedCopyMove&&>(std::get<0>(other))) {}
208 };
209 
210 struct ExplicitCtrFromConstTupleRefRef : TracedCopyMove {
211   constexpr explicit ExplicitCtrFromConstTupleRefRef() = default;
212   constexpr explicit ExplicitCtrFromConstTupleRefRef(std::tuple<const ExplicitCtrFromConstTupleRefRef>&& other)
213       : TracedCopyMove(static_cast<const TracedCopyMove&&>(std::get<0>(other))) {}
214 };
215 
216 template <class T>
217 void conversion_test(T);
218 
219 template <class T, class... Args>
220 concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };
221 
222 struct CopyAssign {
223   int val;
224 
225   constexpr CopyAssign() = default;
226   constexpr CopyAssign(int v) : val(v) {}
227 
228   constexpr CopyAssign& operator=(const CopyAssign&) = default;
229 
230   constexpr const CopyAssign& operator=(const CopyAssign&) const = delete;
231   constexpr CopyAssign& operator=(CopyAssign&&) = delete;
232   constexpr const CopyAssign& operator=(CopyAssign&&) const = delete;
233 };
234 
235 struct ConstCopyAssign {
236   mutable int val;
237 
238   constexpr ConstCopyAssign() = default;
239   constexpr ConstCopyAssign(int v) : val(v) {}
240 
241   constexpr const ConstCopyAssign& operator=(const ConstCopyAssign& other) const {
242     val = other.val;
243     return *this;
244   }
245 
246   constexpr ConstCopyAssign& operator=(const ConstCopyAssign&) = delete;
247   constexpr ConstCopyAssign& operator=(ConstCopyAssign&&) = delete;
248   constexpr const ConstCopyAssign& operator=(ConstCopyAssign&&) const = delete;
249 };
250 
251 struct MoveAssign {
252   int val;
253 
254   constexpr MoveAssign() = default;
255   constexpr MoveAssign(int v) : val(v) {}
256 
257   constexpr MoveAssign& operator=(MoveAssign&&) = default;
258 
259   constexpr MoveAssign& operator=(const MoveAssign&) = delete;
260   constexpr const MoveAssign& operator=(const MoveAssign&) const = delete;
261   constexpr const MoveAssign& operator=(MoveAssign&&) const = delete;
262 };
263 
264 struct ConstMoveAssign {
265   mutable int val;
266 
267   constexpr ConstMoveAssign() = default;
268   constexpr ConstMoveAssign(int v) : val(v) {}
269 
270   constexpr const ConstMoveAssign& operator=(ConstMoveAssign&& other) const {
271     val = other.val;
272     return *this;
273   }
274 
275   constexpr ConstMoveAssign& operator=(const ConstMoveAssign&) = delete;
276   constexpr const ConstMoveAssign& operator=(const ConstMoveAssign&) const = delete;
277   constexpr ConstMoveAssign& operator=(ConstMoveAssign&&) = delete;
278 };
279 
280 template <class T>
281 struct AssignableFrom {
282   T v;
283 
284   constexpr AssignableFrom() = default;
285 
286   template <class U>
287   constexpr AssignableFrom(U&& u)
288     requires std::is_constructible_v<T, U&&>
289   : v(std::forward<U>(u)) {}
290 
291   constexpr AssignableFrom& operator=(const T& t)
292     requires std::is_copy_assignable_v<T>
293   {
294     v = t;
295     return *this;
296   }
297 
298   constexpr AssignableFrom& operator=(T&& t)
299     requires std::is_move_assignable_v<T>
300   {
301     v = std::move(t);
302     return *this;
303   }
304 
305   constexpr const AssignableFrom& operator=(const T& t) const
306     requires std::is_assignable_v<const T&, const T&>
307   {
308     v = t;
309     return *this;
310   }
311 
312   constexpr const AssignableFrom& operator=(T&& t) const
313     requires std::is_assignable_v<const T&, T&&>
314   {
315     v = std::move(t);
316     return *this;
317   }
318 };
319 
320 struct TracedAssignment {
321   int copyAssign = 0;
322   mutable int constCopyAssign = 0;
323   int moveAssign = 0;
324   mutable int constMoveAssign = 0;
325 
326   constexpr TracedAssignment() = default;
327 
328   constexpr TracedAssignment& operator=(const TracedAssignment&) {
329     copyAssign++;
330     return *this;
331   }
332   constexpr const TracedAssignment& operator=(const TracedAssignment&) const {
333     constCopyAssign++;
334     return *this;
335   }
336   constexpr TracedAssignment& operator=(TracedAssignment&&) {
337     moveAssign++;
338     return *this;
339   }
340   constexpr const TracedAssignment& operator=(TracedAssignment&&) const {
341     constMoveAssign++;
342     return *this;
343   }
344 };
345 #endif
346