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

Wush Wu wush978 at gmail.com
Tue Jul 23 18:05:11 CEST 2013


By the way, maybe you should look two files in `inst`.

The `gen_function.R` crawls http://redis.io/commands and generates the
command according to the official redis manual. You could modify
`template.R` to generate the helper functions dynamically based on the
exposed Rcpp function.

Hope it helps.

I may do something like that tomorrow evening.
>
> For now, I did something _much_ simpler still.   We need single C++ source
> file.  Some key features:
>
> -- no more Boost shared_ptr
> -- no more Rcpp::XPtr
> -- "empty" constructor and destructor, nothing to be done
> -- no member variables
> -- one worker function which takes string (with a redis command), runs it
>    and returns the result string
> -- the worker function checks if the redis context pointer is non-NULL; in
>    case it is NULL (eg first use) it creates a context
>
>
> -----------------------------------------------------------------------------
>
> #include <Rcpp.h>
> #include <hiredis/hiredis.h>    // on Ubuntu file
> /usr/include/hiredis/hiredis.h
>
> // We use a static pointer which makes the variable persistent across calls
> // A more formal C++ idiom would be a singleton class, but this is simpler
> static redisContext *prc = NULL;
>
>
> // A simple and lightweight class -- without member variables
> // We could add some member variables to cache the last call, status, ...
> //
> class Redis {
>
> private:
>     void checkAndInit() {
>         if (prc == NULL) {
>             prc = redisConnect("127.0.0.1", 6379);
>             // should test for error here, could even throw() under Rcpp,
> ...
>             Rcpp::Rcout << "Context created\n";
>         } else {
>             Rcpp::Rcout << "Reusing context\n";
>         }
>     }
>
> public:
>     Redis()  { /* Rcpp::Rcout << "In ctor\n"; */ }
>     ~Redis() { /* Rcpp::Rcout << "In dtor\n"; */ }
>
>     std::string execCommand(std::string cmd) {
>         checkAndInit();         // important: ensure prc is set up, re-use
> if so
>         redisReply *reply = static_cast<redisReply*>(redisCommand(prc,
> cmd.c_str()));
>         std::string res(reply->str);
>         freeReplyObject(reply);
>         return(res);
>     }
>
>     void disconnect() {
>         redisFree(prc);
>         prc = NULL;             // just to be on the safe side
>     }
>
>     // could create new functions to (re-)connect with given host and port
> etc pp
> };
>
>
> -----------------------------------------------------------------------------
>
> Couple this with a simple function (which is so simple that I wrote it
> "straight" without even Rcpp attributes. One string in, one string out:
>
>
>
> -----------------------------------------------------------------------------
> // for now, single worker function
> extern "C" SEXP execRedisCommand(SEXP p) {
>     Redis redis;
>     std::string txt = Rcpp::as<std::string>(p);
>     std::string res = redis.execCommand(txt);
>     return Rcpp::wrap(res);
> }
>
> -----------------------------------------------------------------------------
>
>
> (We could create a second function to close redis and call disconnect();
> and we could 'getter' function for the state variables inside the context.)
>
> This function is then used by a single R function:
>
>
> -----------------------------------------------------------------------------
> ## minimal R interface to redis using the hiredis library
> redis <- function(cmd) {
>     ## some sanity checking on cmd would be nice too...
>     .Call("execRedisCommand", cmd, package="Rhiredis")
> }
>
> -----------------------------------------------------------------------------
>
> And that is all.  I added a simple tester:
>
> edd at don:~/git/Rhiredis$ Rscript tests/simpleRedisClient.R
> Context created
> [1] "PONG"
> Reusing context
> [1] "PONG"
> Reusing context
> [1] "PONG"
> Reusing context
> [1] "OK"
> Reusing context
> [1] "42"
> edd at don:~/git/Rhiredis$
>
> As you can see from the verbose text from checkAndInit(), we only need to
> create the redis instance once.
>
> I may still turn this into something based on Rcpp modules. Maybe tomorrow.
>
> The code is for now in a quick fork of your Rhiredis in my github account.
>
> Hope this helps,  Dirk
>
>
> --
> Dirk Eddelbuettel | edd at debian.org | http://dirk.eddelbuettel.com
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130724/a778849b/attachment-0001.html>


More information about the Rcpp-devel mailing list