Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions inst/include/Rcpp/sugar/functions/cumprod.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//
// cumsum.h: Rcpp R/C++ interface class library -- cumsum
//
// Copyright (C) 2010 - 2011 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
//
// This file is part of Rcpp.
//
Expand Down Expand Up @@ -33,23 +34,23 @@ class Cumprod : public Lazy< Rcpp::Vector<RTYPE>, Cumprod<RTYPE, NA, T> > {
typedef Rcpp::Vector<RTYPE> VECTOR;

Cumprod(const VEC_TYPE& object_) : object(object_) {}

VECTOR get() const {
R_xlen_t n = object.size();
VECTOR result(n, Rcpp::traits::get_na<RTYPE>());
STORAGE current = object[0];

if (Rcpp::traits::is_na<RTYPE>(current)) return result;
result[0] = current;
for (R_xlen_t i = 1; i < n; i++) {
current = object[i];
if (Rcpp::traits::is_na<RTYPE>(current)) return result;
result[i] = result[i-1] * current;
result[i] = RCPP_SAFE_MUL(result[i-1], current);
}
return result ;
}
private:
const VEC_TYPE& object;
const VEC_TYPE& object;
};

} // sugar
Expand All @@ -72,5 +73,5 @@ inline sugar::Cumprod<CPLXSXP, NA, T> cumprod(const VectorBase<CPLXSXP, NA, T>&


} // Rcpp
#endif // Rcpp__sugar__cumprod_h
#endif // Rcpp__sugar__cumprod_h

