userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
numeric_cast.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/utils/numeric_cast.hpp
4
/// @brief @copybrief utils::numeric_cast
5
6
#
include
<
cmath
>
7
#
include
<
limits
>
8
#
include
<
stdexcept
>
9
10
#
include
<
fmt
/
format
.
h
>
11
12
#
include
<
userver
/
compiler
/
demangle
.
hpp
>
13
14
USERVER_NAMESPACE_BEGIN
15
16
namespace
utils
{
17
18
namespace
impl {
19
20
template
<
typename
T>
21
using
PrintableValue = std::conditional_t<(
sizeof
(T) > 1), T,
int
>;
22
23
}
24
25
/// Detects loss of range when a numeric type is converted, and throws an
26
/// exception if the range cannot be preserved
27
///
28
/// ## Example usage:
29
///
30
/// @snippet utils/numeric_cast_test.cpp Sample utils::numeric_cast usage
31
template
<
typename
To,
typename
Exception = std::runtime_error,
typename
From>
32
constexpr
To
numeric_cast
(From input) {
// NOLINT(readability-identifier-naming)
33
constexpr
bool
is_integral = std::is_integral_v<From> && std::is_integral_v<To>;
34
constexpr
bool
is_floating_point = std::is_floating_point_v<From> && std::is_floating_point_v<To>;
35
static_assert
(is_integral || is_floating_point);
36
37
using
FromLimits = std::numeric_limits<From>;
38
using
ToLimits = std::numeric_limits<To>;
39
40
constexpr
bool
check_positive_overflow =
41
is_integral ? ToLimits::digits < FromLimits::digits : ToLimits::max() < FromLimits::max();
42
constexpr
bool
check_negative_overflow =
43
is_integral
44
?
45
// signed -> signed: possible loss if narrowing
46
// signed -> unsigned: loss if negative
47
FromLimits::is_signed && (!ToLimits::is_signed || ToLimits::digits < FromLimits::digits)
48
: ToLimits::lowest() > FromLimits::lowest();
49
50
std::string_view overflow_type{};
51
52
if
constexpr
(check_positive_overflow) {
53
if
(input >
static_cast
<From>(ToLimits::max())) {
54
if
(!FromLimits::has_infinity || !std::isinf(input)) {
55
overflow_type =
"positive"
;
56
}
57
}
58
}
59
60
if
constexpr
(check_negative_overflow) {
61
if
(input <
static_cast
<From>(ToLimits::lowest())) {
62
if
(!FromLimits::has_infinity || !std::isinf(input)) {
63
overflow_type =
"negative"
;
64
}
65
}
66
}
67
68
if
(!overflow_type.empty()) {
69
throw
Exception(fmt::format(
70
"Failed to convert {} {} into {} due to {} integer overflow"
,
71
compiler
::GetTypeName<From>(),
72
static_cast
<impl::PrintableValue<From>>(input),
73
compiler
::GetTypeName<To>(),
74
overflow_type
75
));
76
}
77
78
return
static_cast
<To>(input);
79
}
80
81
}
// namespace utils
82
83
USERVER_NAMESPACE_END
userver
utils
numeric_cast.hpp
Generated on
for userver by
Doxygen
1.17.0