diff --git a/NEWS.md b/NEWS.md index 17a55d2d..5b478b8a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,12 +1,13 @@ # cpp11 (development version) -* Fix memory leak when move constructing vectors (#173) -* Fix handling of spaces in Makevars include filenames (@klmr, #160) +* New `cpp11::na()` function to return the NA sentinals for R objects(@sbearrows, #179) +* Incorrectly formatted cpp11 decorators now output a more informative error message (@sbearrows, #127) +* Generated registration code now uses C collation to avoid spurious diffs from `tools::package_native_routine_registration_skeleton()` (@sbearrows, #171) +* Memory lo longer leaks when move constructing vectors (#173) +* Makevars which include filenames now handle spaces in paths properly (@klmr, #160) # cpp11 0.2.7 -* Outputting more informative error message when cpp11 decorators are incorrectly formatted (@sbearrows, #127) -* Fix spurious diffs from `tools::package_native_routine_registration_skeleton()` by temporarily using C collation (@sbearrows, #171) * Fix a transient memory leak for functions that return values from `cpp11::unwind_protect()` and `cpp11::safe` (#154) * `cpp_source()` now gets an argument `dir` to allow customized temporary directory to store generated source files. It makes it easier to debug C++ source files in non-package project via source mapping. (@renkun-ken, #156) diff --git a/cpp11test/src/cpp11.cpp b/cpp11test/src/cpp11.cpp index 7e426cd9..5e0365ff 100644 --- a/cpp11test/src/cpp11.cpp +++ b/cpp11test/src/cpp11.cpp @@ -352,16 +352,16 @@ extern SEXP _cpp11test_rcpp_sum_dbl_foreach_(SEXP); extern SEXP _cpp11test_rcpp_sum_int_for_(SEXP); extern SEXP _cpp11test_remove_altrep(SEXP); extern SEXP _cpp11test_row_sums(SEXP); -extern SEXP _cpp11test_sum_dbl_accumulate_(SEXP); extern SEXP _cpp11test_sum_dbl_accumulate2_(SEXP); -extern SEXP _cpp11test_sum_dbl_for_(SEXP); +extern SEXP _cpp11test_sum_dbl_accumulate_(SEXP); extern SEXP _cpp11test_sum_dbl_for2_(SEXP); extern SEXP _cpp11test_sum_dbl_for3_(SEXP); -extern SEXP _cpp11test_sum_dbl_foreach_(SEXP); +extern SEXP _cpp11test_sum_dbl_for_(SEXP); extern SEXP _cpp11test_sum_dbl_foreach2_(SEXP); +extern SEXP _cpp11test_sum_dbl_foreach_(SEXP); extern SEXP _cpp11test_sum_int_accumulate_(SEXP); -extern SEXP _cpp11test_sum_int_for_(SEXP); extern SEXP _cpp11test_sum_int_for2_(SEXP); +extern SEXP _cpp11test_sum_int_for_(SEXP); extern SEXP _cpp11test_sum_int_foreach_(SEXP); extern SEXP _cpp11test_upper_bound(SEXP, SEXP); extern SEXP run_testthat_tests(SEXP); @@ -398,16 +398,16 @@ static const R_CallMethodDef CallEntries[] = { {"_cpp11test_rcpp_sum_int_for_", (DL_FUNC) &_cpp11test_rcpp_sum_int_for_, 1}, {"_cpp11test_remove_altrep", (DL_FUNC) &_cpp11test_remove_altrep, 1}, {"_cpp11test_row_sums", (DL_FUNC) &_cpp11test_row_sums, 1}, - {"_cpp11test_sum_dbl_accumulate_", (DL_FUNC) &_cpp11test_sum_dbl_accumulate_, 1}, {"_cpp11test_sum_dbl_accumulate2_", (DL_FUNC) &_cpp11test_sum_dbl_accumulate2_, 1}, - {"_cpp11test_sum_dbl_for_", (DL_FUNC) &_cpp11test_sum_dbl_for_, 1}, + {"_cpp11test_sum_dbl_accumulate_", (DL_FUNC) &_cpp11test_sum_dbl_accumulate_, 1}, {"_cpp11test_sum_dbl_for2_", (DL_FUNC) &_cpp11test_sum_dbl_for2_, 1}, {"_cpp11test_sum_dbl_for3_", (DL_FUNC) &_cpp11test_sum_dbl_for3_, 1}, - {"_cpp11test_sum_dbl_foreach_", (DL_FUNC) &_cpp11test_sum_dbl_foreach_, 1}, + {"_cpp11test_sum_dbl_for_", (DL_FUNC) &_cpp11test_sum_dbl_for_, 1}, {"_cpp11test_sum_dbl_foreach2_", (DL_FUNC) &_cpp11test_sum_dbl_foreach2_, 1}, + {"_cpp11test_sum_dbl_foreach_", (DL_FUNC) &_cpp11test_sum_dbl_foreach_, 1}, {"_cpp11test_sum_int_accumulate_", (DL_FUNC) &_cpp11test_sum_int_accumulate_, 1}, - {"_cpp11test_sum_int_for_", (DL_FUNC) &_cpp11test_sum_int_for_, 1}, {"_cpp11test_sum_int_for2_", (DL_FUNC) &_cpp11test_sum_int_for2_, 1}, + {"_cpp11test_sum_int_for_", (DL_FUNC) &_cpp11test_sum_int_for_, 1}, {"_cpp11test_sum_int_foreach_", (DL_FUNC) &_cpp11test_sum_int_foreach_, 1}, {"_cpp11test_upper_bound", (DL_FUNC) &_cpp11test_upper_bound, 2}, {"run_testthat_tests", (DL_FUNC) &run_testthat_tests, 1}, diff --git a/cpp11test/src/test-list.cpp b/cpp11test/src/test-list.cpp index d856e8b8..73cac5ca 100644 --- a/cpp11test/src/test-list.cpp +++ b/cpp11test/src/test-list.cpp @@ -6,10 +6,6 @@ #include "cpp11/raws.hpp" #include "cpp11/strings.hpp" -namespace cpp11 { -std::ostream& operator<<(std::ostream& os, r_bool b) { return os << int(b); } -} // namespace cpp11 - context("list-C++") { test_that("list.push_back()") { cpp11::writable::list x; diff --git a/cpp11test/src/test-nas.cpp b/cpp11test/src/test-nas.cpp new file mode 100644 index 00000000..234a0c5a --- /dev/null +++ b/cpp11test/src/test-nas.cpp @@ -0,0 +1,12 @@ +#include +#include "cpp11/doubles.hpp" +#include "cpp11/integers.hpp" +#include "cpp11/r_bool.hpp" +#include "cpp11/r_string.hpp" + +context("nas-C++") { + test_that("na integer") { expect_true(cpp11::na() == NA_INTEGER); } + test_that("na double") { expect_true(ISNA(cpp11::na())); } + test_that("na bool") { expect_true(cpp11::na() == NA_LOGICAL); } + test_that("na string") { expect_true(cpp11::na() == NA_STRING); } +} diff --git a/inst/include/cpp11/R.hpp b/inst/include/cpp11/R.hpp index 98274a2c..463256d3 100644 --- a/inst/include/cpp11/R.hpp +++ b/inst/include/cpp11/R.hpp @@ -32,4 +32,13 @@ namespace literals { constexpr R_xlen_t operator"" _xl(unsigned long long int value) { return value; } } // namespace literals + +template +inline T na(); + +template +inline bool is_na(const T& value) { + return value == na(); +} + } // namespace cpp11 diff --git a/inst/include/cpp11/doubles.hpp b/inst/include/cpp11/doubles.hpp index abfea8b2..2d5ea9f2 100644 --- a/inst/include/cpp11/doubles.hpp +++ b/inst/include/cpp11/doubles.hpp @@ -11,6 +11,7 @@ #include "cpp11/protect.hpp" // for SEXP, SEXPREC, REAL_ELT, R_Preserve... #include "cpp11/r_vector.hpp" // for vector, vector<>::proxy, vector<>::... #include "cpp11/sexp.hpp" // for sexp + // Specializations for doubles namespace cpp11 { @@ -130,5 +131,13 @@ typedef r_vector doubles; } // namespace writable -inline bool is_na(double x) { return ISNA(x); } +template <> +inline double na() { + return NA_REAL; +} + +template <> +inline bool is_na(const double& x) { + return ISNA(x); +} } // namespace cpp11 diff --git a/inst/include/cpp11/integers.hpp b/inst/include/cpp11/integers.hpp index f922ddd0..b063984d 100644 --- a/inst/include/cpp11/integers.hpp +++ b/inst/include/cpp11/integers.hpp @@ -136,5 +136,9 @@ typedef r_vector integers; } // namespace writable -inline bool is_na(int x) { return x == NA_INTEGER; } +template <> +inline int na() { + return NA_INTEGER; +} + } // namespace cpp11 diff --git a/inst/include/cpp11/r_bool.hpp b/inst/include/cpp11/r_bool.hpp index 5087d307..a76a550d 100644 --- a/inst/include/cpp11/r_bool.hpp +++ b/inst/include/cpp11/r_bool.hpp @@ -1,13 +1,15 @@ #pragma once -#include // for numeric_limits +#include // for numeric_limits +#include #include // for is_convertible, enable_if #include "R_ext/Boolean.h" // for Rboolean #include "cpp11/R.hpp" // for SEXP, SEXPREC, ... #include "cpp11/as.hpp" // for as_sexp #include "cpp11/protect.hpp" // for unwind_protect, preserved -#include "cpp11/sexp.hpp" // for sexp +#include "cpp11/r_vector.hpp" +#include "cpp11/sexp.hpp" // for sexp namespace cpp11 { @@ -49,7 +51,10 @@ class r_bool { int value_ = na; }; -inline bool is_na(r_bool x) { return x == r_bool(); } +inline std::ostream& operator<<(std::ostream& os, r_bool const& value) { + os << ((value == TRUE) ? "TRUE" : "FALSE"); + return os; +} template using enable_if_r_bool = enable_if_t::value, R>; @@ -61,4 +66,9 @@ enable_if_r_bool as_sexp(T from) { return res; } +template <> +inline r_bool na() { + return NA_LOGICAL; +} + } // namespace cpp11 diff --git a/inst/include/cpp11/r_string.hpp b/inst/include/cpp11/r_string.hpp index fb228b0b..93c589a7 100644 --- a/inst/include/cpp11/r_string.hpp +++ b/inst/include/cpp11/r_string.hpp @@ -8,6 +8,7 @@ #include "cpp11/as.hpp" // for as_sexp #include "cpp11/protect.hpp" // for unwind_protect, protect, protect::function #include "cpp11/sexp.hpp" // for sexp + namespace cpp11 { class r_string { @@ -67,8 +68,6 @@ inline SEXP as_sexp(std::initializer_list il) { return data; } -inline bool is_na(const r_string& x) { return x == NA_STRING; } - template using enable_if_r_string = enable_if_t::value, R>; @@ -88,4 +87,10 @@ enable_if_r_string as_sexp(T from) { return res; } + +template <> +inline r_string na() { + return NA_STRING; +} + } // namespace cpp11