knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "README-" )
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); }
#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); } 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) )
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 checkXPtr(func_cpp, "SEXP", c("int", "double")) # returns silently checkXPtr(func_cpp, "int", c("int", "double")) checkXPtr(func_cpp, "SEXP", c("int")) checkXPtr(func_cpp, "SEXP", c("double", "int"))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.