xrpld
Loading...
Searching...
No Matches
safe_cast.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h>
4
5#include <type_traits>
6
7namespace xrpl {
8
9// safe_cast adds compile-time checks to a static_cast to ensure that
10// the destination can hold all values of the source. This is particularly
11// handy when the source or destination is an enumeration type.
12
13template <class Src, class Dest>
16 (std::is_signed_v<Src> != std::is_signed_v<Dest> ? sizeof(Dest) > sizeof(Src)
17 : sizeof(Dest) >= sizeof(Src));
18
19template <class Dest, class Src>
21safeCast(Src s) noexcept
22{
23 static_assert(
24 std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
25 constexpr unsigned kNotSame = std::is_signed_v<Dest> != std::is_signed_v<Src>;
26 static_assert(
27 sizeof(Dest) >= sizeof(Src) + kNotSame,
28 "Destination is too small to hold all values of source");
29 return static_cast<Dest>(s);
30}
31
32template <class Dest, class Src>
34safeCast(Src s) noexcept
35{
36 return static_cast<Dest>(safeCast<std::underlying_type_t<Dest>>(s));
37}
38
39template <class Dest, class Src>
41safeCast(Src s) noexcept
42{
43 return safeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
44}
45
46// unsafe_cast explicitly flags a static_cast as not necessarily able to hold
47// all values of the source. It includes a compile-time check so that if
48// underlying types become safe, it can be converted to a safe_cast.
49
50template <class Dest, class Src>
52unsafeCast(Src s) noexcept
53{
54 static_assert(
56 "Only unsafe if casting signed to unsigned or "
57 "destination is too small");
58 return static_cast<Dest>(s);
59}
60
61template <class Dest, class Src>
63unsafeCast(Src s) noexcept
64{
65 return static_cast<Dest>(unsafeCast<std::underlying_type_t<Dest>>(s));
66}
67
68template <class Dest, class Src>
70unsafeCast(Src s) noexcept
71{
72 return unsafeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
73}
74
75template <class Dest, class Src>
77inline Dest
78safeDowncast(Src* s) noexcept
79{
80#ifdef NDEBUG
81 return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
82#else
83 auto* result = dynamic_cast<Dest>(s);
84 XRPL_ASSERT(result != nullptr, "xrpl::safeDowncast : pointer downcast is valid");
85 return result;
86#endif
87}
88
89template <class Dest, class Src>
91inline Dest
92safeDowncast(Src& s) noexcept
93{
94#ifndef NDEBUG
95 XRPL_ASSERT(
96 dynamic_cast<std::add_pointer_t<std::remove_reference_t<Dest>>>(&s) != nullptr,
97 "xrpl::safeDowncast : reference downcast is valid");
98#endif
99 return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
100}
101
102} // namespace xrpl
T is_enum_v
T is_integral_v
T is_lvalue_reference_v
T is_pointer_v
T is_signed_v
T is_unsigned_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
Dest safeDowncast(Src *s) noexcept
Definition safe_cast.h:78
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safeCast(Src s) noexcept
Definition safe_cast.h:21
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > unsafeCast(Src s) noexcept
Definition safe_cast.h:52