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とか。