#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 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 bool IsInIntegralRange(S value) requires std::is_signed_v && std::is_unsigned_v { return value <= static_cast::type>(std::numeric_limits::max()); } template 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 bool IsInIntegralRange(S value) requires std::is_unsigned_v && std::is_unsigned_v { return value <= std::numeric_limits::max(); } template 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 bool TryIntegralCast(S value, T* result) { if (!NYT::NDetail::IsInIntegralRange(value)) { return false; } *result = static_cast(value); return true; } template T CheckedIntegralCast(S value) { T result; if (!TryIntegralCast(value, &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 bool TryEnumCast(S value, T* result) { std::underlying_type_t underlying; if (!TryIntegralCast>(value, &underlying)) { return false; } auto candidate = static_cast(underlying); if (!TEnumTraits::FindLiteralByValue(candidate)) { return false; } *result = candidate; return true; } template T CheckedEnumCast(S value) { T result; if (!TryEnumCast(value, &result)) { throw TSimpleException(Sprintf("Error casting %s value \"%d\" to enum %s", TypeName().c_str(), static_cast(value), TEnumTraits::GetTypeName().data())); } return result; } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT