Rcpp11
Romain François
romain@r-enthusiasts.com @romain_francois
R
Rcpp
Rcpp11
• C++ = C++11
• Smaller code base (than Rcpp)
• Header only
#include <Rcpp.h>
!
// [[Rcpp::export]]
int foo(){
return 2 ;
}
Rcpp
Rcpp11
0 1 2 3 4
Less code -> faster compiles
!
Interface simplification
NumericVector constructors
Vector() {
Vector( const Vector& other){
Vector( SEXP x ) {
!
Vector( const GenericProxy<Proxy>...
NumericVector constructors
11 constructors in Rcpp
Vector(){
Vector( const Vector& other){
Vector( Vector&& other){
!
expl...
NumericVector constructors
Vector( const int& siz, stored_type (*gen)(U1), const U1& u1) -> replicate
double fun( int powe...
NumericVector constructors
std::vector<double> v = /* ... */ ;
!
// Rcpp
NumericVector x(v.begin(), v.end()) ;
// Rcpp11
N...
Some examples
NumericVector ctors
// C++ uniform initialization
NumericVector x = {1.0, 2.0, 3.0} ;
!
// init with given size
NumericVec...
create
// old school NumericVector::create (Rcpp style).
NumericVector x = NumericVector::create(1.0, 2.0, 3.0) ;
NumericV...
sapply + lambda
sapply + lambda
#include <Rcpp11>
!
// [[export]]
NumericVector foo( NumericVector x ){
return sapply(x, [](double d){
ret...
Rcpp11 release cycle
• Available from CRAN:
!
• Evolves quickly. Get it from github
!
• Next Release: 3.1.1 (same time as ...
attributes companion package
• Standalone impl of Rcpp attributes
[[Rcpp::export]], sourceCpp, compileAttributes
!
• Only ...
Use Rcpp11 in your package
• Write your .cpp files
#include <Rcpp11>
!
// [[export]]
void foo( … ) { … } // your code
Syste...
Header only
• No runtime dependency
!
• Snapshot the code base
!
• Better control for package authors
error handling
C level try/catch
Internal C level try catch
• Problem: evaluate an R call that might error (long jump)
!
• Rcpp solution: wrap the call in ...
Internal C level try catch
SEXP res ;
try_catch( [&](){
// some unsafe C code that might JUMP
res = Rf_eval(expr, env) ;
}...
Internal C level try catch
/* R_ToplevelExec - call fun(data) within a top level context to
insure that this functin canno...
Internal C level try catch
template <typename Fun>
void try_catch( Fun fun ) {
typedef std::pair<Fun*, SEXP&> Pair ;
!
SEX...
Internal C level try catch
template <typename Fun>
void try_catch_helper( void* data ){
typedef std::pair<Fun*, SEXP&> Pai...
Internal C level try catch
SEXP res ;
try_catch( [&](){
// some unsafe C code that might JUMP
res = Rf_eval(expr, env) ;
}...
Internal C level try catch
• Problem: evaluate an R call that might error
• Rcpp solution: wrap the call in R's tryCatch
•...
R_PreserveObject
R_ReleaseObject
/* This code keeps a list of objects which are not assigned to variables
but which are required to persist across garbage ...
Romain François
romain@r-enthusiasts.com @romain_francois
Questions ?
Rcpp11
Upcoming SlideShare
Loading in …5
×

Rcpp11

1,279 views

Published on

Rcpp11 talk at DSC 2014

Published in: Software, Technology, Business
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,279
On SlideShare
0
From Embeds
0
Number of Embeds
51
Actions
Shares
0
Downloads
12
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Rcpp11

  1. 1. Rcpp11 Romain François romain@r-enthusiasts.com @romain_francois
  2. 2. R
  3. 3. Rcpp
  4. 4. Rcpp11 • C++ = C++11 • Smaller code base (than Rcpp) • Header only
  5. 5. #include <Rcpp.h> ! // [[Rcpp::export]] int foo(){ return 2 ; } Rcpp Rcpp11 0 1 2 3 4 Less code -> faster compiles
  6. 6. ! Interface simplification
  7. 7. NumericVector constructors Vector() { Vector( const Vector& other){ Vector( SEXP x ) { ! Vector( const GenericProxy<Proxy>& proxy ){ explicit Vector( const no_init& obj) { Vector( const int& size, const stored_type& u ) { Vector( const std::string& st ){ Vector( const char* st ) { Vector( const int& siz, stored_type (*gen)(void) ) { Vector( const int& size ) { Vector( const Dimension& dims) { Vector( const Dimension& dims, const U& u) { Vector( const VectorBase<RTYPE,NA,VEC>& other ) { Vector( const int& size, const U& u) { Vector( const sugar::SingleLogicalResult<NA,T>& obj ) { Vector( const int& siz, stored_type (*gen)(U1), const U1& u1) { Vector( const int& siz, stored_type (*gen)(U1,U2), const U1& u1, const U2& u2) { Vector( const int& siz, stored_type (*gen)(U1,U2,U3), const U1& u1, const U2& u2, const U3& u3) { Vector( InputIterator first, InputIterator last){ Vector( InputIterator first, InputIterator last, int n) { Vector( InputIterator first, InputIterator last, Func func) { Vector( InputIterator first, InputIterator last, Func func, int n){ Vector( std::initializer_list<init_type> list ) { 23 constructors in Rcpp
  8. 8. NumericVector constructors 11 constructors in Rcpp Vector(){ Vector( const Vector& other){ Vector( Vector&& other){ ! explicit Vector(int n) { explicit Vector(R_xlen_t n) { ! Vector( R_xlen_t n, value_type x ) { Vector( std::initializer_list<value_type> list ){ Vector( std::initializer_list<traits::named_object<value_type>> list ){ ! Vector( const SugarVectorExpression<eT, Expr>& other ) { Vector( const LazyVector<RT,Expr>& other ) { Vector( const GenericProxy<Proxy>& proxy ){
  9. 9. NumericVector constructors Vector( const int& siz, stored_type (*gen)(U1), const U1& u1) -> replicate double fun( int power ){ return pow(2.0, power) ; } ! // Rcpp NumericVector x(10, fun, 10.0) ; // Rcpp11 NumericVector x = replicate(10, fun, 10.0) ;
  10. 10. NumericVector constructors std::vector<double> v = /* ... */ ; ! // Rcpp NumericVector x(v.begin(), v.end()) ; // Rcpp11 NumericVector x = import(begin(v), end(v)) ; NumericVector x = import(v) ; Vector( InputIterator first, InputIterator last) -> import
  11. 11. Some examples
  12. 12. NumericVector ctors // C++ uniform initialization NumericVector x = {1.0, 2.0, 3.0} ; ! // init with given size NumericVector y( 2 ) ; // data is not initialized NumericVector y( 2, 3.0 ) ; // initialize all to 3.0 ! // fuse several vectors (similar to c in R) NumericVector z = fuse(x, y) ; NumericVector z = fuse(x, y, 3.0) ;
  13. 13. create // old school NumericVector::create (Rcpp style). NumericVector x = NumericVector::create(1.0, 2.0, 3.0) ; NumericVector x = NumericVector::create( _["a"] = 1.0, _["b"] = 2.0, _["c"] = 3.0 ) ; ! ! // create as a free function. Rcpp11 style NumericVector x = create(1.0, 2.0, 3.0) ; NumericVector x = create( _["a"] = 1.0, _["b"] = 2.0, _["c"] = 3.0 ) ;
  14. 14. sapply + lambda
  15. 15. sapply + lambda #include <Rcpp11> ! // [[export]] NumericVector foo( NumericVector x ){ return sapply(x, [](double d){ return exp(d * 2) ; }); } x <- 1:3 sapply( x, function(d){ exp(d*2) ; })
  16. 16. Rcpp11 release cycle • Available from CRAN: ! • Evolves quickly. Get it from github ! • Next Release: 3.1.1 (same time as R 3.1.1) > install.packages( "Rcpp11" ) > install_github( "Rcpp11/Rcpp11" )
  17. 17. attributes companion package • Standalone impl of Rcpp attributes [[Rcpp::export]], sourceCpp, compileAttributes ! • Only available from github: > install_github( "Rcpp11/attributes" )
  18. 18. Use Rcpp11 in your package • Write your .cpp files #include <Rcpp11> ! // [[export]] void foo( … ) { … } // your code SystemRequirements: C++11 LinkingTo: Rcpp11 library(attributes) compileAttributes( "mypkg" ) • Express dep on C++11 and Rcpp11 headers • Generate the boiler plate
  19. 19. Header only • No runtime dependency ! • Snapshot the code base ! • Better control for package authors
  20. 20. error handling C level try/catch
  21. 21. Internal C level try catch • Problem: evaluate an R call that might error (long jump) ! • Rcpp solution: wrap the call in R's tryCatch ! • Rcpp11 hack solution: • Leverage R_ToplevelExec / mess with the context • New problem. R_ToplevelExec expectations
  22. 22. Internal C level try catch SEXP res ; try_catch( [&](){ // some unsafe C code that might JUMP res = Rf_eval(expr, env) ; }) ; return res ;
  23. 23. Internal C level try catch /* R_ToplevelExec - call fun(data) within a top level context to insure that this functin cannot be left by a LONGJMP. R errors in the call to fun will result in a jump to top level. The return value is TRUE if fun returns normally, FALSE if it results in a jump to top level. */ ! Rboolean R_ToplevelExec(void (*fun)(void *), void *data) pointer to a function taking data as void* Data
  24. 24. Internal C level try catch template <typename Fun> void try_catch( Fun fun ) { typedef std::pair<Fun*, SEXP&> Pair ; ! SEXP return_value ; ! Pair pair = std::make_pair(&fun, std::ref(return_value)) ; ! bool ok = R_ToplevelExec( &internal::try_catch_helper<Fun>, &pair ) ; ! if( !ok ){ ! SEXP condition = VECTOR_ELT(return_value,0) ; ! if( Rf_isNull(condition) ){ stop("eval error : %s", R_curErrorBuf()) ; } else { Shield<SEXP> msg = Rf_eval( Rf_lang2( Rf_install( "conditionMessage"), condition ), R_GlobalEnv ) ; stop("eval error : %s", CHAR(STRING_ELT(msg, 0)) ) ; } } } The function templated by the real function to call Data, also parameterise by Fun
  25. 25. Internal C level try catch template <typename Fun> void try_catch_helper( void* data ){ typedef std::pair<Fun*, SEXP&> Pair ; Pair* pair = reinterpret_cast<Pair*>(data) ; RCNTXT* ctx = (RCNTXT*) R_GlobalContext ; ctx->callflag = CTXT_FUNCTION ; // first call to .addCondHands to add a handler SEXP args = pairlist( Rf_mkString("error"), Rf_allocVector(VECSXP,1), ctx->cloenv, ctx->cloenv, R_FalseValue ) ; SEXP symb = Rf_install(".addCondHands") ; SEXP ifun = INTERNAL( symb ) ; PRIMFUN(ifun)(symb, ifun, args, R_GlobalEnv ); // call it a second time to get the current R_HandlerStack CAR(args) = R_NilValue ; SEXP value = PRIMFUN(ifun)(symb, ifun, args, R_GlobalEnv ) ; pair->second = VECTOR_ELT(CAR(value),4) ; Fun& fun = *reinterpret_cast<Fun*>(pair->first) ; fun() ; } the actual function passed to R_ToplevelExec hack the contexts Finally calling the real function
  26. 26. Internal C level try catch SEXP res ; try_catch( [&](){ // some unsafe C code that might JUMP res = Rf_eval(expr, env) ; }) ; return res ; Nice syntax : Better performance than Rcpp's solution Rcpp Rcpp11 0 1 2 3 4 5 6 7 8 9 10 11 12 overhead of safely calling a function (microseconds)
  27. 27. Internal C level try catch • Problem: evaluate an R call that might error • Rcpp solution: wrap the call in R's tryCatch • Rcpp11 hack: leverage R_ToplevelExec / mess with the context • Question: Can you help ? Please.
  28. 28. R_PreserveObject R_ReleaseObject
  29. 29. /* This code keeps a list of objects which are not assigned to variables but which are required to persist across garbage collections. The objects are registered with R_PreserveObject and deregistered with R_ReleaseObject. */ ! void R_PreserveObject(SEXP object) { R_PreciousList = CONS(object, R_PreciousList); } ! static SEXP RecursiveRelease(SEXP object, SEXP list) { if (!isNull(list)) { if (object == CAR(list)) return CDR(list); else CDR(list) = RecursiveRelease(object, CDR(list)); } return list; } ! void R_ReleaseObject(SEXP object) { R_PreciousList = RecursiveRelease(object, R_PreciousList); } ! R_PreserveObject / R_ReleaseObject
  30. 30. Romain François romain@r-enthusiasts.com @romain_francois Questions ?

×