Version: SMASH-3.4
numeric_cast.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2022,2024
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_NUMERIC_CAST_H_
11 #define SRC_INCLUDE_SMASH_NUMERIC_CAST_H_
12 
13 #include <string>
14 #include <string_view>
15 
16 namespace smash {
17 
18 namespace detail {
19 
20 /**
21  * Get type of variable as string in a human-readable way.
22  *
23  * @tparam T The type to be returned.
24  * @return A \c std::string containing the name of the type.
25  */
26 template <typename T>
27 constexpr auto type_name() {
28  std::string_view name, prefix, suffix;
29 #ifdef __clang__
30  name = __PRETTY_FUNCTION__;
31  prefix = "auto smash::detail::type_name() [T = ";
32  suffix = "]";
33 #elif defined(__GNUC__)
34  name = __PRETTY_FUNCTION__;
35  prefix = "constexpr auto smash::detail::type_name() [with T = ";
36  suffix = "]";
37 #elif defined(_MSC_VER)
38  name = __FUNCSIG__;
39  prefix = "auto __cdecl smash::detail::type_name<";
40  suffix = ">(void)";
41 #else
42  name = "UNKNOWN";
43  prefix = "";
44  suffix = "";
45 #endif
46  name.remove_prefix(prefix.size());
47  name.remove_suffix(suffix.size());
48  return std::string{name};
49 }
50 
51 } // namespace detail
52 
53 /**
54  * Function template to perform a safe numeric conversion between types.
55  *
56  * \tparam To Destination type
57  * \tparam From Source type
58  * \tparam unnamed The last template parameter makes such that this function
59  * template participates in function overload only if the destination type \c To
60  * is an arithmetic type (typical usage of SFINAE).
61  *
62  * \param[in] from Input value to be converted
63  * \return The input value converted to the new type \c To .
64  * \throw std::domain_error If the value to be converted cannot be represented
65  * by any value of the destination type.
66  *
67  * \note This is adapted from the Microsoft implementation of \c narrow function
68  * in the C++ <a href="https://github.com/microsoft/GSL/tree/main">Guidelines
69  * Support Library</a>, which is released under MIT license.
70  */
71 
72 template <typename To, class From,
73  typename std::enable_if_t<std::is_arithmetic_v<To>, bool> = true>
74 constexpr To numeric_cast(From from) noexcept(false) {
75  /* While this is technically undefined behavior in some cases (i.e., if the
76  source value is of floating-point type and cannot fit into the destination
77  integral type), the resultant behavior is benign on the platforms that we
78  target (i.e., no hardware trap representations are hit). */
79  const To to = static_cast<To>(from);
80 
81  /*
82  * NOTE 1: NaN will always throw, since NaN != NaN
83  *
84  * NOTE 2: The first condition in the if-clause below is not enough because it
85  * might happen that the cast back is matching the initial value when casting
86  * signed to unsigned numbers or vice-versa because of the "wrapping around"
87  * behaviour. See https://stackoverflow.com/a/52863884 for more information.
88  */
89  constexpr const bool is_different_signedness =
90  (std::is_signed_v<To> != std::is_signed_v<From>);
91  if (static_cast<From>(to) != from ||
92  (is_different_signedness && ((to < To{}) != (from < From{})))) {
93  throw std::domain_error("Numeric cast failed converting '" +
94  detail::type_name<From>() + "' to '" +
95  detail::type_name<To>() + "'.");
96  }
97 
98  return to;
99 }
100 
101 } // namespace smash
102 
103 #endif // SRC_INCLUDE_SMASH_NUMERIC_CAST_H_
constexpr auto type_name()
Get type of variable as string in a human-readable way.
Definition: numeric_cast.h:27
Definition: action.h:24
constexpr To numeric_cast(From from) noexcept(false)
Function template to perform a safe numeric conversion between types.
Definition: numeric_cast.h:74