真题
有人可以让我开始了解我需要做什么来实现下面 Rcpp 中的 unlockEnvironment
代码吗? ?
背景
遇到这个post并使用 inline 尝试了 Winston Chang 基于 C 代码的解决方案.它有效,但我觉得我对内联或 C/C++ 知之甚少(几乎一无所知),无法真正了解我在做什么 ;-)
所以我认为这将是一个很好的机会,可以最终开始学习如何使用 R 作为 C 和 C++ 的接口(interface)。我想我想跳上 Rcpp训练这样做!
Winston 的代码 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
)
重构错误
附带说明:当我在我的包项目的 /R
目录中以某种方式组织 Winston 的代码时,我遇到了错误:
大部分时间使用 S4 方法,我试图将 Winston 的代码分解为标准 R 函数 .unlockEnvironment()
,我将其放入文件 /R/.unlockEnvironment.r
然后我会在 /R/unlockEnvironment.r
中为 unlockEnvironment()
创建我的 S4 方法。具有签名 env:environment
的方法随后将简单地调用 .unlockEnvironment(env = env)
。
以这种方式设置,我最终遇到以下错误:
Error in .Primitive(".Call")(, env) : NULL value passed as symbol address
如果我将代码放在 /R/.unlockEnvironment.r
目录中,并将其放在 /R/unlockEnvironment.r
中的相应方法中(从而重新获取内联每次调用 unlockEnvironment()
的相应方法时都会编写代码),一切正常 - 但由于重复资源,效率非常低。
所以我想这一定与 C 代码的编写方式有关,或者与您在使用 inline 时需要组织基于 C 的函数的方式有关。 ?
最佳答案
听起来你的问题基本上是,'我如何使用 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
*/
调用 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!
这里的主要小功能:
- 您可以使用基本/STL C++ 类型或 Rcpp 类型提供签名。注意
bool
是 C++ bool 类型,Environment
是包含环境的 Rcpp 类型。 - Rcpp 属性处理这些 C++ 返回类型到 R 的
SEXP
的自动转换.
您可能喜欢 Hadley 的 adv-r
还有介绍。
关于c++ - 'unlockEnvironment' 通过 'Rcpp' 而不是 'inline' 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25910778/