diff --git a/R/lag.R b/R/lag.R index 0b1f0aa..731e755 100644 --- a/R/lag.R +++ b/R/lag.R @@ -30,7 +30,8 @@ #' @details #' For most applications, it is more efficient and recommended to use `lag_()`. #' For anything that requires dynamic lags, lag by order of another variable, -#' or by-group lags, one can use `lag2_()`. +#' or by-group lags, one can use `lag2_()`. \cr +#' To do cyclic lags, see the examples below for an implementation. #' #' ### `lag2_` #' @@ -99,8 +100,8 @@ #' # lag every 2nd element #' lag2_(x, n = c(1, 0)) # lag vector is recycled #' -#' # Explicit lags along x -#' lags <- lag_sequence(length(x), 1, partial = FALSE) +#' # Explicit Lag(3) using a vector of lags +#' lags <- lag_sequence(length(x), 3, partial = FALSE) #' lag2_(x, n = lags) #' #' # Alternating lags and leads @@ -124,12 +125,13 @@ #' #' # Example of how to do a cyclical lag #' n <- length(x) +#' +#' # When k >= 0 #' k <- min(3, n) -#' if (k >= 0){ -#' lag2_(x, c(rep(-n + k, k), rep(k, n - k))) -#' } else { -#' lag2_(x, c(rep(k, n + k), rep(n + k, -k))) -#' } +#' lag2_(x, c(rep(-n + k, k), rep(k, n - k))) +#' # When k < 0 +#' k <- max(-3, -n) +#' lag2_(x, c(rep(k, n + k), rep(n + k, -k))) #' #' # As it turns out, we can do a grouped lag #' # by supplying group sizes as run lengths and group order as the order @@ -185,13 +187,15 @@ #' # Let's compare this to data.table #' #' library(data.table) -#' setDTthreads(2) +#' default_threads <- getDTthreads() +#' setDTthreads(1) #' dt <- data.table(x = 1:10^5, #' g = sample.int(10^4, 10^5, TRUE)) #' #' bench::mark(dt[, y := shift(x), by = g][][["y"]], #' grouped_lag(dt$x, g = dt$g), #' iterations = 10) +#' setDTthreads(default_threads) #' @rdname lag #' @export lag_ <- function(x, n = 1L, fill = NULL, set = FALSE, recursive = TRUE){ @@ -202,8 +206,3 @@ lag_ <- function(x, n = 1L, fill = NULL, set = FALSE, recursive = TRUE){ lag2_ <- function(x, n = 1L, order = NULL, run_lengths = NULL, fill = NULL, recursive = TRUE){ .Call(`_cheapr_cpp_lag2`, x, n, order, run_lengths, fill, recursive) } -# lag2_ <- function(x, n = 1L, order = if (recursive && is.data.frame(x)) seq_len(nrow(x)) else seq_along(x), -# run_lengths = if (recursive && is.data.frame(x)) nrow(x) else length(x), -# fill = NULL, recursive = TRUE){ -# .Call(`_cheapr_cpp_lag2`, x, n, order, run_lengths, fill, recursive) -# } diff --git a/man/lag.Rd b/man/lag.Rd index 8b761fc..8bc9d73 100644 --- a/man/lag.Rd +++ b/man/lag.Rd @@ -53,7 +53,8 @@ run lengths. \details{ For most applications, it is more efficient and recommended to use \code{lag_()}. For anything that requires dynamic lags, lag by order of another variable, -or by-group lags, one can use \code{lag2_()}. +or by-group lags, one can use \code{lag2_()}. \cr +To do cyclic lags, see the examples below for an implementation. \subsection{\code{lag2_}}{ \code{lag2_} is a generalised form of \code{lag_} that by default performs @@ -125,8 +126,8 @@ x <- 1:10 # lag every 2nd element lag2_(x, n = c(1, 0)) # lag vector is recycled -# Explicit lags along x -lags <- lag_sequence(length(x), 1, partial = FALSE) +# Explicit Lag(3) using a vector of lags +lags <- lag_sequence(length(x), 3, partial = FALSE) lag2_(x, n = lags) # Alternating lags and leads @@ -150,12 +151,13 @@ lag2_(x, order = order(years)) # Example of how to do a cyclical lag n <- length(x) + +# When k >= 0 k <- min(3, n) -if (k >= 0){ - lag2_(x, c(rep(-n + k, k), rep(k, n - k))) -} else { - lag2_(x, c(rep(k, n + k), rep(n + k, -k))) -} +lag2_(x, c(rep(-n + k, k), rep(k, n - k))) +# When k < 0 +k <- max(-3, -n) +lag2_(x, c(rep(k, n + k), rep(n + k, -k))) # As it turns out, we can do a grouped lag # by supplying group sizes as run lengths and group order as the order @@ -211,11 +213,13 @@ grouped_lag(x, g = g) # Let's compare this to data.table library(data.table) -setDTthreads(2) +default_threads <- getDTthreads() +setDTthreads(1) dt <- data.table(x = 1:10^5, g = sample.int(10^4, 10^5, TRUE)) bench::mark(dt[, y := shift(x), by = g][][["y"]], grouped_lag(dt$x, g = dt$g), iterations = 10) +setDTthreads(default_threads) } diff --git a/src/cpp11.cpp b/src/cpp11.cpp index 440b346..e04e834 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -90,10 +90,10 @@ extern "C" SEXP _cheapr_cpp_lcm2_vectorised(SEXP x, SEXP y, SEXP tol, SEXP na_rm END_CPP11 } // lag.cpp -SEXP cpp_lag(SEXP x, int k, SEXP fill, bool set, bool recursive); +SEXP cpp_lag(SEXP x, R_xlen_t k, SEXP fill, bool set, bool recursive); extern "C" SEXP _cheapr_cpp_lag(SEXP x, SEXP k, SEXP fill, SEXP set, SEXP recursive) { BEGIN_CPP11 - return cpp11::as_sexp(cpp_lag(cpp11::as_cpp>(x), cpp11::as_cpp>(k), cpp11::as_cpp>(fill), cpp11::as_cpp>(set), cpp11::as_cpp>(recursive))); + return cpp11::as_sexp(cpp_lag(cpp11::as_cpp>(x), cpp11::as_cpp>(k), cpp11::as_cpp>(fill), cpp11::as_cpp>(set), cpp11::as_cpp>(recursive))); END_CPP11 } // lag.cpp diff --git a/src/gcd.cpp b/src/gcd.cpp index 27823b2..46a515c 100644 --- a/src/gcd.cpp +++ b/src/gcd.cpp @@ -161,7 +161,7 @@ SEXP cpp_lcm(SEXP x, double tol, bool na_rm){ lcm = NA_REAL; } int lcm_int = p_x[0]; - double int_max = double(integer_max_); + double int_max = integer_max_; for (int i = 1; i < n; ++i) { if (!na_rm && !(lcm == lcm)){ lcm = NA_REAL; diff --git a/src/lag.cpp b/src/lag.cpp index 6f97cbe..578825d 100644 --- a/src/lag.cpp +++ b/src/lag.cpp @@ -1,9 +1,24 @@ #include "cheapr_cpp.h" +#include +#include + +template T cpp_sign(T x) { + return (x > 0) - (x < 0); +} + +// Internal fast check for valid order values (here they are 0-indexed) +// Where rng = length(x) - 1 +void check_order_value(unsigned int x, unsigned int rng, int n_prot){ + if (!(x <= rng)){ + Rf_unprotect(n_prot); + Rf_error("order must be an integer vector of unique values between 1 and length(x)"); + } +} [[cpp11::register]] -SEXP cpp_lag(SEXP x, int k, SEXP fill, bool set, bool recursive) { +SEXP cpp_lag(SEXP x, R_xlen_t k, SEXP fill, bool set, bool recursive) { R_xlen_t size = Rf_xlength(x); - int fill_size = Rf_length(fill); + R_xlen_t fill_size = Rf_xlength(fill); int n_protections = 0; if (fill_size > 1){ Rf_error("fill size must be NULL or length 1"); @@ -429,11 +444,11 @@ SEXP cpp_lag(SEXP x, int k, SEXP fill, bool set, bool recursive) { [[cpp11::register]] SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool recursive){ - unsigned int o_size = Rf_length(order); - unsigned int rl_size = Rf_length(run_lengths); - unsigned int lag_size = Rf_length(lag); - unsigned int fill_size = Rf_length(fill); - unsigned int n_protections = 0; + int o_size = Rf_length(order); + int rl_size = Rf_length(run_lengths); + int lag_size = Rf_length(lag); + int fill_size = Rf_length(fill); + int n_protections = 0; if (fill_size > 1){ Rf_error("fill size must be NULL or length 1"); } @@ -442,21 +457,25 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } bool has_order = o_size > 0; bool has_rl = rl_size > 0; + bool recycle_lag = lag_size != 1; Rf_protect(lag = Rf_coerceVector(lag, INTSXP)); ++n_protections; Rf_protect(order = Rf_coerceVector(order, INTSXP)); ++n_protections; Rf_protect(run_lengths = Rf_coerceVector(run_lengths, INTSXP)); ++n_protections; + // std::variant p_o; + // typedef std::conditional::type p_o; int *p_o = INTEGER(order); int *p_rl = INTEGER(run_lengths); int *p_lag = INTEGER(lag); int rl; // Run-length - unsigned int run_start = 0; // Start index of current run - unsigned int run_end = 0; // End index of current run + int run_start = 0; // Start index of current run + int run_end = 0; // End index of current run int oi; int lagi; int k; + int lag1 = p_lag[0]; // Manually set run rl size to 1 if run_lengths = NULL (checked prior) if (!has_rl) rl_size = 1; @@ -468,7 +487,9 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re SEXP new_names = Rf_protect(cpp_lag2(old_names, lag, order, run_lengths, fill, recursive));\ ++n_protections; \ Rf_setAttrib(out, R_NamesSymbol, new_names); \ - } + } \ + + unsigned int o_rng = o_size - 1; SEXP out; switch(TYPEOF(x)){ case NILSXP: { @@ -477,7 +498,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } case LGLSXP: case INTSXP: { - unsigned int size = Rf_length(x); + int size = Rf_length(x); if (has_order && (size != o_size)){ Rf_error("length(order) must equal length(x)"); } @@ -489,7 +510,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re out = Rf_protect(Rf_duplicate(x)); ++n_protections; int *p_out = INTEGER(out); - for (unsigned int i = 0; i != rl_size; ++i){ + for (int i = 0; i != rl_size; ++i){ run_start = run_end; // Start at the end of the previous run // Manually set run rl if order = NULL rl = has_rl ? p_rl[i] : size; // Current run-length @@ -506,13 +527,20 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re Rf_unprotect(n_protections); Rf_error("sum(run_lengths) must be equal to length(x)"); } - // unsigned int trick to calculate inclusive bounded between(x, lo, hi) + // int trick to calculate inclusive bounded between(x, lo, hi) // See: https://stackoverflow.com/questions/17095324/fastest-way-to-determine-if-an-integer-is-between-two-integers-inclusive-with unsigned int rng = (run_end - 1) - run_start; // Loop starting from the end of the previous run-length - for (unsigned int j = run_start; j != run_end; ++j){ - oi = has_order ? p_o[j] - 1 : j; - k = p_lag[j % lag_size]; + for (int j = run_start; j != run_end; ++j){ + // Check that order value is valid + if (has_order){ + oi = p_o[j] - 1; + check_order_value(oi, o_rng, n_protections); + } else { + oi = j; + } + // Costly to use % if we don't need to + k = recycle_lag ? p_lag[j % lag_size] : lag1; lagi = j - k; p_out[oi] = unsigned(lagi - run_start) <= rng ? p_x[has_order ? p_o[lagi] - 1 : lagi] : fill_value; } @@ -525,7 +553,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re break; } case REALSXP: { - unsigned int size = Rf_length(x); + int size = Rf_length(x); if (has_order && (size != o_size)){ Rf_error("length(order) must equal length(x)"); } @@ -537,7 +565,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re out = Rf_protect(Rf_duplicate(x)); ++n_protections; double *p_out = REAL(out); - for (unsigned int i = 0; i != rl_size; ++i){ + for (int i = 0; i != rl_size; ++i){ run_start = run_end; // Start at the end of the previous run rl = has_rl ? p_rl[i] : size; // Current run-length run_end += rl; // Cumulative run-length @@ -555,9 +583,15 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } unsigned int rng = (run_end - 1) - run_start; // Loop starting from the end of the previous run-length - for (unsigned int j = run_start; j != run_end; ++j){ - oi = has_order ? p_o[j] - 1 : j; - k = p_lag[j % lag_size]; + for (int j = run_start; j != run_end; ++j){ + // Check that order value is valid + if (has_order){ + oi = p_o[j] - 1; + check_order_value(oi, o_rng, n_protections); + } else { + oi = j; + } + k = recycle_lag ? p_lag[j % lag_size] : lag1; lagi = j - k; p_out[oi] = unsigned(lagi - run_start) <= rng ? p_x[has_order ? p_o[lagi] - 1 : lagi] : fill_value; } @@ -570,7 +604,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re break; } case STRSXP: { - unsigned int size = Rf_length(x); + int size = Rf_length(x); if (has_order && (size != o_size)){ Rf_error("length(order) must equal length(x)"); } @@ -579,7 +613,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re ++n_protections; out = Rf_protect(Rf_duplicate(x)); ++n_protections; - for (unsigned int i = 0; i != rl_size; ++i){ + for (int i = 0; i != rl_size; ++i){ run_start = run_end; // Start at the end of the previous run rl = has_rl ? p_rl[i] : size; // Current run-length run_end += rl; // Cumulative run-length @@ -597,9 +631,15 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } unsigned int rng = (run_end - 1) - run_start; // Loop starting from the end of the previous run-length - for (unsigned int j = run_start; j != run_end; ++j){ - oi = has_order ? p_o[j] - 1 : j; - k = p_lag[j % lag_size]; + for (int j = run_start; j != run_end; ++j){ + // Check that order value is valid + if (has_order){ + oi = p_o[j] - 1; + check_order_value(oi, o_rng, n_protections); + } else { + oi = j; + } + k = recycle_lag ? p_lag[j % lag_size] : p_lag[0]; lagi = j - k; SET_STRING_ELT(out, oi, unsigned(lagi - run_start) <= rng ? p_x[has_order ? p_o[lagi] - 1 : lagi] : fill_char); } @@ -612,7 +652,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re break; } case CPLXSXP: { - unsigned int size = Rf_length(x); + int size = Rf_length(x); if (has_order && (size != o_size)){ Rf_error("length(order) must equal length(x)"); } @@ -625,7 +665,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re Rcomplex fill_value = fill_size >= 1 ? Rf_asComplex(fill) : COMPLEX(fill_sexp)[0]; out = Rf_protect(Rf_duplicate(x)); ++n_protections; - for (unsigned int i = 0; i != rl_size; ++i){ + for (int i = 0; i != rl_size; ++i){ run_start = run_end; // Start at the end of the previous run rl = has_rl ? p_rl[i] : size; // Current run-length run_end += rl; // Cumulative run-length @@ -643,9 +683,15 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } unsigned int rng = (run_end - 1) - run_start; // Loop starting from the end of the previous run-length - for (unsigned int j = run_start; j != run_end; ++j){ - oi = has_order ? p_o[j] - 1 : j; - k = p_lag[j % lag_size]; + for (int j = run_start; j != run_end; ++j){ + // Check that order value is valid + if (has_order){ + oi = p_o[j] - 1; + check_order_value(oi, o_rng, n_protections); + } else { + oi = j; + } + k = recycle_lag ? p_lag[j % lag_size] : lag1; lagi = j - k; SET_COMPLEX_ELT(out, oi, unsigned(lagi - run_start) <= rng ? p_x[has_order ? p_o[lagi] - 1 : lagi] : fill_value); } @@ -658,7 +704,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re break; } case RAWSXP: { - unsigned int size = Rf_length(x); + int size = Rf_length(x); if (has_order && (size != o_size)){ Rf_error("length(order) must equal length(x)"); } @@ -668,7 +714,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re ++n_protections; out = Rf_protect(Rf_duplicate(x)); ++n_protections; - for (unsigned int i = 0; i != rl_size; ++i){ + for (int i = 0; i != rl_size; ++i){ run_start = run_end; // Start at the end of the previous run rl = has_rl ? p_rl[i] : size; // Current run-length run_end += rl; // Cumulative run-length @@ -686,9 +732,15 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } unsigned int rng = (run_end - 1) - run_start; // Loop starting from the end of the previous run-length - for (unsigned int j = run_start; j != run_end; ++j){ - oi = has_order ? p_o[j] - 1 : j; - k = p_lag[j % lag_size]; + for (int j = run_start; j != run_end; ++j){ + // Check that order value is valid + if (has_order){ + oi = p_o[j] - 1; + check_order_value(oi, o_rng, n_protections); + } else { + oi = j; + } + k = recycle_lag ? p_lag[j % lag_size] : lag1; lagi = j - k; SET_RAW_ELT(out, oi, unsigned(lagi - run_start) <= rng ? p_x[has_order ? p_o[lagi] - 1 : lagi] : fill_raw); } @@ -698,16 +750,16 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } case VECSXP: { if (recursive){ - unsigned int size = Rf_length(x); + int size = Rf_length(x); const SEXP *p_x = VECTOR_PTR_RO(x); out = Rf_protect(Rf_allocVector(VECSXP, size)); ++n_protections; SHALLOW_DUPLICATE_ATTRIB(out, x); - for (unsigned int i = 0; i < size; ++i){ + for (int i = 0; i < size; ++i){ SET_VECTOR_ELT(out, i, cpp_lag2(p_x[i], lag, order, run_lengths, fill, true)); } } else { - unsigned int size = Rf_length(x); + int size = Rf_length(x); if (has_order && (size != o_size)){ Rf_error("length(order) must equal length(x)"); } @@ -717,7 +769,7 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re out = Rf_protect(Rf_allocVector(VECSXP, size)); ++n_protections; const SEXP *p_fill = VECTOR_PTR_RO(fill_value); - for (unsigned int i = 0; i != rl_size; ++i){ + for (int i = 0; i != rl_size; ++i){ run_start = run_end; // Start at the end of the previous run rl = has_rl ? p_rl[i] : size; // Current run-length run_end += rl; // Cumulative run-length @@ -735,9 +787,15 @@ SEXP cpp_lag2(SEXP x, SEXP lag, SEXP order, SEXP run_lengths, SEXP fill, bool re } unsigned int rng = (run_end - 1) - run_start; // Loop starting from the end of the previous run-length - for (unsigned int j = run_start; j != run_end; ++j){ - oi = has_order ? p_o[j] - 1 : j; - k = p_lag[j % lag_size]; + for (int j = run_start; j != run_end; ++j){ + // Check that order value is valid + if (has_order){ + oi = p_o[j] - 1; + check_order_value(oi, o_rng, n_protections); + } else { + oi = j; + } + k = recycle_lag ? p_lag[j % lag_size] : lag1; lagi = j - k; SET_VECTOR_ELT(out, oi, unsigned(lagi - run_start) <= rng ? p_x[has_order ? p_o[lagi] - 1 : lagi] : p_fill[0]); } diff --git a/src/nas.cpp b/src/nas.cpp index 414b7ea..6c9a080 100644 --- a/src/nas.cpp +++ b/src/nas.cpp @@ -252,115 +252,85 @@ bool cpp_all_na(SEXP x, bool return_true_on_empty, bool recursive){ return out; } -// A parallelised version of `is.na()` +// An alternate version of `is.na()` // lists are handled differently in that each element // must contain only NA in all nested elements to be regarded as NA [[cpp11::register]] SEXP cpp_is_na(SEXP x){ R_xlen_t n = Rf_xlength(x); - bool do_parallel = n >= 100000; - int n_cores = do_parallel ? num_cores() : 1; R_xlen_t i; + SEXP out; switch ( TYPEOF(x) ){ + case NILSXP: { + out = Rf_protect(Rf_allocVector(LGLSXP, 0)); + break; + } case LGLSXP: case INTSXP: { - SEXP out = Rf_protect(Rf_allocVector(LGLSXP, n)); + out = Rf_protect(Rf_allocVector(LGLSXP, n)); int *p_out = LOGICAL(out); int *p_x = INTEGER(x); - if (do_parallel){ - OMP_PARALLEL_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = (p_x[i] == NA_INTEGER); - } - } else { - OMP_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = (p_x[i] == NA_INTEGER); - } + OMP_FOR_SIMD + for (i = 0; i < n; ++i){ + p_out[i] = (p_x[i] == NA_INTEGER); } - Rf_unprotect(1); - return out; + break; } case REALSXP: { - SEXP out = Rf_protect(Rf_allocVector(LGLSXP, n)); + out = Rf_protect(Rf_allocVector(LGLSXP, n)); int *p_out = LOGICAL(out); double *p_x = REAL(x); - if (do_parallel){ - OMP_PARALLEL_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = (p_x[i] != p_x[i]); - } - } else { - OMP_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = (p_x[i] != p_x[i]); - } + OMP_FOR_SIMD + for (i = 0; i < n; ++i){ + p_out[i] = (p_x[i] != p_x[i]); } - Rf_unprotect(1); - return out; + break; } case STRSXP: { - SEXP out = Rf_protect(Rf_allocVector(LGLSXP, n)); + out = Rf_protect(Rf_allocVector(LGLSXP, n)); int *p_out = LOGICAL(out); SEXP *p_x = STRING_PTR(x); - if (do_parallel){ - OMP_PARALLEL_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = (p_x[i] == NA_STRING); - } - } else { - OMP_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = (p_x[i] == NA_STRING); - } + OMP_FOR_SIMD + for (i = 0; i < n; ++i){ + p_out[i] = (p_x[i] == NA_STRING); } - Rf_unprotect(1); - return out; + break; } case RAWSXP: { - SEXP out = Rf_protect(Rf_allocVector(LGLSXP, n)); + out = Rf_protect(Rf_allocVector(LGLSXP, n)); int *p_out = LOGICAL(out); memset(p_out, 0, n * sizeof(int)); - Rf_unprotect(1); - return out; + break; } case CPLXSXP: { - SEXP out = Rf_protect(Rf_allocVector(LGLSXP, n)); + out = Rf_protect(Rf_allocVector(LGLSXP, n)); int *p_out = LOGICAL(out); Rcomplex *p_x = COMPLEX(x); - if (do_parallel){ - OMP_PARALLEL_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = ( ((p_x[i]).r != (p_x[i]).r) || ((p_x[i]).i != (p_x[i]).i) ); - } - } else { - OMP_FOR_SIMD - for (i = 0; i < n; ++i){ - p_out[i] = ( ((p_x[i]).r != (p_x[i]).r) || ((p_x[i]).i != (p_x[i]).i) ); - } + OMP_FOR_SIMD + for (i = 0; i < n; ++i){ + p_out[i] = ( ((p_x[i]).r != (p_x[i]).r) || ((p_x[i]).i != (p_x[i]).i) ); } - Rf_unprotect(1); - return out; + break; } case VECSXP: { if (!Rf_isObject(x)){ - SEXP out = Rf_protect(Rf_allocVector(LGLSXP, n)); + out = Rf_protect(Rf_allocVector(LGLSXP, n)); int *p_out = LOGICAL(out); const SEXP *p_x = VECTOR_PTR_RO(x); for (i = 0; i < n; ++i){ p_out[i] = cpp_all_na(p_x[i], false, true); } - Rf_unprotect(1); - return out; } + break; } default: { - SEXP out = Rf_protect(cpp11::package("base")["is.na"](x)); - Rf_unprotect(1); - return out; + out = Rf_protect(cpp11::package("base")["is.na"](x)); + break; } } + Rf_unprotect(1); + return out; } // Memory-efficient which(is.na(x))