1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef TEST_SUPPORT_PROPAGATE_VALUE_CATEGORY
10 #define TEST_SUPPORT_PROPAGATE_VALUE_CATEGORY
12 #include "test_macros.h"
13 #include <type_traits>
16 #error this header may only be used in C++11
19 using UnderlyingVCType
= unsigned;
20 enum ValueCategory
: UnderlyingVCType
{
26 VC_ConstVolatile
= VC_Const
| VC_Volatile
29 inline constexpr ValueCategory
operator&(ValueCategory LHS
, ValueCategory RHS
) {
30 return ValueCategory(LHS
& (UnderlyingVCType
)RHS
);
33 inline constexpr ValueCategory
operator|(ValueCategory LHS
, ValueCategory RHS
) {
34 return ValueCategory(LHS
| (UnderlyingVCType
)RHS
);
37 inline constexpr ValueCategory
operator^(ValueCategory LHS
, ValueCategory RHS
) {
38 return ValueCategory(LHS
^ (UnderlyingVCType
)RHS
);
41 inline constexpr bool isValidValueCategory(ValueCategory VC
) {
42 return (VC
& (VC_LVal
| VC_RVal
)) != (VC_LVal
| VC_RVal
);
45 inline constexpr bool hasValueCategory(ValueCategory Arg
, ValueCategory Key
) {
46 return Arg
== Key
|| ((Arg
& Key
) == Key
);
51 typename
std::remove_cv
<typename
std::remove_reference
<Tp
>::type
>::type
;
54 constexpr ValueCategory
getReferenceQuals() {
55 return std::is_lvalue_reference
<Tp
>::value
57 : (std::is_rvalue_reference
<Tp
>::value
? VC_RVal
: VC_None
);
59 static_assert(getReferenceQuals
<int>() == VC_None
, "");
60 static_assert(getReferenceQuals
<int &>() == VC_LVal
, "");
61 static_assert(getReferenceQuals
<int &&>() == VC_RVal
, "");
64 constexpr ValueCategory
getCVQuals() {
65 using Vp
= typename
std::remove_reference
<Tp
>::type
;
66 return std::is_const
<Vp
>::value
&& std::is_volatile
<Vp
>::value
68 : (std::is_const
<Vp
>::value
70 : (std::is_volatile
<Vp
>::value
? VC_Volatile
: VC_None
));
72 static_assert(getCVQuals
<int>() == VC_None
, "");
73 static_assert(getCVQuals
<int const>() == VC_Const
, "");
74 static_assert(getCVQuals
<int volatile>() == VC_Volatile
, "");
75 static_assert(getCVQuals
<int const volatile>() == VC_ConstVolatile
, "");
76 static_assert(getCVQuals
<int &>() == VC_None
, "");
77 static_assert(getCVQuals
<int const &>() == VC_Const
, "");
80 inline constexpr ValueCategory
getValueCategory() {
81 return getReferenceQuals
<Tp
>() | getCVQuals
<Tp
>();
83 static_assert(getValueCategory
<int>() == VC_None
, "");
84 static_assert(getValueCategory
<int const &>() == (VC_LVal
| VC_Const
), "");
85 static_assert(getValueCategory
<int const volatile &&>() ==
86 (VC_RVal
| VC_ConstVolatile
),
89 template <ValueCategory VC
>
90 struct ApplyValueCategory
{
92 static_assert(isValidValueCategory(VC
), "");
94 template <bool Pred
, class Then
, class Else
>
95 using CondT
= typename
std::conditional
<Pred
, Then
, Else
>::type
;
98 template <class Tp
, class Vp
= UnCVRef
<Tp
>>
99 using ApplyCVQuals
= CondT
<
100 hasValueCategory(VC
, VC_ConstVolatile
), typename
std::add_cv
<Vp
>::type
,
101 CondT
<hasValueCategory(VC
, VC_Const
), typename
std::add_const
<Vp
>::type
,
102 CondT
<hasValueCategory(VC
, VC_Volatile
),
103 typename
std::add_volatile
<Vp
>::type
, Tp
>>>;
105 template <class Tp
, class Vp
= typename
std::remove_reference
<Tp
>::type
>
106 using ApplyReferenceQuals
=
107 CondT
<hasValueCategory(VC
, VC_LVal
),
108 typename
std::add_lvalue_reference
<Vp
>::type
,
109 CondT
<hasValueCategory(VC
, VC_RVal
),
110 typename
std::add_rvalue_reference
<Vp
>::type
, Vp
>>;
113 using Apply
= ApplyReferenceQuals
<ApplyCVQuals
<UnCVRef
<Tp
>>>;
115 template <class Tp
, bool Dummy
= true,
116 typename
std::enable_if
<Dummy
&& (VC
& VC_LVal
), bool>::type
= true>
117 static Apply
<UnCVRef
<Tp
>> cast(Tp
&&t
) {
118 using ToType
= Apply
<UnCVRef
<Tp
>>;
119 return static_cast<ToType
>(t
);
122 template <class Tp
, bool Dummy
= true,
123 typename
std::enable_if
<Dummy
&& (VC
& VC_RVal
), bool>::type
= true>
124 static Apply
<UnCVRef
<Tp
>> cast(Tp
&&t
) {
125 using ToType
= Apply
<UnCVRef
<Tp
>>;
126 return static_cast<ToType
>(std::move(t
));
130 class Tp
, bool Dummy
= true,
131 typename
std::enable_if
<Dummy
&& ((VC
& (VC_LVal
| VC_RVal
)) == VC_None
),
133 static Apply
<UnCVRef
<Tp
>> cast(Tp
&&t
) {
138 template <ValueCategory VC
, class Tp
>
139 using ApplyValueCategoryT
= typename ApplyValueCategory
<VC
>::template Apply
<Tp
>;
142 using PropagateValueCategory
= ApplyValueCategory
<getValueCategory
<Tp
>()>;
144 template <class Tp
, class Up
>
145 using PropagateValueCategoryT
=
146 typename ApplyValueCategory
<getValueCategory
<Tp
>()>::template Apply
<Up
>;
148 template <ValueCategory VC
, class Tp
>
149 typename ApplyValueCategory
<VC
>::template Apply
<Tp
> ValueCategoryCast(Tp
&&t
) {
150 return ApplyValueCategory
<VC
>::cast(std::forward
<Tp
>(t
));
153 #endif // TEST_SUPPORT_PROPAGATE_VALUE_CATEGORY