KaMPIng 0.1.0
(Near) zero-overhead C++ MPI bindings.
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 <kassert/kassert.hpp>
26
27#include "kamping/noexcept.hpp"
28
29namespace kamping {
30
31/// @addtogroup kamping_utility
32/// @{
33
34/// @brief Checks if an integer value can be safely casted into an integer type To, that is, it lies in the range
35/// [min(To), max(To)].
36///
37/// This function works only for integer types which have at most std::numeric_limits<intmax_t>::digits (To and From are
38/// signed) or std::numeric_limits<intmax_t>::digits (else) bits. This function includes checks for these two
39/// assumptions using static_assert()s.
40///
41/// @tparam To Type to be casted to.
42/// @tparam From Type to be casted from, will be auto inferred.
43/// @param value Value you want to cast.
44/// @return \c true if value can be safely casted into type To, that is, value is in To's range.
45/// @return \c false otherwise.
46///
47template <class To, class From>
48constexpr bool in_range(From value) noexcept {
49 static_assert(std::is_integral_v<From>, "From has to be an integral type.");
50 static_assert(std::is_integral_v<To>, "To has to be an integral type.");
51
52 // Check that the 0 is included in From and To. 0 is always included in signed types.
53 static_assert(
54 std::is_signed_v<From> || std::numeric_limits<From>::min() == 0,
55 "The type From has to include the number 0."
56 );
57 static_assert(
58 std::is_signed_v<To> || std::numeric_limits<To>::min() == 0,
59 "The type To has to include the number 0."
60 );
61
62 // Check if we can safely cast To and From into (u)intmax_t.
63 if constexpr (std::is_signed_v<From> && std::is_signed_v<To>) {
64 static_assert(
65 std::numeric_limits<From>::digits <= std::numeric_limits<intmax_t>::digits,
66 "From has more bits than intmax_t."
67 );
68 static_assert(
69 std::numeric_limits<To>::digits <= std::numeric_limits<intmax_t>::digits,
70 "To has more bits than intmax_t."
71 );
72 } else {
73 static_assert(
74 std::numeric_limits<From>::digits <= std::numeric_limits<uintmax_t>::digits,
75 "From has more bits than uintmax_t."
76 );
77 static_assert(
78 std::numeric_limits<To>::digits <= std::numeric_limits<uintmax_t>::digits,
79 "To has more bits than uintmax_t."
80 );
81 }
82
83 // Check if the parameters value is inside To's range.
84 if constexpr (std::is_unsigned_v<From> && std::is_unsigned_v<To>) {
85 return static_cast<uintmax_t>(value) <= static_cast<uintmax_t>(std::numeric_limits<To>::max());
86 } else if constexpr (std::is_signed_v<From> && std::is_signed_v<To>) {
87 return static_cast<intmax_t>(value) >= static_cast<intmax_t>(std::numeric_limits<To>::min())
88 && static_cast<intmax_t>(value) <= static_cast<intmax_t>(std::numeric_limits<To>::max());
89 } else if constexpr (std::is_signed_v<From> && std::is_unsigned_v<To>) {
90 if (value < 0) {
91 return false;
92 } else {
93 return static_cast<uintmax_t>(value) <= static_cast<uintmax_t>(std::numeric_limits<To>::max());
94 }
95 } else if constexpr (std::is_unsigned_v<From> && std::is_signed_v<To>) {
96 return static_cast<uintmax_t>(value) <= static_cast<uintmax_t>(std::numeric_limits<To>::max());
97 }
98}
99
100///
101/// @brief Casts an integer value to the integer type To. If the value is outside To's range, throws an assertion.
102///
103/// Alternatively, exceptions can be used instead of assertions by using \ref throwing_cast().
104///
105/// This function works only for integer types which have at most std::numeric_limits<intmax_t>::digits (To and From are
106/// signed) or std::numeric_limits<intmax_t>::digits (else) bits. These two assumptions are checked by in_range() using
107/// static_assert()s.
108///
109///
110/// @tparam To Type to cast to.
111/// @tparam From Type to cast from, will be auto inferred.
112/// @param value Value you want to cast.
113/// @return Casted value.
114///
115template <class To, class From>
117 KASSERT(in_range<To>(value));
118 return static_cast<To>(value);
119}
120
121///
122/// @brief Casts an integer value to the integer type To. If the value is outside To's range, throws an exception.
123///
124/// Alternatively, assertions can be used instead of exceptions by using \ref asserting_cast().
125///
126/// This function works only for integer types which have at most std::numeric_limits<intmax_t>::digits (To and From are
127/// signed) or std::numeric_limits<intmax_t>::digits (else) bits. These two assumptions are checked by in_range() using
128/// static_assert()s.
129///
130/// @tparam To Type to cast to.
131/// @tparam From Type to cast from, will be auto inferred.
132/// @param value Value you want to cast.
133/// @return Casted value.
134///
135template <class To, class From>
136constexpr To throwing_cast(From value) {
138 in_range<To>(value),
139 value << " is not representable by the target type.",
140 std::range_error
141 );
142 return static_cast<To>(value);
143}
144
145/// @}
146
147} // 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:136
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:116
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:48
Defines the macro KAMPING_NOEXCEPT to be used instad of noexcept.
#define KAMPING_NOEXCEPT
noexcept macro.
Definition noexcept.hpp:19