Skip to content

Support nullable external_ptr<> (implement #312) #446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cpp11test/R/cpp11.R
Original file line number Diff line number Diff line change
Expand Up @@ -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`))
}
Expand Down
16 changes: 16 additions & 0 deletions cpp11test/src/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<cpp11::decay_t<SEXP>>(size_sxp)));
END_CPP11
}
// test-external_pointer.cpp
cpp11::external_pointer<int> 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<int> 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() {
Expand Down Expand Up @@ -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},
Expand Down
9 changes: 9 additions & 0 deletions cpp11test/src/test-external_pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ void deleter(int* ptr) {
delete ptr;
}

// Pacha: Test nullable external_pointer (#312)
[[cpp11::register]] cpp11::external_pointer<int> nullable_extptr_1() {
return cpp11::external_pointer<int>(nullptr);
}

[[cpp11::register]] cpp11::external_pointer<int> nullable_extptr_2() {
return cpp11::external_pointer<int>(R_NilValue);
}

context("external_pointer-C++") {
test_that("external_pointer works") {
std::vector<int>* v = new std::vector<int>;
Expand Down
11 changes: 11 additions & 0 deletions cpp11test/tests/testthat/test-external-pointer.R
Original file line number Diff line number Diff line change
@@ -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)
})
8 changes: 5 additions & 3 deletions inst/include/cpp11/external_pointer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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 <class T, void Deleter(T*)>
Expand Down
Loading