diff --git a/.codecov.yml b/.codecov.yml index 9ec352888..e10eb4a78 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,4 +1,5 @@ comment: false + coverage: status: project: @@ -9,6 +10,9 @@ coverage: default: target: 0% # the (on purpose low) required coverage value +ignore: + - 'R/inline.R' # function factory setup confuses codecov + # layout: "header, diff, tree, changes" # behavior: default # require_changes: false # if true: only post the comment if coverage changes diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index dd6fc6541..5ac954e67 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -4,6 +4,7 @@ on: push: branches: - master + workflow_dispatch: schedule: - cron: "32 1 * * 6" @@ -19,7 +20,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/ChangeLog b/ChangeLog index 9911a8173..24f115bb9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,273 @@ +2026-03-06 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date (twice) + * inst/include/Rcpp/config.h: Idem + * inst/NEWS.Rd: Updated + + * inst/include/Rcpp/Environment.h: For R 4.5.0 or later, use + R_ParentEnv instead of ENCLOS to reach parent environment + +2026-02-27 Iñaki Ucar + + * inst/include/Rcpp/sugar/functions/max.h: Fix UB for empty integer + * inst/include/Rcpp/sugar/functions/min.h: Idem + * inst/tinytest/test_sugar.R: Adapt tests + +2026-02-26 Iñaki Ucar + + * inst/include/Rcpp/sugar/tools/safe_math.h: New header implementing safe + versions of add/sub/mul operations for integral types + * inst/include/Rcpp/sugar/sugar.h: Includes the previous header + + * inst/include/Rcpp/sugar/functions/cumprod.h: Use the previous operations + * inst/include/Rcpp/sugar/functions/cumsum.h: Idem + * inst/include/Rcpp/sugar/functions/diff.h: Idem, also fixed a bug where + the diff was recomputed instead of returning the calculated value + * inst/include/Rcpp/sugar/functions/rowSums.h: Idem + * inst/include/Rcpp/sugar/functions/sum.h: Idem + * inst/include/Rcpp/sugar/operators/minus.h: Idem, also fixed a bug for + an incorrect Extractor specialization in Minus_Primitive_Vector + * inst/include/Rcpp/sugar/operators/plus.h: Idem + * inst/include/Rcpp/sugar/operators/times.h: Idem + + * inst/tinytest/test_sugar.R: New tests covering the new operations + * inst/tinytest/cpp/sugar.cpp: Idem + * inst/tinytest/cpp/sugar_safe_math.cpp: Idem + * inst/tinytest/cpp/sugar_safe_math_fallback.cpp: Idem + +2026-02-17 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + * inst/NEWS.Rd: Updated + +2026-02-17 Iñaki Ucar + + * inst/include/Rcpp/sugar/operators/Comparator_With_One_Value.h: Fix UB + for non-integer RTYPEs in comparator + +2026-01-23 Dirk Eddelbuettel + + * inst/include/Rcpp/DataFrame.h (nrow): Use R_nrow() with R >= 4.6.0 + * inst/include/Rcpp/proxy/AttributeProxy.h (attributeNames): Use + R_getAttribNames() with R >= 4.6.0; + * inst/include/Rcpp/proxy/AttributeProxy.h (hasAttribute): Use + R_hasAttrib with R >= 4.6.0 + +2026-01-22 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + +2026-01-21 Dirk Eddelbuettel + + * inst/include/Rcpp/date_datetime/Datetime.h: Fractional seconds type + switched to 'int' for consistency, print format string re-adjusted + +2026-01-20 Dirk Eddelbuettel + + * inst/include/Rcpp/date_datetime/Datetime.h (format): Correct a + format string reflecting 'unsigned int' rather than 'int' + +2026-01-13 Dirk Eddelbuettel + + * inst/tinytest/cpp/attributes_extended.cpp: New unit tests + * inst/tinytest/test_attributes_extended.R: Idem + * inst/tinytest/test_compile_attributes_errors.R: Idem + * inst/tinytest/test_cppfunction_errors.R: Idem + * inst/tinytest/test_sourcecpp_errors.R: Idem + * R/Attributes.R: Remove #nocov tags + * src/attributes.cpp: Idem + +2026-01-12 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + + * inst/include/Rcpp/exceptions_impl.h: Combine previous and current + methods enabling when 'execinfo.h' is found on selected platforms + +2026-01-08 Dirk Eddelbuettel + + * DESCRIPTION (Date, Version): Release 1.1.1 + + * inst/include/Rcpp/config.h: Idem + * inst/NEWS.Rd: Idem + +2026-01-07 Dirk Eddelbuettel + + * vignettes/pdf/*: Rebuilt + + * vignettes/rmd/Rcpp.bib: Updates to several URLs + * inst/bib/Rcpp.bib: Idem + * vignettes/rmd/*: Idem + * README.md: Idem + +2026-01-06 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + + * vignettes/rmd/Rcpp.bib: Update package versions dates + * inst/bib/Rcpp.bib: Idem + +2026-01-04 Dirk Eddelbuettel + + * inst/include/RcppCommon.h: No longer require RCPP_USING_UNWIND_PROTECT + * inst/include/Rcpp/r/headers.h: Idem + * inst/include/Rcpp/api/meat/Rcpp_eval.h: Idem + * inst/tinytest/cpp/stack.cpp: No longer test with RCPP_USING_UNWIND_PROTECT + * inst/tinytest/test_interface.R: Idem + +2026-01-01 Dirk Eddelbuettel + + * R/Attributes.R: Additional or adjusted #nocov tags + * R/Rcpp.package.skeleton.R: Idem + * R/RcppLdpath.R: Idem + * R/asis.R: Idem + * R/inline.R: Idem + * inst/include/Rcpp/api/meat/Rcpp_eval.h: Idem + * inst/include/Rcpp/internal/caster.h: Idem + * inst/include/Rcpp/internal/export.h: Idem + * inst/include/Rcpp/proxy/NamesProxy.h: Idem + * inst/include/Rcpp/proxy/SlotProxy.h: Idem + * inst/include/Rcpp/vector/Vector.h: Idem + * inst/include/Rcpp/vector/proxy.h: Idem + * inst/include/Rcpp/vector/traits.h: Idem + * inst/include/Rcpp/Environment.h: Idem + * inst/include/Rcpp/Function.h: Idem + * inst/include/Rcpp/Module.h: Idem + * inst/include/Rcpp/S4.h: Idem + * inst/include/Rcpp/as.h: Idem + * inst/include/Rcpp/exceptions.h: Idem + * inst/include/Rcpp/r_cast.h: Idem + * src/attributes.cpp: Idem + * src/barrier.cpp: Idem + +2025-12-30 Dirk Eddelbuettel + + * tests/tinytest.R: Refine decision of when not to run all tests even + when development version number is seen + +2025-12-28 Dirk Eddelbuettel + + * README.md: Replace installation from drat section with r-universe + +2025-12-22 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + + * inst/include/Rcpp/DataFrame.h (nrow): Simplified per #1430 discussion + relying on compact sequence representation removing use of ATTRIB + * inst/include/Rcpp/proxy/AttributeProxy.h (hasAttribute): For R + 4.6.0, rewritten using R_mapAttrib() avoiding to-be-removed ATTRIB() + +2025-12-21 Dirk Eddelbuettel + + * .github/workflows/docker.yaml: Add workflow_dispatch, update + checkout action + +2025-12-19 Dirk Eddelbuettel + + * man/RcppUnitTests.Rd: Removed outdated help page + +2025-12-17 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + + * DESCRIPTION (Depends): Add 'R (>= 3.5.0)' + +2025-12-16 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + + * src/barrier.cpp (dataptr): Remove check for 'R (>= 3.5.0)' + * inst/include/Rcpp/Rmath.h: Remove check for 'R (>= 3.1.2)' + * inst/include/Rcpp/Symbol.h: Remove check for 'R (>= 3.2.0)' + * inst/include/Rcpp/exceptions.h: Remove check for 'R (>= 3.5.0)' + * inst/include/Rcpp/r/headers.h: Idem + + * R/Attributes.R: Remove multiple checks for R version < 3.5.0 + * R/Rcpp.package.skeleton.R: Idem + * inst/tinytest/testRcppInterfaceUser/tests/tests.R: Remove one check + +2025-12-12 Dirk Eddelbuettel + + * inst/tinytest/test_system.R: Wrap suppressMessages() around three + tests for long-obsolete linker and compiler flags + + * inst/include/Rcpp/Environment.h: Replace use of Rf_findVarInFrame + with R_getVarEx (or R_getVar) if R 4.5.0 or later is used + * inst/include/Rcpp/Function.h: Idem + * src/barrier.cpp: Idem + +2025-12-10 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + + * inst/include/Rcpp/Rmath.h: Do not access Rf_rnbeta + * inst/include/Rcpp/sugar/undoRmath.h: Remove #undef + +2025-12-06 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + * inst/NEWS.Rd: Updated + +2025-12-04 Iñaki Ucar + + * inst/include/Rcpp/r/headers.h: Include + * inst/include/RcppCommon.h: Drop , not used anymore + and dropped from the API; drop , included above + * src/api.cpp: Drop , dropped from the API + +2025-12-03 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + +2025-12-02 Dirk Eddelbuettel + + * R/loadRcppModules.R: Remove file with function deprecated years ago + * man/loadRcppModules-deprecated.Rd: Idem + * NAMESPACE: Remove reference to loadRcppModules() + * man/loadModule.Rd: Idem + * man/Rcpp-deprecated.Rd: Idem + * vignettes/rmd/Rcpp-modules.Rmd: Idem + +2025-12-01 Kevin Ushey + + * R/Attributes.R: Update OpenMP plugin for macOS + +2025-11-29 Dirk Eddelbuettel + + * R/RcppLdpath.R: Revisit deprecation warnings via 'message()' to be + turned into warning or deprecation in 12 or more months 'when suitable' + +2025-11-24 Dirk Eddelbuettel + + * inst/include/Rcpp/r/check_r_headers.h: Add RCPP_NO_R_HEADERS_CHECK + override to skip new check + +2025-11-23 Dirk Eddelbuettel + + * inst/include/Rcpp/r/check_r_headers.h: New header to check if R.h + or related R headers were installed first + * inst/include/RcppCommon.h: Call new header as first thing + +2025-11-12 Iñaki Ucar + + * inst/include/Rcpp/macros/mask.h: Lay the ground for Rf_error masking + with a warning at compilation time unless RCPP_NO_MASK_RF_ERROR is defined + * inst/include/RcppCommon.h: Include the previous file in the last place + * src/attributes.cpp: Use parentheses to protect call to Rf_error + * inst/tinytest/cpp/stack.cpp: Idem + * inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp: Idem + 2025-11-04 Dirk Eddelbuettel * .github/workflows/macos.yaml (jobs): Roll macos-13 to macos-14 @@ -10,7 +280,7 @@ 2025-10-21 Iñaki Ucar - * inst/include/Rcpp/exceptions_impl.h: use __has_include to simplify checks + * inst/include/Rcpp/exceptions_impl.h: Use __has_include to simplify checks to enable demangling, making them robust for more platforms 2025-10-13 Dirk Eddelbuettel diff --git a/Contributing.md b/Contributing.md index e57f25b99..8c975175d 100644 --- a/Contributing.md +++ b/Contributing.md @@ -54,10 +54,9 @@ reasonable defaults. ### Asking Questions -Please direct general questions to the -[Rcpp-devel](http://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel) -mailing list (preferred, note that only subscribers can post), or post an -issue at GitHub. +Please direct general questions to the [discussion section of the GitHub +repo](https://github.com/RcppCore/Rcpp/discussions), or post an issue at +GitHub. Are you a new user of Rcpp? You might find the [vignettes](https://cran.r-project.org/package=Rcpp) helpful in getting diff --git a/DESCRIPTION b/DESCRIPTION index 68aeb7f6b..52272f9fe 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: Rcpp Title: Seamless R and C++ Integration -Version: 1.1.0.4 -Date: 2025-10-13 +Version: 1.1.1.6 +Date: 2026-03-06 Authors@R: c(person("Dirk", "Eddelbuettel", role = c("aut", "cre"), email = "edd@debian.org", comment = c(ORCID = "0000-0001-6419-907X")), person("Romain", "Francois", role = "aut", @@ -27,12 +27,12 @@ Description: The 'Rcpp' package provides R functions as well as C++ classes whic Francois (2011, ), the book by Eddelbuettel (2013, ) and the paper by Eddelbuettel and Balamuta (2018, ); see 'citation("Rcpp")' for details. +Depends: R (>= 3.5.0) Imports: methods, utils Suggests: tinytest, inline, rbenchmark, pkgKitten (>= 0.1.2) URL: https://www.rcpp.org, https://dirk.eddelbuettel.com/code/rcpp.html, https://github.com/RcppCore/Rcpp License: GPL (>= 2) BugReports: https://github.com/RcppCore/Rcpp/issues -MailingList: rcpp-devel@lists.r-forge.r-project.org RoxygenNote: 6.1.1 Encoding: UTF-8 VignetteBuilder: Rcpp diff --git a/NAMESPACE b/NAMESPACE index 1af902e22..9f6fdf377 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,7 +16,6 @@ exportMethods(prompt, show, .DollarNames, initialize, "formals<-") export(Module, Rcpp.package.skeleton, populate, - loadRcppModules, # deprecated since Rcpp 0.12.5 released May 2016 setRcppClass, loadRcppClass, loadModule, diff --git a/R/Attributes.R b/R/Attributes.R index 53e9f0a61..9136ec65e 100644 --- a/R/Attributes.R +++ b/R/Attributes.R @@ -1,6 +1,6 @@ # Copyright (C) 2012 - 2022 JJ Allaire, Dirk Eddelbuettel and Romain Francois -# Copyright (C) 2023 - 2024 JJ Allaire, Dirk Eddelbuettel, Romain Francois and Iñaki Ucar +# Copyright (C) 2023 - 2026 JJ Allaire, Dirk Eddelbuettel, Romain Francois and Iñaki Ucar # # This file is part of Rcpp. # @@ -55,16 +55,16 @@ sourceCpp <- function(file = "", file <- normalizePath(file, winslash = "/") # error if the file extension isn't one supported by R CMD SHLIB - if (! tools::file_ext(file) %in% c("cc", "cpp")) { # #nocov start + if (! tools::file_ext(file) %in% c("cc", "cpp")) { stop("The filename '", basename(file), "' does not have an ", "extension of .cc or .cpp so cannot be compiled.") - } # #nocov end + } # validate that there are no spaces in the path on windows - if (.Platform$OS.type == "windows") { # #nocov start - if (grepl(' ', basename(file), fixed=TRUE)) { + if (.Platform$OS.type == "windows") { + if (grepl(' ', basename(file), fixed=TRUE)) { # #nocov start stop("The filename '", basename(file), "' contains spaces. This ", - "is not permitted.") + "is not permitted.") # #nocov end } } else { if (windowsDebugDLL) { @@ -73,7 +73,7 @@ sourceCpp <- function(file = "", "non-Windows platforms.") } windowsDebugDLL <- FALSE # now we do not need to deal with OS choice below - } # #nocov end + } } # get the context (does code generation as necessary) @@ -323,9 +323,9 @@ cppFunction <- function(code, # verify that a single function was exported and return it if (length(exported$functions) == 0) - stop("No function definition found") # #nocov + stop("No function definition found") else if (length(exported$functions) > 1) - stop("More than one function definition") # #nocov + stop("More than one function definition") # #nocov else { functionName <- exported$functions[[1]] invisible(get(functionName, env)) @@ -417,7 +417,7 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) { pkgdir <- normalizePath(pkgdir, winslash = "/") descFile <- file.path(pkgdir,"DESCRIPTION") if (!file.exists(descFile)) - stop("pkgdir must refer to the directory containing an R package") # #nocov + stop("pkgdir must refer to the directory containing an R package") pkgDesc <- read.dcf(descFile)[1,] pkgname = .readPkgDescField(pkgDesc, "Package") depends <- c(.readPkgDescField(pkgDesc, "Depends", character()), @@ -429,7 +429,7 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) { # check the NAMESPACE file to see if dynamic registration is enabled namespaceFile <- file.path(pkgdir, "NAMESPACE") if (!file.exists(namespaceFile)) - stop("pkgdir must refer to the directory containing an R package") # #nocov + stop("pkgdir must refer to the directory containing an R package") pkgNamespace <- readLines(namespaceFile, warn = FALSE) registration <- any(grepl("^\\s*useDynLib.*\\.registration\\s*=\\s*TRUE.*$", pkgNamespace)) @@ -499,21 +499,11 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) { # built-in C++98 plugin .plugins[["cpp98"]] <- function() { - if (getRversion() >= "3.4") # with recent R versions, R can decide - list(env = list(USE_CXX98 = "yes")) - else - list(env = list(PKG_CXXFLAGS ="-std=c++98")) + list(env = list(USE_CXX98 = "yes")) } # built-in C++11 plugin .plugins[["cpp11"]] <- function() { - if (getRversion() >= "3.4") # with recent R versions, R can decide - list(env = list(USE_CXX11 = "yes")) - else if (getRversion() >= "3.1") # with recent R versions, R can decide - list(env = list(USE_CXX1X = "yes")) - else if (.Platform$OS.type == "windows") - list(env = list(PKG_CXXFLAGS = "-std=c++0x")) - else # g++-4.8.1 or later - list(env = list(PKG_CXXFLAGS ="-std=c++11")) + list(env = list(USE_CXX11 = "yes")) } # built-in C++11 plugin for older g++ compiler @@ -525,10 +515,7 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) { ## this is the default in g++-6.1 and later ## per https://gcc.gnu.org/projects/cxx-status.html#cxx14 .plugins[["cpp14"]] <- function() { - if (getRversion() >= "3.4") # with recent R versions, R can decide - list(env = list(USE_CXX14 = "yes")) - else - list(env = list(PKG_CXXFLAGS ="-std=c++14")) + list(env = list(USE_CXX14 = "yes")) } # built-in C++1y plugin for C++14 and C++17 standard under development @@ -538,10 +525,7 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) { # built-in C++17 plugin for C++17 standard (g++-6 or later) .plugins[["cpp17"]] <- function() { - if (getRversion() >= "3.4") # with recent R versions, R can decide - list(env = list(USE_CXX17 = "yes")) - else - list(env = list(PKG_CXXFLAGS ="-std=c++17")) + list(env = list(USE_CXX17 = "yes")) } # built-in C++20 plugin for C++20 @@ -586,10 +570,74 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) { list(env = list(PKG_CXXFLAGS ="-std=c++2b")) } +.openmpPluginDefault <- function() { + list(env = list(PKG_CXXFLAGS = "-fopenmp", PKG_LIBS = "-fopenmp")) # #nocov start +} + +.openmpPluginDarwin <- function() { + + # generate a test script for compilation + script <- tempfile("openmp-detect-", fileext = ".cpp") + writeLines("", con = script) + on.exit(unlink(script, force = TRUE), add = TRUE) + + # get the C++ compiler from R + r <- file.path(R.home("bin"), "R") + output <- tryCatch( + system2(r, c("CMD", "SHLIB", "--dry-run", shQuote(script)), stdout = TRUE), + condition = identity + ) + if (inherits(output, "condition")) + return(.openmpPluginDefault()) + + # extract the compiler invocation from the shlib output + # use some heuristics here... + index <- grep("make would use", output) + compile <- output[[index + 1L]] + + # use everything up to the first include flag, which is normally + # the R headers from CPPFLAGS + idx <- regexpr(" -I", compile, fixed = TRUE) + cxx <- substring(compile, 1L, idx - 1L) + + # check the compiler version + command <- paste(cxx, "--version") + version <- tryCatch( + system(command, intern = TRUE), + condition = identity + ) + if (inherits(version, "condition")) + return(.openmpPluginDefault()) + + # if we're using Apple clang, use alternate flags + # assume libomp was installed following https://mac.r-project.org/openmp/ + if (any(grepl("Apple clang", version))) { + cxxflags <- "-Xclang -fopenmp" + libs <- "-lomp" + } + + # if we're using Homebrew clang, add in libomp include paths + else if (any(grepl("Homebrew clang", version))) { + machine <- Sys.info()[["machine"]] + prefix <- if (machine == "arm64") "/opt/homebrew" else "/usr/local" + cxxflags <- sprintf("-I%s/opt/libomp/include -fopenmp", prefix) + libs <- sprintf("-L%s/opt/libomp/lib -fopenmp", prefix) + + # otherwise, use default -fopenmp flags for other compilers (LLVM clang; gcc) + } else { + cxxflags <- "-fopenmp" + libs <- "-fopenmp" + } + + list(env = list(PKG_CXXFLAGS = cxxflags, PKG_LIBS = libs)) # #nocov end + +} + ## built-in OpenMP plugin -.plugins[["openmp"]] <- function() { - list(env = list(PKG_CXXFLAGS="-fopenmp", - PKG_LIBS="-fopenmp")) +.plugins[["openmp"]] <- if (Sys.info()[["sysname"]] == "Darwin") { + .openmpPluginDarwin +} else { + .openmpPluginDefault } .plugins[["unwindProtect"]] <- function() { # nocov start @@ -1239,41 +1287,39 @@ sourceCppFunction <- function(func, isVoid, dll, symbol) { declarations = character() call_entries = character() - # if we are running R 3.4 or higher we can use an internal utility function + # we are running R 3.4 or higher so we can use an internal utility function # to automatically discover additional native routines that require registration - if (getRversion() >= "3.4") { - - # determine the package directory - pkgdir <- dirname(dirname(targetFile)) - - # get the generated code from R - con <- textConnection(object = NULL, open = "w") - on.exit(close(con), add = TRUE) - tools::package_native_routine_registration_skeleton( - dir = pkgdir, - con = con, - character_only = FALSE - ) - code <- textConnectionValue(con) - # look for lines containing call entries - matches <- regexec('^\\s+\\{"([^"]+)",.*$', code) - matches <- regmatches(code, matches) - matches <- Filter(x = matches, function(x) { - length(x) > 0 # #nocov start - }) - for (match in matches) { - routine <- match[[2]] - if (!routine %in% routines) { - declaration <- grep(sprintf("^extern .* %s\\(.*$", routine), code, - value = TRUE) - # FIXME: maybe we should extend this to *any* routine? - # or is there any case in which `void *` is not SEXP for a .Call? - if (routine == "run_testthat_tests") - declaration <- gsub("void *", "SEXP", declaration, fixed=TRUE) - declarations <- c(declarations, sub("^extern", "RcppExport", declaration)) - call_entries <- c(call_entries, match[[1]]) # #nocov end - } + # determine the package directory + pkgdir <- dirname(dirname(targetFile)) + + # get the generated code from R + con <- textConnection(object = NULL, open = "w") + on.exit(close(con), add = TRUE) + tools::package_native_routine_registration_skeleton( + dir = pkgdir, + con = con, + character_only = FALSE + ) + code <- textConnectionValue(con) + + # look for lines containing call entries + matches <- regexec('^\\s+\\{"([^"]+)",.*$', code) + matches <- regmatches(code, matches) + matches <- Filter(x = matches, function(x) { + length(x) > 0 # #nocov start + }) + for (match in matches) { + routine <- match[[2]] + if (!routine %in% routines) { + declaration <- grep(sprintf("^extern .* %s\\(.*$", routine), code, + value = TRUE) + # FIXME: maybe we should extend this to *any* routine? + # or is there any case in which `void *` is not SEXP for a .Call? + if (routine == "run_testthat_tests") + declaration <- gsub("void *", "SEXP", declaration, fixed=TRUE) + declarations <- c(declarations, sub("^extern", "RcppExport", declaration)) + call_entries <- c(call_entries, match[[1]]) # #nocov end } } diff --git a/R/Module.R b/R/Module.R index e0268012f..10c3cadce 100644 --- a/R/Module.R +++ b/R/Module.R @@ -1,4 +1,4 @@ -# Copyright (C) 2010 - 2021 John Chambers, Dirk Eddelbuettel and Romain Francois +# Copyright (C) 2010 - 2026 John Chambers, Dirk Eddelbuettel and Romain Francois # # This file is part of Rcpp. # diff --git a/R/Rcpp.package.skeleton.R b/R/Rcpp.package.skeleton.R index 40c4fdb3f..d8c989b50 100644 --- a/R/Rcpp.package.skeleton.R +++ b/R/Rcpp.package.skeleton.R @@ -1,4 +1,4 @@ -# Copyright (C) 2009 - 2025 Dirk Eddelbuettel and Romain Francois +# Copyright (C) 2009 - 2026 Dirk Eddelbuettel and Romain Francois # # This file is part of Rcpp. # @@ -93,7 +93,7 @@ Rcpp.package.skeleton <- function(name = "anRpackage", list = character(), email)) fields_written <- c("Package", "Type", "Title", "Version", "Date", "Authors@R", "Description", "License", "Imports", "LinkingTo") - if (!is.na(githubuser)) { + if (!is.na(githubuser)) { # #nocov start x <- cbind(x, matrix("", 1, 1, dimnames=list("", "URL"))) x[1, "URL"] <- paste0("https://github.com/", githubuser, "/", name) x <- cbind(x, matrix("", 1, 1, dimnames=list("", "BugReports"))) @@ -102,7 +102,7 @@ Rcpp.package.skeleton <- function(name = "anRpackage", list = character(), fields_written <- c("Package", "Type", "Title", "Version", "Date", "Authors@R", "Description", "URL", "BugReports", "License", "Imports", "LinkingTo") - } + } # #nocov end x[, "License"] <- license x[, "Title"] <- "Concise Summary of What the Package Does" @@ -118,11 +118,7 @@ Rcpp.package.skeleton <- function(name = "anRpackage", list = character(), lines <- readLines(NAMESPACE) ns <- file(NAMESPACE, open="w") if (!any(grepl("useDynLib", lines))) { - if (getRversion() >= "3.4.0") { - lines <- c(sprintf( "useDynLib(%s, .registration=TRUE)", name), lines) - } else { - lines <- c(sprintf( "useDynLib(%s)", name), lines) # #nocov - } + lines <- c(sprintf( "useDynLib(%s, .registration=TRUE)", name), lines) writeLines(lines, con = ns) message(" >> added useDynLib directive to NAMESPACE" ) } @@ -140,7 +136,7 @@ Rcpp.package.skeleton <- function(name = "anRpackage", list = character(), ## update the package description help page if (havePkgKitten) { # if pkgKitten is available, use it - pkgKitten::playWithPerPackageHelpPage(name, path, maintainer, email) + pkgKitten::playWithPerPackageHelpPage(name, path, maintainer, email) # #nocov } else { .playWithPerPackageHelpPage(name, path, maintainer, email) # #nocov } @@ -202,14 +198,10 @@ Rcpp.package.skeleton <- function(name = "anRpackage", list = character(), # generate native routines if we aren't using attributes (which already generate # them automatically) and we have at least R 3.4 if (!attributes) { - if (getRversion() >= "3.4.0") { - con <- file(file.path(src, "init.c"), "wt") - tools::package_native_routine_registration_skeleton(root, con=con) - close(con) - message(" >> created init.c for package registration") - } else { - message(" >> R version older than 3.4.0 detected, so NO file init.c created.") # #nocov - } + con <- file(file.path(src, "init.c"), "wt") + tools::package_native_routine_registration_skeleton(root, con=con) + close(con) + message(" >> created init.c for package registration") } lines <- readLines(package.doc <- file.path( root, "man", sprintf("%s-package.Rd", name))) diff --git a/R/RcppLdpath.R b/R/RcppLdpath.R index c0a37b528..d8acb323e 100644 --- a/R/RcppLdpath.R +++ b/R/RcppLdpath.R @@ -1,4 +1,4 @@ -# Copyright (C) 2010 - 2021 Dirk Eddelbuettel and Romain Francois +# Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois # # This file is part of Rcpp. # @@ -25,7 +25,7 @@ Rcpp.quoteNonStandard <- function(path) { ## On unix, check if path has only characters that do not need quoting noquote <- .Platform$OS.type == "unix" && grepl("^[[:alnum:]/._~+@%-]*$", path) ## If no quoting needed return unchanged else quote input - if (noquote) path else shQuote(path) + if (noquote) path else shQuote(path) # #nocov } ## Use R's internal knowledge of path settings to find the lib/ directory @@ -33,6 +33,7 @@ Rcpp.quoteNonStandard <- function(path) { RcppLdPath <- function() { #.Deprecated(msg=paste("This function is now deprecated as it has not", # "been needed since 2013.")) + message("'RcppLdPath' has not been needed since 2013 (!!) and may get removed in 2027. Please update your 'Makevars'.") "" } @@ -47,6 +48,7 @@ RcppLdPath <- function() { RcppLdFlags <- function() { #.Deprecated(msg=paste("This function is now deprecated as it has not", # "been needed since 2013.")) + message("'RcppLdFlags' has not been needed since 2013 (!!) and may get removed in 2027. Please update your 'Makevars'.") "" } @@ -64,14 +66,16 @@ RcppCxxFlags <- function(cxx0x=FALSE) { ## Shorter names, and call cat() directly ## CxxFlags defaults to no using c++0x extensions are these are considered non-portable -CxxFlags <- function(cxx0x=FALSE) { +CxxFlags <- function(cxx0x=FALSE) { # #nocov start #.Deprecated(msg=paste("This function is now deprecated as R uses minimally", # "viable compilers om all platforme.")) - cat(RcppCxxFlags(cxx0x=cxx0x)) # #nocov + message("'CxxFlags' has not been needed since 2013 (!!) and may get removed in 2027. Please update your 'Makevars'.") + cat(RcppCxxFlags(cxx0x=cxx0x)) # #nocov end } ## LdFlags defaults to static linking on the non-Linux platforms Windows and OS X LdFlags <- function() { + message("'LdFlags' has not been needed since 2013 (!!) and may get removed in 2027. Please update your 'Makevars'.") cat(RcppLdFlags()) } @@ -80,14 +84,16 @@ RcppCapabilities <- capabilities <- function() .Call( rcpp_capabilities ) # compile, load and call the cxx0x.c script to identify whether # the compiler is GCC >= 4.3 -RcppCxx0xFlags <- function() { +RcppCxx0xFlags <- function() { # #nocov start #.Deprecated(msg=paste("This function is now deprecated as R uses minimally", # "viable compilers om all platforme.")) - script <- Rcpp.system.file( "discovery", "cxx0x.R" ) # #nocov start + message("'RcppCxx0xFlags' has not been needed since 2013 (!!) and may get removed in 2027. Please update your 'Makevars'.") + script <- Rcpp.system.file( "discovery", "cxx0x.R" ) flag <- capture.output( source( script ) ) flag } Cxx0xFlags <- function() { + message("'Cxx0xFlags' has not been needed since 2013 (!!) and may get removed in 2027. Please update your 'Makevars'.") cat(RcppCxx0xFlags()) # #nocov end } diff --git a/R/asis.R b/R/asis.R index ab58d12c8..5fede4fc5 100644 --- a/R/asis.R +++ b/R/asis.R @@ -30,7 +30,7 @@ ##' # %\VignettePackage{Rcpp} ##' # %\VignetteEncoding{UTF-8} ##' # %\VignetteEngine{Rcpp::asis} -asisWeave <- function (file, ...) { +asisWeave <- function (file, ...) { # #nocov start output <- tools::file_path_sans_ext(basename(file)) if (!file.exists(output)) { outputS <- file.path("..", "inst", "doc", output) @@ -53,4 +53,4 @@ asisTangle <- function (file, ..., pattern = "(|[.][^.]*)[.]asis$") { filenameR <- sprintf("%s.R", fullname) cat(sprintf("### This is an R script tangled from '%s'\n", filename), file = filenameR) invisible(filenameR) -} +} # #nocov end diff --git a/R/inline.R b/R/inline.R index 8243e033f..165c615ed 100644 --- a/R/inline.R +++ b/R/inline.R @@ -1,4 +1,4 @@ -# Copyright (C) 2009 - 2017 Dirk Eddelbuettel and Romain Francois +# Copyright (C) 2009 - 2026 Dirk Eddelbuettel and Romain Francois # # This file is part of Rcpp. # @@ -38,12 +38,11 @@ Rcpp.plugin.maker <- function(include.before = "", #endif using namespace Rcpp;", include.before, include.after) - out <- list(env = list( PKG_LIBS = libs ), includes = includes, LinkingTo = LinkingTo , body = function( x ) { - sprintf( "BEGIN_RCPP\n%s\nEND_RCPP", x ) + sprintf( "BEGIN_RCPP\n%s\nEND_RCPP", x ) # #nocov }, Depends = Depends, Imports = Imports) @@ -54,4 +53,3 @@ using namespace Rcpp;", include.before, include.after) } inlineCxxPlugin <- Rcpp.plugin.maker() - diff --git a/R/loadModule.R b/R/loadModule.R index 77ac55139..82d2dcda1 100644 --- a/R/loadModule.R +++ b/R/loadModule.R @@ -1,4 +1,4 @@ -# Copyright (C) 2010 - 2015 John Chambers, Dirk Eddelbuettel and Romain Francois +# Copyright (C) 2010 - 2026 John Chambers, Dirk Eddelbuettel and Romain Francois # # This file is part of Rcpp. # @@ -54,12 +54,12 @@ loadModule <- function( module, what = character(), loadNow, if(exists(metaName, envir = env, inherits = FALSE)) loadM <- get(metaName, envir = env) } - else if(is(module, "Module")) { - loadM <- as.environment(module) # #nocov - module <- get(loadM, "moduleName") # #nocov + else if(is(module, "Module")) { # #nocov start + loadM <- as.environment(module) + module <- get(loadM, "moduleName") } else - stop(gettextf("Argument \"module\" should be a module or the name of a module: got an object of class \"%s\"", class(module))) + stop(gettextf("Argument \"module\" should be a module or the name of a module: got an object of class \"%s\"", class(module))) # #nocov end if(missing(loadNow)) { # test it if(is.null(loadM)) loadM <- tryCatch(Module( module, mustStart = TRUE, where = env ), @@ -104,7 +104,7 @@ loadModule <- function( module, what = character(), loadNow, assignAs <- .moduleNames(what) for( i in seq_along(what) ) { if(.botched) - assign(assignAs[[i]], NULL, envir = storage) + assign(assignAs[[i]], NULL, envir = storage) # #nocov else assign(assignAs[[i]], get(what[[i]], envir = storage), envir = env) } @@ -120,4 +120,3 @@ loadModule <- function( module, what = character(), loadNow, invisible(myCall) # #nocov } } - diff --git a/R/loadRcppModules.R b/R/loadRcppModules.R deleted file mode 100644 index 844da8fc8..000000000 --- a/R/loadRcppModules.R +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2010 - 2016 John Chambers, Dirk Eddelbuettel and Romain Francois -# -# 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 . - -loadRcppModules <- function(direct=TRUE) { # #nocov start - # deprecation added May 2016, 'loadModule' has been prefered for years - .Deprecated("loadModule") - - ## hunt for the namespace of the package that calls this - calls <- sys.calls() - w <- which( sapply( calls, function(call){ - identical( call[[1L]], as.name( "runHook" ) ) - } ) ) - if( !length(w) ) - stop( "loadRcppModules can only be used within a .onLoad function" ) - w <- w[ length(w) ] - call <- calls[[w]] - if( !identical( call[[2L]], ".onLoad" ) ) - stop( "loadRcppModules can only be used within a .onLoad function" ) - f <- sys.frame( w ) - ns <- get("env", f ) - if( !isNamespace( ns ) ) - stop( "loadRcppModules not called from a namespace" ) - pkg <- get( "pkgname", f ) - lib <- get( "libname", f ) - - ## look for declared modules in the DESCRIPTION fields - description <- packageDescription(pkg, lib.loc=lib) - modules <- description[["RcppModules"]] - if( !is.null( modules ) ){ - modules <- strsplit( modules, "[[:space:]]*,[[:space:]]*")[[1L]] - for( m in modules ){ - tryCatch( { - mod <- Module( m, pkg, mustStart = TRUE) - if(isTRUE(direct)){ - populate( mod, ns ) - } else { - forceAssignInNamespace( m, mod, ns ) - } - assign(.moduleMetaName(m), mod, envir = ns) - }, error = function(e){ - stop( sprintf( "failed to load module %s from package %s\n%s", m, pkg, conditionMessage(e) ) ) - }) - } - } -} # #nocov end diff --git a/README.md b/README.md index 0a0f4ffbc..bb42b2f21 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ [![CRAN indirect](https://jangorecki.gitlab.io/rdeps/Rcpp/indirect_usage.svg?sanitize=true)](https://cran.r-project.org/package=Rcpp) [![BioConductor use](https://jangorecki.gitlab.io/rdeps/Rcpp/BioC_usage.svg?sanitize=true)](https://cran.r-project.org/package=Rcpp) [![JSS](https://img.shields.io/badge/JSS-10.18637%2Fjss.v040.i08-brightgreen)](https://doi.org/10.18637/jss.v040.i08) -[![Springer useR!](https://img.shields.io/badge/Springer%20useR!-10.1007%2F978--1--4614--6868--4-brightgreen)](https://www.amazon.com/gp/product/1461468671/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1461468671&linkCode=as2&tag=rcpp-20&linkId=3P5LNUWOAQ2YMEJ6) +[![Springer useR!](https://img.shields.io/badge/Springer%20useR!-10.1007%2F978--1--4614--6868--4-brightgreen)](https://link.springer.com/book/10.1007/978-1-4614-6868-4) [![TAS](https://img.shields.io/badge/TAS-10.1080%2F00031305.2017.1375990-brightgreen)](https://doi.org/10.1080/00031305.2017.1375990) ### Synopsis @@ -37,7 +37,7 @@ provides a good entry point to Rcpp as do the [Rcpp website](https://www.rcpp.org), the [Rcpp page](https://dirk.eddelbuettel.com/code/rcpp.html) and the [Rcpp Gallery](https://gallery.rcpp.org). Full documentation is provided by the -[Rcpp book](https://www.amazon.com/gp/product/1461468671/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1461468671&linkCode=as2&tag=rcpp-20&linkId=3P5LNUWOAQ2YMEJ6). +[Rcpp book](https://link.springer.com/book/10.1007/978-1-4614-6868-4). Other highlights: @@ -78,7 +78,7 @@ Among the other vignettes are the [Rcpp FAQ](https://cran.r-project.org/package=Rcpp/vignettes/Rcpp-FAQ.pdf) and the introduction to [Rcpp Attributes](https://cran.r-project.org/package=Rcpp/vignettes/Rcpp-attributes.pdf). -Additional documentation is available via the [Rcpp book](https://www.amazon.com/gp/product/1461468671/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1461468671&linkCode=as2&tag=rcpp-20&linkId=3P5LNUWOAQ2YMEJ6) +Additional documentation is available via the [Rcpp book](https://link.springer.com/book/10.1007/978-1-4614-6868-4) by Eddelbuettel (2013, Springer); see 'citation("Rcpp")' for details. ### Performance @@ -134,20 +134,20 @@ install.packages("Rcpp") #### Release Candidates -For the last several releases, we also made interim _candidate_ releases available -on the [Rcpp Drat Repo](https://RcppCore.github.io/drat/). Versions from a -[drat](https://github.com/eddelbuettel/drat) repo can be installed either by -just temporarily setting the [drat](https://github.com/eddelbuettel/drat) repo as in +We generally make interim _candidate_ releases available via the [r-universe +page](https://rcppcore.r-universe.dev/Rcpp). It provides a standard R repository which +corresponds to the current main branch in the source repository. Both binary and source +versions can be installed via ```R -install.packages("Rcpp", repos="https://RcppCore.github.io/drat") +install.packages("Rcpp", repos = c("https://rcppcore.r-universe.dev", + "https://cloud.r-project.org")) ``` -or by setting a [drat](https://github.com/eddelbuettel/drat) repo more permanently -(as described in the documentation of the [drat](https://github.com/eddelbuettel/drat) -package). +where other repos can be set as needed. -Testing the release candidates prior to actual release help. Please run this if you can. +Testing the release candidates prior to the actual release helps. Please run +this if you can. #### Source @@ -166,11 +166,9 @@ we cannot test on outdated versions of R or your OS. ### Support -The best place for questions is the -[Rcpp-devel](https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel) -mailing list hosted at R-forge. Note that in order to keep spam down, you must -be a subscriber in order to post. One can also consult the list archives to see -if your question has been asked before. +The best place for questions is the [discussion section of the GitHub +repo](https://github.com/RcppCore/Rcpp/discussions) as the previously used mailing list at R-forge +is no longer operational. The [issue tickets at the GitHub repo](https://github.com/RcppCore/Rcpp/issues) are the primary bug reporting interface. As with the other web resources, diff --git a/cleanup b/cleanup index 9bbece184..e334f7c5c 100755 --- a/cleanup +++ b/cleanup @@ -30,7 +30,9 @@ rm -f confdefs.h config.log config.status \ vignettes/*.toc vignettes/*.tpt vignettes/*.xwm rm -rf autom4te.cache inst/lib/ inst/doc/man/ inst/doc/html/ inst/doc/latex/ \ - inst/doc/auto inst/bib/auto inst/doc/Rcpp-*/auto/ src-* vignettes/auto + inst/doc/auto inst/bib/auto inst/doc/Rcpp-*/auto/ src-* vignettes/auto \ + inst/tinytest/testRcppAttributePackage/inst \ + inst/tinytest/testRcppAttributePackage/R find . -name \*~ -exec rm {} \; find . -name \*.flc -exec rm {} \; diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 3565ac5bb..eaf8c1952 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -3,19 +3,92 @@ \newcommand{\ghpr}{\href{https://github.com/RcppCore/Rcpp/pull/#1}{##1}} \newcommand{\ghit}{\href{https://github.com/RcppCore/Rcpp/issues/#1}{##1}} -\section{Changes in Rcpp release version 1.1.1 (2026-01-xx)}{ +\section{Changes in Rcpp release version 1.1.2 [unreleased] (expected 2026-07-xx)}{ + \itemize{ + \item Changes in Rcpp API: + \itemize{ + \item Use of \code{execinfo.h} is again conditional to avoid build + complexity (Dirk in \ghpr{1445} addressing \ghit{1442}) + \item An internal state component for \code{Datetime} is now \code{int} + (Dirk in \ghpr{1448} and \ghpr{1449} fixing \ghpr{1447}) + \item Three new (in R 4.6.0) attribute accessors are used conditionally + (Dirk in \ghpr{1450} closing \ghit{1432}) + \item An UBSAN error in the Sugar-based NA comparison has been + corrected (Iñaki in \ghpr{1453} fixing \ghit{1452}) + \item Treatment of Inf outside of integer range in Sugar function has + been corrected (Iñaki in \ghpr{1458} fixing \ghit{1455}) + \item Integer overflow protection has been added for sugar functions + (Iñaki in \ghpr{1457} fixing \ghpr{1454}) + \item The parent environment is now accessed via \code{R_ParentEnv} + (Dirk in \ghpr{1460} fixing \ghit{1459}) + } + } +} + +\section{Changes in Rcpp release version 1.1.1 (2026-01-08)}{ \itemize{ \item Changes in Rcpp API: \itemize{ \item An unused old R function for a compiler version check has been removed after checking no known package uses it (Dirk in \ghpr{1395}) \item A narrowing warning is avoided via a cast (Dirk in \ghpr{1398}) + \item Demangling checks have been simplified (Iñaki in \ghpr{1401} + addressing \ghit{1400}) + \item The treatment of signed zeros is now improved in the Sugar code + (Iñaki in \ghpr{1404}) + \item Preparations for phasing out use of \code{Rf_error} have been + made (Iñaki in \ghpr{1407}) + \item The long-deprecated function \code{loadRcppModules()} has been + removed (Dirk in \ghpr{1416} closing \ghit{1415}) + \item Some non-API includes from R were refactored to accommodate + R-devel changes (Iñaki in \ghpr{1418} addressing \ghit{1417}) + \item An accessor to \code{Rf_rnbeta} has been removed (Dirk in + \ghpr{1419} also addressing \ghit{1420}) + \item Code accessing non-API \code{Rf_findVarInFrame} now uses + \code{R_getVarEx} (Dirk in \ghpr{1423} fixing \ghit{1421}) + \item Code conditional on the R version now expects at least R 3.5.0; + older code has been removed (Dirk in \ghpr{1426} fixing \ghit{1425}) + \item The non-API \code{ATTRIB} entry point to the R API is no longer + used (Dirk in \ghpr{1430} addressing \ghit{1429}) + \item The unwind-protect mechanism is now used unconditionally (Dirk + in \ghpr{1437} closing \ghit{1436}) + } + \item Changes in Rcpp Attributes: + \itemize{ + \item The OpenMP plugin has been generalized for different macOS + compiler installations (Kevin in \ghpr{1414}) } \item Changes in Rcpp Documentation: \itemize{ \item Vignettes are now processed via a new "asis" processor adopted from \pkg{R.rsp} (Dirk in \ghpr{1394} fixing \ghit{1393}) \item R is now cited via its DOI (Dirk) + \item A (very) stale help page has been removed (Dirk in \ghpr{1428} + fixing \ghit{1427}) + \item The main README.md was updated emphasizing r-universe in favor of + the local drat repos (Dirk in \ghpr{1431}) + } + \item Changes in Rcpp Deployment: + \itemize{ + \item A temporary change in R-devel concerning NA part in complex variables + was accommodated, and then reverted (Dirk in \ghpr{1399} fixing \ghit{1397}) + \item The macOS CI runners now use macos-14 (Dirk in \ghpr{1405}) + \item A message is shown if \code{R.h} is included before Rcpp headers + as this can lead to errors (Dirk in \ghpr{1411} closing \ghit{1410}) + \item Old helper functions use \code{message()} to signal they are not used, + deprecation and removal to follow (Dirk in \ghpr{1413} closing + \ghit{1412}) + \item Three tests were being silenced following \ghpr{1413} (Dirk in + \ghpr{1422}) + \item The heuristic whether to run all available tests was refined + (Dirk in \ghpr{1434} addressing \ghit{1433}) + \item Coverage has been tweaked via additional \code{#nocov} tags (Dirk + in \ghpr{1435}) + } + \item Non-release Changes: + \itemize{ + \item Two interim non-releases 1.1.0.8.1 and .2 were made in order to + unblock CRAN due to changes in R-devel rather than Rcpp } } } diff --git a/inst/bib/Rcpp.bib b/inst/bib/Rcpp.bib index 648b9eeaf..4c2a6af37 100644 --- a/inst/bib/Rcpp.bib +++ b/inst/bib/Rcpp.bib @@ -10,7 +10,7 @@ @manual{Abrahams+Grosse-Kunstleve:2003:Boost.Python organization = "Boost Consulting", title = "Building Hybrid Systems with Boost.Python", year = 2003, - url = "https://www.boostpro.com/writing/bpl.pdf" + url = "https://www.boost.org/doc/libs/latest/libs/python/doc/html/article.html" } @Book{Abrahams+Gurtovoy:2004:TemplateMetaprogramming, @@ -60,7 +60,7 @@ @InProceedings{Bates+DebRoy:2001:C++Classes Universit\"at Wien, Vienna, Austria}, editor = {Kurt Hornik and Friedrich Leisch}, year = {2001}, - url = {https://www.ci.tuwien.ac.at/Conferences/DSC-2001/Proceedings/}, + url = {https://www.r-project.org/conferences/DSC-2001/Proceedings/}, note = {ISSN 1609-395X} } @@ -76,8 +76,8 @@ @Misc{Brokken:2011:Cpp @Manual{CRAN:anytime, title = {anytime: Anything to 'POSIXct' or 'Date' Converter}, author = {Dirk Eddelbuettel}, - year = {2024}, - note = {R package version 0.3.11}, + year = {2025}, + note = {R package version 0.3.12}, oldurl = CRAN # "package=anytime", doi = DOI # "anytime" } @@ -95,8 +95,8 @@ @Manual{CRAN:BH title = {BH: Boost C++ Header Files}, author = {Dirk Eddelbuettel and John W. Emerson and Michael J. Kane}, - year = {2024}, - note = {R package version 1.87.0-1}, + year = {2025}, + note = {R package version 1.90.0-1}, oldurl = CRAN # "package=BH", doi = DOI # "BH" } @@ -105,7 +105,7 @@ @Manual{CRAN:Matrix title = {\pkg{Matrix}: Sparse and Dense Matrix Classes and Methods}, author = {Douglas Bates and Martin Maechler}, year = 2025, - note = {R package version 1.7-3}, + note = {R package version 1.7-4}, oldurl = CRAN # "package=Matrix", doi = DOI # "Matrix" } @@ -113,8 +113,8 @@ @Manual{CRAN:Matrix @Manual{CRAN:RInside, title = {RInside: C++ classes to embed R in C++ applications}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, - year = 2020, - note = {R package version 0.2.16}, + year = 2025, + note = {R package version 0.2.19}, oldurl = CRAN # "package=RInside", doi = DOI # "RInside" } @@ -152,8 +152,8 @@ @Manual{CRAN:Rcpp author = {Dirk Eddelbuettel and Romain Fran\c{c}ois and JJ Allaire and Kevin Ushey and Qiang Kou and Nathan Russel and John Chambers and Douglas Bates}, - year = 2025, - note = {R package version 1.1.0}, + year = 2026, + note = {R package version 1.1.1}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" } @@ -163,7 +163,7 @@ @Manual{CRAN:Rcpp:Attributes author = {J. J. Allaire and Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {{Rcpp} Attributes}, - year = 2025, + year = 2026, note = {Vignette included in R package Rcpp}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -173,7 +173,7 @@ @Manual{CRAN:Rcpp:FAQ crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Frequently Asked Questions About {Rcpp}}, - year = 2025, + year = 2026, note = {Vignette included in R package {Rcpp}}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -183,7 +183,7 @@ @Manual{CRAN:Rcpp:Libraries crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel}, title = {Thirteen Simple Steps for Creating An R Package with an External C++ Library }, - year = 2025, + year = 2026, note = {Vignette included in R package Rcpp}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -193,7 +193,7 @@ @Manual{CRAN:Rcpp:Modules crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Exposing {C++} functions and classes with {Rcpp} modules}, - year = 2025, + year = 2026, note = {Vignette included in R package Rcpp}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -203,7 +203,7 @@ @Manual{CRAN:Rcpp:Package crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Writing a package that uses {Rcpp}}, - year = 2025, + year = 2026, note = {Vignette included in R package {Rcpp}}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -213,7 +213,7 @@ @Manual{CRAN:Rcpp:Sugar crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Rcpp syntactic sugar}, - year = 2025, + year = 2026, note = {Vignette included in R package {Rcpp}}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -225,7 +225,7 @@ @Manual{CRAN:RcppArmadillo author = {Dirk Eddelbuettel and Romain Fran\c{c}ois and Douglas Bates and Binxiang Ni and Conrad Sanderson}, year = 2025, - note = {R package version 14.4.3-1}, + note = {R package version 15.2.3-1}, oldurl = CRAN # "package=RcppArmadillo", doi = DOI # "RcppArmadillo" } @@ -316,8 +316,8 @@ @Manual{CRAN:RcppZiggurat @Manual{CRAN:Rserve, title = {Rserve: Versatile R Server}, author = {Simon Urbanek}, - year = 2024, - note = {R package version 1.8-15}, + year = 2025, + note = {R package version 1.8-16}, oldurl = CRAN # "package=Rserve", doi = DOI # "Rserve" } @@ -336,8 +336,8 @@ @Manual{CRAN:devtools title = {devtools: Tools to Make Developing R Packages Easier}, author = {Hadley Wickham and Jim Hester and Winston Chang}, - year = 2022, - note = {R package version 2.4.5}, + year = 2025, + note = {R package version 2.4.6}, oldurl = CRAN # "package=devtools", doi = DOI # "devtools" } @@ -345,8 +345,8 @@ @Manual{CRAN:devtools @Manual{CRAN:highlight, title = {highlight: Syntax Highlighter}, author = {Hadley Wickham and Romain Fran\c{c}ois and Andre Simon}, - year = 2023, - note = {R package with version 0.5.1}, + year = 2025, + note = {R package with version 0.5.2}, oldurl = CRAN # "package=highlight", doi = DOI # "highlight" } @@ -423,8 +423,8 @@ @Manual{CRAN:rbenchmark @Manual{CRAN:roxygen2, title = {roxygen2: In-Line documentation for R}, author = {Hadley Wickham and Peter Danenberg and G\a'bor Cs\a'rdi and Manuel Eugster}, - year = 2024, - note = {R package version 7.3.2}, + year = 2025, + note = {R package version 7.3.3}, oldurl = CRAN # "package=roxygen2", doi = DOI # "roxygen2" } @@ -554,7 +554,7 @@ @MISC{Eigen:Web author = {Ga\"{e}l Guennebaud and Beno\^{i}t Jacob and others}, title = {Eigen v3}, year = 2012, - url = {https://eigen.tuxfamily.org} + url = {https://libeigen.gitlib.io/} } @Manual{GSL, @@ -773,8 +773,8 @@ @Article{PeerJ:Rcpp issue = {e3188v1}, year = 2017, month = {August}, - url = {https://doi.org/10.7287/peerj.preprints.3188v1/}, - doi = {10.7287/peerj.preprints.3188v1/} + url = {https://peerj.com/preprints/3188v1/}, + doi = {10.7287/peerj.preprints.3188v1} } @Book{Plauger+Et+Al:2000:STL, @@ -790,7 +790,7 @@ @manual{QuantLib author = {{QuantLib Core Team}}, year = 2021, title = {QuantLib: a free/open-source library for quantitative finance}, - url = {https://quantlib.org} + url = {https://www.quantlib.org} } @manual{R:Administration, @@ -886,7 +886,7 @@ @TechReport{Sanderson:2010:Armadillo Experiments }, institution = {{NICTA}}, year = 2010, - url = "https://arma.sf.net" + url = "https://arma.sourceforge.net" } @Book{Stroustrup:1997:Cpp, @@ -952,7 +952,7 @@ @InProceedings{Urbanek:2003:Rserve Statistical Computing, Vienna, Austria}, editor = {Kurt Hornik and Friedrich Leisch and Achim Zeileis}, year = {2003}, - url = {https://www.ci.tuwien.ac.at/Conferences/DSC-2003/Proceedings/}, + url = {https://www.r-project.org/conferences/DSC-2003/Proceedings/}, note = {{ISSN 1609-395X}} } @@ -996,7 +996,7 @@ @Book{Venables+Ripley:2002:MASS address = {New York}, year = 2002, note = {ISBN 0-387-95457-0}, - url = {https://www.stats.ox.ac.uk/pub/MASS4}, + url = {https://www.stats.ox.ac.uk/pub/MASS4/}, } @misc{arxiv:corels, @@ -1005,7 +1005,7 @@ @misc{arxiv:corels author = {Elaine Angelino and Nicholas Larus-Stone and Daniel Alabi and Margo Seltzer and Cynthia Rudin}, year = 2017, - howpublished = {\href{https://www.arxiv.org/1704.01701}{arXiv:1704.01701}}, + howpublished = {\href{https://www.arxiv.org/abs/1704.01701}{arXiv:1704.01701}}, archivePrefix ={arXiv}, primaryClass = {stat.ML} } @@ -1013,7 +1013,7 @@ @misc{arxiv:corels @Misc{github:corels, author = {Nicholas Laurus-Stone}, title = {corels: {Learning Certifiably Optimal Rule Lists}}, - howpublished = {\url{https://github.com/nlarusstone/corels}. Also online at \url{https://corels.eecs.harvard.edu/corels/}}, + howpublished = {\url{https://github.com/corels/corels}. Also online at \url{https://corels.cs.ubc.ca/corels/Larus-Stone_thesis.pdf}}, month = 06, year = 2019 } @@ -1021,7 +1021,7 @@ @Misc{github:corels @Misc{github:rcppcorels, author = {Dirk Eddelbuettel}, title = {RcppCorels: R binding for the 'Certifiably Optimal RulE ListS (Corels)' Learner}, - howpublished = {\url{https://github.com/eddelbuettel/rcppcorels}}, + howpublished = {\url{https://github.com/corels/rcppcorels}}, month = 11, year = 2019 } diff --git a/inst/include/Rcpp/DataFrame.h b/inst/include/Rcpp/DataFrame.h index c6d8c7741..65a81576f 100644 --- a/inst/include/Rcpp/DataFrame.h +++ b/inst/include/Rcpp/DataFrame.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // DataFrame.h: Rcpp R/C++ interface class library -- data frames // -// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -61,29 +60,21 @@ namespace Rcpp{ } // By definition, the number of rows in a data.frame is contained - // in its row.names attribute. If it has row names of the form 1:n, - // they will be stored as {NA_INTEGER, -}. Unfortunately, - // getAttrib(df, R_RowNamesSymbol) will force an expansion of that - // compact form thereby allocating a huge vector when we just want - // the row.names. Hence this workaround. - inline int nrow() const { - SEXP rn = R_NilValue ; - SEXP att = ATTRIB( Parent::get__() ) ; - while( att != R_NilValue ){ - if( TAG(att) == R_RowNamesSymbol ) { - rn = CAR(att) ; - break ; - } - att = CDR(att) ; - } - if (Rf_isNull(rn)) - return 0; - if (TYPEOF(rn) == INTSXP && LENGTH(rn) == 2 && INTEGER(rn)[0] == NA_INTEGER) - return std::abs(INTEGER(rn)[1]); - return LENGTH(rn); + // in its row.names attribute. Since R 3.5.0 this is returned as a + // compact sequence from which we can just take the (x)length + // But as this makes an allocation an even simpler check on length as + // discussed in #1430 is also possible and preferable. We also switch + // to returning R_xlen_t which as upcast from int is safe + inline R_xlen_t nrow() const { +#if R_VERSION < R_Version(4,6,0) + Shield rn{Rf_getAttrib(Parent::get__(), R_RowNamesSymbol)}; + return Rf_xlength(rn); +#else + return R_nrow(Parent::get__()); +#endif } - template + template void push_back( const T& object){ Parent::push_back(object); set_type_after_push(); @@ -108,8 +99,8 @@ namespace Rcpp{ } // Offer multiple variants to accomodate both old interface here and signatures in other classes - inline int nrows() const { return DataFrame_Impl::nrow(); } - inline int rows() const { return DataFrame_Impl::nrow(); } + inline R_xlen_t nrows() const { return DataFrame_Impl::nrow(); } + inline R_xlen_t rows() const { return DataFrame_Impl::nrow(); } inline R_xlen_t ncol() const { return DataFrame_Impl::length(); } inline R_xlen_t cols() const { return DataFrame_Impl::length(); } diff --git a/inst/include/Rcpp/Environment.h b/inst/include/Rcpp/Environment.h index 901b3fb5e..0f6f79928 100644 --- a/inst/include/Rcpp/Environment.h +++ b/inst/include/Rcpp/Environment.h @@ -1,9 +1,8 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // Environment.h: Rcpp R/C++ interface class library -- access R environments // -// Copyright (C) 2009 - 2013 Dirk Eddelbuettel and Romain Francois -// Copyright (C) 2014 - 2020 Dirk Eddelbuettel, Romain Francois and Kevin Ushey +// Copyright (C) 2009-2013 Dirk Eddelbuettel and Romain François +// Copyright (C) 2014-2026 Dirk Eddelbuettel, Romain François and Kevin Ushey // // This file is part of Rcpp. // @@ -98,13 +97,16 @@ namespace Rcpp{ SEXP get(const std::string& name) const { SEXP env = Storage::get__() ; SEXP nameSym = Rf_install(name.c_str()); +#if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVarInFrame( env, nameSym ) ; - +#else + SEXP res = R_getVarEx(nameSym, env, FALSE, R_UnboundValue); +#endif if( res == R_UnboundValue ) return R_NilValue ; /* We need to evaluate if it is a promise */ if( TYPEOF(res) == PROMSXP){ - res = internal::Rcpp_eval_impl( res, env ) ; + res = internal::Rcpp_eval_impl( res, env ) ; // #nocov } return res ; } @@ -118,7 +120,11 @@ namespace Rcpp{ */ SEXP get(Symbol name) const { SEXP env = Storage::get__() ; +#if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVarInFrame( env, name ) ; +#else + SEXP res = R_getVarEx(name, env, FALSE, R_UnboundValue); +#endif if( res == R_UnboundValue ) return R_NilValue ; @@ -140,7 +146,11 @@ namespace Rcpp{ SEXP find( const std::string& name) const{ SEXP env = Storage::get__() ; SEXP nameSym = Rf_install(name.c_str()); +#if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVar( nameSym, env ) ; +#else + SEXP res = R_getVarEx(nameSym, env, TRUE, R_UnboundValue); +#endif if( res == R_UnboundValue ) throw binding_not_found(name) ; @@ -159,8 +169,11 @@ namespace Rcpp{ */ SEXP find(Symbol name) const{ SEXP env = Storage::get__() ; +#if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVar( name, env ) ; - +#else + SEXP res = R_getVarEx(name, env, TRUE, R_UnboundValue); +#endif if( res == R_UnboundValue ) { // Pass on the const char* to the RCPP_EXCEPTION_CLASS's // const std::string& requirement @@ -184,7 +197,11 @@ namespace Rcpp{ */ bool exists( const std::string& name ) const { SEXP nameSym = Rf_install(name.c_str()); +#if R_VERSION < R_Version(4,5,0) SEXP res = Rf_findVarInFrame( Storage::get__() , nameSym ) ; +#else + SEXP res = R_getVarEx(nameSym, Storage::get__(), FALSE, R_UnboundValue); +#endif return res != R_UnboundValue ; } @@ -372,7 +389,11 @@ namespace Rcpp{ * The parent environment of this environment */ Environment_Impl parent() const { +#if R_VERSION < R_Version(4,5,0) return Environment_Impl( ENCLOS(Storage::get__()) ) ; +#else + return Environment_Impl(R_ParentEnv(Storage::get__())); +#endif } /** diff --git a/inst/include/Rcpp/Function.h b/inst/include/Rcpp/Function.h index c06f65cc8..783318b39 100644 --- a/inst/include/Rcpp/Function.h +++ b/inst/include/Rcpp/Function.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // Function.h: Rcpp R/C++ interface class library -- functions (also primitives and builtins) // -// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -43,12 +42,12 @@ namespace Rcpp{ case BUILTINSXP: Storage::set__(x); break; - default: + default: // #nocov start const char* fmt = "Cannot convert object to a function: " "[type=%s; target=CLOSXP, SPECIALSXP, or " "BUILTINSXP]."; throw not_compatible(fmt, Rf_type2char(TYPEOF(x))); - } + } // #nocov end } /** @@ -70,7 +69,11 @@ namespace Rcpp{ } Function_Impl(const std::string& name, const std::string& ns) { +#if R_VERSION < R_Version(4,5,0) Shield env(Rf_findVarInFrame(R_NamespaceRegistry, Rf_install(ns.c_str()))); +#else + Shield env(R_getVarEx(Rf_install(ns.c_str()), R_NamespaceRegistry, FALSE, R_UnboundValue)); +#endif if (env == R_UnboundValue) { stop("there is no namespace called \"%s\"", ns); } diff --git a/inst/include/Rcpp/Module.h b/inst/include/Rcpp/Module.h index e14d073ad..7556e9f3c 100644 --- a/inst/include/Rcpp/Module.h +++ b/inst/include/Rcpp/Module.h @@ -1,7 +1,7 @@ // Module.h: Rcpp R/C++ interface class library -- Rcpp modules // -// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -571,7 +571,7 @@ namespace Rcpp { public: typedef XPtr XP_Class ; typedef Rcpp::XPtr XP ; - CppClass( SEXP x) : S4(x){}; + CppClass( SEXP x) : S4(x){}; // #nocov CppClass( Module* p, class_Base* cl, std::string& buffer ) : S4("C++Class") { XP_Class clxp( cl, false, R_NilValue, R_NilValue ) ; diff --git a/inst/include/Rcpp/Rmath.h b/inst/include/Rcpp/Rmath.h index 757b88582..ad1958e52 100644 --- a/inst/include/Rcpp/Rmath.h +++ b/inst/include/Rcpp/Rmath.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // Rmath.h: Rcpp R/C++ interface class library -- Wrappers for R's Rmath API // -// Copyright (C) 2012 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2012-2025 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -131,12 +130,10 @@ namespace R { inline double qnbinom(double p, double sz, double pb, int lt, int lg) { return ::Rf_qnbinom(p, sz, pb, lt, lg); } inline double rnbinom(double sz, double pb) { return ::Rf_rnbinom(sz, pb); } -#if R_VERSION >= R_Version(3, 1, 2) inline double dnbinom_mu(double x, double sz, double mu, int lg) { return ::Rf_dnbinom_mu(x, sz, mu, lg); } inline double pnbinom_mu(double x, double sz, double mu, int lt, int lg) { return ::Rf_pnbinom_mu(x, sz, mu, lt, lg); } inline double qnbinom_mu(double x, double sz, double mu, int lt, int lg) { return ::Rf_qnbinom_mu(x, sz, mu, lt, lg); } //inline double rnbinom_mu(double sz, double mu) { return ::Rf_rnbinom_mu(sz, mu); } -#endif /* Poisson Distribution */ inline double dpois(double x, double lb, int lg) { return ::Rf_dpois(x, lb, lg); } @@ -160,7 +157,7 @@ namespace R { inline double dnbeta(double x, double a, double b, double ncp, int lg) { return ::Rf_dnbeta(x, a, b, ncp, lg); } inline double pnbeta(double x, double a, double b, double ncp, int lt, int lg) { return ::Rf_pnbeta(x, a, b, ncp, lt, lg); } inline double qnbeta(double p, double a, double b, double ncp, int lt, int lg) { return ::Rf_qnbeta(p, a, b, ncp, lt, lg); } - inline double rnbeta(double a, double b, double np) { return ::Rf_rnbeta(a, b, np); } + //inline double rnbeta(double a, double b, double np) { return ::Rf_rnbeta(a, b, np); } /* Non-central F Distribution */ inline double dnf(double x, double df1, double df2, double ncp, int lg) { return ::Rf_dnf(x, df1, df2, ncp, lg); } diff --git a/inst/include/Rcpp/S4.h b/inst/include/Rcpp/S4.h index d5fa8746a..2ec8cdebf 100644 --- a/inst/include/Rcpp/S4.h +++ b/inst/include/Rcpp/S4.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // S4.h: Rcpp R/C++ interface class library -- S4 objects // -// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -38,10 +37,10 @@ namespace Rcpp{ * * @param x must be an S4 object */ - S4_Impl(SEXP x) { + S4_Impl(SEXP x) { // #nocov start if( ! ::Rf_isS4(x) ) throw not_s4() ; Storage::set__(x) ; - } + } // #nocov end S4_Impl& operator=( SEXP other ){ Storage::set__( other ) ; @@ -57,7 +56,7 @@ namespace Rcpp{ S4_Impl( const std::string& klass ){ Shield x( R_do_new_object(R_do_MAKE_CLASS(klass.c_str())) ); if (!Rf_inherits(x, klass.c_str())) - throw S4_creation_error( klass ) ; + throw S4_creation_error( klass ) ; // #nocov Storage::set__(x) ; } diff --git a/inst/include/Rcpp/Symbol.h b/inst/include/Rcpp/Symbol.h index 82db25bc4..beabc546c 100644 --- a/inst/include/Rcpp/Symbol.h +++ b/inst/include/Rcpp/Symbol.h @@ -43,21 +43,13 @@ namespace Rcpp{ Storage::set__( x ) ; break; /* nothing to do */ case CHARSXP: { - #if R_VERSION >= R_Version(3,2,0) SEXP charSym = Rf_installChar(x); // R 3.2.0 or later have Rf_installChar - #else - SEXP charSym = Rf_install(CHAR(x)); // cannot be gc()'ed once in symbol table - #endif Storage::set__( charSym ) ; break ; } case STRSXP: { /* FIXME: check that there is at least one element */ - #if R_VERSION >= R_Version(3,2,0) SEXP charSym = Rf_installChar(STRING_ELT(x, 0 )); // R 3.2.0 or later have Rf_installChar - #else - SEXP charSym = Rf_install( CHAR(STRING_ELT(x, 0 )) ); // cannot be gc()'ed once in symbol table - #endif Storage::set__( charSym ); break ; } diff --git a/inst/include/Rcpp/api/meat/Rcpp_eval.h b/inst/include/Rcpp/api/meat/Rcpp_eval.h index 8eb08e0f0..340d2ac7a 100644 --- a/inst/include/Rcpp/api/meat/Rcpp_eval.h +++ b/inst/include/Rcpp/api/meat/Rcpp_eval.h @@ -1,4 +1,5 @@ -// Copyright (C) 2013 Romain Francois +// Copyright (C) 2013 - 2025 Romain Francois +// Copyright (C) 2026 Romain Francois and Dirk Eddelbuettel // // This file is part of Rcpp. // @@ -24,8 +25,6 @@ namespace Rcpp { namespace internal { -#ifdef RCPP_USING_UNWIND_PROTECT - struct EvalData { SEXP expr; SEXP env; @@ -38,40 +37,20 @@ inline SEXP Rcpp_protected_eval(void* eval_data) { } // This is used internally instead of Rf_eval() to make evaluation safer -inline SEXP Rcpp_eval_impl(SEXP expr, SEXP env) { - return Rcpp_fast_eval(expr, env); -} - -#else // R < 3.5.0 - -// Fall back to Rf_eval() when the protect-unwind API is unavailable -inline SEXP Rcpp_eval_impl(SEXP expr, SEXP env) { - return ::Rf_eval(expr, env); +inline SEXP Rcpp_eval_impl(SEXP expr, SEXP env) { // #nocov + return Rcpp_fast_eval(expr, env); // #nocov } -#endif - }} // namespace Rcpp::internal namespace Rcpp { -#ifdef RCPP_USING_UNWIND_PROTECT - inline SEXP Rcpp_fast_eval(SEXP expr, SEXP env) { internal::EvalData data(expr, env); return unwindProtect(&internal::Rcpp_protected_eval, &data); } -#else - -inline SEXP Rcpp_fast_eval(SEXP expr, SEXP env) { - return Rcpp_eval(expr, env); -} - -#endif - - inline SEXP Rcpp_eval(SEXP expr, SEXP env) { // 'identity' function used to capture errors, interrupts diff --git a/inst/include/Rcpp/as.h b/inst/include/Rcpp/as.h index 466761efb..e6990312c 100644 --- a/inst/include/Rcpp/as.h +++ b/inst/include/Rcpp/as.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // as.h: Rcpp R/C++ interface class library -- convert SEXP to C++ objects // -// Copyright (C) 2009 - 2015 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2009 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -30,8 +29,8 @@ namespace Rcpp { template T primitive_as(SEXP x) { if (::Rf_length(x) != 1) { - const char* fmt = "Expecting a single value: [extent=%i]."; - throw ::Rcpp::not_compatible(fmt, ::Rf_length(x)); + const char* fmt = "Expecting a single value: [extent=%i]."; // #nocov + throw ::Rcpp::not_compatible(fmt, ::Rf_length(x)); // #nocov } const int RTYPE = ::Rcpp::traits::r_sexptype_traits::rtype; Shield y(r_cast(x)); @@ -45,14 +44,14 @@ namespace Rcpp { } inline const char* check_single_string(SEXP x) { - if (TYPEOF(x) == CHARSXP) return CHAR(x); + if (TYPEOF(x) == CHARSXP) return CHAR(x); // #nocov start if (! ::Rf_isString(x) || Rf_length(x) != 1) { const char* fmt = "Expecting a single string value: " "[type=%s; extent=%i]."; throw ::Rcpp::not_compatible(fmt, Rf_type2char(TYPEOF(x)), Rf_length(x)); - } + } // #nocov end return CHAR(STRING_ELT(::Rcpp::r_cast(x), 0)); } diff --git a/inst/include/Rcpp/config.h b/inst/include/Rcpp/config.h index d5e330708..8e43d38b1 100644 --- a/inst/include/Rcpp/config.h +++ b/inst/include/Rcpp/config.h @@ -1,8 +1,7 @@ - // config.h: Rcpp R/C++ interface class library -- Rcpp configuration // -// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010-2026 Dirk Eddelbuettel and Romain François // // This file is part of Rcpp. // @@ -27,11 +26,11 @@ #define RcppDevVersion(maj, min, rev, dev) (((maj)*1000000) + ((min)*10000) + ((rev)*100) + (dev)) // the currently released version -#define RCPP_VERSION Rcpp_Version(1,1,0) -#define RCPP_VERSION_STRING "1.1.0" +#define RCPP_VERSION Rcpp_Version(1,1,1) +#define RCPP_VERSION_STRING "1.1.1" // the current source snapshot (using four components, if a fifth is used in DESCRIPTION we ignore it) -#define RCPP_DEV_VERSION RcppDevVersion(1,1,0,4) -#define RCPP_DEV_VERSION_STRING "1.1.0.4" +#define RCPP_DEV_VERSION RcppDevVersion(1,1,1,6) +#define RCPP_DEV_VERSION_STRING "1.1.1.6" #endif diff --git a/inst/include/Rcpp/date_datetime/Datetime.h b/inst/include/Rcpp/date_datetime/Datetime.h index e7d9ff00b..c0c4589cf 100644 --- a/inst/include/Rcpp/date_datetime/Datetime.h +++ b/inst/include/Rcpp/date_datetime/Datetime.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // Datetime.h: Rcpp R/C++ interface class library -- Datetime (POSIXct) // -// Copyright (C) 2010 - 2016 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -94,7 +93,7 @@ namespace Rcpp { private: double m_dt; // fractional seconds since epoch struct tm m_tm; // standard time representation - unsigned int m_us; // microsecond (to complement m_tm) + int m_us; // microsecond (to complement m_tm) // update m_tm based on m_dt void update_tm() { diff --git a/inst/include/Rcpp/exceptions.h b/inst/include/Rcpp/exceptions.h index b5ea6011c..2311442e3 100644 --- a/inst/include/Rcpp/exceptions.h +++ b/inst/include/Rcpp/exceptions.h @@ -3,7 +3,7 @@ // // Copyright (C) 2010 - 2020 Dirk Eddelbuettel and Romain Francois // Copyright (C) 2021 - 2024 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar -// Copyright (C) 2025 Dirk Eddelbuettel, Romain Francois, Iñaki Ucar and James J Balamuta +// Copyright (C) 2025 - 2026 Dirk Eddelbuettel, Romain Francois, Iñaki Ucar and James J Balamuta // // This file is part of Rcpp. // @@ -151,9 +151,7 @@ inline void resumeJump(SEXP token) { token = getLongjumpToken(token); } ::R_ReleaseObject(token); -#if (defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0)) ::R_ContinueUnwind(token); -#endif // #nocov end Rf_error("Internal error: Rcpp longjump failed to resume"); } @@ -189,7 +187,7 @@ struct LongjumpException { template inline void warning(const char* fmt, Args&&... args ) { Rf_warning("%s", tfm::format(fmt, std::forward(args)... ).c_str()); - } + } // #nocov end template inline void NORET stop(const char* fmt, Args&&... args) { diff --git a/inst/include/Rcpp/exceptions_impl.h b/inst/include/Rcpp/exceptions_impl.h index a3e7abdc1..9fe071518 100644 --- a/inst/include/Rcpp/exceptions_impl.h +++ b/inst/include/Rcpp/exceptions_impl.h @@ -2,7 +2,7 @@ // // Copyright (C) 2012 - 2019 Dirk Eddelbuettel and Romain Francois // Copyright (C) 2020 - 2024 Dirk Eddelbuettel, Romain Francois, and Joshua N. Pritikin -// Copyright (C) 2025 Dirk Eddelbuettel, Romain Francois, Joshua N. Pritikin, and Iñaki Ucar +// Copyright (C) 2025 - 2026 Dirk Eddelbuettel, Romain Francois, Joshua N. Pritikin, and Iñaki Ucar // // This file is part of Rcpp. // @@ -23,15 +23,33 @@ #define Rcpp__exceptions_impl__h // enable demangler on platforms where execinfo.h is present +// and that are not actively blacklisted #ifndef RCPP_DEMANGLER_ENABLED -# define RCPP_DEMANGLER_ENABLED 0 -# if defined __has_include -# if __has_include () -# include -# undef RCPP_DEMANGLER_ENABLED -# define RCPP_DEMANGLER_ENABLED 1 +// set a fallback default +#define RCPP_DEMANGLER_ENABLED 0 +# if defined(_WIN32) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) || \ + defined(__DragonFly__) || \ + defined(__CYGWIN__) || \ + defined(__sun) || \ + defined(_AIX) || \ + defined(__MUSL__) || \ + defined(__HAIKU__) || \ + defined(__ANDROID__) +// nothing to do here so just redefining +# undef RCPP_DEMANGLER_ENABLED +# define RCPP_DEMANGLER_ENABLED 0 +# elif defined __has_include +// if we can test for headers +# if __has_include () +// if we have the header, include and use it +# include +# undef RCPP_DEMANGLER_ENABLED +# define RCPP_DEMANGLER_ENABLED 1 +# endif # endif -# endif #endif namespace Rcpp { diff --git a/inst/include/Rcpp/internal/caster.h b/inst/include/Rcpp/internal/caster.h index afd63ed39..771e9f1d8 100644 --- a/inst/include/Rcpp/internal/caster.h +++ b/inst/include/Rcpp/internal/caster.h @@ -1,9 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- -/* :tabSize=4:indentSize=4:noTabs=false:folding=explicit:collapseFolds=1: */ -// + // caster.h: Rcpp R/C++ interface class library -- // -// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -26,9 +24,9 @@ namespace Rcpp{ namespace internal{ -template TO caster(FROM from){ +template TO caster(FROM from){ // #nocov start return static_cast(from) ; -} +} // #nocov end template inline Rcomplex Rcomplex_caster( std::complex from ){ @@ -67,4 +65,3 @@ inline std::complex caster >( Rcomplex from } #endif - diff --git a/inst/include/Rcpp/internal/export.h b/inst/include/Rcpp/internal/export.h index 46ce154c3..04d899433 100644 --- a/inst/include/Rcpp/internal/export.h +++ b/inst/include/Rcpp/internal/export.h @@ -77,11 +77,11 @@ namespace Rcpp{ template void export_range__dispatch( SEXP x, InputIterator first, ::Rcpp::traits::r_type_string_tag ) { - if( ! ::Rf_isString( x) ) { + if( ! ::Rf_isString( x) ) { // #nocov start const char* fmt = "Expecting a string vector: " "[type=%s; required=STRSXP]."; throw ::Rcpp::not_compatible(fmt, Rf_type2char(TYPEOF(x)) ); - } + } // #nocov end R_xlen_t n = ::Rf_xlength(x) ; for( R_xlen_t i=0; i. + +#ifndef Rcpp_macros_mask_h +#define Rcpp_macros_mask_h + +#ifndef RCPP_NO_MASK_RF_ERROR +#ifdef RCPP_MASK_RF_ERROR +#define Rf_error(...) \ + _Pragma("GCC warning \"Use of Rf_error() instead of Rcpp::stop(). Calls \ +to Rf_error() in C++ contexts are unsafe: consider using Rcpp::stop() instead, \ +or define RCPP_NO_MASK_RF_ERROR if this is a false positive. More info:\n\ + - https://github.com/RcppCore/Rcpp/issues/1247\n\ + - https://github.com/RcppCore/Rcpp/pull/1402\"") \ + Rf_error(__VA_ARGS__) +#endif +#endif + +#endif diff --git a/inst/include/Rcpp/proxy/AttributeProxy.h b/inst/include/Rcpp/proxy/AttributeProxy.h index a84043d72..f3e31466f 100644 --- a/inst/include/Rcpp/proxy/AttributeProxy.h +++ b/inst/include/Rcpp/proxy/AttributeProxy.h @@ -78,24 +78,29 @@ class AttributeProxyPolicy { } std::vector attributeNames() const { - std::vector v ; + std::vector v; +#if R_VERSION >= R_Version(4, 6, 0) + SEXP attrs = R_getAttribNames( static_cast(*this)); + R_xlen_t n = XLENGTH(attrs); + for (R_xlen_t i = 0; i < n; i++) { + v.push_back(std::string(CHAR(STRING_ELT(attrs, i)))); + } +#else SEXP attrs = ATTRIB( static_cast(*this).get__()); while( attrs != R_NilValue ){ v.push_back( std::string(CHAR(PRINTNAME(TAG(attrs)))) ) ; attrs = CDR( attrs ) ; } - return v ; +#endif + return v; } - bool hasAttribute( const std::string& attr) const { - SEXP attrs = ATTRIB(static_cast(*this).get__()); - while( attrs != R_NilValue ){ - if( attr == CHAR(PRINTNAME(TAG(attrs))) ){ - return true ; - } - attrs = CDR( attrs ) ; - } - return false; /* give up */ + bool hasAttribute(const std::string& attr) const { +#if R_VERSION >= R_Version(4, 6, 0) + return R_hasAttrib(static_cast(*this).get__(), Rf_install(attr.c_str())); +#else + return static_cast(*this).attr(attr) != R_NilValue; +#endif } diff --git a/inst/include/Rcpp/proxy/NamesProxy.h b/inst/include/Rcpp/proxy/NamesProxy.h index 694dda9b3..b87b4b0bb 100644 --- a/inst/include/Rcpp/proxy/NamesProxy.h +++ b/inst/include/Rcpp/proxy/NamesProxy.h @@ -50,14 +50,14 @@ class NamesProxyPolicy{ Shield safe_x(x); /* check if we can use a fast version */ - if( TYPEOF(x) == STRSXP && parent.size() == Rf_length(x) ){ + if( TYPEOF(x) == STRSXP && parent.size() == Rf_length(x) ){ // #nocov start Rf_namesgets(parent, x); } else { /* use the slower and more flexible version (callback to R) */ SEXP namesSym = Rf_install( "names<-" ); Shield call(Rf_lang3(namesSym, parent, x)); Shield new_vec(Rcpp_fast_eval(call, R_GlobalEnv)); - parent.set__(new_vec); + parent.set__(new_vec); // #nocov end } } diff --git a/inst/include/Rcpp/proxy/SlotProxy.h b/inst/include/Rcpp/proxy/SlotProxy.h index 718a83054..c6d3f4f76 100644 --- a/inst/include/Rcpp/proxy/SlotProxy.h +++ b/inst/include/Rcpp/proxy/SlotProxy.h @@ -28,7 +28,7 @@ class SlotProxyPolicy { public: SlotProxy( CLASS& v, const std::string& name) : parent(v), slot_name(Rf_install(name.c_str())) { if( !R_has_slot( v, slot_name) ){ - throw no_such_slot(name); + throw no_such_slot(name); // #nocov } } diff --git a/inst/include/Rcpp/r/check_r_headers.h b/inst/include/Rcpp/r/check_r_headers.h new file mode 100644 index 000000000..9bddb5619 --- /dev/null +++ b/inst/include/Rcpp/r/check_r_headers.h @@ -0,0 +1,44 @@ +// check_r_headers.h: Rcpp R/C++ interface class library -- R header check +// +// Copyright (C) 2025 - current Dirk Eddelbuettel +// +// 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 . + +#ifndef RCPP__CHECK__R__HEADERS__H +#define RCPP__CHECK__R__HEADERS__H + +// Allow an escape hatch +#if !defined(RCPP_NO_R_HEADERS_CHECK) + + #if defined(R_R_H) && defined(USING_R) + #pragma message "R.h has been included before any Rcpp headers. This can lead to hard-to-debug errors, and is not necessary. See https://github.com/RcppCore/Rcpp/issues/1410" + #endif + + #if defined(RINTERFACE_H_) + #pragma message "Rinterface.h has been included before any Rcpp headers. This can lead to hard-to-debug errors, and is not necessary. See https://github.com/RcppCore/Rcpp/issues/1410" + #endif + + #if defined(R_INTERNALS_H_) + #pragma message "Rinternals.h has been included before any Rcpp headers. This can lead to hard-to-debug errors, and is not necessary. See https://github.com/RcppCore/Rcpp/issues/1410" + #endif + + #if defined(R_DEFINES_H_) + #pragma message "Rdefines.h has been included before any Rcpp headers. This can lead to hard-to-debug errors, and is not necessary. See https://github.com/RcppCore/Rcpp/issues/1410" + #endif + +#endif // escape hatch '!defined(RCPP_NO_R_HEADERS_CHECK)' + +#endif // header guard diff --git a/inst/include/Rcpp/r/headers.h b/inst/include/Rcpp/r/headers.h index c93636c40..7bf972a3c 100644 --- a/inst/include/Rcpp/r/headers.h +++ b/inst/include/Rcpp/r/headers.h @@ -2,6 +2,7 @@ // // Copyright (C) 2008 - 2009 Dirk Eddelbuettel // Copyright (C) 2009 - 2024 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2025 - Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -72,6 +73,7 @@ #include #include #include +#include #include /* Ensure NORET defined (normally provided by R headers with R >= 3.2.0) */ @@ -99,8 +101,4 @@ # pragma pop_macro("makedev") #endif -#if (!defined(RCPP_NO_UNWIND_PROTECT) && defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0)) -# define RCPP_USING_UNWIND_PROTECT -#endif - #endif /* RCPP__R__HEADERS__H */ diff --git a/inst/include/Rcpp/r_cast.h b/inst/include/Rcpp/r_cast.h index 7983f6284..7f26d8966 100644 --- a/inst/include/Rcpp/r_cast.h +++ b/inst/include/Rcpp/r_cast.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// + // rcast.h: Rcpp R/C++ interface class library -- cast from one SEXP type to another // -// Copyright (C) 2010 - 2017 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -156,7 +155,7 @@ namespace Rcpp { } // namespace internal - template SEXP r_cast(SEXP x) { + template SEXP r_cast(SEXP x) { // #nocov start if (TYPEOF(x) == TARGET) { return x; } else { @@ -168,7 +167,7 @@ namespace Rcpp { ); return result; #else - return internal::r_true_cast(x); // #nocov + return internal::r_true_cast(x); // #nocov end #endif } } diff --git a/inst/include/Rcpp/sugar/functions/cumprod.h b/inst/include/Rcpp/sugar/functions/cumprod.h index 59cf8d4bd..0ad8936fd 100644 --- a/inst/include/Rcpp/sugar/functions/cumprod.h +++ b/inst/include/Rcpp/sugar/functions/cumprod.h @@ -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. // @@ -33,23 +34,23 @@ class Cumprod : public Lazy< Rcpp::Vector, Cumprod > { typedef Rcpp::Vector VECTOR; Cumprod(const VEC_TYPE& object_) : object(object_) {} - + VECTOR get() const { R_xlen_t n = object.size(); VECTOR result(n, Rcpp::traits::get_na()); STORAGE current = object[0]; - + if (Rcpp::traits::is_na(current)) return result; result[0] = current; for (R_xlen_t i = 1; i < n; i++) { current = object[i]; if (Rcpp::traits::is_na(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 @@ -72,5 +73,5 @@ inline sugar::Cumprod cumprod(const VectorBase& } // Rcpp -#endif // Rcpp__sugar__cumprod_h +#endif // Rcpp__sugar__cumprod_h diff --git a/inst/include/Rcpp/sugar/functions/cumsum.h b/inst/include/Rcpp/sugar/functions/cumsum.h index e42e5bc35..cb8e53886 100644 --- a/inst/include/Rcpp/sugar/functions/cumsum.h +++ b/inst/include/Rcpp/sugar/functions/cumsum.h @@ -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. // @@ -45,7 +46,7 @@ class Cumsum : public Lazy< Rcpp::Vector , Cumsum > { current = object[i] ; if( Rcpp::traits::is_na(current) ) return result ; - result[i] = result[i-1] + current ; + result[i] = RCPP_SAFE_ADD(result[i-1], current); } return result ; } diff --git a/inst/include/Rcpp/sugar/functions/diff.h b/inst/include/Rcpp/sugar/functions/diff.h index 5d9910c72..b6c43f3fd 100644 --- a/inst/include/Rcpp/sugar/functions/diff.h +++ b/inst/include/Rcpp/sugar/functions/diff.h @@ -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. // @@ -51,7 +52,7 @@ class Diff : public Rcpp::VectorBase< RTYPE, LHS_NA , Diff > set_previous(i+1, y ) ; return traits::get_na() ; // NA } - STORAGE res = y - previous ; + STORAGE res = RCPP_SAFE_SUB(y, previous); set_previous( i+1, y) ; return res ; } @@ -81,7 +82,7 @@ class Diff : 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 ; @@ -105,10 +106,10 @@ class Diff : public Rcpp::VectorBase< RTYPE, false , Diff(R_NegInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to max"); + return(static_cast(R_NegInf)); + } STORAGE max, current ; max = obj[0] ; @@ -60,7 +65,11 @@ namespace sugar{ operator STORAGE() const { R_xlen_t n = obj.size(); - if (n == 0) return(static_cast(R_NegInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to max"); + return(static_cast(R_NegInf)); + } STORAGE max, current ; max = obj[0] ; diff --git a/inst/include/Rcpp/sugar/functions/min.h b/inst/include/Rcpp/sugar/functions/min.h index 7b77407a3..0e8b9410e 100644 --- a/inst/include/Rcpp/sugar/functions/min.h +++ b/inst/include/Rcpp/sugar/functions/min.h @@ -1,7 +1,8 @@ // Min.h: Rcpp R/C++ interface class library -- min // -// Copyright (C) 2012 - 2018 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2012 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -33,7 +34,11 @@ namespace sugar{ operator STORAGE() const { R_xlen_t n = obj.size(); - if (n == 0) return(static_cast(R_PosInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to min"); + return(static_cast(R_PosInf)); + } STORAGE min, current ; min = obj[0] ; @@ -60,7 +65,11 @@ namespace sugar{ operator STORAGE() const { R_xlen_t n = obj.size(); - if (n == 0) return(static_cast(R_PosInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to min"); + return(static_cast(R_PosInf)); + } STORAGE min, current ; min = obj[0] ; diff --git a/inst/include/Rcpp/sugar/functions/rowSums.h b/inst/include/Rcpp/sugar/functions/rowSums.h index 99adbd8d2..ec9b26acb 100644 --- a/inst/include/Rcpp/sugar/functions/rowSums.h +++ b/inst/include/Rcpp/sugar/functions/rowSums.h @@ -1,8 +1,9 @@ // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- // -// rowSums.h: Rcpp R/C++ interface class library -- rowSums, colSums, rowMeans, colMeans +// rowSums.h: Rcpp R/C++ interface class library -- rowSums, colSums, rowMeans, colMeans // -// Copyright (C) 2016 Nathan Russell +// Copyright (C) 2016 - 2025 Nathan Russell +// Copyright (C) 2026 Nathan Russell and Iñaki Ucar // // This file is part of Rcpp. // @@ -27,33 +28,12 @@ namespace sugar { namespace detail { -inline bool check_na(double x) { - return ISNAN(x); -} - -inline bool check_na(int x) { - return x == NA_INTEGER; -} - -inline bool check_na(Rboolean x) { - return x == NA_LOGICAL; -} - -inline bool check_na(SEXP x) { - return x == NA_STRING; -} - -inline bool check_na(Rcomplex x) { - return ISNAN(x.r) || ISNAN(x.i); -} - - inline void incr(double* lhs, double rhs) { *lhs += rhs; } inline void incr(int* lhs, int rhs) { - *lhs += rhs; + *lhs = RCPP_SAFE_ADD(*lhs, rhs); } inline void incr(Rcomplex* lhs, const Rcomplex& rhs) { @@ -159,12 +139,12 @@ class RowSumsImpl : // INTSXP output // // int + NA_LOGICAL (NA_INTEGER) != NA_INTEGER, as is the -// case with NA_REAL, so we specialize for these two SEXPTYPES -// and do explicit accounting of NAs. -// +// case with NA_REAL, so we specialize for these two SEXPTYPES +// and do explicit accounting of NAs. +// // The two specializations, while necessary, are redundant, hence -// the macro. The same applies to the 'na.rm = TRUE' variant, and -// likewise for colSums, rowMeans, and colMeans. +// the macro. The same applies to the 'na.rm = TRUE' variant, and +// likewise for colSums, rowMeans, and colMeans. // #define ROW_SUMS_IMPL_KEEPNA(__RTYPE__) \ \ @@ -178,10 +158,6 @@ private: typedef typename return_traits::type return_vector; \ typedef typename traits::storage_type::type stored_type; \ \ - struct bit { \ - unsigned char x : 1; \ - }; \ - \ public: \ RowSumsImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ : ref(ref_) \ @@ -191,29 +167,22 @@ public: R_xlen_t i, j, nr = ref.nrow(), nc = ref.ncol(); \ return_vector res(nr); \ \ - std::vector na_flags(nr); \ - \ for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ - if (detail::check_na(ref(i, j))) { \ - na_flags[i].x |= 0x1; \ - } \ - detail::incr(&res[i], ref(i, j)); \ - } \ - } \ - \ - for (i = 0; i < nr; i++) { \ - if (na_flags[i].x) { \ - res[i] = NA_INTEGER; \ + if (traits::is_na<__RTYPE__>(res[i])) \ + continue; \ + if (traits::is_na<__RTYPE__>(ref(i, j))) \ + res[i] = traits::get_na<__RTYPE__>(); \ + else detail::incr(&res[i], ref(i, j)); \ } \ } \ \ return res; \ } \ -}; +}; -ROW_SUMS_IMPL_KEEPNA(LGLSXP) -ROW_SUMS_IMPL_KEEPNA(INTSXP) +ROW_SUMS_IMPL_KEEPNA(LGLSXP) +ROW_SUMS_IMPL_KEEPNA(INTSXP) #undef ROW_SUMS_IMPL_KEEPNA @@ -246,7 +215,7 @@ class RowSumsImpl : for (j = 0; j < nc; j++) { for (i = 0; i < nr; i++) { current = ref(i, j); - if (!detail::check_na(current)) { + if (!traits::is_na(current)) { detail::incr(&res[i], current); } } @@ -287,7 +256,7 @@ public: for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ current = ref(i, j); \ - if (!detail::check_na(current)) { \ + if (!traits::is_na<__RTYPE__>(current)) { \ detail::incr(&res[i], current); \ } \ } \ @@ -295,10 +264,10 @@ public: \ return res; \ } \ -}; +}; -ROW_SUMS_IMPL_RMNA(LGLSXP) -ROW_SUMS_IMPL_RMNA(INTSXP) +ROW_SUMS_IMPL_RMNA(LGLSXP) +ROW_SUMS_IMPL_RMNA(INTSXP) #undef ROW_SUMS_IMPL_RMNA @@ -362,10 +331,6 @@ private: typedef typename return_traits::type return_vector; \ typedef typename traits::storage_type::type stored_type; \ \ - struct bit { \ - unsigned char x : 1; \ - }; \ - \ public: \ ColSumsImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ : ref(ref_) \ @@ -375,20 +340,13 @@ public: R_xlen_t i, j, nr = ref.nrow(), nc = ref.ncol(); \ return_vector res(nc); \ \ - std::vector na_flags(nc); \ - \ for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ - if (detail::check_na(ref(i, j))) { \ - na_flags[j].x |= 0x1; \ - } \ - detail::incr(&res[j], ref(i, j)); \ - } \ - } \ - \ - for (j = 0; j < nc; j++) { \ - if (na_flags[j].x) { \ - res[j] = NA_INTEGER; \ + if (traits::is_na<__RTYPE__>(res[j])) \ + continue; \ + if (traits::is_na<__RTYPE__>(ref(i, j))) \ + res[j] = traits::get_na<__RTYPE__>(); \ + else detail::incr(&res[j], ref(i, j)); \ } \ } \ \ @@ -396,11 +354,11 @@ public: } \ }; -COL_SUMS_IMPL_KEEPNA(LGLSXP) -COL_SUMS_IMPL_KEEPNA(INTSXP) +COL_SUMS_IMPL_KEEPNA(LGLSXP) +COL_SUMS_IMPL_KEEPNA(INTSXP) #undef COL_SUMS_IMPL_KEEPNA - + // ColSums // na.rm = TRUE // default input @@ -430,7 +388,7 @@ class ColSumsImpl : for (j = 0; j < nc; j++) { for (i = 0; i < nr; i++) { current = ref(i, j); - if (!detail::check_na(current)) { + if (!traits::is_na(current)) { detail::incr(&res[j], current); } } @@ -471,7 +429,7 @@ public: for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ current = ref(i, j); \ - if (!detail::check_na(current)) { \ + if (!traits::is_na<__RTYPE__>(current)) { \ detail::incr(&res[j], current); \ } \ } \ @@ -481,8 +439,8 @@ public: } \ }; -COL_SUMS_IMPL_RMNA(LGLSXP) -COL_SUMS_IMPL_RMNA(INTSXP) +COL_SUMS_IMPL_RMNA(LGLSXP) +COL_SUMS_IMPL_RMNA(INTSXP) #undef COL_SUMS_IMPL_RMNA @@ -553,10 +511,6 @@ private: typedef typename return_traits::type return_vector; \ typedef typename traits::storage_type::type stored_type; \ \ - struct bit { \ - unsigned char x : 1; \ - }; \ - \ public: \ RowMeansImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ : ref(ref_) \ @@ -566,34 +520,29 @@ public: R_xlen_t i, j, nr = ref.nrow(), nc = ref.ncol(); \ return_vector res(nr); \ \ - std::vector na_flags(nc); \ - \ for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ - if (detail::check_na(ref(i, j))) { \ - na_flags[i].x |= 0x1; \ - } \ - detail::incr(&res[i], ref(i, j)); \ + if (traits::is_na(res[i])) \ + continue; \ + if (traits::is_na<__RTYPE__>(ref(i, j))) \ + res[i] = traits::get_na(); \ + else detail::incr(&res[i], ref(i, j)); \ } \ } \ \ - for (i = 0; i < nr; i++) { \ - if (!na_flags[i].x) { \ + for (i = 0; i < nr; i++) \ + if (!traits::is_na(res[i])) \ detail::div(&res[i], nc); \ - } else { \ - res[i] = NA_REAL; \ - } \ - } \ \ return res; \ } \ }; -ROW_MEANS_IMPL_KEEPNA(LGLSXP) -ROW_MEANS_IMPL_KEEPNA(INTSXP) +ROW_MEANS_IMPL_KEEPNA(LGLSXP) +ROW_MEANS_IMPL_KEEPNA(INTSXP) #undef ROW_MEANS_IMPL_KEEPNA - + // RowMeans // na.rm = TRUE // default input @@ -625,7 +574,7 @@ class RowMeansImpl : for (j = 0; j < nc; j++) { for (i = 0; i < nr; i++) { current = ref(i, j); - if (!detail::check_na(current)) { + if (!traits::is_na(current)) { detail::incr(&res[i], ref(i, j)); ++n_ok[i]; } @@ -674,7 +623,7 @@ public: \ for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ - if (!detail::check_na(ref(i, j))) { \ + if (!traits::is_na<__RTYPE__>(ref(i, j))) { \ detail::incr(&res[i], ref(i, j)); \ ++n_ok[i]; \ } \ @@ -693,8 +642,8 @@ public: } \ }; -ROW_MEANS_IMPL_RMNA(LGLSXP) -ROW_MEANS_IMPL_RMNA(INTSXP) +ROW_MEANS_IMPL_RMNA(LGLSXP) +ROW_MEANS_IMPL_RMNA(INTSXP) #undef ROW_MEANS_IMPL_RMNA @@ -762,10 +711,6 @@ private: typedef typename return_traits::type return_vector; \ typedef typename traits::storage_type::type stored_type; \ \ - struct bit { \ - unsigned char x : 1; \ - }; \ - \ public: \ ColMeansImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ : ref(ref_) \ @@ -775,31 +720,26 @@ public: R_xlen_t i, j, nr = ref.nrow(), nc = ref.ncol(); \ return_vector res(nc); \ \ - std::vector na_flags(nc); \ - \ for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ - if (detail::check_na(ref(i, j))) { \ - na_flags[j].x |= 0x1; \ - } \ - detail::incr(&res[j], ref(i, j)); \ + if (traits::is_na(res[j])) \ + continue; \ + if (traits::is_na<__RTYPE__>(ref(i, j))) \ + res[j] = traits::get_na(); \ + else detail::incr(&res[j], ref(i, j)); \ } \ } \ \ - for (j = 0; j < nc; j++) { \ - if (!na_flags[j].x) { \ + for (j = 0; j < nc; j++) \ + if (!traits::is_na(res[j])) \ detail::div(&res[j], nr); \ - } else { \ - res[j] = NA_REAL; \ - } \ - } \ \ return res; \ } \ }; -COL_MEANS_IMPL_KEEPNA(LGLSXP) -COL_MEANS_IMPL_KEEPNA(INTSXP) +COL_MEANS_IMPL_KEEPNA(LGLSXP) +COL_MEANS_IMPL_KEEPNA(INTSXP) #undef COL_MEANS_IMPL_KEEPNA @@ -834,7 +774,7 @@ class ColMeansImpl : for (j = 0; j < nc; j++) { for (i = 0; i < nr; i++) { current = ref(i, j); - if (!detail::check_na(current)) { + if (!traits::is_na(current)) { detail::incr(&res[j], ref(i, j)); ++n_ok[j]; } @@ -883,7 +823,7 @@ public: \ for (j = 0; j < nc; j++) { \ for (i = 0; i < nr; i++) { \ - if (!detail::check_na(ref(i, j))) { \ + if (!traits::is_na<__RTYPE__>(ref(i, j))) { \ detail::incr(&res[j], ref(i, j)); \ ++n_ok[j]; \ } \ @@ -902,11 +842,11 @@ public: } \ }; -COL_MEANS_IMPL_RMNA(LGLSXP) -COL_MEANS_IMPL_RMNA(INTSXP) +COL_MEANS_IMPL_RMNA(LGLSXP) +COL_MEANS_IMPL_RMNA(INTSXP) #undef COL_MEANS_IMPL_RMNA - + // ColMeans // Input with template parameter NA = false // ColMeansImpl<..., NA_RM = false> diff --git a/inst/include/Rcpp/sugar/functions/sum.h b/inst/include/Rcpp/sugar/functions/sum.h index 601a65a73..fac5d10d4 100644 --- a/inst/include/Rcpp/sugar/functions/sum.h +++ b/inst/include/Rcpp/sugar/functions/sum.h @@ -2,7 +2,8 @@ // // sum.h: Rcpp R/C++ interface class library -- sum // -// 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. // @@ -42,7 +43,7 @@ class Sum : public Lazy< typename Rcpp::traits::storage_type::type , Sum< current = object[i] ; if( Rcpp::traits::is_na(current) ) return Rcpp::traits::get_na() ; - result += current ; + result = RCPP_SAFE_ADD(result, current); } return result ; } @@ -84,7 +85,7 @@ class Sum : public Lazy< typename Rcpp::traits::storage_type(x) ? x : op( x, rhs ) ; + return Rcpp::traits::is_na(x) ? NA_INTEGER : op( x, rhs ) ; } } ; diff --git a/inst/include/Rcpp/sugar/operators/minus.h b/inst/include/Rcpp/sugar/operators/minus.h index f94061726..04bfcb7dc 100644 --- a/inst/include/Rcpp/sugar/operators/minus.h +++ b/inst/include/Rcpp/sugar/operators/minus.h @@ -2,7 +2,8 @@ // // minus.h: Rcpp R/C++ interface class library -- operator- // -// 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. // @@ -42,7 +43,7 @@ namespace sugar{ STORAGE x = lhs[i] ; if( Rcpp::traits::is_na( x ) ) return x ; STORAGE y = rhs[i] ; - return Rcpp::traits::is_na( y ) ? y : ( x - y ) ; + return Rcpp::traits::is_na( y ) ? y : RCPP_SAFE_SUB(x, y); } inline R_xlen_t size() const { return lhs.size() ; } @@ -91,7 +92,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE y = rhs[i] ; if( Rcpp::traits::is_na( y ) ) return y ; - return lhs[i] - y ; + return lhs[i] - y; } inline R_xlen_t size() const { return lhs.size() ; } @@ -140,7 +141,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; if( Rcpp::traits::is_na( x ) ) return x ; - return x - rhs[i] ; + return x - rhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } @@ -188,7 +189,7 @@ namespace sugar{ lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} inline STORAGE operator[]( R_xlen_t i ) const { - return lhs[i] - rhs[i] ; + return lhs[i] - rhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } @@ -238,7 +239,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { if( rhs_na ) return rhs ; STORAGE x = lhs[i] ; - return Rcpp::traits::is_na(x) ? x : (x - rhs) ; + return Rcpp::traits::is_na(x) ? x : RCPP_SAFE_SUB(x, rhs); } inline R_xlen_t size() const { return lhs.size() ; } @@ -284,7 +285,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { if( rhs_na ) return rhs ; STORAGE x = lhs[i] ; - return Rcpp::traits::is_na(x) ? x : (x - rhs) ; + return Rcpp::traits::is_na(x) ? x : x - rhs; } inline R_xlen_t size() const { return lhs.size() ; } @@ -333,7 +334,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { if( lhs_na ) return lhs ; - return lhs - rhs[i] ; + return RCPP_SAFE_SUB(lhs, rhs[i]); } inline R_xlen_t size() const { return rhs.size() ; } @@ -370,14 +371,14 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; - typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef typename Rcpp::traits::Extractor::type VEC_EXT ; Minus_Primitive_Vector( STORAGE lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()), lhs_na( Rcpp::traits::is_na(lhs_) ) {} inline STORAGE operator[]( R_xlen_t i ) const { if( lhs_na ) return lhs ; - return lhs - rhs[i] ; + return lhs - rhs[i]; } inline R_xlen_t size() const { return rhs.size() ; } diff --git a/inst/include/Rcpp/sugar/operators/plus.h b/inst/include/Rcpp/sugar/operators/plus.h index 70f9f0e44..9434f4853 100644 --- a/inst/include/Rcpp/sugar/operators/plus.h +++ b/inst/include/Rcpp/sugar/operators/plus.h @@ -2,7 +2,8 @@ // // plus.h: Rcpp R/C++ interface class library -- operator+ // -// 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. // @@ -42,7 +43,7 @@ namespace sugar{ STORAGE lhs_ = lhs[i] ; if( traits::is_na(lhs_) ) return lhs_ ; STORAGE rhs_ = rhs[i] ; - return traits::is_na(rhs_) ? rhs_ : (lhs_ + rhs_) ; + return traits::is_na(rhs_) ? rhs_ : RCPP_SAFE_ADD(lhs_, rhs_); } inline R_xlen_t size() const { return lhs.size() ; } @@ -99,7 +100,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE rhs_ = rhs[i] ; if( traits::is_na(rhs_) ) return rhs_ ; - return lhs[i] + rhs_ ; + return lhs[i] + rhs_; } inline R_xlen_t size() const { return lhs.size() ; } @@ -152,7 +153,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE lhs_ = lhs[i] ; if( traits::is_na(lhs_) ) return lhs_ ; - return lhs_ + rhs[i] ; + return lhs_ + rhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } @@ -204,7 +205,7 @@ namespace sugar{ lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} inline STORAGE operator[]( R_xlen_t i ) const { - return lhs[i] + rhs[i] ; + return lhs[i] + rhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } @@ -250,7 +251,6 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; - typedef typename Rcpp::traits::Extractor< RTYPE, NA, T>::type EXT ; Plus_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : @@ -260,7 +260,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { if( rhs_na ) return rhs ; STORAGE x = lhs[i] ; - return Rcpp::traits::is_na(x) ? x : (x + rhs) ; + return Rcpp::traits::is_na(x) ? x : RCPP_SAFE_ADD(x, rhs); } inline R_xlen_t size() const { return lhs.size() ; } @@ -308,7 +308,7 @@ namespace sugar{ lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) {} inline STORAGE operator[]( R_xlen_t i ) const { - return rhs_na ? rhs : (rhs + lhs[i] ) ; + return rhs_na ? rhs : (rhs + lhs[i]); } inline R_xlen_t size() const { return lhs.size() ; } @@ -360,7 +360,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; - return Rcpp::traits::is_na(x) ? x : (x + rhs) ; + return Rcpp::traits::is_na(x) ? x : x + rhs; } inline R_xlen_t size() const { return lhs.size() ; } @@ -407,7 +407,7 @@ namespace sugar{ lhs(lhs_.get_ref()), rhs(rhs_) {} inline STORAGE operator[]( R_xlen_t i ) const { - return rhs + lhs[i] ; + return rhs + lhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } diff --git a/inst/include/Rcpp/sugar/operators/times.h b/inst/include/Rcpp/sugar/operators/times.h index d1f335992..54dfe0449 100644 --- a/inst/include/Rcpp/sugar/operators/times.h +++ b/inst/include/Rcpp/sugar/operators/times.h @@ -2,7 +2,8 @@ // // times.h: Rcpp R/C++ interface class library -- operator* // -// 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. // @@ -43,7 +44,7 @@ namespace sugar{ STORAGE lhs_ = lhs[i] ; if( traits::is_na(lhs_) ) return lhs_ ; STORAGE rhs_ = rhs[i] ; - return traits::is_na(rhs_) ? rhs_ : (lhs_ * rhs_) ; + return traits::is_na(rhs_) ? rhs_ : RCPP_SAFE_MUL(lhs_, rhs_) ; } inline R_xlen_t size() const { return lhs.size() ; } @@ -96,7 +97,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE rhs_ = rhs[i] ; if( traits::is_na(rhs_) ) return rhs_ ; - return lhs[i] * rhs_ ; + return lhs[i] * rhs_; } inline R_xlen_t size() const { return lhs.size() ; } @@ -148,7 +149,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE lhs_ = lhs[i] ; if( traits::is_na(lhs_) ) return lhs_ ; - return lhs_ * rhs[i] ; + return lhs_ * rhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } @@ -197,7 +198,7 @@ namespace sugar{ lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} inline STORAGE operator[]( R_xlen_t i ) const { - return lhs[i] * rhs[i] ; + return lhs[i] * rhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } @@ -247,7 +248,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { if( rhs_na ) return rhs ; STORAGE x = lhs[i] ; - return Rcpp::traits::is_na(x) ? x : (x * rhs) ; + return Rcpp::traits::is_na(x) ? x : RCPP_SAFE_MUL(x, rhs); } inline R_xlen_t size() const { return lhs.size() ; } @@ -293,7 +294,7 @@ namespace sugar{ lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) {} inline STORAGE operator[]( R_xlen_t i ) const { - return rhs_na ? rhs : (rhs * lhs[i] ) ; + return rhs_na ? rhs : (rhs * lhs[i]); } inline R_xlen_t size() const { return lhs.size() ; } @@ -345,7 +346,7 @@ namespace sugar{ inline STORAGE operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; - return Rcpp::traits::is_na(x) ? x : (x * rhs) ; + return Rcpp::traits::is_na(x) ? x : x * rhs; } inline R_xlen_t size() const { return lhs.size() ; } @@ -391,7 +392,7 @@ namespace sugar{ lhs(lhs_.get_ref()), rhs(rhs_) {} inline STORAGE operator[]( R_xlen_t i ) const { - return rhs * lhs[i] ; + return rhs * lhs[i]; } inline R_xlen_t size() const { return lhs.size() ; } diff --git a/inst/include/Rcpp/sugar/sugar.h b/inst/include/Rcpp/sugar/sugar.h index 0e2c2e37b..1bf160ab9 100644 --- a/inst/include/Rcpp/sugar/sugar.h +++ b/inst/include/Rcpp/sugar/sugar.h @@ -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. // @@ -23,6 +24,7 @@ #define RCPP_SUGAR_H #include +#include #include #include diff --git a/inst/include/Rcpp/sugar/tools/safe_math.h b/inst/include/Rcpp/sugar/tools/safe_math.h new file mode 100644 index 000000000..46774850d --- /dev/null +++ b/inst/include/Rcpp/sugar/tools/safe_math.h @@ -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 . + +#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 + inline typename std::enable_if::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::value) { + if ((b > 0 && a > std::numeric_limits::max() - b) || + (b < 0 && a < std::numeric_limits::min() - b)) + stop_overflow(caller); + } else { + if (a > std::numeric_limits::max() - b) + stop_overflow(caller); + } + return a + b; + #endif + } + + template + inline typename std::enable_if::value, T>::type + safe_add(T a, T b, const char* caller = nullptr) { return a + b; } + + // Subtraction + template + inline typename std::enable_if::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::value) { + if ((b < 0 && a > std::numeric_limits::max() + b) || + (b > 0 && a < std::numeric_limits::min() + b)) + stop_overflow(caller); + } else { + if (a < b) + stop_overflow(caller); + } + return a - b; + #endif + } + + template + inline typename std::enable_if::value, T>::type + safe_sub(T a, T b, const char* caller = nullptr) { return a - b; } + + // Multiplication + template + inline typename std::enable_if::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::value) { + if ((a > 0 && b > 0 && a > std::numeric_limits::max() / b) || + (a > 0 && b < 0 && b < std::numeric_limits::min() / a) || + (a < 0 && b > 0 && a < std::numeric_limits::min() / b) || + (a < 0 && b < 0 && a < std::numeric_limits::max() / b)) + stop_overflow(caller); + } else { + if (b > 0 && a > std::numeric_limits::max() / b) + stop_overflow(caller); + } + return a * b; + #endif + } + + template + inline typename std::enable_if::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 diff --git a/inst/include/Rcpp/sugar/undoRmath.h b/inst/include/Rcpp/sugar/undoRmath.h index c718b724a..60d5e866b 100644 --- a/inst/include/Rcpp/sugar/undoRmath.h +++ b/inst/include/Rcpp/sugar/undoRmath.h @@ -146,7 +146,7 @@ #undef rhyper #undef rlnorm #undef rlogis -#undef rnbeta +//#undef rnbeta #undef rnbinom #undef rnchisq #undef rnf diff --git a/inst/include/Rcpp/vector/Vector.h b/inst/include/Rcpp/vector/Vector.h index e5440a5f1..76bc56020 100644 --- a/inst/include/Rcpp/vector/Vector.h +++ b/inst/include/Rcpp/vector/Vector.h @@ -1,6 +1,6 @@ // Vector.h: Rcpp R/C++ interface class library -- vectors // -// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -345,10 +345,10 @@ class Vector : return cache.ref( offset(i) ) ; } - inline Proxy at( const size_t& i) { + inline Proxy at( const size_t& i) { // #nocov start return cache.ref( offset(i) ) ; } - inline const_Proxy at( const size_t& i) const { // #nocov start + inline const_Proxy at( const size_t& i) const { return cache.ref( offset(i) ) ; } // #nocov end diff --git a/inst/include/Rcpp/vector/proxy.h b/inst/include/Rcpp/vector/proxy.h index 015b77756..296b93001 100644 --- a/inst/include/Rcpp/vector/proxy.h +++ b/inst/include/Rcpp/vector/proxy.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- -// + // proxy.h: Rcpp R/C++ interface class library -- proxies // -// Copyright (C) 2010 - 2018 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -182,7 +181,7 @@ namespace internal{ R_xlen_t index = 0 ; try{ index = parent.offset(name) ; - parent[ index ] = rhs ; + parent[ index ] = rhs ; // #nocov } catch( const index_out_of_bounds& ex ){ parent.push_back( rhs, name ); } diff --git a/inst/include/Rcpp/vector/traits.h b/inst/include/Rcpp/vector/traits.h index c6d76d694..3e1dcecec 100644 --- a/inst/include/Rcpp/vector/traits.h +++ b/inst/include/Rcpp/vector/traits.h @@ -1,8 +1,7 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- -// + // traits.h: Rcpp R/C++ interface class library -- support traits for vector // -// Copyright (C) 2010 - 2018 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2026 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -56,7 +55,7 @@ namespace traits{ void check_index(R_xlen_t i) const { #ifndef RCPP_NO_BOUNDS_CHECK if (i >= size) { - warning("subscript out of bounds (index %s >= vector size %s)", i, size); + warning("subscript out of bounds (index %s >= vector size %s)", i, size); // #nocov } #endif } @@ -94,7 +93,7 @@ namespace traits{ void check_index(R_xlen_t i) const { #ifndef RCPP_NO_BOUNDS_CHECK if (i >= p->size()) { - warning("subscript out of bounds (index %s >= vector size %s)", i, p->size()); + warning("subscript out of bounds (index %s >= vector size %s)", i, p->size()); // #nocov } #endif } diff --git a/inst/include/RcppCommon.h b/inst/include/RcppCommon.h index 8f28fd035..ea23f5e82 100644 --- a/inst/include/RcppCommon.h +++ b/inst/include/RcppCommon.h @@ -1,10 +1,9 @@ -// // RcppCommon.h: Rcpp R/C++ interface class library -- common include and defines statements // // Copyright (C) 2008 - 2009 Dirk Eddelbuettel // Copyright (C) 2009 - 2020 Dirk Eddelbuettel and Romain Francois -// Copyright (C) 2021 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar +// Copyright (C) 2021 - 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -27,6 +26,7 @@ // #define RCPP_DEBUG_LEVEL 1 // #define RCPP_DEBUG_MODULE_LEVEL 1 +#include #include #include @@ -72,8 +72,6 @@ namespace Rcpp { #include #include #include -#include -#include #include #include @@ -133,9 +131,7 @@ namespace Rcpp { #include #include -#ifdef RCPP_USING_UNWIND_PROTECT - #include -#endif +#include #include #include @@ -191,4 +187,6 @@ namespace Rcpp { #include +#include + #endif diff --git a/inst/skeleton/zzz.R b/inst/skeleton/zzz.R index 0161cafed..a2e19a11a 100644 --- a/inst/skeleton/zzz.R +++ b/inst/skeleton/zzz.R @@ -1,16 +1,7 @@ -## Up until R 2.15.0, the require("methods") is needed but (now) -## triggers an warning from R CMD check -#.onLoad <- function(libname, pkgname){ -# #require("methods") ## needed with R <= 2.15.0 -# loadRcppModules() -#} - - -## For R 2.15.1 and later this also works. Note that calling loadModule() triggers +## For R 2.15.1 and later the approach shown here works (as opposed to the now removed +## and long-deprecated `loadRcppModules()`. Note that calling loadModule() triggers ## a load action, so this does not have to be placed in .onLoad() or evalqOnLoad(). loadModule("NumEx", TRUE) loadModule("yada", TRUE) loadModule("stdVector", TRUE) - - diff --git a/inst/tinytest/cpp/attributes_extended.cpp b/inst/tinytest/cpp/attributes_extended.cpp new file mode 100644 index 000000000..0b3165d24 --- /dev/null +++ b/inst/tinytest/cpp/attributes_extended.cpp @@ -0,0 +1,49 @@ +#include +using namespace Rcpp; + +// Test 4.1: Named Export Parameter +// Coverage target: src/attributes.cpp:360 + +// [[Rcpp::export(name = "custom_exported_name")]] +int test_named_export() { return 123; } + +// [[Rcpp::export(name = "another.custom.name")]] +std::string test_named_export_with_dots() { return "dotted name"; } + +// Test 4.2: Unnamed Export Parameter +// Coverage target: src/attributes.cpp:365 + +// [[Rcpp::export(my_custom_name)]] +int test_unnamed_export_param() { return 456; } + +// Test 4.3: RNG Parameter Variations +// Coverage target: src/attributes.cpp:382-383 + +// [[Rcpp::export(rng = true)]] +int test_rng_lowercase_true() { return 789; } + +// [[Rcpp::export(rng = TRUE)]] +int test_rng_uppercase_true() { return 101; } + +// [[Rcpp::export(rng = false)]] +int test_rng_lowercase_false() { return 202; } + +// Test 4.4: Invisible Parameter Variations +// Coverage target: src/attributes.cpp:391-392 + +// [[Rcpp::export(invisible = true)]] +void test_invisible_lowercase_true() { + // Side effect only - returns invisibly +} + +// [[Rcpp::export(invisible = TRUE)]] +void test_invisible_uppercase_true() { + // Side effect only - returns invisibly +} + +// Test 4.5: exportedCppName with Dots +// Coverage target: src/attributes.cpp:373-377 +// This tests the conversion of dots to underscores in C++ names + +// [[Rcpp::export(name = "test.with.dots")]] +int test_cpp_name_conversion() { return 999; } diff --git a/inst/tinytest/cpp/stack.cpp b/inst/tinytest/cpp/stack.cpp index c3fa41789..a4a5c86eb 100644 --- a/inst/tinytest/cpp/stack.cpp +++ b/inst/tinytest/cpp/stack.cpp @@ -2,7 +2,8 @@ // // misc.cpp: Rcpp R/C++ interface class library -- misc unit tests // -// Copyright (C) 2013 - 2022 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2013 - 2024 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2025 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -55,7 +56,7 @@ SEXP testSendInterrupt() { SEXP maybeThrow(void* data) { bool* fail = (bool*) data; if (*fail) - Rf_error("throw!"); + (Rf_error)("throw!"); // prevent masking else return NumericVector::create(42); } @@ -64,10 +65,7 @@ SEXP maybeThrow(void* data) { SEXP testUnwindProtect(Environment indicator, bool fail) { unwindIndicator my_data(indicator); SEXP out = R_NilValue; - -#ifdef RCPP_USING_UNWIND_PROTECT out = Rcpp::unwindProtect(&maybeThrow, &fail); -#endif return out; } @@ -76,11 +74,7 @@ SEXP testUnwindProtect(Environment indicator, bool fail) { SEXP testUnwindProtectLambda(Environment indicator, bool fail) { unwindIndicator my_data(indicator); SEXP out = R_NilValue; - -#ifdef RCPP_USING_UNWIND_PROTECT out = Rcpp::unwindProtect([&] () { return maybeThrow(&fail); }); -#endif - return out; } @@ -99,10 +93,6 @@ struct FunctionObj { SEXP testUnwindProtectFunctionObject(Environment indicator, bool fail) { unwindIndicator my_data(indicator); SEXP out = R_NilValue; - -#ifdef RCPP_USING_UNWIND_PROTECT out = Rcpp::unwindProtect(FunctionObj(10, fail)); -#endif - return out; } diff --git a/inst/tinytest/cpp/sugar.cpp b/inst/tinytest/cpp/sugar.cpp index d436559b9..80657899a 100644 --- a/inst/tinytest/cpp/sugar.cpp +++ b/inst/tinytest/cpp/sugar.cpp @@ -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. // @@ -285,6 +285,21 @@ List runit_minus( IntegerVector xx ){ ) ; } +// [[Rcpp::export]] +IntegerVector runit_minus_ivv( IntegerVector x, IntegerVector y ){ + return x - y; +} + +// [[Rcpp::export]] +IntegerVector runit_minus_ivp( IntegerVector x, int y ){ + return x - y; +} + +// [[Rcpp::export]] +IntegerVector runit_minus_ipv( int x, IntegerVector y ){ + return x - y; +} + // [[Rcpp::export]] LogicalVector runit_any_equal_not( NumericVector xx, NumericVector yy){ return any( !( xx == yy) ) ; @@ -301,14 +316,53 @@ List runit_plus( IntegerVector xx ){ } // [[Rcpp::export]] -List runit_plus_seqlen(){ +IntegerVector runit_plus_ivv( IntegerVector x, IntegerVector y ){ + return x + y; +} + +// [[Rcpp::export]] +IntegerVector runit_plus_ivp( IntegerVector x, int y ){ + return x + y; +} + +// [[Rcpp::export]] +IntegerVector runit_plus_ipv( int x, IntegerVector y ){ + return x + y; +} + +// [[Rcpp::export]] +List runit_plus_seqlen(IntegerVector xx){ return List::create( seq_len(10) + 10, 10 + seq_len(10), - seq_len(10) + seq_len(10) + seq_len(10) + seq_len(10), + seq_len(10) + xx, + xx + seq_len(10) ) ; } +// [[Rcpp::export]] +List runit_minus_seqlen(IntegerVector xx){ + return List::create( + seq_len(10) - 10, + 10 - seq_len(10), + seq_len(10) - seq_len(10), + seq_len(10) - xx, + xx - seq_len(10) + ) ; +} + +// [[Rcpp::export]] +List runit_times_seqlen(IntegerVector xx){ + return List::create( + seq_len(10) * 10, + 10 * seq_len(10), + seq_len(10) * seq_len(10), + seq_len(10) * xx, + xx * seq_len(10) + ) ; +} + // [[Rcpp::export]] LogicalVector runit_plus_all( IntegerVector xx ){ return all( (xx+xx) < 10 ) ; @@ -428,6 +482,21 @@ List runit_times( IntegerVector xx ){ ) ; } +// [[Rcpp::export]] +IntegerVector runit_times_ivv( IntegerVector x, IntegerVector y ){ + return x * y; +} + +// [[Rcpp::export]] +IntegerVector runit_times_ivp( IntegerVector x, int y ){ + return x * y; +} + +// [[Rcpp::export]] +IntegerVector runit_times_ipv( int x, IntegerVector y ){ + return x * y; +} + // [[Rcpp::export]] List runit_divides( NumericVector xx ){ return List::create( @@ -604,16 +673,27 @@ List runit_log1p( NumericVector xx){ } // [[Rcpp::export]] -double runit_sum( NumericVector xx){ +double runit_sum_nv( NumericVector xx){ return sum( xx ) ; } // [[Rcpp::export]] -NumericVector runit_cumsum( NumericVector xx ){ +int runit_sum_iv( IntegerVector xx){ + return sum( xx ) ; +} + +// [[Rcpp::export]] +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( diff --git a/inst/tinytest/cpp/sugar_safe_math.cpp b/inst/tinytest/cpp/sugar_safe_math.cpp new file mode 100644 index 000000000..9677184b9 --- /dev/null +++ b/inst/tinytest/cpp/sugar_safe_math.cpp @@ -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 . + +#include + +// [[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); +} diff --git a/inst/tinytest/cpp/sugar_safe_math_fallback.cpp b/inst/tinytest/cpp/sugar_safe_math_fallback.cpp new file mode 100644 index 000000000..15fdcc2e9 --- /dev/null +++ b/inst/tinytest/cpp/sugar_safe_math_fallback.cpp @@ -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 . + +#define safe_math__has_builtin(x) 0 +#include + +// [[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); +} diff --git a/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp b/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp index a6beb9b53..4b018f29f 100644 --- a/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp +++ b/inst/tinytest/testRcppInterfaceExporter/src/RcppExports.cpp @@ -43,7 +43,7 @@ RcppExport SEXP _testRcppInterfaceExporter_test_cpp_interface(SEXP xSEXP, SEXP f if (rcpp_isError_gen) { SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen); UNPROTECT(1); - Rf_error("%s", CHAR(rcpp_msgSEXP_gen)); + (Rf_error)("%s", CHAR(rcpp_msgSEXP_gen)); } UNPROTECT(1); return rcpp_result_gen; diff --git a/inst/tinytest/testRcppInterfaceUser/tests/tests.R b/inst/tinytest/testRcppInterfaceUser/tests/tests.R index effb2e482..f5885bd98 100644 --- a/inst/tinytest/testRcppInterfaceUser/tests/tests.R +++ b/inst/tinytest/testRcppInterfaceUser/tests/tests.R @@ -43,9 +43,7 @@ x <- withRestarts( stopifnot(identical(x, "value")) -if (getRversion() >= "3.5.0") { - stopifnot( - testRcppInterfaceUser::peek_flag("cpp_interface_downstream"), - testRcppInterfaceExporter::peek_flag("cpp_interface_upstream") - ) -} +stopifnot( + testRcppInterfaceUser::peek_flag("cpp_interface_downstream"), + testRcppInterfaceExporter::peek_flag("cpp_interface_upstream") +) diff --git a/inst/tinytest/testRcppModule/R/zzz.R b/inst/tinytest/testRcppModule/R/zzz.R index f23b84272..e26fbae91 100644 --- a/inst/tinytest/testRcppModule/R/zzz.R +++ b/inst/tinytest/testRcppModule/R/zzz.R @@ -1,11 +1,6 @@ -# -#.onLoad <- function(libname, pkgname){ -# loadRcppModules() -#} - -## For R 2.15.1 and later this also works. Note that calling loadModule() triggers +## For R 2.15.1 and later the approach shown here works (as opposed to the now removed +## and long-deprecated `loadRcppModules()`. Note that calling loadModule() triggers ## a load action, so this does not have to be placed in .onLoad() or evalqOnLoad(). loadModule("RcppModuleNumEx", TRUE) loadModule("RcppModuleWorld", TRUE) loadModule("stdVector", TRUE) - diff --git a/inst/tinytest/test_attributes_extended.R b/inst/tinytest/test_attributes_extended.R new file mode 100644 index 000000000..dea80a564 --- /dev/null +++ b/inst/tinytest/test_attributes_extended.R @@ -0,0 +1,42 @@ +## Copyright (C) 2026 Dirk Eddelbuettel +## +## 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 . + +if (Sys.getenv("RunAllRcppTests") != "yes") exit_file("Set 'RunAllRcppTests' to 'yes' to run.") + +Rcpp::sourceCpp("cpp/attributes_extended.cpp") + +## Test named exports +expect_equal(custom_exported_name(), 123) +expect_equal(another.custom.name(), "dotted name") + +## Test unnamed export parameter +expect_equal(my_custom_name(), 456) + +## Test RNG parameters +expect_equal(test_rng_lowercase_true(), 789) +expect_equal(test_rng_uppercase_true(), 101) +expect_equal(test_rng_lowercase_false(), 202) + +## Test invisible parameters (should return invisibly) +result1 <- withVisible(test_invisible_lowercase_true()) +expect_false(result1$visible) + +result2 <- withVisible(test_invisible_uppercase_true()) +expect_false(result2$visible) + +## Test C++ name conversion (dots to underscores) +expect_equal(test.with.dots(), 999) diff --git a/inst/tinytest/test_compile_attributes_errors.R b/inst/tinytest/test_compile_attributes_errors.R new file mode 100644 index 000000000..445aacaa1 --- /dev/null +++ b/inst/tinytest/test_compile_attributes_errors.R @@ -0,0 +1,33 @@ +## Copyright (C) 2026 Dirk Eddelbuettel +## +## 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 . + +if (Sys.getenv("RunAllRcppTests") != "yes") exit_file("Set 'RunAllRcppTests' to 'yes' to run.") + +## Test 3.1: Missing DESCRIPTION File +## Coverage target: R/Attributes.R:420 +tmpdir <- tempfile() +dir.create(tmpdir) +expect_error(compileAttributes(tmpdir), "must refer to the directory containing an R package") +unlink(tmpdir, recursive = TRUE) + +## Test 3.2: Missing NAMESPACE File +## Coverage target: R/Attributes.R:432 +tmpdir <- tempfile() +dir.create(tmpdir) +writeLines("Package: TestPkg", file.path(tmpdir, "DESCRIPTION")) +expect_error(compileAttributes(tmpdir), "must refer to the directory containing an R package") +unlink(tmpdir, recursive = TRUE) diff --git a/inst/tinytest/test_cppfunction_errors.R b/inst/tinytest/test_cppfunction_errors.R new file mode 100644 index 000000000..c8b63df1d --- /dev/null +++ b/inst/tinytest/test_cppfunction_errors.R @@ -0,0 +1,36 @@ +## Copyright (C) 2026 Dirk Eddelbuettel +## +## 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 . + +if (Sys.getenv("RunAllRcppTests") != "yes") exit_file("Set 'RunAllRcppTests' to 'yes' to run.") + +## Test 2.1: No Function Definition +## Coverage target: R/Attributes.R:326 +code <- "int x = 5;" # No function, just a variable +expect_error(cppFunction(code), "No function definition found") + +## -- Next test goes awry as of 2026-March so parking it for now +## ## Test 2.2: Multiple Function Definitions +## ## Coverage target: R/Attributes.R:328 +## code <- " +## // [[Rcpp::export]] +## int foo() { return 1; } + +## // [[Rcpp::export]] +## int bar() { return 2; } +## " +## ## compilation dies sooner so we never actually see the messages +## expect_error(cppFunction(code)) #, "More than one function definition") diff --git a/inst/tinytest/test_global_rostream.R b/inst/tinytest/test_global_rostream.R index 156be58fb..04cd7582d 100644 --- a/inst/tinytest/test_global_rostream.R +++ b/inst/tinytest/test_global_rostream.R @@ -19,7 +19,7 @@ .runThisTest <- Sys.getenv("RunAllRcppTests") == "yes" && Sys.getenv("RunVerboseRcppTests") == "yes" if (! .runThisTest) exit_file("Set 'RunVerboseRcppTests' and 'RunAllRcppTests' to 'yes' to run.") - +exit_file("For now") library(Rcpp) mkv <- "PKG_CPPFLAGS = -DRCPP_USE_GLOBAL_ROSTREAM" diff --git a/inst/tinytest/test_interface.R b/inst/tinytest/test_interface.R index 22536db58..707571f27 100644 --- a/inst/tinytest/test_interface.R +++ b/inst/tinytest/test_interface.R @@ -81,16 +81,18 @@ expect_equal(result, 0L) ## Now test client package without protected evaluation unlink(user_name, recursive = TRUE) unlink(paste0(user_name, "-tests"), recursive = TRUE) -build_package(user_name, lib_path, config = "#define RCPP_NO_UNWIND_PROTECT") -result <- tools::testInstalledPackage(user_name, lib.loc = lib_path, types = "test") +## no longer supported in code +## build_package(user_name, lib_path, config = "#define RCPP_NO_UNWIND_PROTECT") -if (result) { - log <- file.path(paste0(user_name, "-tests"), "tests.Rout.fail") - cat(">> UNPROTECTED tests.Rout.fail", readLines(log), sep = "\n", file = stderr()) -} +## result <- tools::testInstalledPackage(user_name, lib.loc = lib_path, types = "test") -expect_equal(result, 0L) +## if (result) { +## log <- file.path(paste0(user_name, "-tests"), "tests.Rout.fail") +## cat(">> UNPROTECTED tests.Rout.fail", readLines(log), sep = "\n", file = stderr()) +## } + +## expect_equal(result, 0L) on.exit({ setwd(old_wd) diff --git a/inst/tinytest/test_sourcecpp_errors.R b/inst/tinytest/test_sourcecpp_errors.R new file mode 100644 index 000000000..9391dbc18 --- /dev/null +++ b/inst/tinytest/test_sourcecpp_errors.R @@ -0,0 +1,42 @@ +## Copyright (C) 2026 Dirk Eddelbuettel +## +## 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 . + +if (Sys.getenv("RunAllRcppTests") != "yes") exit_file("Set 'RunAllRcppTests' to 'yes' to run.") + +## Test 1.1: Invalid File Extension +## Coverage target: R/Attributes.R:58-61 +tmpfile <- tempfile(fileext = ".c") +writeLines("int main() { return 0; }", tmpfile) +expect_error(sourceCpp(tmpfile), "does not have an extension of .cc or .cpp") +unlink(tmpfile) + +## Test 1.2: Filename with Spaces on Windows +## Coverage target: R/Attributes.R:64-68 +if (.Platform$OS.type == "windows") { + tmpfile <- file.path(tempdir(), "test file.cpp") + writeLines("#include ", tmpfile) + expect_error(sourceCpp(tmpfile), "contains spaces") + unlink(tmpfile) +} + +## Test 1.3: windowsDebugDLL on Non-Windows +## Coverage target: R/Attributes.R:70-76 +if (.Platform$OS.type != "windows") { + code <- "// [[Rcpp::export]]\nint test_fn() { return 42; }" + expect_message(sourceCpp(code = code, windowsDebugDLL = TRUE, verbose = TRUE), + "windowsDebugDLL.*ignored") +} diff --git a/inst/tinytest/test_sugar.R b/inst/tinytest/test_sugar.R index 4465cedf7..c6fc58993 100644 --- a/inst/tinytest/test_sugar.R +++ b/inst/tinytest/test_sugar.R @@ -1,6 +1,6 @@ -## Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois -## Copyright (C) 2025 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar +## Copyright (C) 2010 - 2024 Dirk Eddelbuettel and Romain Francois +## Copyright (C) 2025 - 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar ## ## This file is part of Rcpp. ## @@ -20,6 +20,8 @@ if (Sys.getenv("RunAllRcppTests") != "yes") exit_file("Set 'RunAllRcppTests' to 'yes' to run.") Rcpp::sourceCpp("cpp/sugar.cpp") +Rcpp::sourceCpp("cpp/sugar_safe_math.cpp") +Rcpp::sourceCpp("cpp/sugar_safe_math_fallback.cpp") ## There are some (documented, see https://blog.r-project.org/2020/11/02/will-r-work-on-apple-silicon/index.html) ## issues with NA propagation on arm64 / macOS. We not (yet ?) do anything special so we just skip some tests @@ -29,6 +31,22 @@ isArm <- Sys.info()[["machine"]] == "arm64" || Sys.info()[["machine"]] == "aarch ## Needed for a change in R 3.6.0 reducing a bias in very large samples suppressWarnings(RNGversion("3.5.0")) +# test.sugar.safe_math +expect_equal(safe_add(3, 2), 5) +expect_error(safe_add(.Machine$integer.max, 2), "overflow") +expect_equal(safe_sub(3, 2), 1) +expect_error(safe_sub(-.Machine$integer.max, 2), "overflow") +expect_equal(safe_mul(3, 2), 6) +expect_error(safe_mul(.Machine$integer.max, 2), "overflow") + +expect_equal(safe_add_fallback(3, 2), 5) +expect_error(safe_add_fallback(.Machine$integer.max, 2), "overflow") +expect_equal(safe_sub_fallback(3, 2), 1) +expect_error(safe_sub_fallback(-.Machine$integer.max, 2), "overflow") +expect_equal(safe_mul_fallback(3, 2), 6) +expect_error(safe_mul_fallback(.Machine$integer.max, 2), "overflow") + + # test.sugar.abs <- function( ){ x <- rnorm(10) y <- -10:10 @@ -210,6 +228,7 @@ expect_true( identical( fx( NA, 1 ), NA ) ) # test.sugar.diff <- function( ){ +expect_error(runit_diff_int(c(1, 2, -.Machine$integer.max)), "overflow") x <- as.integer(round(rnorm(100,1,100))) expect_equal( runit_diff_int(x) , diff(x) ) x <- rnorm( 100 ) @@ -348,11 +367,19 @@ expect_equal( fx(1:10, 1:10*2) , mapply(seq, 1:10, 1:10*2) ) # test.sugar.minus <- function( ){ +expect_error(runit_minus_ivv(-.Machine$integer.max, 2), "overflow") +expect_error(runit_minus_ivp(-.Machine$integer.max, 2), "overflow") +expect_error(runit_minus_ipv(-.Machine$integer.max, 2), "overflow") fx <- runit_minus expect_equal(fx(1:10) , list( (1:10)-10L, 10L-(1:10), rep(0L,10), (1:10)-10L, 10L-(1:10) )) +# test.sugar.minus.seqlen <- function( ){ +fx <- runit_minus_seqlen +expect_equal( fx(1:10) , list( -9:0, 9:0, rep(0, 10), rep(0, 10), rep(0, 10)) ) + + # test.sugar.any.equal.not <- function( ){ fx <- runit_any_equal_not expect_true( ! fx( 1, 1 ) ) @@ -363,13 +390,16 @@ expect_true( is.na( fx( NA, 1 ) ) ) # test.sugar.plus <- function( ){ +expect_error(runit_plus_ivv(.Machine$integer.max, 2), "overflow") +expect_error(runit_plus_ivp(.Machine$integer.max, 2), "overflow") +expect_error(runit_plus_ipv(.Machine$integer.max, 2), "overflow") fx <- runit_plus expect_equal( fx(1:10) , list( 11:20,11:20,1:10+1:10, 3*(1:10)) ) # test.sugar.plus.seqlen <- function( ){ fx <- runit_plus_seqlen -expect_equal( fx() , list( 11:20,11:20, 1:10+1:10) ) +expect_equal( fx(1:10) , list( 11:20,11:20, 1:10+1:10, 1:10+1:10, 1:10+1:10) ) # test.sugar.plus.all <- function( ){ @@ -455,12 +485,20 @@ expect_equal(fx( seq(-10, 10, length.out = 51), -25:25 ), # test.sugar.times <- function( ){ +expect_error(runit_times_ivv(.Machine$integer.max, 2), "overflow") +expect_error(runit_times_ivp(.Machine$integer.max, 2), "overflow") +expect_error(runit_times_ipv(.Machine$integer.max, 2), "overflow") fx <- runit_times expect_equal(fx(1:10) , list(10L*(1:10), 10L*(1:10), (1:10)*(1:10), (1:10)*(1:10)*(1:10), c(NA,(2:10)*(2:10)), c(NA,10L*(2:10)), c(NA,10L*(2:10)), rep( NA_integer_, 10L ))) +# test.sugar.times.seqlen <- function( ){ +fx <- runit_times_seqlen +expect_equal( fx(1:10) , list( seq(10, 100, 10), seq(10, 100, 10), 1:10*1:10, 1:10*1:10, 1:10*1:10) ) + + # test.sugar.divides <- function( ){ fx <- runit_divides expect_equal(fx(1:10) , @@ -626,20 +664,38 @@ expect_equal(fx(10:6,5:1), VP = psigamma( 10:6, 5 ))) -# test.sugar.sum <- function(){ -fx <- runit_sum +# test.sugar.sum_nv <- function(){ +fx <- runit_sum_nv x <- rnorm( 10 ) expect_equal( fx(x), sum(x) ) x[4] <- NA expect_equal( fx(x), sum(x) ) -# test.sugar.cumsum <- function(){ -fx <- runit_cumsum -x <- rnorm( 10 ) -expect_equal( fx(x), cumsum(x) ) +# test.sugar.sum_iv <- function() { +expect_error(runit_sum_iv(c(2, .Machine$integer.max)), "overflow") +fx <- runit_sum_iv +x <- as.integer(rpois(10, 5)) +expect_equal(fx(x), sum(x)) x[4] <- NA -expect_equal( fx(x), cumsum(x) ) +expect_equal(fx(x), sum(x)) + + +# test.sugar.cumsum_nv <- function(){ +fx <- runit_cumsum_nv +x <- rnorm(10) +expect_equal(fx(x), cumsum(x)) +x[4] <- NA +expect_equal(fx(x), cumsum(x)) + + +# test.sugar.cumsum_iv <- function() { +expect_error(runit_cumsum_iv(c(2, .Machine$integer.max)), "overflow") +fx <- runit_cumsum_iv +x <- as.integer(rpois(10, 5)) +expect_equal(fx(x), cumsum(x)) +x[4] <- NA +expect_equal(fx(x), cumsum(x)) # test.sugar.asvector <- function(){ @@ -826,6 +882,7 @@ expect_equal(fx(x), cumprod(x)) # test.sugar.cumprod_iv <- function() { +expect_error(runit_cumprod_iv(c(2, .Machine$integer.max)), "overflow") fx <- runit_cumprod_iv x <- as.integer(rpois(10, 5)) expect_equal(fx(x), cumprod(x)) @@ -1160,6 +1217,11 @@ expect_equal(dbl_col_means(x, TRUE), colMeans(x, TRUE), info = "numeric / colMea ## {row,col}{Sums,Means} integer tests # test.sugar.rowMeans_integer <- function() { +x <- matrix(rep(.Machine$integer.max, 4), 2) + +expect_error(int_row_sums(x), "overflow") +expect_error(int_col_sums(x), "overflow") + x <- matrix(as.integer(rnorm(9) * 1e4), 3) expect_equal(int_row_sums(x), rowSums(x), info = "integer / rowSums / keep NA / clean input") @@ -1623,12 +1685,10 @@ expect_error(strimws(x[1], "invalid"), info = "strimws -- bad `which` argument") ## 21 July 2018 ## min/max # test.sugar.min.max <- function() { -## min(empty) gives NA for integer, Inf for numeric (#844) -if (!isArm) expect_true(is.na(intmin(integer(0))), "min(integer(0))") +expect_error(intmin(integer(0)), "missing argument") if (!isArm) expect_equal(doublemin(numeric(0)), Inf, info = "min(numeric(0))") -## max(empty_ gives NA for integer, Inf for numeric (#844) -expect_true(is.na(intmax(integer(0))), "max(integer(0))") +expect_error(intmax(integer(0)), "missing argument") expect_equal(doublemax(numeric(0)), -Inf, info = "max(numeric(0))") ## 'normal' values diff --git a/inst/tinytest/test_system.R b/inst/tinytest/test_system.R index 83a99e05f..982a3856c 100644 --- a/inst/tinytest/test_system.R +++ b/inst/tinytest/test_system.R @@ -1,5 +1,5 @@ -## Copyright (C) 2016 - 2019 Dirk Eddelbuettel +## Copyright (C) 2016 - 2025 Dirk Eddelbuettel ## ## This file is part of Rcpp. ## @@ -24,9 +24,9 @@ inc_sys <- tools::file_path_as_absolute( base::system.file("include", package = expect_equal(inc_rcpp, inc_sys, info = "Rcpp.system.file") # test.RcppLd <- function() { -expect_true(Rcpp:::RcppLdPath() == "", info = "RcppLdPath") -expect_true(Rcpp:::RcppLdFlags() == "", info = "RcppLdFlags") -expect_equal(Rcpp:::LdFlags(), NULL, info = "LdFlags") +expect_true(suppressMessages(Rcpp:::RcppLdPath()) == "", info = "RcppLdPath") +expect_true(suppressMessages(Rcpp:::RcppLdFlags()) == "", info = "RcppLdFlags") +expect_equal(suppressMessages(Rcpp:::LdFlags()), NULL, info = "LdFlags") # test.RcppCxx <- function() { expect_true(Rcpp:::canUseCXX0X(), info = "canUseCXX0X") diff --git a/man/Rcpp-deprecated.Rd b/man/Rcpp-deprecated.Rd index b2c8a763e..ddf287bbe 100644 --- a/man/Rcpp-deprecated.Rd +++ b/man/Rcpp-deprecated.Rd @@ -7,9 +7,6 @@ } \details{ \itemize{ - \item \code{\link{loadRcppModules}} calls should now be replaced by - \code{\link{loadModule}} calls, one per Module. - \item \code{\link{LdFlags}} and \code{\link{RcppLdFlags}} are no longer required as no library is provided (or needed) by Rcpp (as it was up until release 0.10.1). diff --git a/man/RcppUnitTests.Rd b/man/RcppUnitTests.Rd deleted file mode 100644 index d1f513e42..000000000 --- a/man/RcppUnitTests.Rd +++ /dev/null @@ -1,28 +0,0 @@ -\name{RcppUnitTests} -\alias{RcppUnitTests} - -\title{Rcpp : unit tests results} -\description{ -Unit tests results for package Rcpp. - -Unit tests are run automatically at build time and reports are included in the -\samp{doc} directory as html or text. -} - -\seealso{ -\ifelse{latex}{}{\ifelse{html}{\url{../doc/unitTests-results/Rcpp-unitTests.html}: html formatted unit test report}{\samp{../doc/unitTests-results/Rcpp-unitTests.html}: html formatted unit test report}} -} - -\examples{ -# unit tests are in the unitTests directory of the package -list.files( system.file("unitTests", package = "Rcpp" ), - pattern = "^runit", full = TRUE ) - -# trigger the unit tests preparation, follow printed instructions -# on how to run them -\dontrun{ -source( system.file("unitTests", "runTests.R", package = "Rcpp" ) ) -} -} - -\keyword{programming} diff --git a/man/loadModule.Rd b/man/loadModule.Rd index 03102946d..c45cdb148 100644 --- a/man/loadModule.Rd +++ b/man/loadModule.Rd @@ -80,9 +80,6 @@ John Chambers } \seealso{ \code{\link{setRcppClass}()} to avoid the explicit call. - -\code{\link{loadRcppModules}()} for a (deprecated) shotgun procedure to load all -modules. } \examples{ \dontrun{ diff --git a/man/loadRcppModules-deprecated.Rd b/man/loadRcppModules-deprecated.Rd deleted file mode 100644 index 167efea9e..000000000 --- a/man/loadRcppModules-deprecated.Rd +++ /dev/null @@ -1,26 +0,0 @@ -\name{loadRcppModules-deprecated} -\alias{loadRcppModules} -\title{ - Loads Rcpp modules on package startup -} -\description{ - \emph{Note:} As of release 0.12.5, this function is deprecated; - \code{\link{loadModule}} should be used instead. - - Function to simplify loading Rcpp modules contained in a package. - This function must be called from the \code{.onLoad} function of a package. - It uses the \code{RcppModules} field of the package \code{DESCRIPTION} file - to query the names of the modules that the package should export, loads each module, - and \code{\link{populate}} each module into the package NAMESPACE. -} -\usage{ - loadRcppModules(direct=TRUE) -} -\arguments{ - \item{direct}{if \code{TRUE} the content of the module is exposed in the - namespace. Otherwise, the module is exposed. } -} -\seealso{ - \code{\link{populate}}, \code{\link{loadModule}} -} -\keyword{interface} diff --git a/src/api.cpp b/src/api.cpp index 36246b0a7..723a90ccc 100644 --- a/src/api.cpp +++ b/src/api.cpp @@ -28,7 +28,6 @@ using namespace Rcpp; #include "internal.h" -#include #ifdef RCPP_HAS_DEMANGLING #include diff --git a/src/attributes.cpp b/src/attributes.cpp index 81c2f5bef..c98110050 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -1,7 +1,7 @@ // attributes.cpp: Rcpp R/C++ interface class library -- Rcpp attributes // // Copyright (C) 2012 - 2020 JJ Allaire, Dirk Eddelbuettel and Romain Francois -// Copyright (C) 2021 - 2025 JJ Allaire, Dirk Eddelbuettel, Romain Francois, Iñaki Ucar and Travers Ching +// Copyright (C) 2021 - 2026 JJ Allaire, Dirk Eddelbuettel, Romain Francois, Iñaki Ucar and Travers Ching // // This file is part of Rcpp. // @@ -357,12 +357,12 @@ namespace attributes { // check for explicit name parameter if (hasParameter(kExportName)) { - return paramNamed(kExportName).value(); // #nocov + return paramNamed(kExportName).value(); } // otherwise un-named parameter in the first slot else if (!params().empty() && params()[0].value().empty()) { - return params()[0].name(); // #nocov + return params()[0].name(); } // otherwise the actual function name { @@ -370,17 +370,17 @@ namespace attributes { } } - std::string exportedCppName() const { // #nocov start + std::string exportedCppName() const { std::string name = exportedName(); std::replace(name.begin(), name.end(), '.', '_'); return name; - } // #nocov end + } bool rng() const { Param rngParam = paramNamed(kExportRng); if (!rngParam.empty()) - return rngParam.value() == kParamValueTrue || // #nocov - rngParam.value() == kParamValueTRUE; // #nocov + return rngParam.value() == kParamValueTrue || + rngParam.value() == kParamValueTRUE; else return true; } @@ -388,8 +388,8 @@ namespace attributes { bool invisible() const { Param invisibleParam = paramNamed(kExportInvisible); if (!invisibleParam.empty()) - return invisibleParam.value() == kParamValueTrue || // #nocov - invisibleParam.value() == kParamValueTRUE; // #nocov + return invisibleParam.value() == kParamValueTrue || + invisibleParam.value() == kParamValueTRUE; else return false; } @@ -2485,8 +2485,8 @@ namespace attributes { if(attribute.hasParameter(kExportSignature)) { args = attribute.customRSignature(); if(!checkRSignature(function, args)) { - std::string rsig_err_msg = "Missing args in " + args; - throw Rcpp::exception(rsig_err_msg.c_str()); + std::string rsig_err_msg = "Missing args in " + args; // #nocov + throw Rcpp::exception(rsig_err_msg.c_str()); // #nocov } } // determine the function name @@ -2953,7 +2953,8 @@ namespace attributes { << " if (rcpp_isError_gen) {" << std::endl << " SEXP rcpp_msgSEXP_gen = Rf_asChar(rcpp_result_gen);" << std::endl << " UNPROTECT(1);" << std::endl - << " Rf_error(\"%s\", CHAR(rcpp_msgSEXP_gen));" << std::endl + // Parentheses to prevent masking + << " (Rf_error)(\"%s\", CHAR(rcpp_msgSEXP_gen));" << std::endl << " }" << std::endl << " UNPROTECT(1);" << std::endl << " return rcpp_result_gen;" << std::endl diff --git a/src/barrier.cpp b/src/barrier.cpp index e3ac21a6a..aa0febb68 100644 --- a/src/barrier.cpp +++ b/src/barrier.cpp @@ -2,7 +2,7 @@ // barrier.cpp: Rcpp R/C++ interface class library -- write barrier // // Copyright (C) 2010 - 2020 Dirk Eddelbuettel and Romain Francois -// Copyright (C) 2021 - 2022 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar +// Copyright (C) 2021 - 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -76,13 +76,8 @@ SEXP* get_vector_ptr(SEXP x) { // [[Rcpp::register]] void* dataptr(SEXP x) { -#if R_VERSION >= R_Version(3,5,0) // DATAPTR_RO was introduced with R 3.5.0 return const_cast(DATAPTR_RO(x)); -#else - // this will get your wrists slapped under recent R CMD check ... - return DATAPTR(x); -#endif } // [[Rcpp::register]] @@ -108,13 +103,13 @@ void Rcpp_precious_init() { R_PreserveObject(Rcpp_precious); // and protect } // [[Rcpp::register]] -void Rcpp_precious_teardown() { +void Rcpp_precious_teardown() { // #nocov start R_ReleaseObject(Rcpp_precious); // release resource -} +} // #nocov end // [[Rcpp::register]] SEXP Rcpp_precious_preserve(SEXP object) { if (object == R_NilValue) { - return R_NilValue; + return R_NilValue; // #nocov } PROTECT(object); SEXP cell = PROTECT(CONS(Rcpp_precious, CDR(Rcpp_precious))); @@ -150,7 +145,11 @@ SEXP get_rcpp_cache() { Rcpp::Shield call(Rf_lang2(getNamespaceSym, RcppString)); Rcpp::Shield RCPP(Rf_eval(call, R_GlobalEnv)); +#if R_VERSION < R_Version(4,5,0) Rcpp_cache = Rf_findVarInFrame(RCPP, Rf_install(".rcpp_cache")); +#else + Rcpp_cache = R_getVar(Rf_install(".rcpp_cache"), RCPP, TRUE); +#endif Rcpp_cache_know = true; } return Rcpp_cache; diff --git a/tests/tinytest.R b/tests/tinytest.R index 5dc5fc2b8..61cc2b8a7 100644 --- a/tests/tinytest.R +++ b/tests/tinytest.R @@ -1,6 +1,17 @@ if (requireNamespace("tinytest", quietly=TRUE)) { + ## if OMP_THREAD_LIMIT is set, and its value is 2, we have a good + ## idea of where we are and we likely do not want to run all tests + if (Sys.getenv("OMP_THREAD_LIMIT", unset="") == "2") { # set and 2 + if (Sys.getenv("RunAllRcppTests", "") != "") { # if unset + Sys.setenv("RunAllRcppTests"="no") + } + if (Sys.getenv("RunVerboseRcppTests", "") != "") { # if unset + Sys.setenv("RunVerboseRcppTests"="no") + } + } + ## Force tests to be executed if in dev release which we define as ## having a sub-release, eg 0.9.15.5 is one whereas 0.9.16 is not if (length(strsplit(format(packageVersion("Rcpp")), "\\.")[[1]]) > 3) { # dev rel, and diff --git a/vignettes/Rcpp-FAQ.pdf b/vignettes/Rcpp-FAQ.pdf index bf46ff147..c2745605c 100644 Binary files a/vignettes/Rcpp-FAQ.pdf and b/vignettes/Rcpp-FAQ.pdf differ diff --git a/vignettes/Rcpp-attributes.pdf b/vignettes/Rcpp-attributes.pdf index b1f7f14bc..7eca2b952 100644 Binary files a/vignettes/Rcpp-attributes.pdf and b/vignettes/Rcpp-attributes.pdf differ diff --git a/vignettes/Rcpp-extending.pdf b/vignettes/Rcpp-extending.pdf index f3ca588c3..1c85d3175 100644 Binary files a/vignettes/Rcpp-extending.pdf and b/vignettes/Rcpp-extending.pdf differ diff --git a/vignettes/Rcpp-introduction.pdf b/vignettes/Rcpp-introduction.pdf index 7c7c2ab79..268930ea9 100644 Binary files a/vignettes/Rcpp-introduction.pdf and b/vignettes/Rcpp-introduction.pdf differ diff --git a/vignettes/Rcpp-jss-2011.pdf b/vignettes/Rcpp-jss-2011.pdf index a8e2483f1..eb0d3b057 100644 Binary files a/vignettes/Rcpp-jss-2011.pdf and b/vignettes/Rcpp-jss-2011.pdf differ diff --git a/vignettes/Rcpp-libraries.pdf b/vignettes/Rcpp-libraries.pdf index 3a8767a62..031023868 100644 Binary files a/vignettes/Rcpp-libraries.pdf and b/vignettes/Rcpp-libraries.pdf differ diff --git a/vignettes/Rcpp-modules.pdf b/vignettes/Rcpp-modules.pdf index ff4dce291..62b1c704e 100644 Binary files a/vignettes/Rcpp-modules.pdf and b/vignettes/Rcpp-modules.pdf differ diff --git a/vignettes/Rcpp-package.pdf b/vignettes/Rcpp-package.pdf index 7ed748fb3..aa2cf4e37 100644 Binary files a/vignettes/Rcpp-package.pdf and b/vignettes/Rcpp-package.pdf differ diff --git a/vignettes/Rcpp-quickref.pdf b/vignettes/Rcpp-quickref.pdf index 3e26d5134..ddca8d948 100644 Binary files a/vignettes/Rcpp-quickref.pdf and b/vignettes/Rcpp-quickref.pdf differ diff --git a/vignettes/Rcpp-sugar.pdf b/vignettes/Rcpp-sugar.pdf index 0122581c9..6f61a6d53 100644 Binary files a/vignettes/Rcpp-sugar.pdf and b/vignettes/Rcpp-sugar.pdf differ diff --git a/vignettes/rmd/Makefile b/vignettes/rmd/Makefile index 973e2cd5a..4de500cf1 100644 --- a/vignettes/rmd/Makefile +++ b/vignettes/rmd/Makefile @@ -11,13 +11,12 @@ rmdvignettes := $(rmdsources:.Rmd=.pdf) all: ${rmdvignettes} Rcpp-jss-2011.pdf -Rcpp-jss-2011.tex: Rcpp-jss-2011.Rnw - Rscript -e 'Sweave("$<")' - -Rcpp-jss-2011.pdf: Rcpp-jss-2011.tex - Rscript -e 'tools::texi2pdf("$<", texi2dvi="pdflatex")' +Rcpp-jss-2011.pdf: Rcpp-jss-2011.Rnw + Rscript -e 'Sweave("Rcpp-jss-2011.Rnw")' + pdflatex Rcpp-jss-2011.tex bibtex Rcpp-jss-2011.aux - Rscript -e 'tools::texi2pdf("$<", texi2dvi="pdflatex")' + pdflatex Rcpp-jss-2011.tex + pdflatex Rcpp-jss-2011.tex Rscript -e 'tools::compactPDF("$@", gs_quality="ebook")' cp -vax $@ .. diff --git a/vignettes/rmd/Rcpp-FAQ.Rmd b/vignettes/rmd/Rcpp-FAQ.Rmd index 92d143dd3..5e7f01ded 100644 --- a/vignettes/rmd/Rcpp-FAQ.Rmd +++ b/vignettes/rmd/Rcpp-FAQ.Rmd @@ -10,9 +10,9 @@ author: address: - code: a - address: \url{http://dirk.eddelbuettel.com} + address: \url{https://dirk.eddelbuettel.com} - code: b - address: \url{https://romain.rbind.io/} + address: \url{https://github.com/romainfrancois} # For footer text lead_author_surname: Eddelbuettel and François @@ -75,7 +75,7 @@ header-includes: > \newcommand{\proglang}[1]{\textsf{#1}} \newcommand{\pkg}[1]{\textbf{#1}} \newcommand{\faq}[1]{FAQ~\ref{#1}} - \newcommand{\rdoc}[2]{\href{http://www.rdocumentation.org/packages/#1/functions/#2}{\code{#2}}} + \newcommand{\rdoc}[2]{\code{#2}} vignette: > %\VignetteIndexEntry{Rcpp-FAQ} @@ -131,7 +131,7 @@ means one needs: `--enable-shared-lib` option; - standard development tools such as `make` etc. -Also see the [RStudio documentation](http://www.rstudio.com/ide/docs/packages/prerequisites) +Also see the [RStudio documentation](https://support.posit.co/hc/en-us/articles/200486498-Package-Development-Prerequisites) on pre-requisites for R package development. ## What compiler can I use {#q:what-compiler} @@ -153,7 +153,7 @@ Specific per-platform notes: manual \citep[Appendix D]{R:Administration}. \item[macOS] users, as noted in the "R Administration" manual \citep[Appendix C.4]{R:Administration}, need to install the Apple Developer Tools - (\textsl{e.g.}, \href{https://developer.apple.com/library/ios/technotes/tn2339/_index.html}{Xcode Command Line Tools} (as well as \texttt{gfortran} if \proglang{R} or + (\textsl{e.g.}, \href{https://developer.apple.com/library/archive/technotes/tn2339/_index.html}{Xcode Command Line Tools} (as well as \texttt{gfortran} if \proglang{R} or Fortran-using packages are to be built); also see \faq{q:OSX} and \faq{q:OSXArma} below. This is frustratingly moving target; consult the \code{r-sig-mac} list (and its archives) for (current) details. @@ -478,7 +478,7 @@ able to mix. In such cases, it is better to provide collaborators with the By default, the macOS operating environment lacks the ability to parallelize sections of code using the [\proglang{OpenMP} -standard](http://openmp.org/wp/). Within \proglang{R} 3.4.*, the default +standard](https://www.openmp.org/specifications/). Within \proglang{R} 3.4.*, the default developer environment was _changed_ to allow for \proglang{OpenMP} to be used on macOS by using a non-default toolchain provided by R Core Team maintainers for macOS. Having said this, it is still important to protect any reference @@ -516,10 +516,10 @@ Below are additional resources that provide information regarding compiling Rcpp [on the `r-sig-mac` list](https://stat.ethz.ch/pipermail/r-sig-mac/2014-April/010835.html), which is generally recommended for macOS-specific questions and further consultation. 2. Another helpful write-up for installation / compilation on macOS Mavericks is provided - [by the BioConductor project](http://www.bioconductor.org/developers/how-to/mavericks-howto/). + [by the BioConductor project](https://contributions.bioconductor.org/cmavericks-best-practices.html). 3. Lastly, another resource that exists for installation / compilation help is provided at - . + . \textbf{Note:} If you are running into trouble compiling code with \pkg{RcppArmadillo}, please also see \faq{q:OSXArma} listed below. @@ -612,11 +612,11 @@ The following questions were asked on the [Rcpp-devel](https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel) mailing list, which is our preferred place to ask questions as it guarantees exposure to a number of advanced Rcpp users. The -[StackOverflow tag for rcpp](http://stackoverflow.com/questions/tagged/rcpp) +[StackOverflow tag for rcpp](https://stackoverflow.com/questions/tagged/rcpp) is an alternative; that site is also easily searchable. Several dozen fully documented examples are provided at the -[Rcpp Gallery](http://gallery.rcpp.org) -- which is also open for new contributions. +[Rcpp Gallery](https://gallery.rcpp.org) -- which is also open for new contributions. ## Can I use templates with \pkg{Rcpp} @@ -718,7 +718,7 @@ operations. That is a mouthful of words meaning that it makes the code go faster by using fiendishly clever ways available via the so-called template meta programming, an advanced \proglang{C++} technique. Also, the \pkg{RcppEigen} package \citep{JSS:RcppEigen} provides an alternative using the -[Eigen](http://eigen.tuxfamily.org) template library. +[Eigen](https://libeigen.gitlab.io) template library. ### Using inline with RcppArmadillo {#using-inline-armadillo} @@ -757,7 +757,7 @@ The focus is on the code `arma::trans(x) * arma::inv(Y) * z`, which performs the same operation as the R code `t(x) %*% solve(Y) %*% z`, although Armadillo turns it into only one operation, which makes it quite fast. Armadillo benchmarks against other \proglang{C++} matrix algebra libraries -are provided on [the Armadillo website](http://arma.sourceforge.net/speed.html). +are provided on [the Armadillo website](https://arma.sourceforge.net/speed.html). It should be noted that code below depends on the version `0.3.5` of \pkg{inline} and the version `0.2.2` of \pkg{RcppArmadillo}. @@ -896,7 +896,7 @@ C Armadillo supports a full range of common linear algebra operations. The \pkg{RcppEigen} package provides an alternative using the -[Eigen](http://eigen.tuxfamily.org) template library. +[Eigen](https://libeigen.gitlab.io) template library. Rcpp Attributes, once again, makes this even easier: @@ -1065,7 +1065,7 @@ suggestion or fix for casting 64-bit integer values: 32-bit integer values fit into `integer` types, up to 53 bit precision fits into `numeric` and beyond that truly large integers may have to converted (rather crudely) to text and re-parsed. Using a different representation as -for example from the [GNU Multiple Precision Arithmetic Library](http://gmplib.org/) +for example from the [GNU Multiple Precision Arithmetic Library](https://gmplib.org/) may be an alternative. However, with care, and via the package \pkg{bit64}, \proglang{R} can use @@ -1083,7 +1083,7 @@ system. Specific per-platform notes: -- **Windows** users probably want the [MiKTeX](http://miktex.org/). +- **Windows** users probably want the [MiKTeX](https://miktex.org/). Suggestions for a more detailed walk through would be appreciated. - **macOS** users seem to fall into camps which like or do not like brew / homebrew. One suggestion was to install @@ -1109,7 +1109,7 @@ generator scripts to explicitly enumerate arguments, and that number has to stop at some limit. We chose 20. A good discussion is available at -[this StackOverflow question](http://stackoverflow.com/questions/27371543) +[this StackOverflow question](https://stackoverflow.com/questions/27371543) concerning data.frame creation with \pkg{Rcpp}. One solution offers a custom `ListBuilder` class to circumvent the limit; another suggests to simply nest lists. @@ -1168,7 +1168,7 @@ Note: In `cpp`, the default `bool` values are `true` and But of course. In a nutshell, this boils down to \emph{what your compiler supports}, and also \emph{what R supports}. We expanded a little on this in -[Rcpp Gallery article](http://gallery.rcpp.org/articles/rcpp-and-c++11-c++14-c++17/) providing more detail. What follows in an abridged summary. +[Rcpp Gallery article](https://gallery.rcpp.org/articles/rcpp-and-c++11-c++14-c++17/) providing more detail. What follows in an abridged summary. You can always \emph{locally} set appropriate `PKG_CXXFLAGS` as an environment variable, or via `~/.R/Makevars`. You can also set plugins and/or R @@ -1201,7 +1201,7 @@ conda install gxx_linux-64 helps within this environment as it installs the corresponding `x86_64-conda_cos6-linux-gnu-c++` compiler. Documentation for this and other systems is provided -[at this page](https://conda.io/docs/user-guide/tasks/build-packages/compiler-tools.html). +[at this page](https://docs.conda.io/docs/user-guide/tasks/build-packages/compiler-tools.html). ## Can I speed up compilation? @@ -1230,12 +1230,12 @@ exclude these different (layered) bits of functionality. You bet. We use \proglang{doxygen} to generate html, latex and man page documentation from the source. The html documentation is available for -[browsing](http://dirk.eddelbuettel.com/code/rcpp/html/index.html), as a -[very large pdf file](http://dirk.eddelbuettel.com/code/rcpp/Rcpp_refman.pdf), +[browsing](https://dirk.eddelbuettel.com/code/rcpp/html/index.html), as a +[very large pdf file](https://dirk.eddelbuettel.com/code/rcpp/Rcpp_refman.pdf), and all three formats are also available a zip-archives: -[html](http://dirk.eddelbuettel.com/code/rcpp/rcpp-doc-html.zip), -[latex](http://dirk.eddelbuettel.com/code/rcpp/rcpp-doc-latex.zip), and -[man](http://dirk.eddelbuettel.com/code/rcpp/rcpp-doc-man.zip). +[html](https://dirk.eddelbuettel.com/code/rcpp/rcpp-doc-html.zip), +[latex](https://dirk.eddelbuettel.com/code/rcpp/rcpp-doc-latex.zip), and +[man](https://dirk.eddelbuettel.com/code/rcpp/rcpp-doc-man.zip). ## Does it really work @@ -1252,13 +1252,12 @@ The mailing list hosted at R-forge is by far the best place. You may also want to look at the list archives to see if your question has been asked before. -You can also use [StackOverflow via its 'rcpp' tag](http://stackoverflow.com/questions/tagged/rcpp). +You can also use [StackOverflow via its 'rcpp' tag](https://stackoverflow.com/questions/tagged/rcpp). ## Where can I read old questions and answers The normal [Rcpp-devel](https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel) -mailing list hosting at R-forge contains an archive, which can be -[searched via swish](http://lists.r-forge.r-project.org/mailman/swish.cgi?query=listname=rcpp-devel). +mailing list hosting at R-forge contains an archive. Alternatively, one can also use [Mail-Archive on Rcpp-devel](http://www.mail-archive.com/rcpp-devel@lists.r-forge.r-project.org/info.html) @@ -1278,7 +1277,7 @@ You can also spread the word about \pkg{Rcpp}. There are many packages on CRAN that use \proglang{C++}, yet are not using \pkg{Rcpp}. You could blog about it, or get the word out otherwise. -Last but not least the [Rcpp Gallery](http://gallery.rcpp.org) is open +Last but not least the [Rcpp Gallery](https://gallery.rcpp.org) is open for user contributions. ## I don't like it. How can I help {#dont-like-help} @@ -1302,7 +1301,7 @@ From late 2008 to late 2013, we used the which contained \pkg{Rcpp} and a number of related packages. It still has the full history as well as number of support files. -We have since switched to a [Git repository at Github](http://github.com/RcppCore/Rcpp) +We have since switched to a [Git repository at Github](https://github.com/RcppCore/Rcpp) for \pkg{Rcpp} (as well as for \pkg{RcppArmadillo} and \pkg{RcppEigen}). # Known Issues @@ -1573,7 +1572,7 @@ elements. With the release of \proglang{R}'s 3.0.0, long vector support was adde allow for largest vector possible to increase up to $2^{52}$ elements on x64 bit operating systems (c.f. [Long Vectors help entry](https://stat.ethz.ch/R-manual/R-devel/library/base/html/LongVectors.html)). Once this was established, support for long vectors within the \pkg{Rcpp} paradigm -was introduced with \pkg{Rcpp} version 0.12.0 (c.f [\pkg{Rcpp} 0.12.0 annoucement](http://dirk.eddelbuettel.com/blog/2015/07/25/)). +was introduced with \pkg{Rcpp} version 0.12.0 (c.f [\pkg{Rcpp} 0.12.0 annoucement](https://dirk.eddelbuettel.com/blog/2015/07/25/)). However, the requirement for using long vectors in \pkg{Rcpp} necessitates the presence of compiler support for the `R_xlen_t`, which is platform diff --git a/vignettes/rmd/Rcpp-attributes.Rmd b/vignettes/rmd/Rcpp-attributes.Rmd index c644917f3..0115031d9 100644 --- a/vignettes/rmd/Rcpp-attributes.Rmd +++ b/vignettes/rmd/Rcpp-attributes.Rmd @@ -12,11 +12,11 @@ author: address: - code: a - address: \url{https://rstudio.com} + address: \url{https://posit.co} - code: b - address: \url{http://dirk.eddelbuettel.com} + address: \url{https://dirk.eddelbuettel.com} - code: c - address: \url{https://romain.rbind.io/} + address: \url{https://github.com/romainfrancois} # For footer text TODO(fold into template, allow free form two-authors) lead_author_surname: Allaire, Eddelbuettel, François diff --git a/vignettes/rmd/Rcpp-extending.Rmd b/vignettes/rmd/Rcpp-extending.Rmd index 11c1f9587..1ff14ed98 100644 --- a/vignettes/rmd/Rcpp-extending.Rmd +++ b/vignettes/rmd/Rcpp-extending.Rmd @@ -10,9 +10,9 @@ author: address: - code: a - address: \url{http://dirk.eddelbuettel.com} + address: \url{https://dirk.eddelbuettel.com} - code: b - address: \url{https://romain.rbind.io/} + address: \url{https://github.com/romainfrancois} # For footer text lead_author_surname: Eddelbuettel and François diff --git a/vignettes/rmd/Rcpp-introduction.Rmd b/vignettes/rmd/Rcpp-introduction.Rmd index b0f1845ec..638a44678 100644 --- a/vignettes/rmd/Rcpp-introduction.Rmd +++ b/vignettes/rmd/Rcpp-introduction.Rmd @@ -11,9 +11,9 @@ author: affiliation: b address: - code: a - address: Debian and R Projects; Chicago, IL, USA; \url{edd@debian.org} + address: Debian and R Projects; Chicago, IL, USA; \code{edd@debian.org} - code: b - address: Depts of Informatics and Statistics, Univ. of Illinois at Urbana-Champaign; Champaign, IL, USA; \url{balamut2@illinois.edu} + address: Depts of Informatics and Statistics, Univ. of Illinois at Urbana-Champaign; Champaign, IL, USA; \code{balamut2@illinois.edu} # For footer text TODO(fold into template, allow free form two-authors) lead_author_surname: Eddelbuettel and Balamuta @@ -189,10 +189,9 @@ the Rtools kit provided by R Core available at \newcommand{\proglang}[1]{\textsf{#1}} \newcommand{\pkg}[1]{\textbf{#1}} \newcommand{\faq}[1]{FAQ~\ref{#1}} - \newcommand{\rdoc}[2]{\href{http://www.rdocumentation.org/packages/#1/functions/#2}{\code{#2}}} + \newcommand{\rdoc}[2]{\code{#2}} \newcommand{\sugar}{\textsl{Rcpp sugar}~} vignette: > @@ -167,7 +167,7 @@ package, and it also includes the different components needed for using ## \proglang{C++} code -If the `attributes` argument is set to `TRUE`[^1], the +If the `attributes` argument is set to `TRUE`[^1], the following \proglang{C++} file is included in the `src/` directory: ```cpp @@ -177,9 +177,9 @@ using namespace Rcpp; // [[Rcpp::export]] List rcpp_hello_world() { - CharacterVector x = + CharacterVector x = CharacterVector::create("foo", "bar"); - NumericVector y = + NumericVector y = NumericVector::create( 0.0, 1.0 ) ; List z = List::create( x, y ) ; @@ -240,7 +240,7 @@ that uses the \proglang{C++} function. # 10BE3573-1514-4C36-9D1C-5A225CD40393 rcpp_hello_world <- function() { - .Call('mypackage_rcpp_hello_world', + .Call('mypackage_rcpp_hello_world', PACKAGE = 'mypackage') } ``` @@ -283,7 +283,7 @@ indicates that the client package needs to use header files exposed by ## Now optional: `Makevars` and `Makevars.win` This behaviour changed with \pkg{Rcpp} release 0.11.0. These files used to be -mandatory, now they are merely optional. +mandatory, now they are merely optional. We will describe the old setting first as it was in use for a few years. The new standard, however, is much easier and is described below. @@ -324,7 +324,7 @@ PKG_LIBS = $(shell \ As of release 0.11.0, this is no longer needed as client packages obtain the required code from \pkg{Rcpp} via explicit function registration. The user -does not have to do anything. +does not have to do anything. This means that `PKG_LIBS` can now be empty---unless some client libraries are needed. For example, \pkg{RcppCNPy} needs compression support @@ -345,7 +345,7 @@ importFrom(Rcpp, evalCpp) This file serves three purposes. First, it ensure that the dynamic library contained in the package we are creating via \rdoc{Rcpp}{Rcpp.package.skeleton} will be loaded and thereby made -available to the newly created \proglang{R} package. +available to the newly created \proglang{R} package. Second, it declares which functions should be globally visible from the namespace of this package. As a reasonable default, we export all functions. @@ -460,7 +460,7 @@ and \pkg{minqa} \citep{CRAN:minqa}. Several other packages follow older (but sti and appropriate) instructions. They can serve examples on how to get data to and from \proglang{C++} routines, but should not be considered templates for how to connect to \pkg{Rcpp}. The full list of packages using \pkg{Rcpp} can -be found at the [CRAN page](http://CRAN.R-project.org/package=Rcpp) of +be found at the [CRAN page](https://CRAN.R-project.org/package=Rcpp) of \pkg{Rcpp}. # Other compilers @@ -488,4 +488,4 @@ detail, and references to further examples were provided. [^1]: Setting `attributes` to `TRUE` is the default. This document does not cover the behavior of `Rcpp.package.skeleton` when `attributes` is set to `FALSE` as we try to encourage package developers to use - attributes. + attributes. diff --git a/vignettes/rmd/Rcpp-quickref.Rmd b/vignettes/rmd/Rcpp-quickref.Rmd index f279d5124..2907427a5 100644 --- a/vignettes/rmd/Rcpp-quickref.Rmd +++ b/vignettes/rmd/Rcpp-quickref.Rmd @@ -10,9 +10,9 @@ author: address: - code: a - address: \url{http://dirk.eddelbuettel.com} + address: \url{https://dirk.eddelbuettel.com} - code: b - address: \url{https://romain.rbind.io/} + address: \url{https://github.com/romainfrancois} # For footer text lead_author_surname: Eddelbuettel and François @@ -173,7 +173,7 @@ NumericMatrix zz2 = xx( Range(0,2), Range(0,2)); # Inline C++ Compile in R ```{r, eval = FALSE} -## Note - this is R code. +## Note - this is R code. ## cppFunction in Rcpp allows rapid testing. require(Rcpp) @@ -221,11 +221,11 @@ RcppExport SEXP myCfun( SEXP x, SEXP y) { // Pointer is faster, but changes to xx // propagate to R ( xx -> x == Rx). NumericVector xx(x); - + // clone is slower and uses extra memory. // Safe. No side effects. NumericVector yy(clone(y)); - + xx[0] = yy[0] = -1.5; int zz = xx[0]; @@ -299,18 +299,18 @@ using namespace Rcpp; // [[Rcpp::export]] double muRcpp(NumericVector x){ int n = x.size(); // Size of vector - double sum = 0; // Sum value - + double sum = 0; // Sum value + // For loop, note cpp index shift to 0 - for(int i = 0; i < n; i++){ + for(int i = 0; i < n; i++){ // Shorthand for sum = sum + x[i] - sum += x[i]; + sum += x[i]; } - + return sum/n; // Obtain and return the Mean } -// Place dependent functions above call or +// Place dependent functions above call or // declare the function definition with: double muRcpp(NumericVector x); @@ -320,12 +320,12 @@ double varRcpp(NumericVector x, bool bias = true){ double mean = muRcpp(x); double sum = 0; int n = x.size(); - - for(int i = 0; i < n; i++){ + + for(int i = 0; i < n; i++){ sum += pow(x[i] - mean, 2.0); // Square } - - return sum/(n-bias); // Return variance + + return sum/(n-bias); // Return variance } ``` @@ -397,8 +397,8 @@ RNGScope scope; // For details see Section 6.7.1--Distribution // functions of the `Writing R Extensions' manual. // In some cases (e.g. rnorm), dist-specific -// arguments can be omitted; when in doubt, -// specify all dist-specific arguments. The use +// arguments can be omitted; when in doubt, +// specify all dist-specific arguments. The use // of doubles rather than integers for dist- // specific arguments is recommended. Unless // explicitly specified, log=FALSE. @@ -477,7 +477,7 @@ Environment e = glob.new_child(); ```cpp // Do NOT expect to have a performance gain -// when calling R functions from R! +// when calling R functions from R! // Retrieve functions from default loaded env. Function rnorm("rnorm"); @@ -485,7 +485,7 @@ rnorm(100, _["mean"] = 10.2, _["sd"] = 3.2 ); // Passing in an R function and obtaining results // Make sure function conforms with return type! -NumericVector callFunction(NumericVector x, +NumericVector callFunction(NumericVector x, Function f) { NumericVector res = f(x); return res; diff --git a/vignettes/rmd/Rcpp-sugar.Rmd b/vignettes/rmd/Rcpp-sugar.Rmd index 2beb2edc2..9384b78a9 100644 --- a/vignettes/rmd/Rcpp-sugar.Rmd +++ b/vignettes/rmd/Rcpp-sugar.Rmd @@ -10,9 +10,9 @@ author: address: - code: a - address: \url{http://dirk.eddelbuettel.com} + address: \url{https://dirk.eddelbuettel.com} - code: b - address: \url{https://romain.rbind.io/} + address: \url{https://github.com/romainfrancois} # For footer text lead_author_surname: Eddelbuettel and François @@ -494,7 +494,7 @@ Note that the parameterization used in these sugar functions may differ between the top-level functions exposed in an \proglang{R} session. For example, the internal \code{rexp} is parameterized by \code{scale}, whereas the R-level \code{stats::rexp} is parameterized by \code{rate}. -Consult \href{http://cran.r-project.org/doc/manuals/r-release/R-exts.html#Distribution-functions}{Distribution Functions} +Consult \href{https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Distribution-functions-1}{Distribution Functions} for more details on the parameterization used for these sugar functions. One point to note is that the programmer using these functions needs to diff --git a/vignettes/rmd/Rcpp.bib b/vignettes/rmd/Rcpp.bib index 648b9eeaf..4c2a6af37 100644 --- a/vignettes/rmd/Rcpp.bib +++ b/vignettes/rmd/Rcpp.bib @@ -10,7 +10,7 @@ @manual{Abrahams+Grosse-Kunstleve:2003:Boost.Python organization = "Boost Consulting", title = "Building Hybrid Systems with Boost.Python", year = 2003, - url = "https://www.boostpro.com/writing/bpl.pdf" + url = "https://www.boost.org/doc/libs/latest/libs/python/doc/html/article.html" } @Book{Abrahams+Gurtovoy:2004:TemplateMetaprogramming, @@ -60,7 +60,7 @@ @InProceedings{Bates+DebRoy:2001:C++Classes Universit\"at Wien, Vienna, Austria}, editor = {Kurt Hornik and Friedrich Leisch}, year = {2001}, - url = {https://www.ci.tuwien.ac.at/Conferences/DSC-2001/Proceedings/}, + url = {https://www.r-project.org/conferences/DSC-2001/Proceedings/}, note = {ISSN 1609-395X} } @@ -76,8 +76,8 @@ @Misc{Brokken:2011:Cpp @Manual{CRAN:anytime, title = {anytime: Anything to 'POSIXct' or 'Date' Converter}, author = {Dirk Eddelbuettel}, - year = {2024}, - note = {R package version 0.3.11}, + year = {2025}, + note = {R package version 0.3.12}, oldurl = CRAN # "package=anytime", doi = DOI # "anytime" } @@ -95,8 +95,8 @@ @Manual{CRAN:BH title = {BH: Boost C++ Header Files}, author = {Dirk Eddelbuettel and John W. Emerson and Michael J. Kane}, - year = {2024}, - note = {R package version 1.87.0-1}, + year = {2025}, + note = {R package version 1.90.0-1}, oldurl = CRAN # "package=BH", doi = DOI # "BH" } @@ -105,7 +105,7 @@ @Manual{CRAN:Matrix title = {\pkg{Matrix}: Sparse and Dense Matrix Classes and Methods}, author = {Douglas Bates and Martin Maechler}, year = 2025, - note = {R package version 1.7-3}, + note = {R package version 1.7-4}, oldurl = CRAN # "package=Matrix", doi = DOI # "Matrix" } @@ -113,8 +113,8 @@ @Manual{CRAN:Matrix @Manual{CRAN:RInside, title = {RInside: C++ classes to embed R in C++ applications}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, - year = 2020, - note = {R package version 0.2.16}, + year = 2025, + note = {R package version 0.2.19}, oldurl = CRAN # "package=RInside", doi = DOI # "RInside" } @@ -152,8 +152,8 @@ @Manual{CRAN:Rcpp author = {Dirk Eddelbuettel and Romain Fran\c{c}ois and JJ Allaire and Kevin Ushey and Qiang Kou and Nathan Russel and John Chambers and Douglas Bates}, - year = 2025, - note = {R package version 1.1.0}, + year = 2026, + note = {R package version 1.1.1}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" } @@ -163,7 +163,7 @@ @Manual{CRAN:Rcpp:Attributes author = {J. J. Allaire and Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {{Rcpp} Attributes}, - year = 2025, + year = 2026, note = {Vignette included in R package Rcpp}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -173,7 +173,7 @@ @Manual{CRAN:Rcpp:FAQ crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Frequently Asked Questions About {Rcpp}}, - year = 2025, + year = 2026, note = {Vignette included in R package {Rcpp}}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -183,7 +183,7 @@ @Manual{CRAN:Rcpp:Libraries crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel}, title = {Thirteen Simple Steps for Creating An R Package with an External C++ Library }, - year = 2025, + year = 2026, note = {Vignette included in R package Rcpp}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -193,7 +193,7 @@ @Manual{CRAN:Rcpp:Modules crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Exposing {C++} functions and classes with {Rcpp} modules}, - year = 2025, + year = 2026, note = {Vignette included in R package Rcpp}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -203,7 +203,7 @@ @Manual{CRAN:Rcpp:Package crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Writing a package that uses {Rcpp}}, - year = 2025, + year = 2026, note = {Vignette included in R package {Rcpp}}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -213,7 +213,7 @@ @Manual{CRAN:Rcpp:Sugar crossref = {CRAN:Rcpp}, author = {Dirk Eddelbuettel and Romain Fran\c{c}ois}, title = {Rcpp syntactic sugar}, - year = 2025, + year = 2026, note = {Vignette included in R package {Rcpp}}, oldurl = CRAN # "package=Rcpp", doi = DOI # "Rcpp" @@ -225,7 +225,7 @@ @Manual{CRAN:RcppArmadillo author = {Dirk Eddelbuettel and Romain Fran\c{c}ois and Douglas Bates and Binxiang Ni and Conrad Sanderson}, year = 2025, - note = {R package version 14.4.3-1}, + note = {R package version 15.2.3-1}, oldurl = CRAN # "package=RcppArmadillo", doi = DOI # "RcppArmadillo" } @@ -316,8 +316,8 @@ @Manual{CRAN:RcppZiggurat @Manual{CRAN:Rserve, title = {Rserve: Versatile R Server}, author = {Simon Urbanek}, - year = 2024, - note = {R package version 1.8-15}, + year = 2025, + note = {R package version 1.8-16}, oldurl = CRAN # "package=Rserve", doi = DOI # "Rserve" } @@ -336,8 +336,8 @@ @Manual{CRAN:devtools title = {devtools: Tools to Make Developing R Packages Easier}, author = {Hadley Wickham and Jim Hester and Winston Chang}, - year = 2022, - note = {R package version 2.4.5}, + year = 2025, + note = {R package version 2.4.6}, oldurl = CRAN # "package=devtools", doi = DOI # "devtools" } @@ -345,8 +345,8 @@ @Manual{CRAN:devtools @Manual{CRAN:highlight, title = {highlight: Syntax Highlighter}, author = {Hadley Wickham and Romain Fran\c{c}ois and Andre Simon}, - year = 2023, - note = {R package with version 0.5.1}, + year = 2025, + note = {R package with version 0.5.2}, oldurl = CRAN # "package=highlight", doi = DOI # "highlight" } @@ -423,8 +423,8 @@ @Manual{CRAN:rbenchmark @Manual{CRAN:roxygen2, title = {roxygen2: In-Line documentation for R}, author = {Hadley Wickham and Peter Danenberg and G\a'bor Cs\a'rdi and Manuel Eugster}, - year = 2024, - note = {R package version 7.3.2}, + year = 2025, + note = {R package version 7.3.3}, oldurl = CRAN # "package=roxygen2", doi = DOI # "roxygen2" } @@ -554,7 +554,7 @@ @MISC{Eigen:Web author = {Ga\"{e}l Guennebaud and Beno\^{i}t Jacob and others}, title = {Eigen v3}, year = 2012, - url = {https://eigen.tuxfamily.org} + url = {https://libeigen.gitlib.io/} } @Manual{GSL, @@ -773,8 +773,8 @@ @Article{PeerJ:Rcpp issue = {e3188v1}, year = 2017, month = {August}, - url = {https://doi.org/10.7287/peerj.preprints.3188v1/}, - doi = {10.7287/peerj.preprints.3188v1/} + url = {https://peerj.com/preprints/3188v1/}, + doi = {10.7287/peerj.preprints.3188v1} } @Book{Plauger+Et+Al:2000:STL, @@ -790,7 +790,7 @@ @manual{QuantLib author = {{QuantLib Core Team}}, year = 2021, title = {QuantLib: a free/open-source library for quantitative finance}, - url = {https://quantlib.org} + url = {https://www.quantlib.org} } @manual{R:Administration, @@ -886,7 +886,7 @@ @TechReport{Sanderson:2010:Armadillo Experiments }, institution = {{NICTA}}, year = 2010, - url = "https://arma.sf.net" + url = "https://arma.sourceforge.net" } @Book{Stroustrup:1997:Cpp, @@ -952,7 +952,7 @@ @InProceedings{Urbanek:2003:Rserve Statistical Computing, Vienna, Austria}, editor = {Kurt Hornik and Friedrich Leisch and Achim Zeileis}, year = {2003}, - url = {https://www.ci.tuwien.ac.at/Conferences/DSC-2003/Proceedings/}, + url = {https://www.r-project.org/conferences/DSC-2003/Proceedings/}, note = {{ISSN 1609-395X}} } @@ -996,7 +996,7 @@ @Book{Venables+Ripley:2002:MASS address = {New York}, year = 2002, note = {ISBN 0-387-95457-0}, - url = {https://www.stats.ox.ac.uk/pub/MASS4}, + url = {https://www.stats.ox.ac.uk/pub/MASS4/}, } @misc{arxiv:corels, @@ -1005,7 +1005,7 @@ @misc{arxiv:corels author = {Elaine Angelino and Nicholas Larus-Stone and Daniel Alabi and Margo Seltzer and Cynthia Rudin}, year = 2017, - howpublished = {\href{https://www.arxiv.org/1704.01701}{arXiv:1704.01701}}, + howpublished = {\href{https://www.arxiv.org/abs/1704.01701}{arXiv:1704.01701}}, archivePrefix ={arXiv}, primaryClass = {stat.ML} } @@ -1013,7 +1013,7 @@ @misc{arxiv:corels @Misc{github:corels, author = {Nicholas Laurus-Stone}, title = {corels: {Learning Certifiably Optimal Rule Lists}}, - howpublished = {\url{https://github.com/nlarusstone/corels}. Also online at \url{https://corels.eecs.harvard.edu/corels/}}, + howpublished = {\url{https://github.com/corels/corels}. Also online at \url{https://corels.cs.ubc.ca/corels/Larus-Stone_thesis.pdf}}, month = 06, year = 2019 } @@ -1021,7 +1021,7 @@ @Misc{github:corels @Misc{github:rcppcorels, author = {Dirk Eddelbuettel}, title = {RcppCorels: R binding for the 'Certifiably Optimal RulE ListS (Corels)' Learner}, - howpublished = {\url{https://github.com/eddelbuettel/rcppcorels}}, + howpublished = {\url{https://github.com/corels/rcppcorels}}, month = 11, year = 2019 }