mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 10:35:50 +00:00
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d). This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
86 lines
2.7 KiB
C++
86 lines
2.7 KiB
C++
#ifndef XRPL_BASICS_SAFE_CAST_H_INCLUDED
|
|
#define XRPL_BASICS_SAFE_CAST_H_INCLUDED
|
|
|
|
#include <type_traits>
|
|
|
|
namespace ripple {
|
|
|
|
// safe_cast adds compile-time checks to a static_cast to ensure that
|
|
// the destination can hold all values of the source. This is particularly
|
|
// handy when the source or destination is an enumeration type.
|
|
|
|
template <class Src, class Dest>
|
|
concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
|
(std::is_signed<Src>::value || std::is_unsigned<Dest>::value) &&
|
|
(std::is_signed<Src>::value != std::is_signed<Dest>::value
|
|
? sizeof(Dest) > sizeof(Src)
|
|
: sizeof(Dest) >= sizeof(Src));
|
|
|
|
template <class Dest, class Src>
|
|
inline constexpr std::
|
|
enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
|
safe_cast(Src s) noexcept
|
|
{
|
|
static_assert(
|
|
std::is_signed_v<Dest> || std::is_unsigned_v<Src>,
|
|
"Cannot cast signed to unsigned");
|
|
constexpr unsigned not_same =
|
|
std::is_signed_v<Dest> != std::is_signed_v<Src>;
|
|
static_assert(
|
|
sizeof(Dest) >= sizeof(Src) + not_same,
|
|
"Destination is too small to hold all values of source");
|
|
return static_cast<Dest>(s);
|
|
}
|
|
|
|
template <class Dest, class Src>
|
|
inline constexpr std::
|
|
enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
|
safe_cast(Src s) noexcept
|
|
{
|
|
return static_cast<Dest>(safe_cast<std::underlying_type_t<Dest>>(s));
|
|
}
|
|
|
|
template <class Dest, class Src>
|
|
inline constexpr std::
|
|
enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
|
safe_cast(Src s) noexcept
|
|
{
|
|
return safe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
|
}
|
|
|
|
// unsafe_cast explicitly flags a static_cast as not necessarily able to hold
|
|
// all values of the source. It includes a compile-time check so that if
|
|
// underlying types become safe, it can be converted to a safe_cast.
|
|
|
|
template <class Dest, class Src>
|
|
inline constexpr std::
|
|
enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
|
unsafe_cast(Src s) noexcept
|
|
{
|
|
static_assert(
|
|
!SafeToCast<Src, Dest>,
|
|
"Only unsafe if casting signed to unsigned or "
|
|
"destination is too small");
|
|
return static_cast<Dest>(s);
|
|
}
|
|
|
|
template <class Dest, class Src>
|
|
inline constexpr std::
|
|
enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
|
unsafe_cast(Src s) noexcept
|
|
{
|
|
return static_cast<Dest>(unsafe_cast<std::underlying_type_t<Dest>>(s));
|
|
}
|
|
|
|
template <class Dest, class Src>
|
|
inline constexpr std::
|
|
enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
|
unsafe_cast(Src s) noexcept
|
|
{
|
|
return unsafe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
|
}
|
|
|
|
} // namespace ripple
|
|
|
|
#endif
|