I want to implement a cumulative all through R's C interface. I was able to hack something together that produces the correct results, but I have little idea what idiomatic C should look like. The code should be easy to understand, even if you don't know about R.
Description
The cumulative all takes a LGLSXP
(logical S-expression) input. The function should output a LGLSXP
of the same length as the input, where each element represents whether all values up to this point were true
.
The three valued logic works like this:
(true & false) -> false
, (true & na) -> na
, (false & na) -> false
LGLSXP
A LGLSXP
is a pointer to a struct that contains an int
array that represents 3 valued logic with 0
as false
, INT_MIN
as NA
and 1
as true
. This array can be accessed with LOGICAL()
. You can read about SEXPs here.
Code
#include <R.h>
#include <Rinternals.h>
SEXP cumall_impl(SEXP x) {
SEXP res = PROTECT(allocVector(LGLSXP, XLENGTH(x)));
R_xlen_t n = XLENGTH(x);
if (n == 0){
UNPROTECT(1);
return(res);
} else {
memset(LOGICAL(res), 0, n * sizeof(int));
}
int *p_x = LOGICAL(x);
int *p_res = LOGICAL(res);
p_res[0] = p_x[0];
for (R_xlen_t i = 1; i < n; i++) {
if (p_x[i] == TRUE)
p_res[i] = p_res[i - 1];
else if (p_x[i] == NA_LOGICAL)
p_res[i] = NA_LOGICAL;
else
break;
}
UNPROTECT(1);
return res;
}
Remarks
PROTECT()
andUNPROTECT()
are necessary to prevent R's garbage collector from interferingLOGICAL()
accesses the underlying array of aLGLSXP
TRUE
,NA_LOGICAL
etc are provided by the headers.
Headers
- The most important definitions are in Rinternals.h and R.h.
- The
NA_LOGICAL
is defined in Arith.h and arithmetic.c - I am not sure where/how
TRUE
andFALSE
are really defined. Likely sources are Boolean.h and Rdefines.h
I am thankful for all suggestions, be it coding style, variable naming or critique to how I formulated my question
if (p_x[i] == TRUE)
seems wrong. I'd expect all values that are neitherNA_LOGICAL
norFALSE
, not just the oneTRUE
, to cause thatif()
test to be true. If we can rely on 2's complement, perhapsif (p_x[i] & INT_MAX)
\$\endgroup\$int
array...". If so better to sayint
. If not always anint
,sizeof(int)
inmemset(LOGICAL(res), 0, n * sizeof(int));
is suspicious. I guess it comes down to it would make for a more effective review with<R.h>, <Rinternals.h>
posted or referenced. \$\endgroup\$