-1

A continuation of this question: In Rcpp, how to get a user-defined structure from C into R

How do you get the Rcpp template to return strings and numbers, rather than some type of "Vectors"? I am attempting to port someone else's C code into R and they use all kinds of different data types (char,unsigned char,short,unsigned short,int,float,long int,long unsigned int,double - no, really, all of these are in the actual header!) that I need to "coerce" into strings and numbers in R. Seeing the comment from "Ralf Stubner", I modified your example to generate a MWE showing the problem:

#include <RcppCommon.h>

typedef struct {
  char   firstname[128];
//  long unsigned int big_number;
} HEADER_INFO;

namespace Rcpp {
  template <>
    SEXP wrap(const HEADER_INFO& x);
}

#include <Rcpp.h>

namespace Rcpp {
  template <>
    SEXP wrap(const HEADER_INFO& x) {
      Rcpp::CharacterVector firstname(x.firstname, x.firstname + 128);
//      Rcpp::Integer big_number(x.big_number);
      return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = firstname
//                                           ,Rcpp::Named("big_number") = big_number
      ));
    };
}

//  [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
  HEADER_INFO header;
  strcpy( header.firstname, "Albert" );
//  header.big_number = 123456789012345;
  return header;
}

/*** R
getHeaderInfo()
*/

When you run this in R:

> getHeaderInfo()
$firstname
  [1] "65"  "108" "98"  "101" "114" "116" "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [19] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [37] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [55] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [73] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
 [91] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"  
[109] "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "0"   "127" "16" 
[127] "72"  "-29"

The unsigned long entries are commented out because I could not find a datatype in the Rcpp Namespace that would compile. Is it true that types such as "Rcpp::Integer" and "Rcpp::Double" don't exist? If I have to use IntegerVector, then how do I tell the template that I want to refer to the result in R as just an integer and not as vector of length 1?

Mark Bower
  • 569
  • 2
  • 16
  • 2
    In R there is no such thing as "just an integer" that is "not [a] vector of length 1". Try, for example, `is.vector(1L)` or `is.vector(1)`. Any C++ function that returns an integer, if called from R, will result in a vector of length one on the R side. – duckmayr Jul 03 '18 at 16:45
  • 2
    Correct. But if you must, `Rcpp` will happily transfer an `int` or `double` for you. – Dirk Eddelbuettel Jul 03 '18 at 17:09

1 Answers1

1

I see that the range-based constructor for Rcpp::CharacterVector was confusing. That was necessary because an array of char *, i.e. an array of strings was used. Here we have only a single string (of fixed max length). Rcpp is intelligent enough to convert this to a CharacterVector of length one all by itself.

The case of the big number is more interesting. First of all, it is unclear what an unsigned long int is. It is defined as at least 32bit, and on 32bit systems (and 64bit Windows IIRC) this is the case. On 64bit Linux (and MacOS?) a 64bit integer is used. Now R only knows int as integer type, which is typically 32bit wide but signed and therefore to small. However, a double can represent much larger integers exactly, a trick that R itself uses in various places. So on a system with 32bit unsigned long int we can use:

#include <RcppCommon.h>

typedef struct {
  char   firstname[128];
  long unsigned int big_number;
} HEADER_INFO;

namespace Rcpp {
  template <>
  SEXP wrap(const HEADER_INFO& x);
}

#include <Rcpp.h>

namespace Rcpp {
  template <>
  SEXP wrap(const HEADER_INFO& x) {
    static_assert(sizeof(long) <= 6, "long is to large");
    double big_number = x.big_number;
    return Rcpp::wrap(Rcpp::List::create(Rcpp::Named("firstname") = x.firstname,
                     Rcpp::Named("big_number") = big_number));
  };
}

//  [[Rcpp::export]]
HEADER_INFO getHeaderInfo() {
  HEADER_INFO header;
  strcpy( header.firstname, "Albert" );
  header.big_number = 4294967295;
  return header;
}

/*** R
getHeaderInfo()
 */

Output:

> getHeaderInfo()
$firstname
[1] "Albert"

$big_number
[1] 4294967295

Both list elements are actually vectors of length one.

On a system with 64bit unsigned long int this won't compile due to the static_assert. On such a system you could use the same trick as used by the bit64 package: copy the bit pattern of the 64bit integer into a 64bit floating point number (i.e. double). That can be safely transferred to R. However, the bit64 package interprets these as signed integers. So really large numbers will overflow to negative numbers. See for example integer64 and Rcpp compatibility and http://gallery.rcpp.org/articles/creating-integer64-and-nanotime-vectors/. I know of no simple solution for unsigned numbers. I think you will have to find out if there is any practical limit to what is expected in these unsigned long int.

Ralf Stubner
  • 26,263
  • 3
  • 40
  • 75
  • Thank you for being HELPFUL. I wonder if others remember that they, too, benefit from help at times. I totally agree that the "long unsigned int" is problematic; I had that discussion with the code-writer several times when I ported this code to Java. (Got it to work and it is in wide use today, but the "fix" was ugly). Looking at what you got to work makes me glad I asked the question; there is nothing like that in the book or vignettes. I don't even know what this code means or does, but it works. I'll try to extend this to all of my required cases. Thank you! – Mark Bower Jul 04 '18 at 04:43
  • 1
    @Mark You are making me curious: You read Chapter 6 of the Rcpp book and the vignette on extending Rcpp, right? And you still have difficulties understanding my code, let alone writing something like this yourself? I would like to understand these difficulties. Maybe more introductory documentation is needed. Please let me know if you are interested in an off-site discussion. – Ralf Stubner Jul 04 '18 at 11:18
  • Thank you for asking! After your question, I went back and re-read Ch6, again, and compared the examples there and in the other online examples to your code. I've programmed in C and R for several decades, but would have to answer "no", I could not have come up with your code from the examples. One difficulty may be the implicit operations of Rcpp, which make sense to those who already know, but which seem like magic to someone like me. If it works, I love the magic, too! If I encounter and error, then I have to write you folks for more magic. I'll give an example in the next Comment. – Mark Bower Jul 05 '18 at 18:18