xrpld
Loading...
Searching...
No Matches
safe_cast.h
1#pragma once
2
3#include <xrpl/beast/utility/instrumentation.h> // IWYU pragma: keep
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>
20constexpr Dest
21safeCast(Src s) noexcept
23{
24 static_assert(
25 std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
26 constexpr unsigned kNotSame = std::is_signed_v<Dest> != std::is_signed_v<Src>;
27 static_assert(
28 sizeof(Dest) >= sizeof(Src) + kNotSame,
29 "Destination is too small to hold all values of source");
30 return static_cast<Dest>(s);
31}
32
33template <class Dest, class Src>
34constexpr Dest
35safeCast(Src s) noexcept
37{
38 return static_cast<Dest>(safeCast<std::underlying_type_t<Dest>>(s));
39}
40
41template <class Dest, class Src>
42constexpr Dest
43safeCast(Src s) noexcept
45{
46 return safeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
47}
48
49// unsafe_cast explicitly flags a static_cast as not necessarily able to hold
50// all values of the source. It includes a compile-time check so that if
51// underlying types become safe, it can be converted to a safe_cast.
52
53template <class Dest, class Src>
54constexpr Dest
55unsafeCast(Src s) noexcept
57{
58 static_assert(
60 "Only unsafe if casting signed to unsigned or "
61 "destination is too small");
62 return static_cast<Dest>(s);
63}
64
65template <class Dest, class Src>
66constexpr Dest
67unsafeCast(Src s) noexcept
69{
70 return static_cast<Dest>(unsafeCast<std::underlying_type_t<Dest>>(s));
71}
72
73template <class Dest, class Src>
74constexpr Dest
75unsafeCast(Src s) noexcept
77{
78 return unsafeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
79}
80
81template <class Dest, class Src>
83inline Dest
84safeDowncast(Src* s) noexcept
85{
86#ifdef NDEBUG
87 return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
88#else
89 auto* result = dynamic_cast<Dest>(s);
90 XRPL_ASSERT(result != nullptr, "xrpl::safeDowncast : pointer downcast is valid");
91 return result;
92#endif
93}
94
95template <class Dest, class Src>
97inline Dest
98safeDowncast(Src& s) noexcept
99{
100#ifndef NDEBUG
101 XRPL_ASSERT(
102 dynamic_cast<std::add_pointer_t<std::remove_reference_t<Dest>>>(&s) != nullptr,
103 "xrpl::safeDowncast : reference downcast is valid");
104#endif
105 return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
106}
107
108} // 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:84
constexpr Dest safeCast(Src s) noexcept
Definition safe_cast.h:21
constexpr Dest unsafeCast(Src s) noexcept
Definition safe_cast.h:55