c++ - 'unlockEnvironment' 通过 'Rcpp' 而不是 'inline' 实现

标签 c++ c r inline rcpp

真题

有人可以让我开始了解我需要做什么来实现下面 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!

这里的主要小功能:

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

您可能喜欢 Hadley 的 adv-r 还有介绍。

关于c++ - 'unlockEnvironment' 通过 'Rcpp' 而不是 'inline' 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25910778/

相关文章:

c++ - IDA PRO 将 C++ 代码转换为 C 代码 __OFSUB__ 宏

c++ - 带有 if 语句的嵌套 for 循环的时间复杂度

r - Shiny 的 fileInput 不保留文件名

c++ - 对 sprintf 可变参数使用一个指针

c++ - 如何重载/专门化模板类函数来处理算术类型和容器类

c - 使用popen的非阻塞管道?

c - useDynLib() 错误且compileAttributes 不返回任何内容 : embedding a C library into an R package

c++ - 在派生模板类中专门化方法形式基类

c++ - 链接对象和静态库

R安装包tabplot