[Rcpp-devel] What is the best practice to expose a C st ructure from 3rd party library into R?

Dirk Eddelbuettel edd at debian.org
Mon Jul 22 13:57:56 CEST 2013


On 22 July 2013 at 13:19, romain at r-enthusiasts.com wrote:
| Le 2013-07-22 10:12, Wush Wu a écrit :
| > 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 [1] for details. 
| 
| Cool.

Seconded. I love redis (and rredis).
 
| > Thanks for the Rcpp, it is much easier to wrap a C library into R and
| > extend the features of R. 
| 
| Great. That's why we do it.

Yup.
 
| > 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);
| > ```

I always use a _class_ instead of a struct to ge a ctor and dtor.

For database connections, this is _very_ useful:  from the load function of
your package, initialise the class (keep maybe as a package-global singleton
which is a common C++ pattern), and then the structure is keep around as long
as the package is loaded. You db interactions from R can then use it.

| > 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.
| 
| Yes. And at the R level you deal with an external pointer. One usually 
| then have to maintain what they exactly mean in R.
| 
| > # 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.
| 
| Gotta look into why this happens.

I think we do have modules that work happily with finalizers. Hm.
 
| > # 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.
| 
| I would essentially do what you do: use RCPP_MODULE to expose a C++ 
| class so that the C++ class manages scoping : constructor, destructor, 
| etc ...
| 
| class A_cpp {
| public:
|      A_cpp( ) : obj( initA() ){}
|      ~A_cpp(){ freeA(obj); obj = NULL ; }
| 
|      int get_flag(){ return obj->flag ; }
|      void set_flag( int x ){ obj->flag = x ; }
| 
| private:
|      A* obj ;
| } ;

+1
 
| RCPP_MODULE(Whatever){
|      class_<A_cpp>( "A" )
|          .constructor()
|          .property( "flag", &A_cpp::get_flag, &A_cpp::set_flag )
|      ;
| }
| 
| Then in R:
| 
| a <- new( A )
| a$flag
| a$flag <- 12L
| a$flag
| 
| I would probably do some tricks with macros to avoid writing boiler 
| plate get_ and set_, something like this :
| 
| #define GET_SET(_type_,_name_)                  \
| _type_ get_##_name_(){ return obj->_name_ ; }   \
| void set_##_name_(_type_ x){ obj->_name_ = x ; }
| 
| so that you'd use:
| 
| GET_SET(int,flag)
| ...

When I wrapped database apis in the past, I knew I only need a small handful
of worker functions, so I just wrote the functions using plain old Rcpp. But
that was also before Modules.  Now I'd probably start with modules.

Dirk

 
| 
| With the devel version of Rcpp, you can use as to get hold of a 
| reference (or a const reference) of your object from the SEXP:
| 
| int get_flag( SEXP s4obj ){
|      A_cpp& obj = as<A_cpp&>( s4obj ) ;
|      return obj.get_flag() ;
| }
| 
| But you could also expose this simply as :
| 
| int get_flag( A_cpp& obj ){
|      return obj.get_flag() ;
| }
| 
| To have access to this "as", you have to declare some class traits, but 
| the RCPP_EXPOSED_CLASS can help you with this.
| Here is a working .cpp file that demonstrate all this.
| 
| #include <Rcpp.h>
| using namespace Rcpp ;
| 
| struct A{
|      int flag ;
| };
| 
| A* initA(){return new A() ; }
| void freeA(A* a){ delete a; }
| 
| #define GET_SET(_type_,_name_)                  \
| _type_ get_##_name_(){ return obj->_name_ ; }   \
| void set_##_name_(_type_ x){ obj->_name_ = x ; }
| 
| RCPP_EXPOSED_CLASS(A_cpp);
| class A_cpp {
| public:
|      A_cpp( ) : obj( initA() ){}
|      ~A_cpp(){ freeA(obj); obj = NULL ; }
| 
|      GET_SET(int,flag)
| 
| private:
|      A* obj ;
| } ;
| 
| int get_flag( SEXP s4obj ){
|      A_cpp& obj = as<A_cpp&>( s4obj ) ;
|      return obj.get_flag() ;
| }
| 
| RCPP_MODULE(Whatever){
|      class_<A_cpp>( "A" )
|          .constructor()
|          .property( "flag", &A_cpp::get_flag, &A_cpp::set_flag )
|      ;
|      function( "get_flag", &get_flag ) ;
| 
| }
| 
| 
| /*** R
| 
| a <- new( A )
| a$flag
| a$flag <- 12L
| a$flag
| get_flag( a )
| 
| ***/
| 
| I hope this clarifies a few things, or at least puts you on a good 
| track.
| 
| Let us know.
| 
| Romain
| 
| 
| 
| > Thanks.
| >
| > Wush
| >
| > Links:
| > ------
| > [1] http://rpubs.com/wush978/rhiredis
| _______________________________________________
| Rcpp-devel mailing list
| Rcpp-devel at lists.r-forge.r-project.org
| https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
-- 
Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com


More information about the Rcpp-devel mailing list