---
title: "Introduction"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Introduction}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
knitr::knit_engines$set(callme = callme:::callme_engine)
library(callme)
```
```{css, echo=FALSE}
.callme { background-color: #E3F2FD; }
pre.callme span { background-color: #E3F2FD; }
```
## Introduction
`{callme}` is a package for easily compiling inline C code for use within R.
Complied C code can be used to improve the speed of critical sections of code e.g.
tight loops of numeric operations.
In this introductory vignette, some common elements are described for C code
which operates with R objects
## Code Layout in Vignettes
The C code chunks in these vignettes is streamlined for display purposes.
In general when using `{callme}` you must:
1. Define the C code
* in a string (usually called `code` in examples in this package)
* in a `.c` file
2. Call `callme::compile(code)` or `callme::compile("file.c")`
This standard way of compiling the code in R is shown below:
```{r eval=FALSE}
code <- r"(
SEXP print_with_c(SEXP string) {
Rprintf("Printing in C: '%s'\n", CHAR(asChar(string)));
return R_NilValue;
}
)"
callme::compile(code, invisible = TRUE)
print_with_c("hello")
```
In order to focus on the actual C code (with C code syntax highlighting),
C code will simply be shown in a blue box. Assigning the code to a string,
and calling `callme::compile(code)` are hidden by default (`Click to show R code`
will reveal this code).
```{callme}
#| invisible=TRUE
SEXP print_with_c(SEXP string) {
Rprintf("Printing in C: '%s'\n", CHAR(asChar(string)));
return R_NilValue;
}
```
```{r}
print_with_c("hello")
```
## Example: Add two vectors of floating point numbers
The following code adds two vectors of floating point values and returns
the result (i.e. `a + b`).
```{callme}
SEXP add(SEXP a, SEXP b) {
// Sanity checks
if (length(a) != length(b)) {
error("'a' and 'b' must be the same length");
}
// Get a pointer to the actual numeric data in 'a' and 'b'
double *ap = REAL(a);
double *bp = REAL(b);
// Allocate a new R object 'res' and protect it from garbage collection
int N = length(a);
SEXP res = PROTECT(allocVector(REALSXP, N));
// Get a pointer to the actual numeric data in 'res'
double *resp = REAL(res);
// Add elements of two arrays in C
for (int i = 0; i < N; i++) {
resp[i] = ap[i] + bp[i];
}
// Unwind any protection and return the R result
UNPROTECT(1);
return res;
}
```
```{r}
add(c(1, 2, 3), c(4, 5, 6))
```
## Elements to note in the example
The following elements highlighted here are described in more detail in
other vignettes within this package.
### Function signature
Function signatures must be of the format `SEXP funcname(SEXP arg1, SEXP arg2, ... SEXP argn)`
### Sanity checking
There is a much greater need for checking for sane arguments in C compared to
R. In R, an out-of-bounds memory access might only result in an `NA` value, but
in C such a bad memory access can cause memory corruption and crashes.
In the example above, the lengths of the two input vectors were checked as
automatic vector recyling does not happen in C like it does in R.
### Unpack R objects into C equivalents
All R objects are of type `SEXP` and are a combination of metadata and
the actual dta useful to C.
The C compatible data must be extraced from the `SEXP` e.g. find the pointer
to the array of doubles using:
```{callme}
#| compile = FALSE, headers = FALSE, rcode = FALSE
double *ap = REAL(a);
```
### Allocte new R objects within C
New R objects can be created within C using `allocVector()` and related functions.
It is important to `PROTECT()` any R objects created within C - otherwise
R's garbage collection will consider them unused and try to free the memory
in which they store data.
### Return object from C to R
The final returned object must also be of type `SEXP`. This object may
have been created with a call to `allocVector()` but there are convenience
functions for creating and returning single values e.g. `ScalarInteger()`