Rcpp Version 1.1.2
Loading...
Searching...
No Matches
safe_math.h
Go to the documentation of this file.
1// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
2//
3// safe_math.h: Rcpp R/C++ interface class library --
4//
5// Copyright (C) 2026 IƱaki Ucar
6//
7// This file is part of Rcpp.
8//
9// Rcpp is free software: you can redistribute it and/or modify it
10// under the terms of the GNU General Public License as published by
11// the Free Software Foundation, either version 2 of the License, or
12// (at your option) any later version.
13//
14// Rcpp is distributed in the hope that it will be useful, but
15// WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17// GNU General Public License for more details.
18//
19// You should have received a copy of the GNU General Public License
20// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21
22#ifndef Rcpp__sugar__tools_safe_math_h
23#define Rcpp__sugar__tools_safe_math_h
24
25#ifndef safe_math__has_builtin
26# ifdef __has_builtin
27# define safe_math__has_builtin(x) __has_builtin(x)
28# else
29# define safe_math__has_builtin(x) 0
30# endif
31#endif
32
33#define RCPP_SAFE_ADD(a, b) Rcpp::sugar::detail::safe_add(a, b, __func__)
34#define RCPP_SAFE_SUB(a, b) Rcpp::sugar::detail::safe_sub(a, b, __func__)
35#define RCPP_SAFE_MUL(a, b) Rcpp::sugar::detail::safe_mul(a, b, __func__)
36
37namespace Rcpp {
38namespace sugar {
39namespace detail {
40
41 inline void stop_overflow(const char* caller) {
42 if (caller)
43 Rcpp::stop("[%s] Integer overflow!", caller);
44 Rcpp::stop("Integer overflow!");
45 }
46
47 // Addition
48 template <typename T>
49 inline typename std::enable_if<std::is_integral<T>::value, T>::type
50 safe_add(T a, T b, const char* caller = nullptr) {
51 #if safe_math__has_builtin(__builtin_add_overflow)
52 T result;
53 if (__builtin_add_overflow(a, b, &result))
54 stop_overflow(caller);
55 return result;
56 #else // fallback
57 if (std::is_signed<T>::value) {
58 if ((b > 0 && a > std::numeric_limits<T>::max() - b) ||
59 (b < 0 && a < std::numeric_limits<T>::min() - b))
60 stop_overflow(caller);
61 } else {
62 if (a > std::numeric_limits<T>::max() - b)
63 stop_overflow(caller);
64 }
65 return a + b;
66 #endif
67 }
68
69 template <typename T>
70 inline typename std::enable_if<!std::is_integral<T>::value, T>::type
71 safe_add(T a, T b, const char* caller = nullptr) { return a + b; }
72
73 // Subtraction
74 template <typename T>
75 inline typename std::enable_if<std::is_integral<T>::value, T>::type
76 safe_sub(T a, T b, const char* caller = nullptr) {
77 #if safe_math__has_builtin(__builtin_sub_overflow)
78 T result;
79 if (__builtin_sub_overflow(a, b, &result))
80 stop_overflow(caller);
81 return result;
82 #else // fallback
83 if (std::is_signed<T>::value) {
84 if ((b < 0 && a > std::numeric_limits<T>::max() + b) ||
85 (b > 0 && a < std::numeric_limits<T>::min() + b))
86 stop_overflow(caller);
87 } else {
88 if (a < b)
89 stop_overflow(caller);
90 }
91 return a - b;
92 #endif
93 }
94
95 template <typename T>
96 inline typename std::enable_if<!std::is_integral<T>::value, T>::type
97 safe_sub(T a, T b, const char* caller = nullptr) { return a - b; }
98
99 // Multiplication
100 template <typename T>
101 inline typename std::enable_if<std::is_integral<T>::value, T>::type
102 safe_mul(T a, T b, const char* caller = nullptr) {
103 #if safe_math__has_builtin(__builtin_mul_overflow)
104 T result;
105 if (__builtin_mul_overflow(a, b, &result))
106 stop_overflow(caller);
107 return result;
108 #else // fallback
109 if (a == 0 || b == 0) return 0;
110 if (std::is_signed<T>::value) {
111 if ((a > 0 && b > 0 && a > std::numeric_limits<T>::max() / b) ||
112 (a > 0 && b < 0 && b < std::numeric_limits<T>::min() / a) ||
113 (a < 0 && b > 0 && a < std::numeric_limits<T>::min() / b) ||
114 (a < 0 && b < 0 && a < std::numeric_limits<T>::max() / b))
115 stop_overflow(caller);
116 } else {
117 if (b > 0 && a > std::numeric_limits<T>::max() / b)
118 stop_overflow(caller);
119 }
120 return a * b;
121 #endif
122 }
123
124 template <typename T>
125 inline typename std::enable_if<!std::is_integral<T>::value, T>::type
126 safe_mul(T a, T b, const char* caller = nullptr) { return a * b; }
127
128} // namespace detail
129} // namespace sugar
130} // namespace Rcpp
131
132#undef safe_math__has_builtin
133
134#endif
std::enable_if< std::is_integral< T >::value, T >::type safe_mul(T a, T b, const char *caller=nullptr)
Definition safe_math.h:102
std::enable_if< std::is_integral< T >::value, T >::type safe_sub(T a, T b, const char *caller=nullptr)
Definition safe_math.h:76
std::enable_if< std::is_integral< T >::value, T >::type safe_add(T a, T b, const char *caller=nullptr)
Definition safe_math.h:50
void stop_overflow(const char *caller)
Definition safe_math.h:41
Rcpp API.
Definition algo.h:28
void NORET stop(const std::string &message)
Definition exceptions.h:119