Could someone get me started on what I need to do to implement the code of unlockEnvironment
below in Rcpp?
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!
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
)
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?
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:
bool
is the C++ bool type, and Environment
is an Rcpp type encompassing environments.SEXP
.You might like Hadley's adv-r
introduction as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With