‘unlockEnvironment’通过’Rcpp’而不是’inline’实现
实际问题
有人可以让我开始我需要做什么来实现unlockEnvironment
下面的unlockEnvironment代码?
背景
看过这篇文章 ,尝试了基于C代码的Winston Chang的解决方案。 它有效,但我觉得我知道太少(实际上没什么,都是)关于内联或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 )
重构错误
旁注:当我在我的包项目的/R
目录中以某种方式组织它时,我遇到了Winston代码的错误:
在大多数情况下使用S4方法,我试图将Winston的代码分解为我放入文件/R/.unlockEnvironment.r
R / .unlockEnvironment()
的标准R函数.unlockEnvironment()
然后,我将在/R/unlockEnvironment.r
为unlockEnvironment()
创建我的S4方法。 具有签名env:environment
的方法将简单地调用.unlockEnvironment(env = env)
。
以这种方式设置东西,我最终得到以下错误:
.Primitive(“。Call”)(,env)中的错误:作为符号地址传递的NULL值
如果我将/R/.unlockEnvironment.r
目录中的代码放在/R/.unlockEnvironment.r
中的相应方法中(因此每次调用unlockEnvironment()
的相应方法时重新获取内联代码),一切正常很好 – 但由于反复重新采购,效率非常低。
所以我想这必须要么与C代码的编写方式有关,要么与使用内联时组织基于C的函数的方式有关?
听起来你的问题基本上等于’我如何使用Rcpp::attributes
‘? 我建议您回顾一下Rcpp Gallery中的许多示例,以了解更多信息。
主要思路:编写一些C ++代码,将其放入.cpp
文件,然后调用Rcpp::sourceCpp(
加载它。 对于这个特例:
#include 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!
这里的主要小function:
- 您可以使用base / STL C ++类型或Rcpp类型提供签名。 请注意,
bool
是C ++ bool类型,而Environment
是包含环境的Rcpp类型。 - Rcpp Attributes处理这些C ++返回类型到R的
SEXP
自动转换。
您可能也喜欢Hadley的推荐。