//===----------------------------------------------------------------------===// // // 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 TEST_SUPPORT_PROPAGATE_VALUE_CATEGORY #define TEST_SUPPORT_PROPAGATE_VALUE_CATEGORY #include "test_macros.h" #include #if TEST_STD_VER < 11 #error this header may only be used in C++11 #endif using UnderlyingVCType = unsigned; enum ValueCategory : UnderlyingVCType { VC_None = 0, VC_LVal = 1 << 0, VC_RVal = 1 << 1, VC_Const = 1 << 2, VC_Volatile = 1 << 3, VC_ConstVolatile = VC_Const | VC_Volatile }; inline constexpr ValueCategory operator&(ValueCategory LHS, ValueCategory RHS) { return ValueCategory(LHS & (UnderlyingVCType)RHS); } inline constexpr ValueCategory operator|(ValueCategory LHS, ValueCategory RHS) { return ValueCategory(LHS | (UnderlyingVCType)RHS); } inline constexpr ValueCategory operator^(ValueCategory LHS, ValueCategory RHS) { return ValueCategory(LHS ^ (UnderlyingVCType)RHS); } inline constexpr bool isValidValueCategory(ValueCategory VC) { return (VC & (VC_LVal | VC_RVal)) != (VC_LVal | VC_RVal); } inline constexpr bool hasValueCategory(ValueCategory Arg, ValueCategory Key) { return Arg == Key || ((Arg & Key) == Key); } template using UnCVRef = typename std::remove_cv::type>::type; template constexpr ValueCategory getReferenceQuals() { return std::is_lvalue_reference::value ? VC_LVal : (std::is_rvalue_reference::value ? VC_RVal : VC_None); } static_assert(getReferenceQuals() == VC_None, ""); static_assert(getReferenceQuals() == VC_LVal, ""); static_assert(getReferenceQuals() == VC_RVal, ""); template constexpr ValueCategory getCVQuals() { using Vp = typename std::remove_reference::type; return std::is_const::value && std::is_volatile::value ? VC_ConstVolatile : (std::is_const::value ? VC_Const : (std::is_volatile::value ? VC_Volatile : VC_None)); } static_assert(getCVQuals() == VC_None, ""); static_assert(getCVQuals() == VC_Const, ""); static_assert(getCVQuals() == VC_Volatile, ""); static_assert(getCVQuals() == VC_ConstVolatile, ""); static_assert(getCVQuals() == VC_None, ""); static_assert(getCVQuals() == VC_Const, ""); template inline constexpr ValueCategory getValueCategory() { return getReferenceQuals() | getCVQuals(); } static_assert(getValueCategory() == VC_None, ""); static_assert(getValueCategory() == (VC_LVal | VC_Const), ""); static_assert(getValueCategory() == (VC_RVal | VC_ConstVolatile), ""); template struct ApplyValueCategory { private: static_assert(isValidValueCategory(VC), ""); template using CondT = typename std::conditional::type; public: template > using ApplyCVQuals = CondT< hasValueCategory(VC, VC_ConstVolatile), typename std::add_cv::type, CondT::type, CondT::type, Tp>>>; template ::type> using ApplyReferenceQuals = CondT::type, CondT::type, Vp>>; template using Apply = ApplyReferenceQuals>>; template ::type = true> static Apply> cast(Tp &&t) { using ToType = Apply>; return static_cast(t); } template ::type = true> static Apply> cast(Tp &&t) { using ToType = Apply>; return static_cast(std::move(t)); } template < class Tp, bool Dummy = true, typename std::enable_if::type = true> static Apply> cast(Tp &&t) { return t; } }; template using ApplyValueCategoryT = typename ApplyValueCategory::template Apply; template using PropagateValueCategory = ApplyValueCategory()>; template using PropagateValueCategoryT = typename ApplyValueCategory()>::template Apply; template typename ApplyValueCategory::template Apply ValueCategoryCast(Tp &&t) { return ApplyValueCategory::cast(std::forward(t)); }; #endif // TEST_SUPPORT_PROPAGATE_VALUE_CATEGORY