Title: | Enhanced Foreign Function Interface Supporting Long Vectors |
---|---|
Description: | Provides .C64(), which is an enhanced version of .C() and .Fortran() from the foreign function interface. .C64() supports long vectors, arguments of type 64-bit integer, and provides a mechanism to avoid unnecessary copies of read-only and write-only arguments. This makes it a convenient and fast interface to C/C++ and Fortran code. |
Authors: | Kaspar Moesinger [aut], Florian Gerber [aut] , Reinhard Furrer [cre, ctb] |
Maintainer: | Reinhard Furrer <[email protected]> |
License: | GPL (>= 2) |
Version: | 1.2 |
Built: | 2024-12-04 07:00:13 UTC |
Source: | CRAN |
.C64
can be used to call compiled and loaded C/C++ functions and Fortran subroutines.
.C64
is similar to .C
and .Fortran
, but
supports long vectors, i.e., vectors with more than 2^31-1
elements
does the necessary castings to expose the R representation of "64-bit integers" (numeric vectors) to 64-bit integer arguments of the compiled function. The latter are int64_t in C code and integer (kind = 8) in Fortran code
provides a mechanism the control duplication of the R objects exposed to the compiled code
checks if the provided R objects are of the expected types and coerces them if necessary
Compared to .C
, .C64
has the additional arguments SIGNATURE
, INTENT
and VERBOSE
.
SIGNATURE
specifies the types of the arguments of the compiled function.
INTENT
indicates whether the compiled function "reads", "writes",
or "read and writes" to the R objects passed to the compiled function.
This information is then used to duplicate R objects if and only if necessary.
.C64( .NAME, SIGNATURE, ..., INTENT = NULL, NAOK = FALSE, PACKAGE = "", VERBOSE = getOption("dotCall64.verbose") )
.C64( .NAME, SIGNATURE, ..., INTENT = NULL, NAOK = FALSE, PACKAGE = "", VERBOSE = getOption("dotCall64.verbose") )
.NAME |
character vector of length 1. Name of the compiled function to be called. |
SIGNATURE |
character vector of the same length as the number of arguments of the compiled function.
Accepted strings are |
... |
arguments passed to the compiled function. One R object for each argument. Up to 65 arguments are supported. |
INTENT |
character vector of the same length as the number of arguments of the compiled function.
Accepted strings are |
NAOK |
logical vector of length 1. If |
PACKAGE |
character vector of length 1. Specifies where to search for the function given in |
VERBOSE |
numeric vector of length 1. If |
list of R objects similar to the list of arguments specified as ...
arguments.
The objects of the list reflect the changes made by the compiled C or Fortran function.
F. Gerber, K. Moesinger, R. Furrer (2018), dotCall64: An R package providing an efficient interface to compiled C, C++, and Fortran code supporting long vectors, SoftwareX 7, 217-221, https://doi.org/10.1016/j.softx.2018.06.002.
F. Gerber, K. Moesinger, and R. Furrer (2017), Extending R packages to support 64-bit compiled code: An illustration with spam64 and GIMMS NDVI3g data, Computer & Geoscience 104, 109-119, https://doi.org/10.1016/j.cageo.2016.11.015.
## Consider the following C function, which is included ## in the dotCall64 package: ## void get_c(double *input, int *index, double *output) { ## output[0] = input[index[0] - 1]; ## } ## ## We can use .C64() to call get_c() from R: .C64("get_c", SIGNATURE = c("double", "integer", "double"), input = 1:10, index = 9, output = double(1))$output ## Not run: ## 'input' can be a long vector x_long <- double(2^31) ## requires 16 GB RAM x_long[9] <- 9; x_long[2^31] <- -1 .C64("get_c", SIGNATURE = c("double", "integer", "double"), input = x_long, index = 9, output = double(1))$output ## Since 'index' is of type 'signed int' (a 32-bit integer), ## it can only address the first 2^31-1 elements of 'input'. ## To also address elements beyond 2^31-1, we change the ## definition of the C function as follows: ## #include <stdint.h> // for int64_t ## void get64_c(double *input, int64_t *index, double *output) { ## output[0] = input[index[0] - 1]; ## } ## Now, we can use .C64() to call get64_c() from R. .C64("get64_c", SIGNATURE = c("double", "int64", "double"), input = x_long, index = 2^31, output = double(1))$output ## Note that 2^31 is of type double and .C64() casts it into an ## int64_t type before calling the C function get64_c(). ## The performance of the previous call can be improved by ## setting additional arguments: .C64("get64_c", SIGNATURE = c("double", "int64", "double"), x = x_long, i = 2^31, r = numeric_dc(1), INTENT = c("r", "r", "w"), NAOK = TRUE, PACKAGE = "dotCall64", VERBOSE = 0)$r ## Consider the same function defined in Fortran: ## subroutine get64_f(input, index, output) ## double precision :: input(*), output(*) ## integer (kind = 8) :: index ! specific to GFortran ## output(1) = input(index) ## end ## The function is provided in dotCall64 and can be called with .C64("get64_f", SIGNATURE = c("double", "int64", "double"), input = x_long, index = 2^31, output = double(1))$output ## End(Not run)
## Consider the following C function, which is included ## in the dotCall64 package: ## void get_c(double *input, int *index, double *output) { ## output[0] = input[index[0] - 1]; ## } ## ## We can use .C64() to call get_c() from R: .C64("get_c", SIGNATURE = c("double", "integer", "double"), input = 1:10, index = 9, output = double(1))$output ## Not run: ## 'input' can be a long vector x_long <- double(2^31) ## requires 16 GB RAM x_long[9] <- 9; x_long[2^31] <- -1 .C64("get_c", SIGNATURE = c("double", "integer", "double"), input = x_long, index = 9, output = double(1))$output ## Since 'index' is of type 'signed int' (a 32-bit integer), ## it can only address the first 2^31-1 elements of 'input'. ## To also address elements beyond 2^31-1, we change the ## definition of the C function as follows: ## #include <stdint.h> // for int64_t ## void get64_c(double *input, int64_t *index, double *output) { ## output[0] = input[index[0] - 1]; ## } ## Now, we can use .C64() to call get64_c() from R. .C64("get64_c", SIGNATURE = c("double", "int64", "double"), input = x_long, index = 2^31, output = double(1))$output ## Note that 2^31 is of type double and .C64() casts it into an ## int64_t type before calling the C function get64_c(). ## The performance of the previous call can be improved by ## setting additional arguments: .C64("get64_c", SIGNATURE = c("double", "int64", "double"), x = x_long, i = 2^31, r = numeric_dc(1), INTENT = c("r", "r", "w"), NAOK = TRUE, PACKAGE = "dotCall64", VERBOSE = 0)$r ## Consider the same function defined in Fortran: ## subroutine get64_f(input, index, output) ## double precision :: input(*), output(*) ## integer (kind = 8) :: index ! specific to GFortran ## output(1) = input(index) ## end ## The function is provided in dotCall64 and can be called with .C64("get64_f", SIGNATURE = c("double", "int64", "double"), input = x_long, index = 2^31, output = double(1))$output ## End(Not run)
vector_dc
and its shortcuts numeric_dc
and
integer_dc
are helper functions used in calls to .C64
.
They return an R object of class c("vector_dc", "list")
,
which contains information on the type and length of the vector to allocate.
Using vector_dc
together with INTENT = "w"
argument of .C64
leads to performance gains by avoiding unnecessary castings and copies.
vector_dc(mode = "logical", length = 0L) numeric_dc(length = 0) integer_dc(length = 0)
vector_dc(mode = "logical", length = 0L) numeric_dc(length = 0) integer_dc(length = 0)
mode |
character vector of length 1. Storage mode of the vector. |
length |
numeric vector of length 1. Length of the vector. |
object of class vector_dc
and list
.
vector_dc("integer", 20)
vector_dc("integer", 20)