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