#ifndef CAST_INL_H_ #error "Direct inclusion of this file is not allowed, include cast.h" // For the sake of sane code completion. #include "cast.h" #endif #include "enum.h" #include #include #include namespace NYT { //////////////////////////////////////////////////////////////////////////////// namespace NDetail { template constexpr bool IsInIntegralRange(S value) requires std::is_signed_v && std::is_signed_v { return value >= std::numeric_limits::lowest() && value <= std::numeric_limits::max(); } template constexpr bool IsInIntegralRange(S value) requires std::is_signed_v && std::is_unsigned_v { return value <= static_cast::type>(std::numeric_limits::max()); } template constexpr bool IsInIntegralRange(S value) requires std::is_unsigned_v && std::is_signed_v { return value >= 0 && static_cast::type>(value) <= std::numeric_limits::max(); } template constexpr bool IsInIntegralRange(S value) requires std::is_unsigned_v && std::is_unsigned_v { return value <= std::numeric_limits::max(); } template constexpr bool IsInIntegralRange(S value) requires std::is_enum_v { return IsInIntegralRange(static_cast>(value)); } template TString FormatInvalidCastValue(T value) { return ::ToString(value); } inline TString FormatInvalidCastValue(signed char value) { return TString("'") + value + TString("'"); } inline TString FormatInvalidCastValue(unsigned char value) { return TString("'") + value + TString("'"); } #ifdef __cpp_char8_t inline TString FormatInvalidCastValue(char8_t value) { return FormatInvalidCastValue(static_cast(value)); } #endif } // namespace NDetail //////////////////////////////////////////////////////////////////////////////// template constexpr bool CanFitSubtype() { return NDetail::IsInIntegralRange(std::numeric_limits::min()) && NDetail::IsInIntegralRange(std::numeric_limits::max()); } template constexpr bool IsInIntegralRange(S value) { return NDetail::IsInIntegralRange(value); } template constexpr std::optional TryCheckedIntegralCast(S value) { [[unlikely]] if (!NDetail::IsInIntegralRange(value)) { return std::nullopt; } return static_cast(value); } template T CheckedIntegralCast(S value) { auto result = TryCheckedIntegralCast(value); if (!result) { throw TSimpleException(Sprintf("Error casting %s value \"%s\" to %s: value is out of expected range [%s; %s]", TypeName().c_str(), NYT::NDetail::FormatInvalidCastValue(value).c_str(), TypeName().c_str(), ::ToString(std::numeric_limits::lowest()).c_str(), ::ToString(std::numeric_limits::max()).c_str())); } return *result; } template requires TEnumTraits::IsEnum constexpr std::optional TryCheckedEnumCast(S value, bool enableUnknown) { auto underlying = TryCheckedIntegralCast>(value); [[unlikely]] if (!underlying) { return std::nullopt; } auto candidate = static_cast(*underlying); [[unlikely]] if (!TEnumTraits::IsValidValue(candidate)) { if (enableUnknown) { if constexpr (constexpr auto optionalUnknownValue = TEnumTraits::TryGetUnknownValue()) { if constexpr (TEnumTraits::IsBitEnum) { return static_cast(*underlying & ToUnderlying(TEnumTraits::GetAllSetValue())) | *optionalUnknownValue; } else { return *optionalUnknownValue; } } } return std::nullopt; } return candidate; } template requires TEnumTraits::IsEnum T CheckedEnumCast(S value) { auto result = TryCheckedEnumCast(value, /*enableUnknown*/ true); [[unlikely]] if (!result) { if constexpr (std::is_signed_v) { throw TSimpleException(Sprintf("Error casting %s value \"%" PRIi64 "\" to enum %s", TypeName().c_str(), static_cast(value), TEnumTraits::GetTypeName().data())); } else { throw TSimpleException(Sprintf("Error casting %s value \"%" PRIu64 "\" to enum %s", TypeName().c_str(), static_cast(value), TEnumTraits::GetTypeName().data())); } } return *result; } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT