Skip to content

Commit

Permalink
Implement none() in C
Browse files Browse the repository at this point in the history
Turns out that negate() adds too much overhead with C implementation of every()
  • Loading branch information
ErdaradunGaztea committed Feb 6, 2025
1 parent 038fac8 commit e89a9a2
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 6 deletions.
7 changes: 6 additions & 1 deletion R/every-some-none.R
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,10 @@ some <- function(.x, .p, ...) {
#' @export
#' @rdname every
none <- function(.x, .p, ...) {
every(.x, negate(.p), ...)
.p <- as_mapper(.p, ...)

n <- vec_size(.x)
i <- 0L

.Call(none_impl, environment(), n, i)
}
16 changes: 11 additions & 5 deletions src/every.c → src/every-some-none.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@
#include "checks.h"

static SEXP make_call();
static SEXP test_predicate(SEXP env, SEXP ffi_n, SEXP ffi_i, bool initial_value);
static SEXP test_predicate(SEXP env, SEXP ffi_n, SEXP ffi_i, bool initial_value, bool early_stop_if);

SEXP every_impl(SEXP env, SEXP ffi_n, SEXP ffi_i);
SEXP some_impl(SEXP env, SEXP ffi_n, SEXP ffi_i);
SEXP none_impl(SEXP env, SEXP ffi_n, SEXP ffi_i);

SEXP every_impl(SEXP env, SEXP ffi_n, SEXP ffi_i) {
return test_predicate(env, ffi_n, ffi_i, true);
return test_predicate(env, ffi_n, ffi_i, true, false);
}

SEXP some_impl(SEXP env, SEXP ffi_n, SEXP ffi_i) {
return test_predicate(env, ffi_n, ffi_i, false);
return test_predicate(env, ffi_n, ffi_i, false, true);
}

SEXP none_impl(SEXP env, SEXP ffi_n, SEXP ffi_i) {
return test_predicate(env, ffi_n, ffi_i, true, true);
}

/**
Expand All @@ -27,9 +32,10 @@ SEXP some_impl(SEXP env, SEXP ffi_n, SEXP ffi_i) {
* @param ffi_n Length of .x
* @param ffi_i Integer for iterating over elements of .x; should be equal to 0
* @param initial_value Answer if length of .x is 0
* @param early_stop_if Value to stop iterating on
* @return A single R logical value, one of TRUE/FALSE/NA
*/
static SEXP test_predicate(SEXP env, SEXP ffi_n, SEXP ffi_i, bool initial_value) {
static SEXP test_predicate(SEXP env, SEXP ffi_n, SEXP ffi_i, bool initial_value, bool early_stop_if) {
int n = INTEGER_ELT(ffi_n, 0);
int* p_i = INTEGER(ffi_i);

Expand Down Expand Up @@ -64,7 +70,7 @@ static SEXP test_predicate(SEXP env, SEXP ffi_n, SEXP ffi_i, bool initial_value)
int res_value = LOGICAL(res)[0];
UNPROTECT(1); // res

if (res_value == !initial_value) {
if (res_value == early_stop_if) {
*p_out = !initial_value;
break;
}
Expand Down
2 changes: 2 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extern SEXP pluck_impl(SEXP, SEXP, SEXP, SEXP);
extern SEXP flatten_impl(SEXP);
extern SEXP every_impl(SEXP, SEXP, SEXP);
extern SEXP some_impl(SEXP, SEXP, SEXP);
extern SEXP none_impl(SEXP, SEXP, SEXP);
extern SEXP map_impl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP map2_impl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP pmap_impl(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP);
Expand All @@ -28,6 +29,7 @@ static const R_CallMethodDef CallEntries[] = {
{"flatten_impl", (DL_FUNC) &flatten_impl, 1},
{"every_impl", (DL_FUNC) &every_impl, 3},
{"some_impl", (DL_FUNC) &some_impl, 3},
{"none_impl", (DL_FUNC) &none_impl, 3},
{"map_impl", (DL_FUNC) &map_impl, 6},
{"map2_impl", (DL_FUNC) &map2_impl, 6},
{"pmap_impl", (DL_FUNC) &pmap_impl, 8},
Expand Down

0 comments on commit e89a9a2

Please sign in to comment.