[Rcpp-devel] What is the best practice to expose a C structure from 3rd party library into R?
Wush Wu
wush978 at gmail.com
Mon Jul 22 10:12:54 CEST 2013
Hi all,
I wrote a wrapper of hiredis, which is a minimalistic C client for the
Redis database. Its name is `Rhiredis` and is much faster than rredis, an
existed redis client of R. Please see http://rpubs.com/wush978/rhiredis for
details.
Thanks for the Rcpp, it is much easier to wrap a C library into R and
extend the features of R.
However, I still want to know if there is a better approach. I tried three
approaches. Here is my opinions.
# Preliminary
Given a 3rd party C library, it usually provides a C structure and
functions of memory management. For example:
```c
struct A {
int flag;
// ...
};
A* initA();
void freeA(A* a);
```
The structure `A` need to be stored into a R object and pass to another
function.
Also, the user might need to access `A.flag`. For simplicity, there is only
one field in this example. However, there might be a number of fields in
practice.
# XPtr
Thanks for the user guide of Rcpp modules , this is the first approach I
tried.
We could expose `A` into R as follow:
```cpp
Rcpp::XPtr<A, freeA> a(initA());
```
However, we should write helper function to accessing `A.flag` for every
fields.
# RCPP_MODULE
The guids of Rcpp modules also provides another approach:
```cpp
RCPP_EXPOSED_CLASS(A)
RCPP_MODULE(A) {
class_<A>("A")
.field("flag", &A::flag)
;
}
//'@export
//[[Rcpp::export]]
SEXP init() {
BEGIN_RCPP
return wrap(*initA());
END_RCPP
}
```
This will produce a S4 class named `A` in R which stores C structure `A`.
However, it also produces memory leak because no `freeA` is called.
Adding `.finalizer(freeA)` in `RCPP_MODULE` will cause an error of freeing
memory twice.
# Embed `A` into C++ class and expose the class with RCPP_MODULE
This approach is implemented in `Rhiredis`.
Finally, I still need to write helper function to expose the field of `A`.
But the user could access these flag in R with operator `$`.
Note that I still need a function to extract the pointer of `A` from
exposed S4 object:
```cpp
template<class T>
T* extract_ptr(SEXP s) {
Rcpp::S4 s4(s);
Rcpp::Environment env(s4);
Rcpp::XPtr<T> xptr(env.get(".pointer"));
return static_cast<T*>(R_ExternalPtrAddr(xptr));
}
```
Please give me some suggestion if you know a better or a different approach.
Thanks.
Wush
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130722/6145122c/attachment-0001.html>
More information about the Rcpp-devel
mailing list