Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'unlockEnvironment' implemented via 'Rcpp' instead of 'inline'

Tags:

c++

c

r

inline

rcpp

Actual question

Could someone get me started on what I need to do to implement the code of unlockEnvironment below in Rcpp?

Background

Came across this post and tried Winston Chang's solution based on C code with inline. It works, but I have the feeling I know too little (practically nothing, that is) about either inline or C/C++ to really know what I'm doing ;-)

So I thought this would be a great opportunity to finally start learning on how to use R as an interface to C and C++. And I think I'd like to hopp on the Rcpp train for doing so!

The code from Winston's Gist

require("inline")

inc <- '
/* This is taken from envir.c in the R 2.15.1 source
https://github.com/SurajGupta/r-source/blob/master/src/main/envir.c
*/
#define FRAME_LOCK_MASK (1<<14)
#define FRAME_IS_LOCKED(e) (ENVFLAGS(e) & FRAME_LOCK_MASK)
#define UNLOCK_FRAME(e) SET_ENVFLAGS(e, ENVFLAGS(e) & (~ FRAME_LOCK_MASK))
'
src <- '
if (TYPEOF(env) == NILSXP)
error("use of NULL environment is defunct");
if (TYPEOF(env) != ENVSXP)
error("not an environment");

UNLOCK_FRAME(env);

// Return TRUE if unlocked; FALSE otherwise
SEXP result = PROTECT( Rf_allocVector(LGLSXP, 1) );
LOGICAL(result)[0] = FRAME_IS_LOCKED(env) == 0;
UNPROTECT(1);

return result;
'
unlockEnvironment <- inline::cfunction(
  signature(env = "environment"),
  includes = inc,
  body = src
)

Refactoring error

On a side note: I ran into an error with Winston's code when I organize it in a certain way in the /R directory of my package project:

Using S4 methods most of the time, I tried to factor Winston's code out into a standard R function .unlockEnvironment() that I put into the file /R/.unlockEnvironment.r

I then would create my S4 methods for unlockEnvironment() in /R/unlockEnvironment.r. The method with signature env:environment would then simply call .unlockEnvironment(env = env).

Setting up things that way, I end up with the following error:

Error in .Primitive(".Call")(, env) : NULL value passed as symbol address

If I put the code in /R/.unlockEnvironment.r directory with in the respective method in /R/unlockEnvironment.r (thus re-sourcing the inline code each time the respective method of unlockEnvironment() is called), everything works just fine - but it's very inefficient because of the repeated re-sourcing.

So I guess this must have either something to do with the way the C code is written or with the way you need to organize your C-based functions when using inline?

like image 908
Rappster Avatar asked Feb 12 '23 00:02

Rappster


1 Answers

It sounds like your question basically amounts to, 'how do I use Rcpp::attributes'? And I would suggest that you go over many of the examples in the Rcpp Gallery to learn a bit more.

The main idea: write some C++ code, put it a .cpp file, then call Rcpp::sourceCpp(<file>) to load it. For this particular example:

#include <Rcpp.h>
using namespace Rcpp;

/* This is taken from envir.c in the R 2.15.1 source
https://github.com/SurajGupta/r-source/blob/master/src/main/envir.c
*/
#define FRAME_LOCK_MASK (1<<14)
#define FRAME_IS_LOCKED(e) (ENVFLAGS(e) & FRAME_LOCK_MASK)
#define UNLOCK_FRAME(e) SET_ENVFLAGS(e, ENVFLAGS(e) & (~ FRAME_LOCK_MASK))

// [[Rcpp::export]]
bool unlock_environment(Environment env) {
  UNLOCK_FRAME(env);
  return FRAME_IS_LOCKED(env) == 0;
}

/*** R
env <- new.env()
lockEnvironment(env)
try(env$a <- 1) ## error
unlock_environment(env)
env$a <- 1
*/

Calling Rcpp::sourceCpp() on a file with these contents gives me:

> Rcpp::sourceCpp('~/scratch/unlock.cpp')

> env <- new.env()

> lockEnvironment(env)

> try(env$a <- 1) ## error
Error in env$a <- 1 : cannot add bindings to a locked environment

> unlock_environment(env)
[1] TRUE

> env$a <- 1 ## success!

The main little features here:

  1. You can provide signatures using base / STL C++ types, or Rcpp types as well. Note that bool is the C++ bool type, and Environment is an Rcpp type encompassing environments.
  2. Rcpp Attributes handles automatic conversion of these C++ return types to R's SEXP.

You might like Hadley's adv-r introduction as well.

like image 188
Kevin Ushey Avatar answered Feb 14 '23 15:02

Kevin Ushey