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 LIBCXX_TEST_STD_UTILITIES_TUPLE_CNSTR_TYPES_H
9 #define LIBCXX_TEST_STD_UTILITIES_TUPLE_CNSTR_TYPES_H
10 
11 #include "test_allocator.h"
12 #include <type_traits>
13 
14 struct MutableCopy {
15   int val;
16   bool alloc_constructed{false};
17 
18   constexpr MutableCopy() = default;
MutableCopyMutableCopy19   constexpr MutableCopy(int _val) : val(_val) {}
20   constexpr MutableCopy(MutableCopy&) = default;
21   constexpr MutableCopy(const MutableCopy&) = delete;
22 
MutableCopyMutableCopy23   constexpr MutableCopy(std::allocator_arg_t, const test_allocator<int>&, MutableCopy& o)
24       : val(o.val), alloc_constructed(true) {}
25 };
26 
27 template <>
28 struct std::uses_allocator<MutableCopy, test_allocator<int>> : std::true_type {};
29 
30 struct ConstCopy {
31   int val;
32   bool alloc_constructed{false};
33 
34   constexpr ConstCopy() = default;
35   constexpr ConstCopy(int _val) : val(_val) {}
36   constexpr ConstCopy(const ConstCopy&) = default;
37   constexpr ConstCopy(ConstCopy&) = delete;
38 
39   constexpr ConstCopy(std::allocator_arg_t, const test_allocator<int>&, const ConstCopy& o)
40       : val(o.val), alloc_constructed(true) {}
41 };
42 
43 template <>
44 struct std::uses_allocator<ConstCopy, test_allocator<int>> : std::true_type {};
45 
46 struct MutableMove {
47   int val;
48   bool alloc_constructed{false};
49 
50   constexpr MutableMove() = default;
51   constexpr MutableMove(int _val) : val(_val) {}
52   constexpr MutableMove(MutableMove&&) = default;
53   constexpr MutableMove(const MutableMove&&) = delete;
54 
55   constexpr MutableMove(std::allocator_arg_t, const test_allocator<int>&, MutableMove&& o)
56       : val(o.val), alloc_constructed(true) {}
57 };
58 
59 template <>
60 struct std::uses_allocator<MutableMove, test_allocator<int>> : std::true_type {};
61 
62 struct ConstMove {
63   int val;
64   bool alloc_constructed{false};
65 
66   constexpr ConstMove() = default;
67   constexpr ConstMove(int _val) : val(_val) {}
68   constexpr ConstMove(const ConstMove&& o) : val(o.val) {}
69   constexpr ConstMove(ConstMove&&) = delete;
70 
71   constexpr ConstMove(std::allocator_arg_t, const test_allocator<int>&, const ConstMove&& o)
72       : val(o.val), alloc_constructed(true) {}
73 };
74 
75 template <>
76 struct std::uses_allocator<ConstMove, test_allocator<int>> : std::true_type {};
77 
78 template <class T>
79 struct ConvertibleFrom {
80   T v;
81   bool alloc_constructed{false};
82 
83   constexpr ConvertibleFrom() = default;
84   constexpr ConvertibleFrom(T& _v)
85     requires(std::is_constructible_v<T, T&>)
86   : v(_v) {}
87   constexpr ConvertibleFrom(const T& _v)
88     requires(std::is_constructible_v<T, const T&> && !std::is_const_v<T>)
89   : v(_v) {}
90   constexpr ConvertibleFrom(T&& _v)
91     requires(std::is_constructible_v<T, T &&>)
92   : v(std::move(_v)) {}
93   constexpr ConvertibleFrom(const T&& _v)
94     requires(std::is_constructible_v<T, const T &&> && !std::is_const_v<T>)
95   : v(std::move(_v)) {}
96 
97   template <class U>
98     requires std::is_constructible_v<ConvertibleFrom, U&&>
99   constexpr ConvertibleFrom(std::allocator_arg_t, const test_allocator<int>&, U&& _u)
100       : ConvertibleFrom{std::forward<U>(_u)} {
101     alloc_constructed = true;
102   }
103 };
104 
105 template <class T>
106 struct std::uses_allocator<ConvertibleFrom<T>, test_allocator<int>> : std::true_type {};
107 
108 template <class T>
109 struct ExplicitConstructibleFrom {
110   T v;
111   bool alloc_constructed{false};
112 
113   constexpr explicit ExplicitConstructibleFrom() = default;
114   constexpr explicit ExplicitConstructibleFrom(T& _v)
115     requires(std::is_constructible_v<T, T&>)
116   : v(_v) {}
117   constexpr explicit ExplicitConstructibleFrom(const T& _v)
118     requires(std::is_constructible_v<T, const T&> && !std::is_const_v<T>)
119   : v(_v) {}
120   constexpr explicit ExplicitConstructibleFrom(T&& _v)
121     requires(std::is_constructible_v<T, T &&>)
122   : v(std::move(_v)) {}
123   constexpr explicit ExplicitConstructibleFrom(const T&& _v)
124     requires(std::is_constructible_v<T, const T &&> && !std::is_const_v<T>)
125   : v(std::move(_v)) {}
126 
127   template <class U>
128     requires std::is_constructible_v<ExplicitConstructibleFrom, U&&>
129   constexpr ExplicitConstructibleFrom(std::allocator_arg_t, const test_allocator<int>&, U&& _u)
130       : ExplicitConstructibleFrom{std::forward<U>(_u)} {
131     alloc_constructed = true;
132   }
133 };
134 
135 template <class T>
136 struct std::uses_allocator<ExplicitConstructibleFrom<T>, test_allocator<int>> : std::true_type {};
137 
138 struct TracedCopyMove {
139   int nonConstCopy = 0;
140   int constCopy = 0;
141   int nonConstMove = 0;
142   int constMove = 0;
143   bool alloc_constructed = false;
144 
145   constexpr TracedCopyMove() = default;
146   constexpr TracedCopyMove(const TracedCopyMove& other)
147       : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy + 1), nonConstMove(other.nonConstMove),
148         constMove(other.constMove) {}
149   constexpr TracedCopyMove(TracedCopyMove& other)
150       : nonConstCopy(other.nonConstCopy + 1), constCopy(other.constCopy), nonConstMove(other.nonConstMove),
151         constMove(other.constMove) {}
152 
153   constexpr TracedCopyMove(TracedCopyMove&& other)
154       : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove + 1),
155         constMove(other.constMove) {}
156 
157   constexpr TracedCopyMove(const TracedCopyMove&& other)
158       : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove),
159         constMove(other.constMove + 1) {}
160 
161   template <class U>
162     requires std::is_constructible_v<TracedCopyMove, U&&>
163   constexpr TracedCopyMove(std::allocator_arg_t, const test_allocator<int>&, U&& _u)
164       : TracedCopyMove{std::forward<U>(_u)} {
165     alloc_constructed = true;
166   }
167 };
168 
169 template <>
170 struct std::uses_allocator<TracedCopyMove, test_allocator<int>> : std::true_type {};
171 
172 // If the constructor tuple(tuple<UTyles...>&) is not available,
173 // the fallback call to `tuple(const tuple&) = default;` or any other
174 // constructor that takes const ref would increment the constCopy.
175 inline constexpr bool nonConstCopyCtrCalled(const TracedCopyMove& obj) {
176   return obj.nonConstCopy == 1 && obj.constCopy == 0 && obj.constMove == 0 && obj.nonConstMove == 0;
177 }
178 
179 // If the constructor tuple(const tuple<UTyles...>&&) is not available,
180 // the fallback call to `tuple(const tuple&) = default;` or any other
181 // constructor that takes const ref would increment the constCopy.
182 inline constexpr bool constMoveCtrCalled(const TracedCopyMove& obj) {
183   return obj.nonConstMove == 0 && obj.constMove == 1 && obj.constCopy == 0 && obj.nonConstCopy == 0;
184 }
185 
186 struct NoConstructorFromInt {};
187 
188 struct CvtFromTupleRef : TracedCopyMove {
189   constexpr CvtFromTupleRef() = default;
190   constexpr CvtFromTupleRef(std::tuple<CvtFromTupleRef>& other)
191       : TracedCopyMove(static_cast<TracedCopyMove&>(std::get<0>(other))) {}
192 };
193 
194 struct ExplicitCtrFromTupleRef : TracedCopyMove {
195   constexpr explicit ExplicitCtrFromTupleRef() = default;
196   constexpr explicit ExplicitCtrFromTupleRef(std::tuple<ExplicitCtrFromTupleRef>& other)
197       : TracedCopyMove(static_cast<TracedCopyMove&>(std::get<0>(other))) {}
198 };
199 
200 struct CvtFromConstTupleRefRef : TracedCopyMove {
201   constexpr CvtFromConstTupleRefRef() = default;
202   constexpr CvtFromConstTupleRefRef(const std::tuple<CvtFromConstTupleRefRef>&& other)
203       : TracedCopyMove(static_cast<const TracedCopyMove&&>(std::get<0>(other))) {}
204 };
205 
206 struct ExplicitCtrFromConstTupleRefRef : TracedCopyMove {
207   constexpr explicit ExplicitCtrFromConstTupleRefRef() = default;
208   constexpr explicit ExplicitCtrFromConstTupleRefRef(std::tuple<const ExplicitCtrFromConstTupleRefRef>&& other)
209       : TracedCopyMove(static_cast<const TracedCopyMove&&>(std::get<0>(other))) {}
210 };
211 
212 template <class T>
213 void conversion_test(T);
214 
215 template <class T, class... Args>
216 concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };
217 
218 #endif
219