C++でのオブジェクトをRで使い回す

TokyoCabinetをRから使えるようなライブラリを書くとしたら、例えばこんな感じできる。

しかし、これだとgetやputをするたびにopen&closeしに行っているのでアホな感じである。TCHDBのポインタを使い回したいわけです。だが、Rでそれをどうやって使い回せるのか知らないorz。というわけで調べていたんだけど、全然分からなくってTwitterになげいていたら、@mokjpnさんと@R_Linuxさんに助けていただいた。ありがとうございます!!結論から言うと、Writing R ExtentionsのExternal pointers and weak referencesのところを見て解決した。日本語版のWriting R Extentionsとかには載ってない内容であった*1

小さめのサンプルだと、こんな感じでポインターをやりとりできる。

#include <iostream>
#include <R.h> 
#include <Rinternals.h>

class Hoge {
public:
  int n;
  Hoge(int i) {
	n = i + 100;
  };
};

extern "C" {
  SEXP Hoge_put(SEXP i) {
	Hoge* hoge = new Hoge(REAL(i)[0]);
	SEXP Rptr; 
	Rptr = R_MakeExternalPtr((void *)hoge, R_NilValue, R_NilValue); 
	return Rptr; 
  };
};

extern "C" {
  SEXP Hoge_get(SEXP Rptr) {
	Hoge* p = (Hoge*) R_ExternalPtrAddr(Rptr);
	std::cout << "n: " << p->n << std::endl;
	delete p;
	return R_NilValue;
  };
};

コンパイル。

/Users/syou6162/dummy_r_package% R CMD SHLIB hoge.cpp
g++ -arch i386 -I/Library/Frameworks/R.framework/Resources/include -I/Library/Frameworks/R.framework/Resources/include/i386  -I/usr/local/include    -fPIC  -g -O2 -c hoge.cpp -o hoge.o
g++ -arch i386 -dynamiclib -Wl,-headerpad_max_install_names -mmacosx-version-min=10.4 -undefined dynamic_lookup -single_module -multiply_defined suppress -L/usr/local/lib -o hoge.so hoge.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
ld warning: duplicate dylib /usr/local/lib/libgcc_s.1.dylib

実行するとポインターを経由してあれこれできるということが分かる。

> dyn.load("/Users/syou6162/dummy_r_package/hoge.so")
> (hoge <- .Call("Hoge_put", 200))
<pointer: 0x91edb0>
> .Call("Hoge_get", hoge)
n: 300
NULL

R_ExternalPtrAddrとかでぐぐっていると、useR!2009でのbigmemoryの発表とかが出てきて「ああ、そうだよな。。。」という感じになった*2。あれは使い回さないと無理ですよね。とりあえずこれでRのTokyoCabinetを叩けるのができそうである(簡単なのではあるが)。

*1:結構古いので

*2:あと、http://www.stats.ox.ac.uk/~ruth/RCourse/Rcourse94up.pdfとか。