'unlockEnvironment'通过'Rcpp'而不是'inline'实现

Rap*_*ter 3 c c++ r inline rcpp

实际问题

有人可以让我开始我需要做什么来实现Rcpp中unlockEnvironment下面的代码?

背景

碰到这个职位,并根据与C语言代码试图温斯顿畅的解决方案在线.它有效,但我觉得我对内联或C/C++知之甚少(实际上没什么,都是真的知道我在做什么;-)

所以我认为这将是一个很好的机会,最终开始学习如何使用R作为C和C++的接口.而且我想我会跳上Rcpp火车这样做!

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
)
Run Code Online (Sandbox Code Playgroud)

重构错误

旁注:当我在/R我的包项目目录中以某种方式组织它时,我遇到了Winston代码的错误:

在大多数情况下使用S4方法,我试图将Winston的代码分解为.unlockEnvironment()我放入文件的标准R函数/R/.unlockEnvironment.r

然后我会给我的S4方法unlockEnvironment()/R/unlockEnvironment.r.env:environment然后签名的方法将简单地调用.unlockEnvironment(env = env).

设置这样的东西,我最终得到以下错误:

.Primitive(".Call")(,env)中的错误:作为符号地址传递的NULL值

如果我将代码放在/R/.unlockEnvironment.r相应方法的目录中/R/unlockEnvironment.r(因此每次unlockEnvironment()调用相应的方法时重新获取内联代码),一切都运行正常 - 但由于重复的重新获取,它的效率非常低.

所以我想这必须要么与C代码的编写方式有关,要么与使用内联时组织基于C的函数的方式有关?

Kev*_*hey 7

听起来你的问题基本上等于'我该如何使用Rcpp::attributes'?我建议您查看Rcpp Gallery中的许多示例以了解更多信息.

主要思想:编写一些C++代码,将其放入.cpp文件,然后调用Rcpp::sourceCpp(<file>)加载它.对于这个特例:

#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
*/
Run Code Online (Sandbox Code Playgroud)

调用Rcpp::sourceCpp()包含这些内容的文件可以让我:

> 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!
Run Code Online (Sandbox Code Playgroud)

这里的主要小功能:

  1. 您可以使用base/STL C++类型或Rcpp类型提供签名.请注意,这bool是C++ bool类型,并且Environment是包含环境的Rcpp类型.
  2. Rcpp Attributes处理这些C++返回类型到R的自动转换SEXP.

您可能也喜欢Hadley的adv-r介绍.