2017-07-30 14:15 GMT+02:00 Dirk Eddelbuettel <[email protected]>: > > On 30 July 2017 at 02:38, Iñaki Úcar wrote: > | One last question: would you consider adding a cppXPtr() function to > | Rcpp? It would work as cppFunction(), but it would return a XPtr > | instead of the function. I have a working example if you are > | interested. > > "Possibly" -- API and functionality extensions are easier than changes; it > still adds extra documentation and testing. > > Can you detail what you are proposing some more, show an example etc pp?
Of course. RcppDE would be a use case for this (and my simulator,
another one). Currently, the user must provide not only the C++
function, but also the adapter: a getter that instantiates an XPtr and
pushes it to R space. It is not difficult, but 1) it's not so
immediate nor intuitive, you need to instruct the user about this, and
2) it's repetitive and a nuisance.
So my proposal is to automate this. A new cppXPtr() function would
accept a single C++ function, just like cppFunction, but instead of
exporting it, it would:
- Detect the function signature. This is easy to do with some regexp,
because it should be C-compatible and you won't have to deal with more
complicated stuff like templates, etc. Example: "SEXP foo(int n,
double l) { return rexp(n, l); }" would produce
- name: foo
- args: (int n, double l)
- retv: SEXP
- Construct and append a getter. For the example above,
SEXP getXPtr() {
typedef SEXP (*funcPtr)(int n, double l);
return XPtr<funcPtr>(new funcPtr(&foo));
}
- Export the getter, call it, remove the getter from the environment
and return the externalptr.
An initial implementation, reusing code (omitted) from cppFunction,
would be (please, find attached a complete example):
cppXPtr <- function(...) { # same args as cppFunction
# get signature
func <- strsplit(code, "[[:space:]]*\\{")[[1]][[1]]
func <- strsplit(func, "[[:space:]]*\\(")[[1]]
args <- func[[2]]
func <- strsplit(func, "[[:space:]]+")[[1]]
name <- func[[length(func)]]
retv <- func[seq_len(length(func)-1)]
# process depends
# process plugins
# remainder of scaffolding
# prepend scaffolding to code
# append a getter
code <- paste(c(
code,
"// [[Rcpp::export]]",
"SEXP getXPtr() {",
paste(" typedef", retv, "(*funcPtr)(", args, ";"),
paste(" return XPtr<funcPtr>(new funcPtr(&", name, "));"),
"}"), collapse="\n")
# print the generated code if we are in verbose mode
# source cpp into specified environment
# verify that two functions were exported and return the XPtr
if (length(exported$functions) == 0)
stop("No function definition found")
else if (length(exported$functions) > 2)
stop("More than one function definition")
else {
ptr <- env$getXPtr()
rm(list=exported$functions, envir = env)
ptr
}
}
Iñaki
#include <Rcpp.h>
using namespace Rcpp;
typedef SEXP (*funcPtr)(int, double);
// [[Rcpp::export]]
NumericVector execute(SEXP x, int n, double l) {
funcPtr func = *XPtr<funcPtr>(x);
return func(n, l);
}
cppXPtr.R
Description: Binary data
main.R
Description: Binary data
_______________________________________________ Rcpp-devel mailing list [email protected] https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
