The RcppXPtrUtils package provides the means to compile user-supplied C++ functions with ‘Rcpp’ and retrieve an XPtr that can be passed to other C++ components.
Install the release version from CRAN:
install.packages("RcppXPtrUtils")
The installation from GitHub can be done with the remotes package:
remotes::install_github("Enchufa2/RcppXPtrUtils")
Let’s suppose we have a package with a core written in C++, connected to
an R API with Rcpp
. It accepts a user-supplied R function to perform
some processing:
#include <Rcpp.h>
using namespace Rcpp;
template <typename T>
NumericVector core_processing(T func, double l) {
double accum = 0;
for (int i=0; i<1e3; i++)
accum += sum(as<NumericVector>(func(3, l)));
return NumericVector(1, accum);
}
// [[Rcpp::export]]
NumericVector execute_r(Function func, double l) {
return core_processing<Function>(func, l);
}
But calling R from C++ is slow, so we can think about improving the
performance by accepting a compiled function. In order to do this, the
core can be easily extended to accept an XPtr
to a compiled function:
typedef SEXP (*funcPtr)(int, double);
// [[Rcpp::export]]
NumericVector execute_cpp(SEXP func_, double l) {
funcPtr func = *XPtr<funcPtr>(func_);
return core_processing<funcPtr>(func, l);
}
To easily leverage this feature, the RcppXPtrUtils
package provides
cppXPtr()
, which compiles a user-supplied C++ function using
Rcpp::cppFunction()
and returns an XPtr
:
# compile the code above
# Rcpp::sourceCpp(code='...')
library(RcppXPtrUtils)
func_r <- function(n, l) rexp(n, l)
func_cpp <- cppXPtr("SEXP foo(int n, double l) { return rexp(n, l); }")
microbenchmark::microbenchmark(
execute_r(func_r, 1.5),
execute_cpp(func_cpp, 1.5)
)
#> Unit: microseconds
#> expr min lq mean median uq
#> execute_r(func_r, 1.5) 14910.161 16261.928 17628.8078 17468.1140 18635.388
#> execute_cpp(func_cpp, 1.5) 213.123 223.125 310.2708 237.0265 279.808
#> max neval cld
#> 22657.568 100 b
#> 2417.878 100 a
The object returned by cppXPtr()
is just an externalptr
wrapped into
an object of class XPtr
, which stores the signature of the function.
If you are a package author, you probably want to re-export cppXPtr()
and ensure that user-supplied C++ functions comply with the internal
signatures in order to avoid runtime errors. This can be done with the
checkXPtr()
function:
func_cpp
#> 'SEXP foo(int n, double l)' <pointer: 0x55909eb28830>
checkXPtr(func_cpp, "SEXP", c("int", "double")) # returns silently
checkXPtr(func_cpp, "int", c("int", "double"))
#> Error in checkXPtr(func_cpp, "int", c("int", "double")): Bad XPtr signature:
#> Wrong return type 'int', should be 'SEXP'.
checkXPtr(func_cpp, "SEXP", c("int"))
#> Error in checkXPtr(func_cpp, "SEXP", c("int")): Bad XPtr signature:
#> Wrong number of arguments, should be 2'.
checkXPtr(func_cpp, "SEXP", c("double", "int"))
#> Error in checkXPtr(func_cpp, "SEXP", c("double", "int")): Bad XPtr signature:
#> Wrong argument type 'double', should be 'int'.
#> Wrong argument type 'int', should be 'double'.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.