2
//[[Rcpp::export]]
int Class_data(SEXP data) {
    /*
       return 0 if class of data is matrix
       else return -1 
    */
}

How to determine the class of data in the above case? If data belongs to matrix class return 0 else return -1.

cryptomanic
  • 5,986
  • 3
  • 18
  • 30

2 Answers2

13

Depending on what type of object you are checking for, there may be a predefined Rf_isWhatever macro, or you may need to use the Rf_inherits(object, "Whatever") macro, both defined in the R source code, and available through the Rcpp header. For example,

#include <Rcpp.h>

// [[Rcpp::export]]
int is_matrix(SEXP data) {
    return Rf_isMatrix(data) ? 0 : -1;
}

// [[Rcpp::export]]
int is_data_frame(SEXP x) {
    return Rf_inherits(x, "data.frame") ? 0 : -1;
}

/*** R

is_matrix(matrix(1:6, 2))
#[1] 0

is_matrix(data.frame(1:5))
#[1] -1

is_data_frame(data.frame(1:5))
#[1] 0

is_data_frame(matrix(1:6, 2))
#[1] -1

*/

For reference, you can check the source code to see what is available.

nrussell
  • 18,382
  • 4
  • 47
  • 60
  • I have tried Rf_inherits for matrix but it is not working? – cryptomanic Jun 06 '16 at 20:27
  • 1
    Correct, `Rf_inherits` will not be appropriate for all classes, but in such cases there should be an `Rf_is...` macro provided. I believe this is just a consequence of R's loosely defined class system. `Rf_inherits` just [checks for the class attribute](https://github.com/wch/r-source/blob/7199ea1d53538c55e4ca51a993ec2a394dd63a1f/src/include/Rinlinedfuns.h#L375-L388), which is not present for matrices. You can see this by noting that `attr(matrix(1:6, 2), "class")` returns `NULL`. – nrussell Jun 06 '16 at 21:28
7

Normally, you would know in advance what type the object is when working with Rcpp as you would specify:

//[[Rcpp::export]]
int Class_data(Rcpp::NumericMatrix) {
  // code to reduce return to int
  return 1;
}

Of course, there are exceptions when working with different element types (e.g. logical vs. character vs. numeric) and having one call function. I've included an example of this at the end.

Though, in the case when you do not, the best to do is use isMatrix in R's vocab:

INLINE_FUN Rboolean isMatrix(SEXP s)
{
    SEXP t;
    if (isVector(s)) {
    t = getAttrib(s, R_DimSymbol);
    /* You are not supposed to be able to assign a non-integer dim,
       although this might be possible by misuse of ATTRIB. */
    if (TYPEOF(t) == INTSXP && LENGTH(t) == 2)
        return TRUE;
    }
    return FALSE;
}

Implementation

To handle a larger amount of objects (logical, character, etc..), you want an internal switch given in R's do_is() function.

That may be a bit too big though and you may want help in dispatching different object types. To do so, see this example:

#include <Rcpp.h>

// Create a template generic (look up C++ templates)
template <int RTYPE>
int count_me(Vector<RTYPE> v){
    return v.size() ; // Just want to show it can return sizes of different array types
}

// [[Rcpp::export]]
int fake_switch(SEXP x){

    // customize with different functions
    // Or, just pass different types into the template.
    switch( TYPEOF(x) ){
    case INTSXP: return count_me<INTSXP>(x); // integers
    case REALSXP: return count_me<REALSXP>(x); // numeric
    case STRSXP: return count_me<STRSXP>(x); // strings
    default: Rcpp::stop("type not handled"); // no support for obj
    }
    return -1; // should never be trigger but here to make the compiler happy
}
coatless
  • 20,011
  • 13
  • 69
  • 84