diff --git a/cpp11test/R/cpp11.R b/cpp11test/R/cpp11.R index 038e7b76..8703b3da 100644 --- a/cpp11test/R/cpp11.R +++ b/cpp11test/R/cpp11.R @@ -236,6 +236,14 @@ rcpp_push_and_truncate_ <- function(size_sxp) { .Call(`_cpp11test_rcpp_push_and_truncate_`, size_sxp) } +nullable_extptr_1 <- function() { + .Call(`_cpp11test_nullable_extptr_1`) +} + +nullable_extptr_2 <- function() { + .Call(`_cpp11test_nullable_extptr_2`) +} + test_destruction_inner <- function() { invisible(.Call(`_cpp11test_test_destruction_inner`)) } diff --git a/cpp11test/src/cpp11.cpp b/cpp11test/src/cpp11.cpp index 421de637..781825be 100644 --- a/cpp11test/src/cpp11.cpp +++ b/cpp11test/src/cpp11.cpp @@ -443,6 +443,20 @@ extern "C" SEXP _cpp11test_rcpp_push_and_truncate_(SEXP size_sxp) { return cpp11::as_sexp(rcpp_push_and_truncate_(cpp11::as_cpp>(size_sxp))); END_CPP11 } +// test-external_pointer.cpp +cpp11::external_pointer nullable_extptr_1(); +extern "C" SEXP _cpp11test_nullable_extptr_1() { + BEGIN_CPP11 + return cpp11::as_sexp(nullable_extptr_1()); + END_CPP11 +} +// test-external_pointer.cpp +cpp11::external_pointer nullable_extptr_2(); +extern "C" SEXP _cpp11test_nullable_extptr_2() { + BEGIN_CPP11 + return cpp11::as_sexp(nullable_extptr_2()); + END_CPP11 +} // test-protect-nested.cpp void test_destruction_inner(); extern "C" SEXP _cpp11test_test_destruction_inner() { @@ -500,6 +514,8 @@ static const R_CallMethodDef CallEntries[] = { {"_cpp11test_my_warning_n1", (DL_FUNC) &_cpp11test_my_warning_n1, 1}, {"_cpp11test_my_warning_n1fmt", (DL_FUNC) &_cpp11test_my_warning_n1fmt, 1}, {"_cpp11test_my_warning_n2fmt", (DL_FUNC) &_cpp11test_my_warning_n2fmt, 2}, + {"_cpp11test_nullable_extptr_1", (DL_FUNC) &_cpp11test_nullable_extptr_1, 0}, + {"_cpp11test_nullable_extptr_2", (DL_FUNC) &_cpp11test_nullable_extptr_2, 0}, {"_cpp11test_protect_many_", (DL_FUNC) &_cpp11test_protect_many_, 1}, {"_cpp11test_protect_many_cpp11_", (DL_FUNC) &_cpp11test_protect_many_cpp11_, 1}, {"_cpp11test_protect_many_preserve_", (DL_FUNC) &_cpp11test_protect_many_preserve_, 1}, diff --git a/cpp11test/src/test-external_pointer.cpp b/cpp11test/src/test-external_pointer.cpp index 897fd4f2..b8699ae0 100644 --- a/cpp11test/src/test-external_pointer.cpp +++ b/cpp11test/src/test-external_pointer.cpp @@ -10,6 +10,15 @@ void deleter(int* ptr) { delete ptr; } +// Pacha: Test nullable external_pointer (#312) +[[cpp11::register]] cpp11::external_pointer nullable_extptr_1() { + return cpp11::external_pointer(nullptr); +} + +[[cpp11::register]] cpp11::external_pointer nullable_extptr_2() { + return cpp11::external_pointer(R_NilValue); +} + context("external_pointer-C++") { test_that("external_pointer works") { std::vector* v = new std::vector; diff --git a/cpp11test/tests/testthat/test-external-pointer.R b/cpp11test/tests/testthat/test-external-pointer.R new file mode 100644 index 00000000..b82c6d80 --- /dev/null +++ b/cpp11test/tests/testthat/test-external-pointer.R @@ -0,0 +1,11 @@ +# Pacha: test that nullable external pointer is consistent (#312) +test_that("nullable external pointer is consistent", { + + len <- 1e5 + set.seed(42) + x <- rnorm(len) + sum_base <- sum(x) + + expect_equal(nullable_extptr_1(), NULL) + expect_equal(nullable_extptr_2(), NULL) +}) diff --git a/inst/include/cpp11/external_pointer.hpp b/inst/include/cpp11/external_pointer.hpp index a62134ec..fd785c6f 100644 --- a/inst/include/cpp11/external_pointer.hpp +++ b/inst/include/cpp11/external_pointer.hpp @@ -23,8 +23,9 @@ class external_pointer { sexp data_ = R_NilValue; static SEXP valid_type(SEXP data) { - if (data == nullptr) { - throw type_error(EXTPTRSXP, NILSXP); + // Pacha: Allow nullable external_pointer (#312) + if (data == R_NilValue) { + return data; } if (detail::r_typeof(data) != EXTPTRSXP) { throw type_error(EXTPTRSXP, detail::r_typeof(data)); @@ -120,7 +121,8 @@ class external_pointer { data_ = tmp; } - operator bool() noexcept { return data_ != nullptr; } + // Pacha: Support nullable external_pointer (#312) + operator bool() const noexcept { return data_ != R_NilValue; } }; template