| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LIBCXX_TEST_STD_UTILITIES_TUPLE_CNSTR_TYPES_H |
| #define LIBCXX_TEST_STD_UTILITIES_TUPLE_CNSTR_TYPES_H |
| |
| #include "test_allocator.h" |
| #include <type_traits> |
| #include <tuple> |
| |
| // Types that can be used to test copy/move operations |
| |
| struct MutableCopy { |
| int val; |
| bool alloc_constructed{false}; |
| |
| constexpr MutableCopy() = default; |
| constexpr MutableCopy(int _val) : val(_val) {} |
| constexpr MutableCopy(MutableCopy&) = default; |
| constexpr MutableCopy(const MutableCopy&) = delete; |
| |
| constexpr MutableCopy(std::allocator_arg_t, const test_allocator<int>&, MutableCopy& o) |
| : val(o.val), alloc_constructed(true) {} |
| }; |
| |
| template <> |
| struct std::uses_allocator<MutableCopy, test_allocator<int>> : std::true_type {}; |
| |
| struct ConstCopy { |
| int val; |
| bool alloc_constructed{false}; |
| |
| constexpr ConstCopy() = default; |
| constexpr ConstCopy(int _val) : val(_val) {} |
| constexpr ConstCopy(const ConstCopy&) = default; |
| constexpr ConstCopy(ConstCopy&) = delete; |
| |
| constexpr ConstCopy(std::allocator_arg_t, const test_allocator<int>&, const ConstCopy& o) |
| : val(o.val), alloc_constructed(true) {} |
| }; |
| |
| template <> |
| struct std::uses_allocator<ConstCopy, test_allocator<int>> : std::true_type {}; |
| |
| struct MutableMove { |
| int val; |
| bool alloc_constructed{false}; |
| |
| constexpr MutableMove() = default; |
| constexpr MutableMove(int _val) : val(_val) {} |
| constexpr MutableMove(MutableMove&&) = default; |
| constexpr MutableMove(const MutableMove&&) = delete; |
| |
| constexpr MutableMove(std::allocator_arg_t, const test_allocator<int>&, MutableMove&& o) |
| : val(o.val), alloc_constructed(true) {} |
| }; |
| |
| template <> |
| struct std::uses_allocator<MutableMove, test_allocator<int>> : std::true_type {}; |
| |
| struct ConstMove { |
| int val; |
| bool alloc_constructed{false}; |
| |
| constexpr ConstMove() = default; |
| constexpr ConstMove(int _val) : val(_val) {} |
| constexpr ConstMove(const ConstMove&& o) : val(o.val) {} |
| constexpr ConstMove(ConstMove&&) = delete; |
| |
| constexpr ConstMove(std::allocator_arg_t, const test_allocator<int>&, const ConstMove&& o) |
| : val(o.val), alloc_constructed(true) {} |
| }; |
| |
| template <> |
| struct std::uses_allocator<ConstMove, test_allocator<int>> : std::true_type {}; |
| |
| template <class T> |
| struct ConvertibleFrom { |
| T v; |
| bool alloc_constructed{false}; |
| |
| constexpr ConvertibleFrom() = default; |
| constexpr ConvertibleFrom(T& _v) |
| requires(std::is_constructible_v<T, T&>) |
| : v(_v) {} |
| constexpr ConvertibleFrom(const T& _v) |
| requires(std::is_constructible_v<T, const T&> && !std::is_const_v<T>) |
| : v(_v) {} |
| constexpr ConvertibleFrom(T&& _v) |
| requires(std::is_constructible_v<T, T &&>) |
| : v(std::move(_v)) {} |
| constexpr ConvertibleFrom(const T&& _v) |
| requires(std::is_constructible_v<T, const T &&> && !std::is_const_v<T>) |
| : v(std::move(_v)) {} |
| |
| template <class U> |
| requires std::is_constructible_v<ConvertibleFrom, U&&> |
| constexpr ConvertibleFrom(std::allocator_arg_t, const test_allocator<int>&, U&& _u) |
| : ConvertibleFrom{std::forward<U>(_u)} { |
| alloc_constructed = true; |
| } |
| }; |
| |
| template <class T> |
| struct std::uses_allocator<ConvertibleFrom<T>, test_allocator<int>> : std::true_type {}; |
| |
| template <class T> |
| struct ExplicitConstructibleFrom { |
| T v; |
| bool alloc_constructed{false}; |
| |
| constexpr explicit ExplicitConstructibleFrom() = default; |
| constexpr explicit ExplicitConstructibleFrom(T& _v) |
| requires(std::is_constructible_v<T, T&>) |
| : v(_v) {} |
| constexpr explicit ExplicitConstructibleFrom(const T& _v) |
| requires(std::is_constructible_v<T, const T&> && !std::is_const_v<T>) |
| : v(_v) {} |
| constexpr explicit ExplicitConstructibleFrom(T&& _v) |
| requires(std::is_constructible_v<T, T &&>) |
| : v(std::move(_v)) {} |
| constexpr explicit ExplicitConstructibleFrom(const T&& _v) |
| requires(std::is_constructible_v<T, const T &&> && !std::is_const_v<T>) |
| : v(std::move(_v)) {} |
| |
| template <class U> |
| requires std::is_constructible_v<ExplicitConstructibleFrom, U&&> |
| constexpr ExplicitConstructibleFrom(std::allocator_arg_t, const test_allocator<int>&, U&& _u) |
| : ExplicitConstructibleFrom{std::forward<U>(_u)} { |
| alloc_constructed = true; |
| } |
| }; |
| |
| template <class T> |
| struct std::uses_allocator<ExplicitConstructibleFrom<T>, test_allocator<int>> : std::true_type {}; |
| |
| struct TracedCopyMove { |
| int nonConstCopy = 0; |
| int constCopy = 0; |
| int nonConstMove = 0; |
| int constMove = 0; |
| bool alloc_constructed = false; |
| |
| constexpr TracedCopyMove() = default; |
| constexpr TracedCopyMove(const TracedCopyMove& other) |
| : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy + 1), nonConstMove(other.nonConstMove), |
| constMove(other.constMove) {} |
| constexpr TracedCopyMove(TracedCopyMove& other) |
| : nonConstCopy(other.nonConstCopy + 1), constCopy(other.constCopy), nonConstMove(other.nonConstMove), |
| constMove(other.constMove) {} |
| |
| constexpr TracedCopyMove(TracedCopyMove&& other) |
| : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove + 1), |
| constMove(other.constMove) {} |
| |
| constexpr TracedCopyMove(const TracedCopyMove&& other) |
| : nonConstCopy(other.nonConstCopy), constCopy(other.constCopy), nonConstMove(other.nonConstMove), |
| constMove(other.constMove + 1) {} |
| |
| template <class U> |
| requires std::is_constructible_v<TracedCopyMove, U&&> |
| constexpr TracedCopyMove(std::allocator_arg_t, const test_allocator<int>&, U&& _u) |
| : TracedCopyMove{std::forward<U>(_u)} { |
| alloc_constructed = true; |
| } |
| }; |
| |
| template <> |
| struct std::uses_allocator<TracedCopyMove, test_allocator<int>> : std::true_type {}; |
| |
| // If the constructor tuple(tuple<UTypes...>&) is not available, |
| // the fallback call to `tuple(const tuple&) = default;` or any other |
| // constructor that takes const ref would increment the constCopy. |
| inline constexpr bool nonConstCopyCtrCalled(const TracedCopyMove& obj) { |
| return obj.nonConstCopy == 1 && obj.constCopy == 0 && obj.constMove == 0 && obj.nonConstMove == 0; |
| } |
| |
| // If the constructor tuple(const tuple<UTypes...>&&) is not available, |
| // the fallback call to `tuple(const tuple&) = default;` or any other |
| // constructor that takes const ref would increment the constCopy. |
| inline constexpr bool constMoveCtrCalled(const TracedCopyMove& obj) { |
| return obj.nonConstMove == 0 && obj.constMove == 1 && obj.constCopy == 0 && obj.nonConstCopy == 0; |
| } |
| |
| struct NoConstructorFromInt {}; |
| |
| struct CvtFromTupleRef : TracedCopyMove { |
| constexpr CvtFromTupleRef() = default; |
| constexpr CvtFromTupleRef(std::tuple<CvtFromTupleRef>& other) |
| : TracedCopyMove(static_cast<TracedCopyMove&>(std::get<0>(other))) {} |
| }; |
| |
| struct ExplicitCtrFromTupleRef : TracedCopyMove { |
| constexpr explicit ExplicitCtrFromTupleRef() = default; |
| constexpr explicit ExplicitCtrFromTupleRef(std::tuple<ExplicitCtrFromTupleRef>& other) |
| : TracedCopyMove(static_cast<TracedCopyMove&>(std::get<0>(other))) {} |
| }; |
| |
| struct CvtFromConstTupleRefRef : TracedCopyMove { |
| constexpr CvtFromConstTupleRefRef() = default; |
| constexpr CvtFromConstTupleRefRef(const std::tuple<CvtFromConstTupleRefRef>&& other) |
| : TracedCopyMove(static_cast<const TracedCopyMove&&>(std::get<0>(other))) {} |
| }; |
| |
| struct ExplicitCtrFromConstTupleRefRef : TracedCopyMove { |
| constexpr explicit ExplicitCtrFromConstTupleRefRef() = default; |
| constexpr explicit ExplicitCtrFromConstTupleRefRef(std::tuple<const ExplicitCtrFromConstTupleRefRef>&& other) |
| : TracedCopyMove(static_cast<const TracedCopyMove&&>(std::get<0>(other))) {} |
| }; |
| |
| template <class T> |
| void conversion_test(T); |
| |
| template <class T, class... Args> |
| concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); }; |
| |
| struct CopyAssign { |
| int val; |
| |
| constexpr CopyAssign() = default; |
| constexpr CopyAssign(int v) : val(v) {} |
| |
| constexpr CopyAssign& operator=(const CopyAssign&) = default; |
| |
| constexpr const CopyAssign& operator=(const CopyAssign&) const = delete; |
| constexpr CopyAssign& operator=(CopyAssign&&) = delete; |
| constexpr const CopyAssign& operator=(CopyAssign&&) const = delete; |
| }; |
| |
| struct ConstCopyAssign { |
| mutable int val; |
| |
| constexpr ConstCopyAssign() = default; |
| constexpr ConstCopyAssign(int v) : val(v) {} |
| |
| constexpr const ConstCopyAssign& operator=(const ConstCopyAssign& other) const { |
| val = other.val; |
| return *this; |
| } |
| |
| constexpr ConstCopyAssign& operator=(const ConstCopyAssign&) = delete; |
| constexpr ConstCopyAssign& operator=(ConstCopyAssign&&) = delete; |
| constexpr const ConstCopyAssign& operator=(ConstCopyAssign&&) const = delete; |
| }; |
| |
| struct MoveAssign { |
| int val; |
| |
| constexpr MoveAssign() = default; |
| constexpr MoveAssign(int v) : val(v) {} |
| |
| constexpr MoveAssign& operator=(MoveAssign&&) = default; |
| |
| constexpr MoveAssign& operator=(const MoveAssign&) = delete; |
| constexpr const MoveAssign& operator=(const MoveAssign&) const = delete; |
| constexpr const MoveAssign& operator=(MoveAssign&&) const = delete; |
| }; |
| |
| struct ConstMoveAssign { |
| mutable int val; |
| |
| constexpr ConstMoveAssign() = default; |
| constexpr ConstMoveAssign(int v) : val(v) {} |
| |
| constexpr const ConstMoveAssign& operator=(ConstMoveAssign&& other) const { |
| val = other.val; |
| return *this; |
| } |
| |
| constexpr ConstMoveAssign& operator=(const ConstMoveAssign&) = delete; |
| constexpr const ConstMoveAssign& operator=(const ConstMoveAssign&) const = delete; |
| constexpr ConstMoveAssign& operator=(ConstMoveAssign&&) = delete; |
| }; |
| |
| template <class T> |
| struct AssignableFrom { |
| T v; |
| |
| constexpr AssignableFrom() = default; |
| |
| template <class U> |
| constexpr AssignableFrom(U&& u) |
| requires std::is_constructible_v<T, U&&> |
| : v(std::forward<U>(u)) {} |
| |
| constexpr AssignableFrom& operator=(const T& t) |
| requires std::is_copy_assignable_v<T> |
| { |
| v = t; |
| return *this; |
| } |
| |
| constexpr AssignableFrom& operator=(T&& t) |
| requires std::is_move_assignable_v<T> |
| { |
| v = std::move(t); |
| return *this; |
| } |
| |
| constexpr const AssignableFrom& operator=(const T& t) const |
| requires std::is_assignable_v<const T&, const T&> |
| { |
| v = t; |
| return *this; |
| } |
| |
| constexpr const AssignableFrom& operator=(T&& t) const |
| requires std::is_assignable_v<const T&, T&&> |
| { |
| v = std::move(t); |
| return *this; |
| } |
| }; |
| |
| struct TracedAssignment { |
| int copyAssign = 0; |
| mutable int constCopyAssign = 0; |
| int moveAssign = 0; |
| mutable int constMoveAssign = 0; |
| |
| constexpr TracedAssignment() = default; |
| |
| constexpr TracedAssignment& operator=(const TracedAssignment&) { |
| copyAssign++; |
| return *this; |
| } |
| constexpr const TracedAssignment& operator=(const TracedAssignment&) const { |
| constCopyAssign++; |
| return *this; |
| } |
| constexpr TracedAssignment& operator=(TracedAssignment&&) { |
| moveAssign++; |
| return *this; |
| } |
| constexpr const TracedAssignment& operator=(TracedAssignment&&) const { |
| constMoveAssign++; |
| return *this; |
| } |
| }; |
| #endif |