5 changes: 3 additions & 2 deletions inst/include/Rcpp/sugar/functions/cumsum.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//
// cumsum.h: Rcpp R/C++ interface class library -- cumsum
//
// Copyright (C) 2010 - 2011 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
//
// This file is part of Rcpp.
//
Expand Down Expand Up @@ -45,7 +46,7 @@ class Cumsum : public Lazy< Rcpp::Vector<RTYPE> , Cumsum<RTYPE,NA,T> > {
current = object[i] ;
if( Rcpp::traits::is_na<RTYPE>(current) )
return result ;
result[i] = result[i-1] + current ;
result[i] = RCPP_SAFE_ADD(result[i-1], current);
}
return result ;
}
Expand Down
11 changes: 6 additions & 5 deletions inst/include/Rcpp/sugar/functions/diff.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//
// diff.h: Rcpp R/C++ interface class library -- diff
//
// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
//
// This file is part of Rcpp.
//
Expand Down Expand Up @@ -51,7 +52,7 @@ class Diff : public Rcpp::VectorBase< RTYPE, LHS_NA , Diff<RTYPE,LHS_NA,LHS_T> >
set_previous(i+1, y ) ;
return traits::get_na<RTYPE>() ; // NA
}
STORAGE res = y - previous ;
STORAGE res = RCPP_SAFE_SUB(y, previous);
set_previous( i+1, y) ;
return res ;
}
Expand Down Expand Up @@ -81,7 +82,7 @@ class Diff<REALSXP, LHS_NA, LHS_T> : public Rcpp::VectorBase< REALSXP, LHS_NA, D
inline double operator[]( R_xlen_t i ) const {
double y = lhs[i+1] ;
if( previous_index != i ) previous = lhs[i] ;
double res = y - previous ;
double res = RCPP_SAFE_SUB(y, previous);
previous = y ;
previous_index = i+1 ;
return res ;
Expand All @@ -105,10 +106,10 @@ class Diff<RTYPE,false,LHS_T> : public Rcpp::VectorBase< RTYPE, false , Diff<RTY
inline STORAGE operator[]( R_xlen_t i ) const {
STORAGE y = lhs[i+1] ;
if( previous_index != i ) previous = lhs[i] ;
STORAGE diff = y - previous ;
STORAGE diff = RCPP_SAFE_SUB(y, previous);
previous = y ;
previous_index = i+1 ;
return y - previous ;
return RCPP_SAFE_SUB(y, previous);
}
inline R_xlen_t size() const { return lhs.size() - 1 ; }

Expand Down
184 changes: 62 additions & 122 deletions inst/include/Rcpp/sugar/functions/rowSums.h

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion inst/include/Rcpp/sugar/sugar.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
//
// sugar.h: Rcpp R/C++ interface class library -- main file for Rcpp::sugar
//
// Copyright (C) 2010 - 2012 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
//
// This file is part of Rcpp.
//
Expand All @@ -23,6 +24,7 @@
#define RCPP_SUGAR_H

#include <Rcpp/sugar/tools/iterator.h>
#include <Rcpp/sugar/tools/safe_math.h>
#include <Rcpp/sugar/block/block.h>

#include <Rcpp/hash/hash.h>
Expand Down
134 changes: 134 additions & 0 deletions inst/include/Rcpp/sugar/tools/safe_math.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
//
// safe_math.h: Rcpp R/C++ interface class library --
//
// Copyright (C) 2026 Iñaki Ucar
//
// This file is part of Rcpp.
//
// Rcpp is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Rcpp is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.

#ifndef Rcpp__sugar__tools_safe_math_h
#define Rcpp__sugar__tools_safe_math_h

#ifndef safe_math__has_builtin
# ifdef __has_builtin
# define safe_math__has_builtin(x) __has_builtin(x)
# else
# define safe_math__has_builtin(x) 0
# endif
#endif

#define RCPP_SAFE_ADD(a, b) Rcpp::sugar::detail::safe_add(a, b, __func__)
#define RCPP_SAFE_SUB(a, b) Rcpp::sugar::detail::safe_sub(a, b, __func__)
#define RCPP_SAFE_MUL(a, b) Rcpp::sugar::detail::safe_mul(a, b, __func__)

namespace Rcpp {
namespace sugar {
namespace detail {

inline void stop_overflow(const char* caller) {
if (caller)
Rcpp::stop("[%s] Integer overflow!", caller);
Rcpp::stop("Integer overflow!");
}

// Addition
template <typename T>
inline typename std::enable_if<std::is_integral<T>::value, T>::type
safe_add(T a, T b, const char* caller = nullptr) {
#if safe_math__has_builtin(__builtin_add_overflow)
T result;
if (__builtin_add_overflow(a, b, &result))
stop_overflow(caller);
return result;
#else // fallback
if (std::is_signed<T>::value) {
if ((b > 0 && a > std::numeric_limits<T>::max() - b) ||
(b < 0 && a < std::numeric_limits<T>::min() - b))
stop_overflow(caller);
} else {
if (a > std::numeric_limits<T>::max() - b)
stop_overflow(caller);
}
return a + b;
#endif
}

template <typename T>
inline typename std::enable_if<!std::is_integral<T>::value, T>::type
safe_add(T a, T b, const char* caller = nullptr) { return a + b; }

// Subtraction
template <typename T>
inline typename std::enable_if<std::is_integral<T>::value, T>::type
safe_sub(T a, T b, const char* caller = nullptr) {
#if safe_math__has_builtin(__builtin_sub_overflow)
T result;
if (__builtin_sub_overflow(a, b, &result))
stop_overflow(caller);
return result;
#else // fallback
if (std::is_signed<T>::value) {
if ((b < 0 && a > std::numeric_limits<T>::max() + b) ||
(b > 0 && a < std::numeric_limits<T>::min() + b))
stop_overflow(caller);
} else {
if (a < b)
stop_overflow(caller);
}
return a - b;
#endif
}

template <typename T>
inline typename std::enable_if<!std::is_integral<T>::value, T>::type
safe_sub(T a, T b, const char* caller = nullptr) { return a - b; }

// Multiplication
template <typename T>
inline typename std::enable_if<std::is_integral<T>::value, T>::type
safe_mul(T a, T b, const char* caller = nullptr) {
#if safe_math__has_builtin(__builtin_mul_overflow)
T result;
if (__builtin_mul_overflow(a, b, &result))
stop_overflow(caller);
return result;
#else // fallback
if (a == 0 || b == 0) return 0;
if (std::is_signed<T>::value) {
if ((a > 0 && b > 0 && a > std::numeric_limits<T>::max() / b) ||
(a > 0 && b < 0 && b < std::numeric_limits<T>::min() / a) ||
(a < 0 && b > 0 && a < std::numeric_limits<T>::min() / b) ||
(a < 0 && b < 0 && a < std::numeric_limits<T>::max() / b))
stop_overflow(caller);
} else {
if (b > 0 && a > std::numeric_limits<T>::max() / b)
stop_overflow(caller);
}
return a * b;
#endif
}

template <typename T>
inline typename std::enable_if<!std::is_integral<T>::value, T>::type
safe_mul(T a, T b, const char* caller = nullptr) { return a * b; }

} // namespace detail
} // namespace sugar
} // namespace Rcpp

#undef safe_math__has_builtin

#endif
12 changes: 9 additions & 3 deletions inst/tinytest/cpp/sugar.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

// sugar.cpp: Rcpp R/C++ interface class library -- sugar unit tests
//
// Copyright (C) 2012 - 2025 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2025 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
// Copyright (C) 2012 - 2024 Dirk Eddelbuettel and Romain Francois
// Copyright (C) 2025 - 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
//
// This file is part of Rcpp.
//
Expand Down Expand Up @@ -609,11 +609,17 @@ double runit_sum( NumericVector xx){
}

// [[Rcpp::export]]
NumericVector runit_cumsum( NumericVector xx ){
NumericVector runit_cumsum_nv( NumericVector xx ){
NumericVector res = cumsum( xx ) ;
return res ;
}

// [[Rcpp::export]]
IntegerVector runit_cumsum_iv( IntegerVector xx ){
IntegerVector res = cumsum( xx ) ;
return res ;
}

// [[Rcpp::export]]
List runit_asvector( NumericMatrix z, NumericVector x, NumericVector y){
return List::create(
Expand Down
36 changes: 36 additions & 0 deletions inst/tinytest/cpp/sugar_safe_math.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

// sugar_safe_math.cpp: Rcpp R/C++ interface class library -- safe math unit tests
//
// Copyright (C) 2026 Iñaki Ucar
//
// This file is part of Rcpp.
//
// Rcpp is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Rcpp is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.

#include <Rcpp.h>

// [[Rcpp::export]]
int safe_add(int a, int b){
return RCPP_SAFE_ADD(a, b);
}

// [[Rcpp::export]]
int safe_sub(int a, int b){
return RCPP_SAFE_SUB(a, b);
}

// [[Rcpp::export]]
int safe_mul(int a, int b){
return RCPP_SAFE_MUL(a, b);
}
37 changes: 37 additions & 0 deletions inst/tinytest/cpp/sugar_safe_math_fallback.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

// sugar_safe_math.cpp: Rcpp R/C++ interface class library -- safe math unit tests
//
// Copyright (C) 2026 Iñaki Ucar
//
// This file is part of Rcpp.
//
// Rcpp is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Rcpp is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.

#define safe_math__has_builtin(x) 0
#include <Rcpp.h>

// [[Rcpp::export]]
int safe_add_fallback(int a, int b){
return RCPP_SAFE_ADD(a, b);
}

// [[Rcpp::export]]
int safe_sub_fallback(int a, int b){
return RCPP_SAFE_SUB(a, b);
}

// [[Rcpp::export]]
int safe_mul_fallback(int a, int b){
return RCPP_SAFE_MUL(a, b);
}
Loading