simplecall - demo package for calling C code with .Call()
simplecall
is a small demo package showing how C code could be included
in a package and called with .Call()
.
This package now includes demo code for:
- creating a list in C
- creating a data.frame in C
There are probably more succinct ways of doing this, and if you know such a way, please hit me up on twitter
Installation
You can install from GitHub with:
# install.package('remotes')
remotes::install_github('coolbutuseless/simplecall)
Creating a R List within C
Example code is included to create a list completely within C and return it to R
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Creating a list within C and returning it to R
//
// 1. Create individual integer/real/whatever vectors
// 2. allocate a VECSXP of the correct size
// 3. assign each member into the list
// 4. create names and assign them to the list
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP create_list_in_c_() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Each member of the list gets allocated separately
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int n = 10;
SEXP idx_ = PROTECT(allocVector(INTSXP , n));
SEXP x_ = PROTECT(allocVector(REALSXP, n));
SEXP y_ = PROTECT(allocVector(REALSXP, n));
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Assign some dummy values into the members
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (int i = 0; i < n; i++) {
INTEGER(idx_)[i] = i + 1;
REAL(x_)[i] = i + 10;
REAL(y_)[i] = i + 100;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Allocate a list with 3 members
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP list_ = PROTECT(allocVector(VECSXP, 3));
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Add members to the list
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SET_VECTOR_ELT(list_, 0, idx_);
SET_VECTOR_ELT(list_, 1, x_);
SET_VECTOR_ELT(list_, 2, y_);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set the names on the list.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP names = PROTECT(allocVector(STRSXP, 3));
SET_STRING_ELT(names, 0, mkChar("idx"));
SET_STRING_ELT(names, 1, mkChar("x"));
SET_STRING_ELT(names, 2, mkChar("y"));
setAttrib(list_, R_NamesSymbol, names);
UNPROTECT(5);
return list_;
}
simplecall::create_list_in_c()
$idx
[1] 1 2 3 4 5 6 7 8 9 10
$x
[1] 10 11 12 13 14 15 16 17 18 19
$y
[1] 100 101 102 103 104 105 106 107 108 109
Creating a R data.frame within C
Example code is included to create a data.frame completely within C and return it to R
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Creating a data.frame within C and returning it to R
//
// 1. Create individual integer/real/whatever vectors
// 2. allocate a VECSXP of the correct size
// 3. assign each member into the data.frame
// 4. create names and assign them to the data.frame
// 5. set the class to "data.frame"
// 6. set rownames on the data.frame
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP create_data_frame_in_c_() {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Each member of the list gets allocated separately
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int n = 10;
SEXP idx_ = PROTECT(allocVector(INTSXP , n));
SEXP x_ = PROTECT(allocVector(REALSXP, n));
SEXP y_ = PROTECT(allocVector(REALSXP, n));
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Assign some dummy values into the members
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (int i = 0; i < n; i++) {
INTEGER(idx_)[i] = i + 1;
REAL(x_)[i] = i + 10;
REAL(y_)[i] = i + 100;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Allocate a data.frame
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP df_ = PROTECT(allocVector(VECSXP, 3));
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Add columns to the data.frame
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SET_VECTOR_ELT(df_, 0, idx_);
SET_VECTOR_ELT(df_, 1, x_);
SET_VECTOR_ELT(df_, 2, y_);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Treat the VECSXP as a data.frame rather than a list
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SET_CLASS(df_, mkString("data.frame"));
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set the names on the list.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP names = PROTECT(allocVector(STRSXP, 3));
SET_STRING_ELT(names, 0, mkChar("idx"));
SET_STRING_ELT(names, 1, mkChar("x"));
SET_STRING_ELT(names, 2, mkChar("y"));
setAttrib(df_, R_NamesSymbol, names);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set the row.names on the list.
// Use the shortcut as used in .set_row_names() in R
// i.e. set rownames to c(NA_integer, -len) and it will
// take care of the rest. This is equivalent to rownames(x) <- NULL
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SEXP rownames = PROTECT(allocVector(INTSXP, 2));
SET_INTEGER_ELT(rownames, 0, NA_INTEGER);
SET_INTEGER_ELT(rownames, 1, -n);
setAttrib(df_, R_RowNamesSymbol, rownames);
UNPROTECT(6);
return df_;
}
simplecall::create_data_frame_in_c()
idx x y
1 1 10 100
2 2 11 101
3 3 12 102
4 4 13 103
5 5 14 104
6 6 15 105
7 7 16 106
8 8 17 107
9 9 18 108
10 10 19 109
Similar packages
This is one of a series of small demo packages for
calling other languages from R:
- {simplec} - calling C with
.C()
- {simplecall} - calling C with
.Call()
- {simplercpp} - calling C++ with
{Rcpp}
- {simplefortran} - calling Fortran with
.Fortran()
Installation
Resources
Acknowledgements
- R Core for developing and maintaining such a wonderful language.
- CRAN maintainers, for patiently shepherding packages onto CRAN and maintaining the repository