KaMPIng 0.2.0
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
checking_casts.hpp
Go to the documentation of this file.
1// This file is part of KaMPIng.
2//
3// Copyright 2021 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14/// @file
15/// @brief Helper functions that make casts safer.
16
17#pragma once
18
19#include <cstdint>
20#include <limits>
21#include <stdexcept>
22#include <string>
23#include <type_traits>
24
25#include "kamping/kassert/kassert.hpp"
26#include "kamping/noexcept.hpp"
27
28namespace kamping {
29
30/// @addtogroup kamping_utility
31/// @{
32
33/// @brief Checks if an integer value can be safely casted into an integer type To, that is, it lies in the range
34/// [min(To), max(To)].
35///
36/// This function works only for integer types which have at most std::numeric_limits<intmax_t>::digits (To and From are
37/// signed) or std::numeric_limits<intmax_t>::digits (else) bits. This function includes checks for these two
38/// assumptions using static_assert()s.
39///
40/// @tparam To Type to be casted to.
41/// @tparam From Type to be casted from, will be auto inferred.
42/// @param value Value you want to cast.
43/// @return \c true if value can be safely casted into type To, that is, value is in To's range.
44/// @return \c false otherwise.
45///
46template <class To, class From>
47constexpr bool in_range(From value) noexcept {
48 static_assert(std::is_integral_v<From>, "From has to be an integral type.");
49 static_assert(std::is_integral_v<To>, "To has to be an integral type.");
50
51 // Check that the 0 is included in From and To. 0 is always included in signed types.
52 static_assert(
53 std::is_signed_v<From> || std::numeric_limits<From>::min() == 0,
54 "The type From has to include the number 0."
55 );
56 static_assert(
57 std::is_signed_v<To> || std::numeric_limits<To>::min() == 0,
58 "The type To has to include the number 0."
59 );
60
61 // Check if we can safely cast To and From into (u)intmax_t.
62 if constexpr (std::is_signed_v<From> && std::is_signed_v<To>) {
63 static_assert(
64 std::numeric_limits<From>::digits <= std::numeric_limits<intmax_t>::digits,
65 "From has more bits than intmax_t."
66 );
67 static_assert(
68 std::numeric_limits<To>::digits <= std::numeric_limits<intmax_t>::digits,
69 "To has more bits than intmax_t."
70 );
71 } else {
72 static_assert(
73 std::numeric_limits<From>::digits <= std::numeric_limits<uintmax_t>::digits,
74 "From has more bits than uintmax_t."
75 );
76 static_assert(
77 std::numeric_limits<To>::digits <= std::numeric_limits<uintmax_t>::digits,
78 "To has more bits than uintmax_t."
79 );
80 }
81
82 // Check if the parameters value is inside To's range.
83 if constexpr (std::is_unsigned_v<From> && std::is_unsigned_v<To>) {
84 return static_cast<uintmax_t>(value) <= static_cast<uintmax_t>(std::numeric_limits<To>::max());
85 } else if constexpr (std::is_signed_v<From> && std::is_signed_v<To>) {
86 return static_cast<intmax_t>(value) >= static_cast<intmax_t>(std::numeric_limits<To>::min())
87 && static_cast<intmax_t>(value) <= static_cast<intmax_t>(std::numeric_limits<To>::max());
88 } else if constexpr (std::is_signed_v<From> && std::is_unsigned_v<To>) {
89 if (value < 0) {
90 return false;
91 } else {
92 return static_cast<uintmax_t>(value) <= static_cast<uintmax_t>(std::numeric_limits<To>::max());
93 }
94 } else if constexpr (std::is_unsigned_v<From> && std::is_signed_v<To>) {
95 return static_cast<uintmax_t>(value) <= static_cast<uintmax_t>(std::numeric_limits<To>::max());
96 }
97}
98
99///
100/// @brief Casts an integer value to the integer type To. If the value is outside To's range, throws an assertion.
101///
102/// Alternatively, exceptions can be used instead of assertions by using \ref throwing_cast().
103///
104/// This function works only for integer types which have at most std::numeric_limits<intmax_t>::digits (To and From are
105/// signed) or std::numeric_limits<intmax_t>::digits (else) bits. These two assumptions are checked by in_range() using
106/// static_assert()s.
107///
108///
109/// @tparam To Type to cast to.
110/// @tparam From Type to cast from, will be auto inferred.
111/// @param value Value you want to cast.
112/// @return Casted value.
113///
114template <class To, class From>
117 return static_cast<To>(value);
118}
119
120///
121/// @brief Casts an integer value to the integer type To. If the value is outside To's range, throws an exception.
122///
123/// Alternatively, assertions can be used instead of exceptions by using \ref asserting_cast().
124///
125/// This function works only for integer types which have at most std::numeric_limits<intmax_t>::digits (To and From are
126/// signed) or std::numeric_limits<intmax_t>::digits (else) bits. These two assumptions are checked by in_range() using
127/// static_assert()s.
128///
129/// @tparam To Type to cast to.
130/// @tparam From Type to cast from, will be auto inferred.
131/// @param value Value you want to cast.
132/// @return Casted value.
133///
134template <class To, class From>
135constexpr To throwing_cast(From value) {
137 in_range<To>(value),
138 value << " is not representable by the target type.",
139 std::range_error
140 );
141 return static_cast<To>(value);
142}
143
144/// @}
145
146} // namespace kamping
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
constexpr To throwing_cast(From value)
Casts an integer value to the integer type To. If the value is outside To's range,...
Definition checking_casts.hpp:135
constexpr To asserting_cast(From value) KAMPING_NOEXCEPT
Casts an integer value to the integer type To. If the value is outside To's range,...
Definition checking_casts.hpp:115
constexpr bool in_range(From value) noexcept
Checks if an integer value can be safely casted into an integer type To, that is, it lies in the rang...
Definition checking_casts.hpp:47
Defines the macro KAMPING_NOEXCEPT to be used instad of noexcept.
#define KAMPING_NOEXCEPT
noexcept macro.
Definition noexcept.hpp:19