The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

RcppXPtrUtils: XPtr Add-Ons for ‘Rcpp’

Build Status Coverage Status CRAN_Status_Badge Downloads

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.

Installation

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")

Use case

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'.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.