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