When calling unlist or c, the type will be promoted to the smallest type capable of representing everything:
> c(as.integer(1), 2.3, '3')
[1] "1" "2.3" "3"
> c(TRUE, 5)
[1] 1 5
> unlist(list(as.integer(1:5), as.complex(2:4)))
[1] 1+0i 2+0i 3+0i 4+0i 5+0i 2+0i 3+0i 4+0i
How can I access this logic from C/C++ code?
I have looked for the C sources of c and unlist and found the following code in both do_c_dflt and do_unlist (main/bind.c):
if (data.ans_flags & 512) mode = EXPRSXP;
else if (data.ans_flags & 256) mode = VECSXP;
else if (data.ans_flags & 128) mode = STRSXP;
else if (data.ans_flags & 64) mode = CPLXSXP;
else if (data.ans_flags & 32) mode = REALSXP;
else if (data.ans_flags & 16) mode = INTSXP;
else if (data.ans_flags & 2) mode = LGLSXP;
else if (data.ans_flags & 1) mode = RAWSXP;
The variable data, which is of type BindData, is computed by a routine AnswerType that seems to define the coercion logic. However, the type BindData is declared in bind.c only.
So: Is R's general coercion logic exported anywhere, or am I bound to copy-paste the code from bind.c? (Sorry for the pun...)
Kevin just posted an article on the Rcpp Gallery which is pretty close in spirit, it tests explicitly using the macros from R's API:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List do_stuff( List x_ ) {
List x = clone(x_);
for( List::iterator it = x.begin(); it != x.end(); ++it ) {
switch( TYPEOF(*it) ) {
case REALSXP: {
NumericVector tmp = as<NumericVector>(*it);
tmp = tmp * 2;
break;
}
case INTSXP: {
if( Rf_isFactor(*it) ) break; // factors have type INTSXP too
IntegerVector tmp = as<IntegerVector>(*it);
tmp = tmp + 1;
break;
}
default: {
stop("incompatible SEXP encountered;");
}
}
}
return x;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With