1310 functions analysed · 873 typed · 413 untypeable · 24 timed out · 145 entry points (79 typed) · checker unknown
SEXP _r_pairlist(SEXP* tags, SEXP* cars) {
if (!cars) {
r_stop_internal("NULL `cars`.");
}
SEXP list = PROTECT(Rf_cons(R_NilValue, R_NilValue));
SEXP node = list;
while (*cars) {
SEXP next_node = Rf_cons(*cars, R_NilValue);
SETCDR(node, next_node);
node = next_node;
if (tags) {
SET_TAG(next_node, *tags);
++tags;
}
++cars;
}
UNPROTECT(1);
return CDR(list);
}static void abort_parse(r_obj* code, const char* why) {
if (r_peek_option("rlang__verbose_errors") != r_null) {
r_obj_print(code);
}
r_abort("Internal error: %s", why);
}bool allow_null_as_bool(enum vctrs_allow_null allow_null) {
return (bool) allow_null;
}bool any_has_suffix(r_obj* names) {
r_ssize n = r_length(names);
r_obj* const * v_names = r_chr_cbegin(names);
for (r_ssize i = 0; i < n; ++i) {
if (suffix_pos(r_str_c_string(v_names[i])) >= 0) {
return true;
}
}
return false;
}r_obj* apply_name_spec(r_obj* name_spec, r_obj* outer, r_obj* inner, r_ssize n) {
if (r_inherits(name_spec, "rlang_zap")) {
return r_null;
}
if (name_spec_is_inner(name_spec)) {
// Ignore `outer` entirely
return inner;
}
if (outer == r_null) {
// `outer` doesn't exist, no need to apply `name_spec`
return inner;
}
if (r_typeof(outer) != R_TYPE_string) {
r_stop_internal("`outer` must be a scalar string.");
}
if (outer == strings_empty || outer == r_globals.na_str) {
if (inner == r_null) {
return chrs_empty;
} else {
return inner;
}
}
if (r_is_empty_names(inner)) {
if (n == 0) {
return r_globals.empty_chr;
}
if (n == 1) {
return r_str_as_character(outer);
}
inner = KEEP(r_seq(1, n + 1));
} else {
inner = KEEP(inner);
}
switch (r_typeof(name_spec)) {
case R_TYPE_closure:
break;
case R_TYPE_character:
name_spec = glue_as_name_spec(name_spec);
break;
default:
name_spec = r_as_function(name_spec, ".name_spec");
break;
case R_TYPE_null: {
const char* reason;
if (n > 1) {
reason = "a vector of length > 1";
} else {
reason = "a named vector";
}
r_abort("Can't merge the outer name `%s` with %s.\n"
"Please supply a `.name_spec` specification.",
r_str_c_string(outer),
reason);
}}
KEEP(name_spec);
r_obj* outer_chr = KEEP(r_str_as_character(outer));
r_obj* out = KEEP(vctrs_dispatch2(syms_dot_name_spec, name_spec,
syms_outer, outer_chr,
syms_inner, inner));
if (out != r_null) {
if (r_typeof(out) != R_TYPE_character) {
r_abort("`.name_spec` must return a character vector.");
}
vec_check_recyclable(out, n, VCTRS_ALLOW_NULL_no, vec_args.empty, r_lazy_null);
}
FREE(4);
return out;
}enum vctrs_allow_null arg_as_allow_null(r_obj* x, const char* arg) {
return r_arg_as_bool(x, arg) ? VCTRS_ALLOW_NULL_yes : VCTRS_ALLOW_NULL_no;
}r_obj* as_df_col(r_obj* x,
r_obj* outer,
bool* allow_pack,
struct r_lazy error_call) {
if (is_data_frame(x)) {
*allow_pack = true;
return r_clone(x);
}
r_ssize ndim = vec_bare_dim_n(x);
if (ndim > 2) {
r_abort_lazy_call(error_call, "Can't bind arrays.");
}
if (ndim > 0) {
*allow_pack = true;
return shaped_as_df_col(x, outer);
}
*allow_pack = false;
return vec_as_df_col(x, outer);
}r_obj* as_df_row_impl(r_obj* x,
struct name_repair_opts* name_repair,
struct r_lazy error_call) {
if (x == r_null) {
return x;
}
if (is_data_frame(x)) {
return df_repair_names(x, name_repair);
}
int nprot = 0;
r_obj* dim = KEEP_N(vec_bare_dim(x), &nprot);
r_ssize ndim = (dim == r_null) ? 1 : r_length(dim);
if (ndim > 2) {
r_abort_lazy_call(error_call, "Can't bind arrays.");
}
if (ndim == 2) {
r_obj* out = KEEP_N(r_as_data_frame(x), &nprot);
r_attrib_poke_names(out, vec_as_names(KEEP_N(colnames2(x), &nprot), name_repair));
FREE(nprot);
return out;
}
// Take names before removing dimensions so we get colnames if needed
r_obj* nms = KEEP_N(vec_names2(x), &nprot);
nms = KEEP_N(vec_as_names(nms, name_repair), &nprot);
if (dim != r_null) {
x = KEEP_N(r_clone_referenced(x), &nprot);
r_attrib_poke(x, r_syms.dim, r_null);
r_attrib_poke(x, r_syms.dim_names, r_null);
}
// Remove names first as they are promoted to data frame column names.
// Can be a user side object, so use `VCTRS_OWNERSHIP_foreign`.
x = KEEP_N(vec_set_names(x, r_null, VCTRS_OWNERSHIP_foreign), &nprot);
x = KEEP_N(vec_chop_unsafe(x, r_null, r_null), &nprot);
r_attrib_poke_names(x, nms);
x = new_data_frame(x, 1);
FREE(nprot);
return x;
}void attrib_append_row_names(r_obj* x, r_obj* row_names) {
#if R_VERSION >= R_Version(4, 6, 0)
r_attrib_poke(x, r_syms.row_names, row_names);
#else
r_obj* attrib = ATTRIB(x);
attrib = KEEP(r_new_node(row_names, attrib));
r_node_poke_tag(attrib, r_syms.row_names);
SET_ATTRIB(x, attrib);
FREE(1);
#endif
}r_obj* base_c_invoke(
r_obj* xs,
r_obj* name_spec,
struct r_lazy error_call
) {
if (vctrs_debug_verbose) {
r_obj* x = list_first_non_null(xs, NULL);
r_printf(
"Falling back to `base::c()` for class `%s`.\n",
r_chr_get_c_string(r_class(x), 0)
);
}
if (name_spec_is_inner(name_spec)) {
// We don't support most `name_spec` options in the fallback,
// but we do allow this one because it is extremely useful
// and easy to implement
name_spec = r_null;
if (r_names(xs) != r_null) {
// Remove outer names, but remember we likely don't own `xs`!
xs = KEEP(r_clone_referenced(xs));
r_attrib_poke_names(xs, r_null);
FREE(1);
}
}
KEEP(xs);
if (name_spec != r_null) {
stop_name_spec_in_fallback(xs, error_call);
}
r_obj* ffi_call = KEEP(r_call2(r_sym("base_c_invoke"), xs));
r_obj* out = r_eval(ffi_call, vctrs_ns_env);
FREE(2);
return out;
}r_obj* base_list_combine_fallback(
r_obj* xs,
bool has_indices,
r_obj* indices,
enum vctrs_index_style indices_style,
r_ssize size,
bool has_default,
r_obj* default_,
enum list_combine_multiple multiple,
enum assignment_slice_value slice_xs,
r_obj* name_spec,
struct vctrs_arg* p_xs_arg,
struct vctrs_arg* p_default_arg,
struct r_lazy error_call
) {
if (!has_indices) {
// Sequential combination, nothing fancy here
return base_c_invoke(xs, name_spec, error_call);
}
// Otherwise we have `indices`. We need to recreate a bunch of the "main" path
// logic, and then combine all `xs` together and reorder using the `indices`.
//
// We end up doing something like:
//
// ```
// vec_slice_fallback(base_c(!!!xs), order(vec_c(!!!indices)))
// ```
// Normalize `indices` to the location style, because that's what the fallback
// is designed to handle. It's also the style we convert `default` to.
switch (indices_style) {
case VCTRS_INDEX_STYLE_location: {
indices = list_location_to_location_indices(indices);
break;
}
case VCTRS_INDEX_STYLE_condition: {
indices_style = VCTRS_INDEX_STYLE_location;
indices = list_condition_to_location_indices(indices);
break;
}
default: r_stop_unreachable();
}
KEEP(indices);
// Normalize and check `xs` sizes
//
// - If `slice_xs = no`, each `x` must be size 1 or the size of the `index`
// - Size 1 must be recycled up to the size of the `index`
// - If `slice_xs = yes`, each `x` must be size 1 or size `size`
// - Size 1 must be recycled up to the size of the `index`
// - Size `size` must be sliced down to the size of the `index`
switch (slice_xs) {
case ASSIGNMENT_SLICE_VALUE_no: {
xs = vec_recycle_xs_fallback(xs, indices, p_xs_arg, error_call);
break;
}
case ASSIGNMENT_SLICE_VALUE_yes: {
xs = vec_slice_xs_fallback(xs, indices, size, p_xs_arg, error_call);
break;
}
default: r_stop_unreachable();
}
KEEP(xs);
// Reverse `xs` and `indices` if required for `multiple`
//
// - Done after recycling/slicing of `xs` because `p_xs_arg` is used there
// and we need to generate correct index locations in errors.
// - Done before `default` handling because `default` is always pushed
// at the end.
switch (multiple) {
case LIST_COMBINE_MULTIPLE_last: {
// Nothing to do, this is the standard behavior
break;
}
case LIST_COMBINE_MULTIPLE_first: {
xs = KEEP(vec_reverse(xs));
indices = KEEP(vec_reverse(indices));
FREE(2);
break;
}
}
KEEP(xs);
KEEP(indices);
if (has_default) {
// Materialize the `default`'s index in location style, as that is what
// we normalized `indices` to.
r_obj* default_index = KEEP(compute_default_index(indices, indices_style, size));
default_index = KEEP(compact_condition_materialize_location(default_index));
// `default` recycles against the output size
const r_ssize default_size = vec_size(default_);
const r_ssize default_index_size = r_length(default_index);
// Other `xs` have been sliced already, we now need to sliced `default`,
// which is always provided in `slice_xs = yes` style.
if (default_size == 1) {
// Recycle "up" to the size of the index
default_ = vec_recycle_fallback(default_, default_index_size, p_default_arg, error_call);
} else if (default_size == size) {
// Slice "down" to the size of the index
default_ = vec_slice_fallback(default_, default_index);
} else {
// `default` is the wrong size, error
vec_check_recyclable(default_, size, VCTRS_ALLOW_NULL_no, p_default_arg, error_call);
}
KEEP(default_);
// Append the default to `xs` and `indices` before the fallback
xs = KEEP(push_default(xs, default_));
indices = KEEP(push_default_index(indices, default_index));
FREE(5);
}
KEEP(xs);
KEEP(indices);
// Remove all `NULL`s from `xs` and their corresponding slot in `indices`.
//
// `base_c_invoke()` does this as well, but we need to remove the `indices` slot
// at the same time.
//
// - Done after `default_index` computation, so `default_index` doesn't capture
// dropped indices.
// - Done after `vec_recycle_xs_fallback()` so we have correct indices in recycling
// error messages.
if (vec_any_missing(xs)) {
r_obj* complete = KEEP(vec_detect_complete(xs));
complete = KEEP(r_lgl_which(complete, false));
xs = KEEP(vec_slice_unsafe(xs, complete));
indices = KEEP(vec_slice_unsafe(indices, complete));
FREE(4);
}
KEEP(xs);
KEEP(indices);
r_obj* out = KEEP(base_c_invoke(xs, name_spec, error_call));
r_obj* index = KEEP(build_fallback_index(indices, size, error_call));
out = vec_slice_fallback(out, index);
FREE(10);
return out;
}r_obj* c_data_frame_class(r_obj* cls) {
if (r_typeof(cls) != R_TYPE_character) {
r_abort_call(r_null, "`class` must be NULL or a character vector");
}
return chr_c(cls, classes_data_frame);
}void check_condition_index(
r_obj* x,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
if (!is_condition_index(x)) {
r_abort_lazy_call(
call,
"%s must be a logical vector, not %s.",
vec_arg_format(p_x_arg),
r_obj_type_friendly(x)
);
}
}void check_names(r_obj* x, r_obj* names) {
if (names == r_null) {
return;
}
if (r_typeof(names) != R_TYPE_character) {
r_abort(
"`names` must be a character vector, not a %s.",
r_type_as_c_string(r_typeof(names))
);
}
r_ssize x_size = vec_size(x);
r_ssize names_size = vec_size(names);
if (x_size != names_size) {
r_abort(
"The size of `names`, %i, must be the same as the size of `x`, %i.",
names_size,
x_size
);
}
}void check_rcrd(SEXP x) {
if (!Rf_isVectorList(x))
Rf_errorcall(R_NilValue, "Corrupt rcrd: not a list");
if (Rf_length(x) == 0)
Rf_errorcall(R_NilValue, "Corrupt rcrd: length 0");
}void check_recyclable_against_index(
r_obj* value,
r_obj* index,
r_ssize size,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style,
struct vctrs_arg* p_value_arg,
struct r_lazy call
) {
r_ssize check_size;
switch (slice_value) {
case ASSIGNMENT_SLICE_VALUE_no: {
switch (index_style) {
case VCTRS_INDEX_STYLE_location: check_size = vec_subscript_size(index); break;
case VCTRS_INDEX_STYLE_condition: check_size = vec_condition_subscript_sum(index, true); break;
default: r_stop_unreachable();
}
break;
}
case ASSIGNMENT_SLICE_VALUE_yes: check_size = size; break;
default: r_stop_unreachable();
}
vec_check_recyclable(value, check_size, VCTRS_ALLOW_NULL_no, p_value_arg, call);
}void check_rep_each_times(int times,
r_ssize i,
struct r_lazy call,
struct vctrs_arg* p_times_arg) {
if (times < 0) {
if (times == r_globals.na_int) {
stop_rep_each_times_missing(i, call, p_times_arg);
} else {
stop_rep_each_times_negative(i, call, p_times_arg);
}
} else if (times_is_oob(times)) {
stop_rep_each_times_oob(times, i, call, p_times_arg);
}
}void check_rep_times(int times,
struct r_lazy call,
struct vctrs_arg* p_times_arg) {
if (times < 0) {
if (times == r_globals.na_int) {
stop_rep_times_missing(call, p_times_arg);
} else {
stop_rep_times_negative(call, p_times_arg);
}
} else if (times_is_oob(times)) {
stop_rep_times_oob(times, call, p_times_arg);
}
}r_obj* check_unique_names(r_obj* names,
const struct name_repair_opts* opts) {
r_obj* ffi_arg = KEEP(r_lazy_eval(opts->name_repair_arg));
r_obj* ffi_call = KEEP(r_lazy_eval(opts->call));
r_obj* out = KEEP(vctrs_dispatch3(syms_check_unique_names, fns_check_unique_names,
syms_names, names,
r_syms.arg, ffi_arg,
syms_call, ffi_call));
// Restore visibility
r_eval(r_null, r_envs.empty);
FREE(3);
return out;
}r_obj* chop_fallback_shaped(r_obj* x, struct vctrs_chop_indices* p_indices) {
const r_ssize out_size = indices_out_size(p_indices, x);
r_obj* out = KEEP(r_alloc_list(out_size));
for (r_ssize i = 0; i < out_size; ++i) {
r_obj* index = indices_next(p_indices);
index = KEEP(vec_subscript_materialize(index));
// `vec_slice_fallback()` will also `vec_restore()` for us
r_obj* elt = vec_slice_fallback(x, index);
r_list_poke(out, i, elt);
FREE(1);
}
FREE(1);
return out;
}bool chr_all_same(
const char** p_x,
const r_ssize size
) {
if (size == 0) {
return true;
}
const char* first = p_x[0];
for (r_ssize i = 1; i < size; ++i) {
if (first != p_x[i]) {
return false;
}
}
return true;
}bool chr_all_same_byte(
const char** p_x,
const r_ssize size
) {
if (size == 0) {
return true;
}
const uint8_t first = (uint8_t) *p_x[0];
for (r_ssize i = 1; i < size; ++i) {
const uint8_t this = (uint8_t) *p_x[i];
if (this != first) {
return false;
}
}
return true;
}SEXP chr_apply(SEXP x, SEXP chr_proxy_collate) {
// Don't use vctrs dispatch utils because we match argument positionally
SEXP call = PROTECT(Rf_lang2(syms_chr_proxy_collate, syms_x));
SEXP mask = PROTECT(r_alloc_empty_environment(R_GlobalEnv));
Rf_defineVar(syms_chr_proxy_collate, chr_proxy_collate, mask);
Rf_defineVar(syms_x, x, mask);
SEXP out = PROTECT(Rf_eval(call, mask));
if (vec_typeof(out) != VCTRS_TYPE_character) {
Rf_errorcall(
R_NilValue,
"`chr_proxy_collate` must return a character vector."
);
}
R_len_t x_size = vec_size(x);
R_len_t out_size = vec_size(out);
if (x_size != out_size) {
Rf_errorcall(
R_NilValue,
"`chr_proxy_collate` must return a vector of the same length (%i, not %i).",
x_size,
out_size
);
}
UNPROTECT(3);
return out;
}r_obj* chr_assign(
r_obj* x,
r_obj* index,
r_obj* value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_BARRIER(r_obj*, r_chr_cbegin, r_chr_poke);
}SEXP chr_c(SEXP x, SEXP y) {
r_ssize x_n = r_length(x);
r_ssize y_n = r_length(y);
if (x_n == 0) {
return y;
}
if (y_n == 0) {
return x;
}
r_ssize out_n = r_ssize_add(x_n, y_n);
SEXP out = PROTECT(r_alloc_vector(STRSXP, out_n));
const SEXP* p_x = STRING_PTR_RO(x);
const SEXP* p_y = STRING_PTR_RO(y);
for (r_ssize i = 0; i < x_n; ++i) {
SET_STRING_ELT(out, i, p_x[i]);
}
for (r_ssize i = 0, j = x_n; i < y_n; ++i, ++j) {
SET_STRING_ELT(out, j, p_y[i]);
}
UNPROTECT(1);
return out;
}r_ssize chr_col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
COL_DETECT_MISSING(r_obj*, r_chr_cbegin, chr_is_missing);
}void chr_col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_COL_DETECT_RUN_BOUNDS_BOOL(r_obj*, r_chr_cbegin, chr_equal_na_equal);
}r_obj* chr_detect_missing(r_obj* x) {
DETECT_MISSING(r_obj*, r_chr_cbegin, chr_is_missing);
}void chr_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_DETECT_RUN_BOUNDS_BOOL(r_obj*, r_chr_cbegin, chr_equal_na_equal);
}uint32_t chr_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return chr_dict_hash_with(d, d, i);
}uint32_t chr_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_chr_equal_na_equal);
}bool chr_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_chr_is_incomplete(d->p_poly_vec->p_vec, i);
}static inline int chr_equal_na_equal(SEXP x, SEXP y) {
return x == y;
}static inline int chr_equal_na_propagate(SEXP x, SEXP y) {
if (chr_is_missing(x) || chr_is_missing(y)) {
return NA_LOGICAL;
} else {
return chr_equal_na_equal(x, y);
}
}struct r_ssize_int_pair chr_extract_without_missings(
r_ssize size,
const SEXP* p_x,
const char** p_x_strings
) {
r_ssize n_missing = 0;
int max_string_size = 0;
r_ssize loc = 0;
for (r_ssize i = 0; i < size; ++i) {
SEXP elt = p_x[i];
if (elt == NA_STRING) {
++n_missing;
} else {
const int elt_string_size = (int) Rf_length(elt);
if (max_string_size < elt_string_size) {
max_string_size = elt_string_size;
}
p_x_strings[loc] = CHAR(elt);
++loc;
}
}
return (struct r_ssize_int_pair) {
.x = n_missing,
.y = max_string_size
};
}r_ssize chr_find_encoding_start(r_obj* x, r_ssize size) {
r_obj* const* p_x = r_chr_cbegin(x);
for (r_ssize i = 0; i < size; ++i) {
r_obj* const elt = p_x[i];
if (!str_is_ascii_or_utf8(elt)) {
return i;
}
}
return size;
}r_ssize chr_first_missing(r_obj* x) {
FIRST_MISSING(r_obj*, r_chr_cbegin, chr_is_missing);
}void chr_handle_missings(
r_ssize size,
r_ssize n_missing,
const bool na_last,
const SEXP* p_x,
int* p_o,
int* p_o_aux
) {
r_ssize loc_missing = na_last ? (size - n_missing) : 0;
r_ssize loc_not_missing = na_last ? 0 : n_missing;
for (r_ssize i = 0; i < size; ++i) {
SEXP elt = p_x[i];
if (elt == NA_STRING) {
p_o_aux[loc_missing] = p_o[i];
++loc_missing;
} else {
p_o_aux[loc_not_missing] = p_o[i];
++loc_not_missing;
}
}
// Copy back
r_memcpy(p_o, p_o_aux, size * sizeof(*p_o_aux));
}static inline uint32_t chr_hash(r_obj* x) {
HASH(r_obj*, r_chr_cbegin, chr_hash_scalar);
}static inline void chr_hash_fill_na_equal(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL(r_obj*, r_chr_cbegin, chr_hash_scalar);
}static inline void chr_hash_fill_na_propagate(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL_NA_PROPAGATE(r_obj*, r_chr_cbegin, chr_hash_scalar, chr_is_missing);
}static inline uint32_t chr_hash_scalar(r_obj* x) {
return uint64_hash((uintptr_t) x);
}bool chr_is_missing(r_obj* x) {
return x == r_globals.na_str;
}void chr_order_insertion(
const r_ssize size,
const bool decreasing,
const char** p_x,
int* p_o,
struct group_infos* p_group_infos
) {
// Don't think this can occur, but safer this way
if (size == 0) {
return;
}
const int direction = decreasing ? -1 : 1;
for (r_ssize i = 1; i < size; ++i) {
const char* elt = p_x[i];
const int elt_o = p_o[i];
r_ssize j = i - 1;
while (j >= 0) {
const char* cmp_elt = p_x[j];
if (str_ge(elt, cmp_elt, direction)) {
break;
}
// It seems to help performance to avoid loading this
// before the if statement, since it often isn't needed
const int cmp_elt_o = p_o[j];
// Swap
p_x[j + 1] = cmp_elt;
p_o[j + 1] = cmp_elt_o;
// Next
--j;
}
// Place original elements in new location
// closer to start of the vector
p_x[j + 1] = elt;
p_o[j + 1] = elt_o;
}
// We've ordered a small chunk, we need to push at least one group size.
// Depends on the post-ordered results so we have to do this
// in a separate loop.
r_ssize group_size = 1;
const char* previous = p_x[0];
for (r_ssize i = 1; i < size; ++i) {
const char* current = p_x[i];
// Continue the current group run
if (current == previous) {
++group_size;
continue;
}
// Push current run size and reset size tracker
groups_size_maybe_push(group_size, p_group_infos);
group_size = 1;
previous = current;
}
// Push final group run
groups_size_maybe_push(group_size, p_group_infos);
}void chr_order_radix(
const r_ssize size,
const bool decreasing,
const int max_string_size,
const char** p_x,
int* p_o,
const char** p_x_aux,
int* p_o_aux,
uint8_t* p_bytes,
struct group_infos* p_group_infos
) {
int pass = 0;
// If `pass == max_string_size == 0`, we are already done!
//
// This is needed when a vector of `NA` followed by all `""` are passed in. The
// `NA` make it look unsorted, but then the `NA` are removed, so we are left
// with a vector of `""` with `max_string_size == 0`.
//
// Without this, we can infloop because the `next_pass == max_string_size`
// exit never occurs because `next_pass` starts above `max_string_size`. We
// have a test to make sure we return the correct result.
if (pass == max_string_size) {
groups_size_maybe_push(size, p_group_infos);
return;
}
chr_order_radix_recurse(
size,
decreasing,
pass,
max_string_size,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_group_infos
);
}bool class_implements_base_c(r_obj* cls) {
if (s3_class_find_method("c", cls, base_method_table) != r_null) {
return true;
}
if (s4_class_find_method(cls, s4_c_method_table) != r_null) {
return true;
}
return false;
}enum vctrs_class_type class_type(r_obj* x) {
if (!r_is_object(x)) {
return VCTRS_CLASS_none;
}
r_obj* cls = KEEP(r_class(x));
// Avoid corrupt objects where `x` is an object, but the class is NULL
if (cls == r_null) {
FREE(1);
return VCTRS_CLASS_none;
}
enum vctrs_class_type type = class_type_impl(cls);
FREE(1);
return type;
}enum vctrs_class_type class_type_impl(r_obj* cls) {
int n = r_length(cls);
r_obj* const* p = r_chr_cbegin(cls);
// First check for bare types for which we know how many strings are
// the classes composed of
switch (n) {
case 1: {
r_obj* p0 = p[0];
if (p0 == strings_data_frame) {
return VCTRS_CLASS_bare_data_frame;
} else if (p0 == strings_factor) {
return VCTRS_CLASS_bare_factor;
} else if (p0 == strings_date) {
return VCTRS_CLASS_bare_date;
} else if (p0 == strings.AsIs) {
return VCTRS_CLASS_bare_asis;
}
break;
}
case 2: {
r_obj* p0 = p[0];
r_obj* p1 = p[1];
if (p0 == strings_ordered &&
p1 == strings_factor) {
return VCTRS_CLASS_bare_ordered;
}
if (p1 == strings_posixt) {
if (p0 == strings_posixct) {
return VCTRS_CLASS_bare_posixct;
} else if (p0 == strings_posixlt) {
return VCTRS_CLASS_bare_posixlt;
}
}
break;
}
case 3: {
if (p[0] == strings_tbl_df &&
p[1] == strings_tbl &&
p[2] == strings_data_frame) {
return VCTRS_CLASS_bare_tibble;
}
break;
}}
// Now check for inherited classes
p = p + n - 1;
r_obj* last = *p;
if (last == strings_data_frame) {
return VCTRS_CLASS_data_frame;
} else if (last == strings_list) {
return VCTRS_CLASS_list;
}
return VCTRS_CLASS_unknown;
}bool class_type_is_data_frame(enum vctrs_class_type type) {
switch (type) {
case VCTRS_CLASS_data_frame:
case VCTRS_CLASS_bare_data_frame:
case VCTRS_CLASS_bare_tibble:
return true;
default:
return false;
}
}void col_detect_complete_switch(SEXP x, R_len_t size, int* p_out) {
switch (vec_proxy_typeof(x)) {
case VCTRS_TYPE_logical: lgl_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_integer: int_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_double: dbl_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_complex: cpl_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_character: chr_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_raw: raw_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_list: list_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_dataframe: r_stop_internal("Data frame columns should have been flattened by now.");
case VCTRS_TYPE_null: r_abort("Unexpected `NULL` column found in a data frame.");
case VCTRS_TYPE_scalar: stop_scalar_type(x, vec_args.empty, r_lazy_null);
default: stop_unimplemented_vctrs_type("vec_detect_complete", vec_proxy_typeof(x));
}
}r_ssize col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
const enum vctrs_type type = vec_proxy_typeof(x);
switch (type) {
case VCTRS_TYPE_logical: return lgl_col_detect_missing(x, v_loc, loc_size);
case VCTRS_TYPE_integer: return int_col_detect_missing(x, v_loc, loc_size);
case VCTRS_TYPE_double: return dbl_col_detect_missing(x, v_loc, loc_size);
case VCTRS_TYPE_complex: return cpl_col_detect_missing(x, v_loc, loc_size);
case VCTRS_TYPE_raw: return raw_col_detect_missing(x, v_loc, loc_size);
case VCTRS_TYPE_character: return chr_col_detect_missing(x, v_loc, loc_size);
case VCTRS_TYPE_list: return list_col_detect_missing(x, v_loc, loc_size);
case VCTRS_TYPE_dataframe: r_stop_internal("Data frame columns should have been flattened by now.");
case VCTRS_TYPE_null: r_abort("Unexpected `NULL` column found in a data frame.");
case VCTRS_TYPE_scalar: stop_scalar_type(x, vec_args.empty, r_lazy_null);
default: stop_unimplemented_vctrs_type("vec_detect_missing", type);
}
}void col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
switch (vec_proxy_typeof(x)) {
case VCTRS_TYPE_logical: lgl_col_detect_run_bounds_bool(x, size, which, v_out); break;
case VCTRS_TYPE_integer: int_col_detect_run_bounds_bool(x, size, which, v_out); break;
case VCTRS_TYPE_double: dbl_col_detect_run_bounds_bool(x, size, which, v_out); break;
case VCTRS_TYPE_complex: cpl_col_detect_run_bounds_bool(x, size, which, v_out); break;
case VCTRS_TYPE_character: chr_col_detect_run_bounds_bool(x, size, which, v_out); break;
case VCTRS_TYPE_raw: raw_col_detect_run_bounds_bool(x, size, which, v_out); break;
case VCTRS_TYPE_list: list_col_detect_run_bounds_bool(x, size, which, v_out); break;
case VCTRS_TYPE_dataframe: r_stop_internal("Data frame columns should be flattened.");
case VCTRS_TYPE_scalar: r_abort("Can't compare scalars.");
default: r_abort("Unimplemented type.");
}
}SEXP colnames(SEXP x) {
return vctrs_dispatch1(syms_colnames, fns_colnames,
syms_x, x);
}r_obj* colnames2(r_obj* x) {
r_obj* names = colnames(x);
if (names == r_null) {
return r_alloc_character(Rf_ncols(x));
} else {
return names;
}
}bool* compact_condition_begin(r_obj* x) {
return (bool*) r_raw_begin(x);
}const bool* compact_condition_cbegin(r_obj* x) {
return (const bool*) r_raw_cbegin(x);
}r_obj* compact_condition_materialize(r_obj* x) {
const bool* v_x = compact_condition_cbegin(x);
const r_ssize size = compact_condition_size(x);
r_obj* out = KEEP(r_alloc_logical(size));
int* v_out = r_lgl_begin(out);
for (r_ssize i = 0; i < size; ++i) {
v_out[i] = v_x[i];
}
FREE(1);
return out;
}r_obj* compact_condition_materialize_location(r_obj* x) {
const bool* v_x = compact_condition_cbegin(x);
const r_ssize size = compact_condition_size(x);
return p_bool_which(v_x, size);
}r_ssize compact_condition_size(r_obj* x) {
// Should always be the same as the length, but you never know
return r_length(x) / sizeof(bool);
}r_ssize compact_condition_sum(r_obj* x) {
const bool* v_x = compact_condition_cbegin(x);
const r_ssize size = compact_condition_size(x);
return p_bool_sum(v_x, size);
}SEXP compact_rep(R_len_t i, R_len_t n) {
if (n < 0) {
r_stop_internal("Negative `n` in `compact_rep()`.");
}
SEXP rep = PROTECT(Rf_allocVector(INTSXP, 2));
int* p = INTEGER(rep);
init_compact_rep(p, i, n);
r_attrib_poke_class(rep, compact_rep_classes);
UNPROTECT(1);
return rep;
}SEXP compact_rep_materialize(SEXP x) {
int i = r_int_get(x, 0);
int n = r_int_get(x, 1);
SEXP out = PROTECT(Rf_allocVector(INTSXP, n));
r_int_fill(out, i, n);
UNPROTECT(1);
return out;
}r_ssize compact_rownames_length(r_obj* x) {
return abs(r_int_get(x, 1));
}SEXP compact_seq(R_len_t start, R_len_t size, bool increasing) {
if (start < 0) {
r_stop_internal("`start` must not be negative.");
}
if (size < 0) {
r_stop_internal("`size` must not be negative.");
}
if (!increasing && size > start + 1) {
r_stop_internal("`size` must not be larger than `start` for decreasing sequences.");
}
SEXP info = PROTECT(Rf_allocVector(INTSXP, 3));
int* p = INTEGER(info);
init_compact_seq(p, start, size, increasing);
r_attrib_poke_class(info, compact_seq_classes);
UNPROTECT(1);
return info;
}SEXP compact_seq_materialize(SEXP x) {
int* p = INTEGER(x);
R_len_t start = p[0] + 1;
R_len_t size = p[1];
R_len_t step = p[2];
SEXP out = PROTECT(Rf_allocVector(INTSXP, size));
int* out_data = INTEGER(out);
for (R_len_t i = 0; i < size; ++i, ++out_data, start += step) {
*out_data = start;
}
UNPROTECT(1);
return out;
}r_ssize compute_iter_loc(r_ssize size, enum vctrs_run_bound which) {
switch (which) {
case VCTRS_RUN_BOUND_start: return 0;
case VCTRS_RUN_BOUND_end: return size - 1;
default: r_stop_internal("Unknown `which` value.");
}
}r_ssize compute_iter_step(enum vctrs_run_bound which) {
switch (which) {
case VCTRS_RUN_BOUND_start: return 1;
case VCTRS_RUN_BOUND_end: return -1;
default: r_stop_internal("Unknown `which` value.");
}
}r_obj* compute_nesting_container_info(r_obj* haystack,
r_ssize size_haystack,
const enum vctrs_ops* v_ops) {
int n_prot = 0;
const r_ssize n_cols = r_length(haystack);
// Outputs:
// - `haystack` order
// - Container id vector
// - Number of containers as a scalar
// - Boolean for if there are any-non-equi conditions
r_obj* out = KEEP_N(r_alloc_list(4), &n_prot);
bool any_non_equi = false;
int first_non_equi = 0;
for (r_ssize i = 0; i < n_cols; ++i) {
const enum vctrs_ops op = v_ops[i];
if (op != VCTRS_OPS_eq) {
any_non_equi = true;
first_non_equi = i;
break;
}
}
if (!any_non_equi) {
// Container info isn't required for only `==`
r_list_poke(out, 0, vec_order(haystack, chrs_asc, chrs_smallest, true, r_null));
r_list_poke(out, 1, r_globals.empty_int);
r_list_poke(out, 2, r_int(1));
r_list_poke(out, 3, r_lgl(any_non_equi));
FREE(n_prot);
return out;
}
r_obj* info = KEEP_N(vec_order_info(
haystack,
chrs_asc,
chrs_smallest,
true,
r_null
), &n_prot);
r_obj* o_haystack = r_list_get(info, 0);
const int* v_o_haystack = r_int_cbegin(o_haystack);
r_obj* group_sizes = r_list_get(info, 1);
const int* v_group_sizes = r_int_cbegin(group_sizes);
const r_ssize n_groups = r_length(group_sizes);
// This is the haystack we compute container ids with.
// This is initially the whole `haystack`, but will be adjusted to contain
// fewer columns if there are `==` conditions before the first non-equi
// condition.
r_keep_loc haystack_container_pi;
r_obj* haystack_container = haystack;
KEEP_HERE(haystack_container, &haystack_container_pi);
++n_prot;
// If there are `==` conditions before the first non-equi condition,
// we separate those columns from the haystack and compute their group sizes,
// which are used for computing the container ids.
bool has_outer_group_sizes = false;
const int* v_outer_group_sizes = NULL;
if (first_non_equi != 0) {
// We have equality comparisons before the first non-equi comparison.
// In this case, we can skip nested containment ordering for the equality
// comparisons before the first non-equi comparison if we pass on the
// group sizes of the ordered equality columns as `v_outer_group_sizes`.
r_obj* const* v_haystack = r_list_cbegin(haystack);
r_obj* const* v_haystack_names = r_chr_cbegin(r_names(haystack));
// "Outer" data frame columns before the first non-equi condition
r_obj* haystack_outer = KEEP_N(r_alloc_list(first_non_equi), &n_prot);
r_obj* haystack_outer_names = r_alloc_character(first_non_equi);
r_attrib_poke_names(haystack_outer, haystack_outer_names);
r_init_data_frame(haystack_outer, size_haystack);
for (r_ssize i = 0; i < first_non_equi; ++i) {
r_list_poke(haystack_outer, i, v_haystack[i]);
r_chr_poke(haystack_outer_names, i, v_haystack_names[i]);
}
// "Inner" data frame columns at and after the first non-equi condition
r_obj* haystack_inner = KEEP_N(r_alloc_list(n_cols - first_non_equi), &n_prot);
r_obj* haystack_inner_names = r_alloc_character(n_cols - first_non_equi);
r_attrib_poke_names(haystack_inner, haystack_inner_names);
r_init_data_frame(haystack_inner, size_haystack);
for (r_ssize i = first_non_equi, j = 0; i < n_cols; ++i, ++j) {
r_list_poke(haystack_inner, j, v_haystack[i]);
r_chr_poke(haystack_inner_names, j, v_haystack_names[i]);
}
// Compute the order info of the outer columns, just to pluck off the
// group sizes. These automatically create a set of groups that
// "surround" the non-equi columns.
r_obj* info = vec_order_info(
haystack_outer,
chrs_asc,
chrs_smallest,
true,
r_null
);
r_obj* outer_group_sizes = KEEP_N(r_list_get(info, 1), &n_prot);
v_outer_group_sizes = r_int_cbegin(outer_group_sizes);
has_outer_group_sizes = true;
// Inner columns become the new container haystack
haystack_container = haystack_inner;
KEEP_AT(haystack_container, haystack_container_pi);
}
r_obj* container_ids_info = KEEP_N(compute_nesting_container_ids(
haystack_container,
v_o_haystack,
v_group_sizes,
v_outer_group_sizes,
size_haystack,
n_groups,
has_outer_group_sizes
), &n_prot);
const int n_containers = r_as_int(r_list_get(container_ids_info, 1));
if (n_containers == 1) {
// If only a single container exists at this point, either there was
// only 1 non-equi column which must already be in order, or we hit the
// somewhat rare case of having a >1 col `haystack_container` data frame
// that is already in nested containment order. In that case, original
// haystack ordering is sufficient and we don't need the ids.
r_list_poke(out, 0, o_haystack);
r_list_poke(out, 1, r_globals.empty_int);
r_list_poke(out, 2, r_int(1));
r_list_poke(out, 3, r_lgl(any_non_equi));
FREE(n_prot);
return out;
}
// Otherwise, we need to recompute the haystack ordering accounting for
// `container_ids`. One way to do this is to append `container_ids` to the
// front of the `haystack` data frame and recompute the order, but since
// we already have `o_haystack` and `group_sizes`, we can build a simpler
// proxy for `haystack` that orders the exact same, but faster. So we end
// up with a two column data frame of `container_ids` and `haystack_proxy`
// to compute the new order for.
r_obj* container_ids = r_list_get(container_ids_info, 0);
r_obj* haystack_proxy = KEEP_N(r_alloc_integer(size_haystack), &n_prot);
int* v_haystack_proxy = r_int_begin(haystack_proxy);
r_ssize loc_o_haystack = 0;
// Insert group number as the proxy value
for (r_ssize i = 0; i < n_groups; ++i) {
const r_ssize group_size = v_group_sizes[i];
for (r_ssize j = 0; j < group_size; ++j) {
v_haystack_proxy[v_o_haystack[loc_o_haystack] - 1] = i;
++loc_o_haystack;
}
}
r_obj* df = KEEP_N(r_alloc_list(2), &n_prot);
r_list_poke(df, 0, container_ids);
r_list_poke(df, 1, haystack_proxy);
r_obj* df_names = r_alloc_character(2);
r_attrib_poke_names(df, df_names);
r_chr_poke(df_names, 0, r_str("container_ids"));
r_chr_poke(df_names, 1, r_str("haystack_proxy"));
r_init_data_frame(df, size_haystack);
o_haystack = KEEP_N(vec_order(
df,
chrs_asc,
chrs_smallest,
true,
r_null
), &n_prot);
r_list_poke(out, 0, o_haystack);
r_list_poke(out, 1, container_ids);
r_list_poke(out, 2, r_int(n_containers));
r_list_poke(out, 3, r_lgl(any_non_equi));
FREE(n_prot);
return out;
}r_ssize compute_size(r_ssize size, r_obj* conditions) {
if (size != -1) {
return size;
}
if (r_length(conditions) == 0) {
return 0;
}
return r_length(r_list_get(conditions, 0));
}void counters_increment(struct counters* counters) {
++(counters->next);
}uint32_t cpl_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return cpl_dict_hash_with(d, d, i);
}uint32_t cpl_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_cpl_equal_na_equal);
}bool cpl_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_cpl_is_incomplete(d->p_poly_vec->p_vec, i);
}static inline int cpl_equal_na_equal(Rcomplex x, Rcomplex y) {
return dbl_equal_na_equal(x.r, y.r) && dbl_equal_na_equal(x.i, y.i);
}static inline uint32_t cpl_hash_scalar(r_complex x) {
uint32_t hash = 0;
hash = hash_combine(hash, dbl_hash_scalar(x.r));
hash = hash_combine(hash, dbl_hash_scalar(x.i));
return hash;
}bool cpl_is_missing(r_complex x) {
return dbl_is_missing(x.r) || dbl_is_missing(x.i);
}r_complex cpl_normalise_missing(r_complex x) {
const double na = r_globals.na_dbl;
const double nan = R_NaN;
const enum vctrs_dbl r_type = dbl_classify(x.r);
const enum vctrs_dbl i_type = dbl_classify(x.i);
switch (r_type) {
case VCTRS_DBL_number:
switch (i_type) {
case VCTRS_DBL_number: return x;
case VCTRS_DBL_missing: return (r_complex) { .r = na, .i = na};
case VCTRS_DBL_nan: return (r_complex) { .r = nan, .i = nan};
}
case VCTRS_DBL_missing:
switch (i_type) {
case VCTRS_DBL_number: return (r_complex) { .r = na, .i = na};
case VCTRS_DBL_missing: return x;
case VCTRS_DBL_nan: return x;
}
case VCTRS_DBL_nan:
switch (i_type) {
case VCTRS_DBL_number: return (r_complex) { .r = nan, .i = nan};
case VCTRS_DBL_missing: return x;
case VCTRS_DBL_nan: return x;
}
}
never_reached("cpl_normalise_missing");
}SEXP date_as_date(SEXP x) {
return date_validate(x);
}SEXP date_as_posixct(SEXP x, SEXP to) {
SEXP tzone = PROTECT(tzone_get(to));
// Date -> character -> POSIXct
// This is the only way to retain the same clock time
SEXP out = PROTECT(r_date_as_character(x));
out = PROTECT(r_chr_date_as_posixct(out, tzone));
UNPROTECT(3);
return out;
}SEXP date_as_posixlt(SEXP x, SEXP to) {
SEXP tzone = PROTECT(tzone_get(to));
// Date -> character -> POSIXlt
// This is the only way to retain the same clock time
SEXP out = PROTECT(r_date_as_character(x));
out = PROTECT(r_chr_date_as_posixlt(out, tzone));
UNPROTECT(3);
return out;
}SEXP date_datetime_ptype2(SEXP x, SEXP y) {
SEXP x_class = PROTECT(Rf_getAttrib(x, R_ClassSymbol));
SEXP x_first_class = STRING_ELT(x_class, 0);
SEXP tzone = (x_first_class == strings_date) ? tzone_get(y) : tzone_get(x);
PROTECT(tzone);
SEXP out = new_empty_datetime(tzone);
UNPROTECT(2);
return out;
}static SEXP date_validate(SEXP x) {
switch (TYPEOF(x)) {
case REALSXP:
return x;
case INTSXP:
// Keeps attributes
return Rf_coerceVector(x, REALSXP);
default:
r_stop_internal("Corrupt `Date` with unknown type %s.",
Rf_type2char(TYPEOF(x)));
}
}static SEXP datetime_validate_type(SEXP x) {
switch (TYPEOF(x)) {
case REALSXP:
return x;
case INTSXP:
// Keeps attributes
return Rf_coerceVector(x, REALSXP);
default:
r_stop_internal("Corrupt `POSIXct` with unknown type %s.",
Rf_type2char(TYPEOF(x)));
}
never_reached("datetime_validate_type");
}static SEXP datetime_validate_tzone(SEXP x) {
SEXP tzone = Rf_getAttrib(x, syms_tzone);
if (tzone != R_NilValue) {
return x;
}
x = PROTECT(r_clone_referenced(x));
Rf_setAttrib(x, syms_tzone, chrs_empty);
UNPROTECT(1);
return x;
}void dbl_adjust_nan_distinct(
const bool decreasing,
const bool na_last,
const r_ssize size,
double* p_x_dbl,
uint64_t* p_x_u64
) {
const int direction = decreasing ? -1 : 1;
const uint64_t na_u64 = na_last ? UINT64_MAX : 0;
const uint64_t nan_u64 = na_last ? UINT64_MAX - 1 : 1;
for (r_ssize i = 0; i < size; ++i) {
double elt = p_x_dbl[i];
const enum vctrs_dbl type = dbl_classify(elt);
switch (type) {
case VCTRS_DBL_number: {
elt = elt * direction;
p_x_u64[i] = dbl_map_to_uint64(elt);
break;
}
case VCTRS_DBL_missing: {
p_x_u64[i] = na_u64;
break;
}
case VCTRS_DBL_nan: {
p_x_u64[i] = nan_u64;
break;
}
}
}
}void dbl_adjust_nan_identical(
const bool decreasing,
const bool na_last,
const r_ssize size,
double* p_x_dbl,
uint64_t* p_x_u64
) {
const int direction = decreasing ? -1 : 1;
const uint64_t na_u64 = na_last ? UINT64_MAX : 0;
for (r_ssize i = 0; i < size; ++i) {
double elt = p_x_dbl[i];
if (isnan(elt)) {
p_x_u64[i] = na_u64;
continue;
}
elt = elt * direction;
p_x_u64[i] = dbl_map_to_uint64(elt);
}
}r_obj* dbl_as_integer(r_obj* x, bool* lossy) {
double* data = r_dbl_begin(x);
r_ssize n = r_length(x);
r_obj* out = KEEP(r_alloc_integer(n));
int* out_data = r_int_begin(out);
for (r_ssize i = 0; i < n; ++i, ++data, ++out_data) {
double elt = *data;
if (elt <= INT_MIN || elt >= INT_MAX + 1.0) {
*lossy = true;
FREE(1);
return r_null;
}
if (isnan(elt)) {
*out_data = r_globals.na_int;
continue;
}
int value = (int) elt;
if (value != elt) {
*lossy = true;
FREE(1);
return r_null;
}
*out_data = value;
}
FREE(1);
return out;
}r_obj* dbl_as_location(r_obj* subscript,
r_ssize n,
const struct location_opts* opts) {
subscript = KEEP(vec_cast(subscript,
r_globals.empty_int,
vec_args.empty,
vec_args.empty,
r_lazy_null));
subscript = int_as_location(subscript, n, opts);
FREE(1);
return subscript;
}r_obj* dbl_as_logical(r_obj* x, bool* lossy) {
double* data = r_dbl_begin(x);
r_ssize n = r_length(x);
r_obj* out = KEEP(r_alloc_logical(n));
int* out_data = r_lgl_begin(out);
for (r_ssize i = 0; i < n; ++i, ++data, ++out_data) {
double elt = *data;
if (isnan(elt)) {
*out_data = r_globals.na_lgl;
continue;
}
if (elt != 0 && elt != 1) {
*lossy = true;
FREE(1);
return r_null;
}
*out_data = (int) elt;
}
FREE(1);
return out;
}r_obj* dbl_cast_subscript(r_obj* subscript,
const struct subscript_opts* opts,
ERR* err) {
double* p = r_dbl_begin(subscript);
r_ssize n = r_length(subscript);
r_obj* out = KEEP(r_alloc_integer(n));
int* out_p = r_int_begin(out);
for (r_ssize i = 0; i < n; ++i) {
double elt = p[i];
// Generally `(int) nan` results in the correct `na_int` value,
// but this is not guaranteed, so we have to explicitly check for it.
// https://stackoverflow.com/questions/10366485/problems-casting-nan-floats-to-int
if (isnan(elt)) {
out_p[i] = r_globals.na_int;
continue;
}
if (!isfinite(elt) || elt <= INT_MIN || elt > INT_MAX) {
// Once we throw lazy errors from the cast method, we should
// throw the error here as well
FREE(1);
return dbl_cast_subscript_fallback(subscript, opts, err);
}
int elt_int = (int) elt;
if (elt != elt_int) {
FREE(1);
return dbl_cast_subscript_fallback(subscript, opts, err);
}
out_p[i] = elt_int;
}
FREE(1);
return out;
}r_obj* dbl_cast_subscript_fallback(r_obj* subscript,
const struct subscript_opts* opts,
ERR* err) {
struct cast_opts cast_opts = {
.x = subscript,
.to = r_globals.empty_int,
opts->subscript_arg
};
r_obj* out = KEEP(vec_cast_e(&cast_opts, err));
if (*err) {
r_obj* err_obj = KEEP(*err);
r_obj* body = KEEP(vctrs_eval_mask1(syms_new_dbl_cast_subscript_body,
syms_lossy_err, err_obj));
*err = new_error_subscript_type(subscript, opts, body);
FREE(3);
return r_null;
}
FREE(1);
return out;
}enum vctrs_dbl dbl_classify(double x) {
if (!isnan(x)) {
return VCTRS_DBL_number;
}
union vctrs_dbl_indicator indicator;
indicator.value = x;
if (indicator.key[vctrs_indicator_pos] == 1954) {
return VCTRS_DBL_missing;
} else {
return VCTRS_DBL_nan;
}
}int dbl_cmp(double x,
double y,
enum vctrs_dbl x_type,
enum vctrs_dbl y_type,
int direction,
int na_order,
int na_nan_order) {
switch (x_type) {
case VCTRS_DBL_number:
switch (y_type) {
case VCTRS_DBL_number: return dbl_cmp_numbers(x, y, direction);
case VCTRS_DBL_missing: return -na_order;
case VCTRS_DBL_nan: return -na_order;
}
case VCTRS_DBL_missing:
switch (y_type) {
case VCTRS_DBL_number: return na_order;
case VCTRS_DBL_missing: return 0;
case VCTRS_DBL_nan: return na_nan_order;
}
case VCTRS_DBL_nan:
switch (y_type) {
case VCTRS_DBL_number: return na_order;
case VCTRS_DBL_missing: return -na_nan_order;
case VCTRS_DBL_nan: return 0;
}
}
never_reached("dbl_cmp");
}int dbl_cmp_numbers(double x, double y, int direction) {
const int cmp = (x > y) - (x < y);
return cmp * direction;
}int dbl_compare_na_equal(double x, double y) {
enum vctrs_dbl x_class = dbl_classify(x);
enum vctrs_dbl y_class = dbl_classify(y);
switch (x_class) {
case VCTRS_DBL_number: {
switch (y_class) {
case VCTRS_DBL_number: return dbl_compare_scalar(x, y);
case VCTRS_DBL_missing: return 1;
case VCTRS_DBL_nan: return 1;
}
}
case VCTRS_DBL_missing: {
switch (y_class) {
case VCTRS_DBL_number: return -1;
case VCTRS_DBL_missing: return 0;
case VCTRS_DBL_nan: return 1;
}
}
case VCTRS_DBL_nan: {
switch (y_class) {
case VCTRS_DBL_number: return -1;
case VCTRS_DBL_missing: return -1;
case VCTRS_DBL_nan: return 0;
}
}
}
r_stop_unreachable();
}int dbl_compare_scalar(double x, double y) {
return (x > y) - (x < y);
}uint8_t dbl_compute_skips(const uint64_t* p_x, r_ssize size, bool* p_skips) {
uint8_t radix_start = PASS_TO_RADIX(0, DBL_MAX_RADIX_PASS);
uint8_t shift_start = radix_start * 8;
for (uint8_t i = 0; i < DBL_MAX_RADIX_PASS; ++i) {
p_skips[i] = true;
}
uint8_t p_bytes[DBL_MAX_RADIX_PASS];
const uint64_t elt0 = p_x[0];
// Get bytes of first element in MSD->LSD order.
// Placed in `p_bytes` in a way that aligns with the `pass` variable
for (uint8_t pass = 0, shift = shift_start;
pass < DBL_MAX_RADIX_PASS;
++pass, shift += SHIFT_ADJUSTMENT) {
p_bytes[pass] = dbl_extract_uint64_byte(elt0, shift);
}
// Check to see which passes are skippable
for (r_ssize i = 1; i < size; ++i) {
uint8_t n_skips = DBL_MAX_RADIX_PASS;
const uint64_t elt = p_x[i];
for (uint8_t pass = 0, shift = shift_start;
pass < DBL_MAX_RADIX_PASS;
++pass, shift += SHIFT_ADJUSTMENT) {
bool skip = p_skips[pass];
if (skip) {
p_skips[pass] = (p_bytes[pass] == dbl_extract_uint64_byte(elt, shift));
} else {
--n_skips;
}
}
// No passes are skippable
if (n_skips == 0) {
break;
}
}
uint8_t pass = 0;
// Shift forward to the first pass with varying bytes
while (pass < DBL_MAX_RADIX_PASS && p_skips[pass]) {
++pass;
}
return pass;
}uint32_t dbl_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return dbl_dict_hash_with(d, d, i);
}uint32_t dbl_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_dbl_equal_na_equal);
}bool dbl_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_dbl_is_incomplete(d->p_poly_vec->p_vec, i);
}static inline int dbl_equal_na_equal(double x, double y) {
switch (dbl_classify(x)) {
case VCTRS_DBL_number: return isnan(y) ? false : x == y;
case VCTRS_DBL_missing: return dbl_classify(y) == VCTRS_DBL_missing;
case VCTRS_DBL_nan: return dbl_classify(y) == VCTRS_DBL_nan;
default: r_stop_unreachable();
}
}static inline int dbl_equal_na_propagate(double x, double y) {
if (dbl_is_missing(x) || dbl_is_missing(y)) {
return NA_LOGICAL;
} else {
// Faster than `dbl_equal_na_equal()`,
// which has unneeded missing value checks
return x == y;
}
}uint64_t dbl_flip_uint64(uint64_t x) {
const uint64_t mask = (x & HEX_UINT64_SIGN) ? HEX_UINT64_ONES : HEX_UINT64_SIGN;
return x ^ mask;
}static inline uint32_t dbl_hash_scalar(double x) {
// Seems like something designed specifically for doubles should work better
// but I haven't been able to find anything
// Hash all NAs and NaNs to same value (i.e. ignoring significand)
double value;
switch (dbl_classify(x)) {
case VCTRS_DBL_number: value = x; break;
case VCTRS_DBL_missing: value = NA_REAL; break;
case VCTRS_DBL_nan: value = R_NaN; break;
default: r_stop_unreachable();
}
// Treat positive/negative 0 as equivalent
if (value == 0.0) {
value = 0.0;
}
union {
double d;
uint64_t i;
} value_union;
value_union.d = value;
return uint64_hash(value_union.i);
}bool dbl_is_missing(double x) {
return isnan(x);
}void dbl_order(
SEXP x,
bool decreasing,
bool na_last,
bool nan_distinct,
r_ssize size,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
const double* p_x = REAL_RO(x);
dbl_order_impl(
p_x,
decreasing,
na_last,
nan_distinct,
size,
true,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
}void dbl_order_chunk(
bool decreasing,
bool na_last,
bool nan_distinct,
r_ssize size,
int* p_o,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
void* p_x_chunk = p_lazy_x_chunk->p_data;
dbl_order_chunk_impl(
decreasing,
na_last,
nan_distinct,
size,
p_x_chunk,
p_o,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
}void dbl_order_chunk_impl(
bool decreasing,
bool na_last,
bool nan_distinct,
r_ssize size,
void* p_x,
int* p_o,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
const enum vctrs_sortedness sortedness = dbl_sortedness(
p_x,
size,
decreasing,
na_last,
nan_distinct,
p_group_infos
);
if (sortedness != VCTRS_SORTEDNESS_unsorted) {
ord_resolve_sortedness_chunk(sortedness, size, p_o);
return;
}
dbl_adjust(decreasing, na_last, nan_distinct, size, p_x);
if (size <= ORDER_INSERTION_BOUNDARY) {
dbl_order_insertion(size, p_x, p_o, p_group_infos);
return;
}
uint64_t* p_x_aux = (uint64_t*) init_lazy_raw(p_lazy_x_aux);
int* p_o_aux = (int*) init_lazy_raw(p_lazy_o_aux);
uint8_t* p_bytes = (uint8_t*) init_lazy_raw(p_lazy_bytes);
r_ssize* p_counts = (r_ssize*) init_lazy_raw(p_lazy_counts);
r_memset(p_counts, 0, p_lazy_counts->size);
dbl_order_radix(
size,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts,
p_group_infos
);
}void dbl_order_impl(
const double* p_x,
bool decreasing,
bool na_last,
bool nan_distinct,
r_ssize size,
bool copy,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
const enum vctrs_sortedness sortedness = dbl_sortedness(
p_x,
size,
decreasing,
na_last,
nan_distinct,
p_group_infos
);
// Handle sorted cases and set ordering to initialized
if (sortedness != VCTRS_SORTEDNESS_unsorted) {
int* p_o = p_order->p_data;
ord_resolve_sortedness(sortedness, size, p_o);
p_order->initialized = true;
return;
}
int* p_o = init_order(p_order);
void* p_x_chunk;
if (copy) {
p_x_chunk = init_lazy_raw(p_lazy_x_chunk);
r_memcpy(p_x_chunk, p_x, size * sizeof(*p_x));
} else {
p_x_chunk = p_lazy_x_chunk->p_data;
}
dbl_adjust(decreasing, na_last, nan_distinct, size, p_x_chunk);
if (size <= ORDER_INSERTION_BOUNDARY) {
dbl_order_insertion(size, p_x_chunk, p_o, p_group_infos);
return;
}
uint64_t* p_x_aux = (uint64_t*) init_lazy_raw(p_lazy_x_aux);
int* p_o_aux = (int*) init_lazy_raw(p_lazy_o_aux);
uint8_t* p_bytes = (uint8_t*) init_lazy_raw(p_lazy_bytes);
r_ssize* p_counts = (r_ssize*) init_lazy_raw(p_lazy_counts);
r_memset(p_counts, 0, p_lazy_counts->size);
dbl_order_radix(
size,
p_x_chunk,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts,
p_group_infos
);
}void dbl_order_insertion(
const r_ssize size,
uint64_t* p_x,
int* p_o,
struct group_infos* p_group_infos
) {
// Don't think this can occur, but safer this way
if (size == 0) {
return;
}
for (r_ssize i = 1; i < size; ++i) {
const uint64_t x_elt = p_x[i];
const int o_elt = p_o[i];
r_ssize j = i - 1;
while (j >= 0) {
const uint64_t x_cmp_elt = p_x[j];
if (x_elt >= x_cmp_elt) {
break;
}
int o_cmp_elt = p_o[j];
// Swap
p_x[j + 1] = x_cmp_elt;
p_o[j + 1] = o_cmp_elt;
// Next
--j;
}
// Place original elements in new location
// closer to start of the vector
p_x[j + 1] = x_elt;
p_o[j + 1] = o_elt;
}
// We've ordered a small chunk, we need to push at least one group size.
// Depends on the post-ordered results so we have to do this
// in a separate loop.
r_ssize group_size = 1;
uint64_t previous = p_x[0];
for (r_ssize i = 1; i < size; ++i) {
const uint64_t current = p_x[i];
// Continue the current group run
if (current == previous) {
++group_size;
continue;
}
// Push current run size and reset size tracker
groups_size_maybe_push(group_size, p_group_infos);
group_size = 1;
previous = current;
}
// Push final group run
groups_size_maybe_push(group_size, p_group_infos);
}void dbl_order_radix(
const r_ssize size,
uint64_t* p_x,
int* p_o,
uint64_t* p_x_aux,
int* p_o_aux,
uint8_t* p_bytes,
r_ssize* p_counts,
struct group_infos* p_group_infos
) {
bool p_skips[DBL_MAX_RADIX_PASS];
uint8_t pass = dbl_compute_skips(p_x, size, p_skips);
// Skipped all passes - Happens when `x` is 1 value repeated
if (pass == DBL_MAX_RADIX_PASS) {
groups_size_maybe_push(size, p_group_infos);
return;
}
dbl_order_radix_recurse(
size,
pass,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts,
p_skips,
p_group_infos
);
}r_obj* df_assign(r_obj* x,
r_obj* index,
r_obj* value,
const struct vec_proxy_assign_opts* p_opts) {
r_obj* out = KEEP(vec_clone_referenced(x, p_opts->ownership));
r_ssize n = r_length(out);
if (r_length(value) != n) {
r_stop_internal("Can't assign %d columns to df of length %d.",
r_length(value),
n);
}
// During assignment, if we have deep ownership over `x` we can
// propagate that ownership to the columns, otherwise we have no
// known ownership over the columns
enum vctrs_ownership col_ownership;
switch (p_opts->ownership) {
case VCTRS_OWNERSHIP_foreign: col_ownership = VCTRS_OWNERSHIP_foreign; break;
case VCTRS_OWNERSHIP_shallow: col_ownership = VCTRS_OWNERSHIP_foreign; break;
case VCTRS_OWNERSHIP_deep: col_ownership = VCTRS_OWNERSHIP_deep; break;
default: r_stop_unreachable();
}
const struct vec_proxy_assign_opts col_proxy_assign_opts = {
.assign_names = p_opts->assign_names,
.ignore_outer_names = p_opts->ignore_outer_names,
.slice_value = p_opts->slice_value,
.call = p_opts->call,
.x_arg = p_opts->x_arg,
.value_arg = p_opts->value_arg,
.index_style = p_opts->index_style,
.ownership = col_ownership,
.recursively_proxied = p_opts->recursively_proxied
};
for (r_ssize i = 0; i < n; ++i) {
r_obj* out_elt = r_list_get(out, i);
r_obj* value_elt = r_list_get(value, i);
// No need to cast or recycle because those operations are
// recursive and have already been performed. However, proxy and
// restore are not necessarily recursive and we might need to
// proxy each element we recurse into.
//
// NOTE: `vec_proxy_assign_opts()` proxies `value_elt`.
r_obj* proxy_elt = KEEP(p_opts->recursively_proxied ? out_elt : vec_proxy(out_elt));
r_obj* assigned_elt = KEEP(vec_proxy_assign_opts(proxy_elt, index, value_elt, &col_proxy_assign_opts));
if (!p_opts->recursively_proxied) {
const struct vec_restore_opts col_restore_opts = {
.ownership = col_ownership,
.recursively_proxied = false
};
assigned_elt = vec_restore_opts(assigned_elt, out_elt, &col_restore_opts);
}
r_list_poke(out, i, assigned_elt);
FREE(2);
}
FREE(1);
return out;
}r_obj* df_cast_loop(const struct cast_opts* opts, r_obj* names) {
r_obj* x = opts->x;
r_obj* to = opts->to;
r_ssize len = r_length(names);
r_obj* out = KEEP(r_alloc_list(len));
r_attrib_poke(out, r_syms.names, names);
r_ssize size = df_size(x);
r_ssize i = 0;
struct vctrs_arg* named_x_arg = new_subscript_arg(opts->p_x_arg, names, len, &i);
KEEP(named_x_arg->shelter);
struct vctrs_arg* named_to_arg = new_subscript_arg(opts->p_to_arg, names, len, &i);
KEEP(named_to_arg->shelter);
for (; i < len; ++i) {
struct cast_opts col_opts = {
.x = r_list_get(x, i),
.to = r_list_get(to, i),
.p_x_arg = named_x_arg,
.p_to_arg = named_to_arg,
.call = opts->call,
.s3_fallback = opts->s3_fallback
};
r_obj* col = vec_cast_opts(&col_opts);
r_list_poke(out, i, col);
}
// Restore data frame size before calling `vec_restore()`. `x` and
// `to` might not have any columns to compute the original size.
init_data_frame(out, size);
r_attrib_poke(out, r_syms.row_names, df_rownames(x));
FREE(3);
return out;
}r_obj* df_cast_opts(const struct cast_opts* opts) {
r_obj* x_names = KEEP(r_names(opts->x));
r_obj* to_names = KEEP(r_names(opts->to));
if (x_names == r_null || to_names == r_null) {
r_stop_internal("Data frame must have names.");
}
r_obj* out = r_null;
if (obj_equal(x_names, to_names)) {
out = df_cast_loop(opts, x_names);
} else {
out = df_cast_match(opts, x_names, to_names);
}
FREE(2);
return out;
}void df_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
if (size == 0) {
// Algorithm requires at least 1 value
return;
}
const r_ssize n_col = r_length(x);
r_obj* const* v_x = r_list_cbegin(x);
r_ssize loc = compute_iter_loc(size, which);
const r_ssize step = compute_iter_step(which);
// `v_out` will eventually be `true` if we are in a run
// continuation, and `false` if we are starting a new run.
v_out[loc] = false;
loc += step;
for (r_ssize i = 1; i < size; ++i) {
v_out[loc] = true;
loc += step;
}
for (r_ssize i = 0; i < n_col; ++i) {
col_detect_run_bounds_bool(v_x[i], size, which, v_out);
}
// Now invert to detect the bounds
for (r_ssize i = 0; i < size; ++i) {
v_out[i] = !v_out[i];
}
}uint32_t df_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return df_dict_hash_with(d, d, i);
}uint32_t df_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_df_equal_na_equal);
}bool df_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_df_is_incomplete(d->p_poly_vec->p_vec, i);
}SEXP df_expand_args(SEXP x, SEXP args) {
SEXP decreasing = VECTOR_ELT(args, 0);
SEXP na_largest = VECTOR_ELT(args, 1);
r_ssize n_decreasing = r_length(decreasing);
r_ssize n_na_largest = r_length(na_largest);
r_ssize n_cols = r_length(x);
// They will be recycled correctly even if columns get flattened
if (n_decreasing == 1 && n_na_largest == 1) {
return args;
}
// Must start out with the same length as the number of columns
if (n_decreasing != 1 && n_decreasing != n_cols) {
Rf_errorcall(
R_NilValue,
"`direction` should have length 1 or length equal to the number of "
"columns of `x` when `x` is a data frame."
);
}
if (n_na_largest != 1 && n_na_largest != n_cols) {
Rf_errorcall(
R_NilValue,
"`na_value` should have length 1 or length equal to the number of "
"columns of `x` when `x` is a data frame."
);
}
SEXP expansions = PROTECT(Rf_allocVector(INTSXP, n_cols));
int* p_expansions = INTEGER(expansions);
int size = 0;
bool needs_expansion = false;
// Compute expansion factor
for (r_ssize i = 0; i < n_cols; ++i) {
SEXP col = VECTOR_ELT(x, i);
int expansion = vec_decreasing_expansion(col);
if (expansion != 1) {
needs_expansion = true;
}
p_expansions[i] = expansion;
size += expansion;
}
if (!needs_expansion) {
UNPROTECT(1);
return args;
}
decreasing = expand_arg(decreasing, p_expansions, n_decreasing, size);
SET_VECTOR_ELT(args, 0, decreasing);
na_largest = expand_arg(na_largest, p_expansions, n_na_largest, size);
SET_VECTOR_ELT(args, 1, na_largest);
UNPROTECT(1);
return args;
}r_ssize df_first_missing(r_obj* x) {
const r_ssize n_cols = r_length(x);
const r_ssize size = vec_size(x);
r_ssize i = 0;
if (n_cols > 0) {
// First perform a very cheap check to see if there is at least 1 missing
// value in the first column. If not, then we are done. If there is at least
// 1 missing value, we start the loop below from there by updating `i`. This
// avoids the more expensive rowwise poly-op loop when there aren't any
// missing values.
r_obj* col = r_list_get(x, 0);
i = vec_first_missing(col);
if (i == size) {
return size;
}
}
int n_prot = 0;
struct poly_vec* p_poly_x = new_poly_vec(x, VCTRS_TYPE_dataframe);
KEEP_N(p_poly_x->shelter, &n_prot);
const void* v_x = p_poly_x->p_vec;
r_ssize out = size;
for (; i < size; ++i) {
if (p_df_is_missing(v_x, i)) {
out = i;
break;
}
}
FREE(n_prot);
return out;
}r_ssize df_raw_size(r_obj* x) {
r_ssize n = df_rownames_size(x);
if (n >= 0) {
return n;
}
return df_raw_size_from_list(x);
}r_obj* df_repair_names(r_obj* x, struct name_repair_opts* name_repair) {
r_obj* nms = KEEP(r_names(x));
r_obj* repaired = KEEP(vec_as_names(nms, name_repair));
// Should this go through proxy and restore so that classes can
// update metadata and check invariants when special columns are
// renamed?
if (nms != repaired) {
x = KEEP(r_clone_referenced(x));
r_attrib_poke_names(x, repaired);
FREE(1);
}
FREE(2);
return x;
}r_obj* df_rownames(r_obj* x) {
return r_attrib_get(x, R_RowNamesSymbol);
}r_obj* df_rownames_size_cb(r_obj* tag, r_obj* value, void* _data) {
if (tag == r_syms.row_names) {
// Found row names
return value;
} else {
// Continue iterating
return NULL;
}
}r_ssize df_size_from_n(r_obj* n) {
if (r_typeof(n) != R_TYPE_integer || r_length(n) != 1) {
r_abort("`n` must be an integer of size 1.");
}
r_ssize out = r_int_get(n, 0);
if (out == r_globals.na_int) {
r_abort("`n` can't be missing.");
}
if (out < 0) {
r_abort("`n` can't be negative.");
}
return out;
}bool dict_hash_is_missing(struct dictionary* d, R_len_t i) {
return d->hash[i] == HASH_MISSING;
}int dim2(
int x_dimension,
int y_dimension,
int axis,
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg
) {
if (x_dimension == y_dimension) {
return x_dimension;
} else if (x_dimension == 1) {
return y_dimension;
} else if (y_dimension == 1) {
return x_dimension;
} else {
stop_incompatible_shape(x, y, x_dimension, y_dimension, axis, p_x_arg, p_y_arg);
}
}r_obj* dims_shape2(
r_obj* x_dimensions,
r_obj* y_dimensions,
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg
) {
r_ssize x_dimensionality = r_length(x_dimensions);
r_ssize y_dimensionality = r_length(y_dimensions);
r_obj* max_dimensions;
r_ssize max_dimensionality;
r_ssize min_dimensionality;
if (x_dimensionality >= y_dimensionality) {
max_dimensions = x_dimensions;
max_dimensionality = x_dimensionality;
min_dimensionality = y_dimensionality;
} else {
max_dimensions = y_dimensions;
max_dimensionality = y_dimensionality;
min_dimensionality = x_dimensionality;
}
// Sanity check, should never be true
if (max_dimensionality == 0) {
r_stop_internal("`max_dimensionality` must have length.");
}
const int* p_x_dimensions = r_int_cbegin(x_dimensions);
const int* p_y_dimensions = r_int_cbegin(y_dimensions);
const int* p_max_dimensions = r_int_cbegin(max_dimensions);
r_obj* out = KEEP(r_alloc_integer(max_dimensionality));
int* p_out = r_int_begin(out);
// Set the first axis to zero
p_out[0] = 0;
// Start loop at the second axis
r_ssize i = 1;
for (; i < min_dimensionality; ++i) {
const int axis = i + 1;
const int x_dimension = p_x_dimensions[i];
const int y_dimension = p_y_dimensions[i];
p_out[i] = dim2(x_dimension, y_dimension, axis, x, y, p_x_arg, p_y_arg);
}
for (; i < max_dimensionality; ++i) {
p_out[i] = p_max_dimensions[i];
}
FREE(1);
return out;
}bool duplicated_any_loop(struct dictionary* d, R_len_t n) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: DUPLICATED_ANY_LOOP(nil_dict_hash_scalar); break;
case VCTRS_TYPE_logical: DUPLICATED_ANY_LOOP(lgl_dict_hash_scalar); break;
case VCTRS_TYPE_integer: DUPLICATED_ANY_LOOP(int_dict_hash_scalar); break;
case VCTRS_TYPE_double: DUPLICATED_ANY_LOOP(dbl_dict_hash_scalar); break;
case VCTRS_TYPE_complex: DUPLICATED_ANY_LOOP(cpl_dict_hash_scalar); break;
case VCTRS_TYPE_character: DUPLICATED_ANY_LOOP(chr_dict_hash_scalar); break;
case VCTRS_TYPE_raw: DUPLICATED_ANY_LOOP(raw_dict_hash_scalar); break;
case VCTRS_TYPE_list: DUPLICATED_ANY_LOOP(list_dict_hash_scalar); break;
case VCTRS_TYPE_dataframe: DUPLICATED_ANY_LOOP(df_dict_hash_scalar); break;
default: stop_unimplemented_vctrs_type("duplicated_any_loop", d->p_poly_vec->type);
}
}bool equal_string(SEXP x, const char** x_utf8, SEXP y) {
// Try fast pointer comparison
if (x == y)
return true;
if (*x_utf8 == NULL)
*x_utf8 = Rf_translateCharUTF8(x);
// Try slower conversion to common encoding
const char* y_utf = Rf_translateCharUTF8(y);
return (strcmp(y_utf, *x_utf8) == 0);
}SEXP expand_arg(
SEXP arg,
const int* p_expansions,
r_ssize n_arg,
r_ssize size
) {
if (n_arg == 1) {
return arg;
}
SEXP out = PROTECT(Rf_allocVector(LGLSXP, size));
int* p_out = LOGICAL(out);
int* p_arg = LOGICAL(arg);
int k = 0;
// Fill `out` with repeated `arg` values to match expanded size
for (r_ssize i = 0; i < n_arg; ++i) {
int col_arg = p_arg[i];
int expansion = p_expansions[i];
for (r_ssize j = 0; j < expansion; ++j) {
p_out[k] = col_arg;
++k;
}
}
UNPROTECT(1);
return out;
}static inline SEXP expr_protect(SEXP x) {
switch (TYPEOF(x)) {
case SYMSXP:
case LANGSXP:
return Rf_lang2(fns_quote, x);
default:
return x;
}
}SEXP fct_as_character(SEXP x, struct vctrs_arg* x_arg) {
SEXP levels = PROTECT(Rf_getAttrib(x, R_LevelsSymbol));
if (TYPEOF(levels) != STRSXP) {
stop_corrupt_factor_levels(x, x_arg);
}
UNPROTECT(1);
return Rf_asCharacterFactor(x);
}SEXP fct_as_factor(SEXP x,
SEXP to,
bool* lossy,
struct vctrs_arg* x_arg,
struct vctrs_arg* to_arg) {
SEXP x_levels = PROTECT(Rf_getAttrib(x, R_LevelsSymbol));
SEXP to_levels = PROTECT(Rf_getAttrib(to, R_LevelsSymbol));
if (TYPEOF(x_levels) != STRSXP) {
stop_corrupt_factor_levels(x, x_arg);
}
if (TYPEOF(to_levels) != STRSXP) {
stop_corrupt_factor_levels(to, to_arg);
}
SEXP out = fct_as_factor_impl(x, x_levels, to_levels, lossy, false);
UNPROTECT(2);
return out;
}r_obj* ffi_altrep_lazy_character_is_materialized(r_obj* x) {
return r_lgl(R_altrep_data2(x) != r_null);
}r_obj* ffi_as_df_col(r_obj* x, r_obj* outer, r_obj* frame) {
struct r_lazy error_call = { .x = frame, .env = r_null };
bool allow_pack;
return as_df_col(x, r_chr_get(outer, 0), &allow_pack, error_call);
}r_obj* ffi_as_minimal_names(r_obj* names) {
if (r_typeof(names) != R_TYPE_character) {
r_abort("`names` must be a character vector");
}
r_ssize i = 0;
r_ssize n = r_length(names);
r_obj* const * v_names = r_chr_cbegin(names);
for (; i < n; ++i) {
if (v_names[i] == r_globals.na_str) {
break;
}
}
if (i == n) {
return names;
}
names = KEEP(r_clone(names));
for (; i < n; ++i) {
if (v_names[i] == r_globals.na_str) {
r_chr_poke(names, i, strings_empty);
}
}
FREE(1);
return names;
}r_obj* ffi_as_not_s4(r_obj* x) {
return r_as_not_s4(x);
}r_obj* ffi_cast(r_obj* x,
r_obj* to,
r_obj* frame) {
struct r_lazy x_arg_ = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_);
struct r_lazy to_arg_ = { .x = syms.to_arg, .env = frame };
struct vctrs_arg to_arg = new_lazy_arg(&to_arg_);
struct r_lazy call = { .x = syms_call, .env = frame };
return vec_cast(x, to, &x_arg, &to_arg, call);
}r_obj* ffi_chr_is_ascii_or_utf8(r_obj* x) {
const r_ssize size = r_length(x);
r_obj* const* v_x = r_chr_cbegin(x);
r_obj* out = KEEP(r_alloc_logical(size));
int* v_out = r_lgl_begin(out);
for (r_ssize i = 0; i < size; ++i) {
v_out[i] = str_is_ascii_or_utf8(v_x[i]);
}
FREE(1);
return out;
}r_obj* ffi_compute_nesting_container_info(r_obj* haystack, r_obj* condition) {
r_ssize n_cols = r_length(haystack);
enum vctrs_ops* v_ops = (enum vctrs_ops*) R_alloc(n_cols, sizeof(enum vctrs_ops));
parse_condition(condition, n_cols, v_ops);
const r_ssize size_haystack = vec_size(haystack);
return compute_nesting_container_info(haystack, size_haystack, v_ops);
}r_obj* ffi_data_frame(r_obj* x,
r_obj* size,
r_obj* name_repair,
r_obj* frame) {
struct r_lazy error_call = { .x = syms.dot_error_call, .env = frame };
struct name_repair_opts name_repair_opts = new_name_repair_opts(name_repair,
lazy_args.dot_name_repair,
false,
error_call);
KEEP(name_repair_opts.shelter);
r_ssize c_size = 0;
if (size == r_null) {
c_size = vec_size_common(x, 0, vec_args.empty, error_call);
} else {
c_size = vec_as_short_length(size, vec_args.dot_size, error_call);
}
r_obj* out = data_frame(x, c_size, &name_repair_opts, error_call);
FREE(1);
return out;
}r_obj* ffi_df_ptype2_opts(r_obj* x, r_obj* y, r_obj* opts, r_obj* frame) {
struct r_lazy x_arg_ = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_);
struct r_lazy y_arg_ = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_);
struct r_lazy call = { .x = r_syms.call, .env = frame };
const enum s3_fallback s3_fallback = s3_fallback_from_opts(opts);
return df_ptype2(
x,
y,
&x_arg,
&y_arg,
call,
s3_fallback
);
}r_obj* ffi_interval_complement(r_obj* start,
r_obj* end,
r_obj* lower,
r_obj* upper) {
return vec_interval_complement(start, end, lower, upper);
}r_obj* ffi_interval_locate_containers(r_obj* start, r_obj* end) {
return vec_interval_locate_containers(start, end);
}r_obj* ffi_list_sizes(r_obj* x, r_obj* frame) {
struct r_lazy call = { .x = frame, .env = r_null };
return list_sizes(x, vec_args.x, call);
}r_obj* ffi_obj_check_vector(r_obj* x, r_obj* frame) {
struct r_lazy call = { .x = r_syms.call, .env = frame };
struct r_lazy arg_lazy = { .x = r_syms.arg, .env = frame };
struct vctrs_arg arg = new_lazy_arg(&arg_lazy);
// Not exposed at the R level for single vector checks
const enum vctrs_allow_null allow_null = VCTRS_ALLOW_NULL_no;
obj_check_vector(x, allow_null, &arg, call);
return r_null;
}SEXP ffi_obj_encode_utf8(SEXP x) {
return obj_encode_utf8(x);
}r_obj* ffi_obj_equal(r_obj* x, r_obj* y) {
return r_lgl(obj_equal(x, y));
}r_obj* ffi_obj_is_list(r_obj* x) {
return r_lgl(obj_is_list(x));
}r_obj* ffi_obj_is_vector(r_obj* x) {
// Not exposed at the R level for single vector checks
const enum vctrs_allow_null allow_null = VCTRS_ALLOW_NULL_no;
return r_lgl(obj_is_vector(x, allow_null));
}r_obj* ffi_ptype(r_obj* x, r_obj* x_arg_ffi, r_obj* frame) {
struct vctrs_arg x_arg = vec_as_arg(x_arg_ffi);
struct r_lazy call = { .x = r_syms.call, .env = frame };
return vec_ptype(x, &x_arg, call);
}r_obj* ffi_ptype2(r_obj* x,
r_obj* y,
r_obj* frame) {
struct r_lazy x_arg_ = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_);
struct r_lazy y_arg_ = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_);
struct r_lazy call = { .x = syms_call, .env = frame };
int _;
return vec_ptype2(
x,
y,
&x_arg,
&y_arg,
call,
S3_FALLBACK_false,
&_
);
}r_obj* ffi_ptype2_opts(r_obj* x,
r_obj* y,
r_obj* ffi_opts,
r_obj* frame) {
struct r_lazy x_arg_ = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_);
struct r_lazy y_arg_ = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_);
struct r_lazy call = { .x = r_syms.call, .env = frame, };
enum s3_fallback s3_fallback = s3_fallback_from_opts(ffi_opts);
int _;
return vec_ptype2(
x,
y,
&x_arg,
&y_arg,
call,
s3_fallback,
&_
);
}r_obj* ffi_recycle(r_obj* x,
r_obj* size_obj,
r_obj* frame) {
if (x == r_null || size_obj == r_null) {
return r_null;
}
struct r_lazy recycle_call = { .x = frame, .env = r_null };
size_obj = KEEP(vec_cast(size_obj,
r_globals.empty_int,
vec_args.empty,
vec_args.empty,
recycle_call));
R_len_t size = r_int_get(size_obj, 0);
FREE(1);
struct r_lazy x_arg_ = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_);
struct r_lazy call = { .x = syms_call, .env = frame };
return vec_recycle(x, size, &x_arg, call);
}r_obj* ffi_size(r_obj* x, r_obj* frame) {
struct r_lazy call = { .x = frame, .env = r_null };
return r_len(vec_size_params(x, vec_args.x, call));
}r_obj* ffi_typeof2(r_obj* x, r_obj* y) {
enum vctrs_type2 type = vec_typeof2(x, y);
return r_chr(vctrs_type2_as_str(type));
}r_obj* ffi_typeof2_s3(r_obj* x, r_obj* y) {
enum vctrs_type2_s3 type = vec_typeof2_s3(x, y);
return r_chr(vctrs_type2_s3_as_str(type));
}r_obj* ffi_vec_any_missing(r_obj* x) {
return r_lgl(vec_any_missing(x));
}r_obj* ffi_vec_bare_df_restore(r_obj* x, r_obj* to) {
// Never own user objects
const struct vec_restore_opts opts = {
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
return vec_bare_df_restore(x, to, &opts);
}r_obj* ffi_vec_check_recyclable(r_obj* x, r_obj* ffi_size, r_obj* frame) {
struct r_lazy call = { .x = r_syms.call, .env = frame };
struct r_lazy arg_lazy = { .x = r_syms.arg, .env = frame };
struct vctrs_arg arg = new_lazy_arg(&arg_lazy);
const r_ssize size = r_arg_as_ssize(ffi_size, "size");
// Not exposed at the R level for single vector checks
const enum vctrs_allow_null allow_null = VCTRS_ALLOW_NULL_no;
vec_check_recyclable(x, size, allow_null, &arg, call);
return r_null;
}r_obj* ffi_vec_check_size(r_obj* x, r_obj* ffi_size, r_obj* frame) {
struct r_lazy call = { .x = r_syms.call, .env = frame };
struct r_lazy arg_lazy = { .x = r_syms.arg, .env = frame };
struct vctrs_arg arg = new_lazy_arg(&arg_lazy);
const r_ssize size = r_arg_as_ssize(ffi_size, "size");
// Not exposed at the R level for single vector checks
const enum vctrs_allow_null allow_null = VCTRS_ALLOW_NULL_no;
vec_check_size(x, size, allow_null, &arg, call);
return r_null;
}r_obj* ffi_vec_chop(r_obj* x, r_obj* indices, r_obj* sizes) {
return vec_chop(x, indices, sizes);
}r_obj* ffi_vec_detect_missing(r_obj* x) {
return vec_detect_missing(x);
}r_obj* ffi_vec_detect_run_bounds(r_obj* x, r_obj* ffi_start, r_obj* frame) {
struct r_lazy error_call = { .x = frame, .env = r_null };
const enum vctrs_run_bound which = as_run_bound(ffi_start, error_call);
return vec_detect_run_bounds(x, which, error_call);
}r_obj* ffi_vec_expand_grid(r_obj* xs,
r_obj* ffi_vary,
r_obj* ffi_name_repair,
r_obj* frame) {
struct r_lazy error_call = { .x = syms.dot_error_call, .env = frame };
enum vctrs_expand_vary vary = parse_vary(ffi_vary);
struct name_repair_opts name_repair_opts = new_name_repair_opts(
ffi_name_repair,
lazy_args.dot_name_repair,
false,
error_call
);
KEEP(name_repair_opts.shelter);
r_obj* out = vec_expand_grid(xs, vary, &name_repair_opts, error_call);
FREE(1);
return out;
}r_obj* ffi_vec_identify_runs(r_obj* x, r_obj* frame) {
struct r_lazy error_call = { .x = frame, .env = r_null };
return vec_identify_runs(x, error_call);
}r_obj* ffi_vec_pall(r_obj* ffi_xs, r_obj* ffi_missing, r_obj* ffi_size, r_obj* ffi_frame) {
struct r_lazy xs_arg_lazy = { .x = syms.dot_arg, .env = ffi_frame };
struct vctrs_arg xs_arg = new_lazy_arg(&xs_arg_lazy);
const struct r_lazy error_call = { .x = syms.dot_error_call, .env = ffi_frame };
const enum vec_parallel_missing missing = parse_vec_parallel_missing(ffi_missing, error_call);
const r_ssize size = (ffi_size == r_null) ? -1 : r_arg_as_ssize(ffi_size, ".size");
return vec_pall(ffi_xs, missing, size, &xs_arg, error_call);
}r_obj* ffi_vec_pany(r_obj* ffi_xs, r_obj* ffi_missing, r_obj* ffi_size, r_obj* ffi_frame) {
struct r_lazy xs_arg_lazy = { .x = syms.dot_arg, .env = ffi_frame };
struct vctrs_arg xs_arg = new_lazy_arg(&xs_arg_lazy);
const struct r_lazy error_call = { .x = syms.dot_error_call, .env = ffi_frame };
const enum vec_parallel_missing missing = parse_vec_parallel_missing(ffi_missing, error_call);
const r_ssize size = (ffi_size == r_null) ? -1 : r_arg_as_ssize(ffi_size, ".size");
return vec_pany(ffi_xs, missing, size, &xs_arg, error_call);
}r_obj* ffi_vec_rep_each(r_obj* x, r_obj* times, r_obj* frame) {
struct r_lazy error_call = { .x = r_syms.error_call, .env = frame };
struct r_lazy x_arg_lazy = { .x = syms.times_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_lazy);
struct r_lazy times_arg_lazy = { .x = syms.times_arg, .env = frame };
struct vctrs_arg times_arg = new_lazy_arg(×_arg_lazy);
return vec_rep_each(x, times, error_call, &x_arg, ×_arg);
}r_obj* ffi_vec_restore(r_obj* x, r_obj* to) {
// Never own user objects, so foreign ownership.
// Hooked to `vec_restore()`, which is called after an R level non-recursive
// `vec_proxy()`, so not recursively proxied.
struct vec_restore_opts opts = {
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
return vec_restore_opts(x, to, &opts);
}r_obj* ffi_vec_restore_default(r_obj* x, r_obj* to) {
// Never own user objects
return vec_restore_default(x, to, VCTRS_OWNERSHIP_foreign);
}r_obj* ffi_vec_restore_recurse(r_obj* x, r_obj* to) {
// Never own user objects, but we are restoring recursively here for testing purposes
struct vec_restore_opts opts = {
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = true
};
return vec_restore_opts(x, to, &opts);
}r_obj* ffi_vec_run_sizes(r_obj* x, r_obj* frame) {
struct r_lazy error_call = { .x = frame, .env = r_null };
return vec_run_sizes(x, error_call);
}r_obj* ffi_vec_set_difference(r_obj* x,
r_obj* y,
r_obj* ptype,
r_obj* frame) {
struct r_lazy call = { .x = r_syms.error_call, .env = frame };
struct r_lazy x_arg_lazy = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_lazy);
struct r_lazy y_arg_lazy = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_lazy);
return vec_set_difference(x, y, ptype, &x_arg, &y_arg, call);
}r_obj* ffi_vec_set_intersect(r_obj* x,
r_obj* y,
r_obj* ptype,
r_obj* frame) {
struct r_lazy call = { .x = r_syms.error_call, .env = frame };
struct r_lazy x_arg_lazy = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_lazy);
struct r_lazy y_arg_lazy = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_lazy);
return vec_set_intersect(x, y, ptype, &x_arg, &y_arg, call);
}r_obj* ffi_vec_set_names(r_obj* x, r_obj* names) {
// Comes from the R side, so `VCTRS_OWNERSHIP_foreign`
return vec_set_names(x, names, VCTRS_OWNERSHIP_foreign);
}r_obj* ffi_vec_set_symmetric_difference(r_obj* x,
r_obj* y,
r_obj* ptype,
r_obj* frame) {
struct r_lazy call = { .x = r_syms.error_call, .env = frame };
struct r_lazy x_arg_lazy = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_lazy);
struct r_lazy y_arg_lazy = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_lazy);
return vec_set_symmetric_difference(x, y, ptype, &x_arg, &y_arg, call);
}r_obj* ffi_vec_set_union(r_obj* x,
r_obj* y,
r_obj* ptype,
r_obj* frame) {
struct r_lazy call = { .x = r_syms.error_call, .env = frame };
struct r_lazy x_arg_lazy = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_lazy);
struct r_lazy y_arg_lazy = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_lazy);
return vec_set_union(x, y, ptype, &x_arg, &y_arg, call);
}r_obj* ffi_vec_shape2(r_obj* x, r_obj* y, r_obj* frame) {
struct r_lazy x_arg_ = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_);
struct r_lazy y_arg_ = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_);
return vec_shape2(x, y, &x_arg, &y_arg);
}r_obj* ffi_vec_shaped_ptype(r_obj* ptype, r_obj* x, r_obj* y, r_obj* frame) {
struct r_lazy x_arg_ = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_);
struct r_lazy y_arg_ = { .x = syms.y_arg, .env = frame };
struct vctrs_arg y_arg = new_lazy_arg(&y_arg_);
return vec_shaped_ptype(ptype, x, y, &x_arg, &y_arg);
}r_obj* ffi_vec_unrep(r_obj* x, r_obj* frame) {
struct r_lazy error_call = { .x = frame, .env = r_null };
return vec_unrep(x, error_call);
}int fill_arg_buffer(struct vctrs_arg* arg,
char* buf,
r_ssize cur_size,
r_ssize tot_size) {
if (arg->parent) {
cur_size = fill_arg_buffer(arg->parent, buf, cur_size, tot_size);
if (cur_size < 0) {
return cur_size;
}
}
r_ssize written = arg->fill(arg->data, buf + cur_size, tot_size - cur_size);
if (written < 0) {
return written;
} else {
return cur_size + written;
}
}static r_obj* generate_sys_call(const char* name, int** n_addr) {
r_obj* sys_n = KEEP(r_int(0));
*n_addr = r_int_begin(sys_n);
r_obj* sys_args = KEEP(r_new_node(sys_n, r_null));
r_obj* sys_call = KEEP(r_new_call(r_base_ns_get(name), sys_args));
r_preserve(sys_call);
FREE(3);
return sys_call;
}static inline SEXP get_opts_action(const struct subscript_opts* opts) {
switch (opts->action) {
case SUBSCRIPT_ACTION_DEFAULT: return R_NilValue;
case SUBSCRIPT_ACTION_SUBSET: return chrs_subset;
case SUBSCRIPT_ACTION_EXTRACT: return chrs_extract;
case SUBSCRIPT_ACTION_ASSIGN: return chrs_assign;
case SUBSCRIPT_ACTION_RENAME: return chrs_rename;
case SUBSCRIPT_ACTION_REMOVE: return chrs_remove;
case SUBSCRIPT_ACTION_NEGATE: return chrs_negate;
}
never_reached("get_opts_action");
}r_obj* glue_as_name_spec(r_obj* spec) {
if (!r_is_string(spec)) {
r_abort("Glue specification in `.name_spec` must be a single string.");
}
return vctrs_dispatch1(syms_glue_as_name_spec, fns_glue_as_name_spec,
syms_internal_spec, spec);
}struct group_info* groups_current(struct group_infos* p_group_infos) {
return p_group_infos->p_p_group_info[p_group_infos->current];
}r_ssize groups_realloc_size(r_ssize data_size, r_ssize max_data_size) {
uint64_t new_data_size;
if (data_size == 0) {
// First allocation
new_data_size = GROUP_DATA_SIZE_DEFAULT;
} else {
// Avoid potential overflow when doubling size
new_data_size = ((uint64_t) data_size) * 2;
}
// Clamp maximum allocation size to the size of the input
if (new_data_size > max_data_size) {
return max_data_size;
}
// Can now safely cast back to `r_ssize`
return (r_ssize) new_data_size;
}void groups_size_maybe_push(r_ssize size, struct group_infos* p_group_infos) {
if (p_group_infos->ignore_groups) {
return;
} else {
groups_size_push(size, p_group_infos);
}
}void groups_size_push(r_ssize size, struct group_infos* p_group_infos) {
if (size == 0) {
Rf_errorcall(R_NilValue, "Internal error: Group `size` to push should never be zero.");
}
struct group_info* p_group_info = groups_current(p_group_infos);
// Extend `data` as required - reprotects itself
if (p_group_info->data_size == p_group_info->n_groups) {
r_ssize new_data_size = groups_realloc_size(
p_group_info->data_size,
p_group_infos->max_data_size
);
group_realloc(new_data_size, p_group_info);
}
// Push group size
p_group_info->p_data[p_group_info->n_groups] = size;
// Bump number of groups
++p_group_info->n_groups;
// Update max group size
if (p_group_info->max_group_size < size) {
p_group_info->max_group_size = size;
}
}void groups_swap(struct group_infos* p_group_infos) {
if (p_group_infos->ignore_groups) {
return;
}
struct group_info* p_group_info_pre = groups_current(p_group_infos);
// Make the swap
p_group_infos->current = 1 - p_group_infos->current;
struct group_info* p_group_info_post = groups_current(p_group_infos);
// Clear the info from last time the swap was made
p_group_info_post->max_group_size = 0;
p_group_info_post->n_groups = 0;
// Ensure the new group info is at least as big as the old group info
if (p_group_info_post->data_size < p_group_info_pre->data_size) {
r_ssize new_data_size = p_group_info_pre->data_size;
group_realloc(new_data_size, p_group_info_post);
}
}SEXP growable_values(struct growable* g) {
return Rf_lengthgets(g->x, g->n);
}r_ssize indices_out_size(struct vctrs_chop_indices* p_indices, r_obj* x) {
if (p_indices->has_indices) {
return r_length(p_indices->indices);
} else if (p_indices->has_sizes) {
return r_length(p_indices->sizes);
} else {
return vec_size(x);
}
}void init_bare_data_frame(r_obj* x, r_ssize n) {
if (r_length(x) == 0) {
r_attrib_poke(x, r_syms.names, r_globals.empty_chr);
}
init_compact_rownames(x, n);
}void init_chr_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = (const void*) r_chr_cbegin(p_poly_vec->vec);
}void init_compact_rep(int* p, R_len_t i, R_len_t n) {
p[0] = i;
p[1] = n;
}void init_compact_rownames(r_obj* x, r_ssize n_rows) {
r_obj* rn = KEEP(new_compact_rownames(n_rows));
r_attrib_poke(x, r_syms.row_names, rn);
FREE(1);
}void init_compact_seq(int* p, R_len_t start, R_len_t size, bool increasing) {
int step = increasing ? 1 : -1;
p[0] = start;
p[1] = size;
p[2] = step;
}void init_cpl_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = (const void*) r_cpl_cbegin(p_poly_vec->vec);
}void init_data_frame(r_obj* x, r_ssize n) {
r_attrib_poke(x, r_syms.class_, classes_data_frame);
init_bare_data_frame(x, n);
}void init_dbl_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = (const void*) r_dbl_cbegin(p_poly_vec->vec);
}void init_df_poly_vec(struct poly_vec* p_poly_vec) {
r_obj* df = p_poly_vec->vec;
r_ssize n_col = r_length(df);
r_obj* shelter = KEEP(r_alloc_list(4));
r_list_poke(shelter, 0, p_poly_vec->shelter);
p_poly_vec->shelter = shelter;
r_obj* data_handle = KEEP(r_alloc_raw(sizeof(struct poly_df_data)));
struct poly_df_data* data = (struct poly_df_data*) r_raw_begin(data_handle);
r_list_poke(shelter, 1, data_handle);
r_obj* col_type_handle = KEEP(r_alloc_raw(n_col * sizeof(enum vctrs_type)));
enum vctrs_type* v_col_type = (enum vctrs_type*) r_raw_begin(col_type_handle);
r_list_poke(shelter, 2, col_type_handle);
r_obj* col_ptr_handle = KEEP(r_alloc_raw(n_col * sizeof(void*)));
const void** v_col_ptr = (const void**) r_raw_begin(col_ptr_handle);
r_list_poke(shelter, 3, col_ptr_handle);
for (r_ssize i = 0; i < n_col; ++i) {
r_obj* col = r_list_get(df, i);
v_col_type[i] = vec_proxy_typeof(col);
v_col_ptr[i] = r_vec_cbegin(col);
}
data->v_col_type = v_col_type;
data->v_col_ptr = v_col_ptr;
data->n_col = n_col;
p_poly_vec->p_vec = (void*) data;
FREE(4);
}static void init_factor(SEXP x, SEXP levels) {
if (TYPEOF(x) != INTSXP) {
r_stop_internal("Only integers can be made into factors.");
}
Rf_setAttrib(x, R_LevelsSymbol, levels);
Rf_setAttrib(x, R_ClassSymbol, classes_factor);
}void init_int_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = (const void*) r_int_cbegin(p_poly_vec->vec);
}void* init_lazy_raw(struct lazy_raw* p_x) {
if (p_x->data != R_NilValue) {
return p_x->p_data;
}
p_x->data = Rf_allocVector(RAWSXP, p_x->size);
REPROTECT(p_x->data, p_x->data_pi);
p_x->p_data = (void*) RAW(p_x->data);
return p_x->p_data;
}void init_lgl_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = (const void*) r_lgl_cbegin(p_poly_vec->vec);
}void init_list_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = (const void*) r_list_cbegin(p_poly_vec->vec);
}void init_nil_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = NULL;
}int* init_order(struct order* p_order) {
if (p_order->initialized) {
return p_order->p_data;
}
// Initialize `x` with sequential 1-based ordering
for (r_ssize i = 0; i < p_order->size; ++i) {
p_order->p_data[i] = i + 1;
}
p_order->initialized = true;
return p_order->p_data;
}static void init_ordered(SEXP x, SEXP levels) {
if (TYPEOF(x) != INTSXP) {
r_stop_internal("Only integers can be made into ordered factors.");
}
Rf_setAttrib(x, R_LevelsSymbol, levels);
Rf_setAttrib(x, R_ClassSymbol, classes_ordered);
}void init_raw_poly_vec(struct poly_vec* p_poly_vec) {
p_poly_vec->p_vec = (const void*) r_raw_cbegin(p_poly_vec->vec);
}void int64_unpack(int64_t x, r_ssize i, double* v_left, double* v_right) {
const uint64_t x_u64 = ((uint64_t) x) - INT64_MIN;
const uint32_t left_u32 = (uint32_t) (x_u64 >> 32);
const uint32_t right_u32 = (uint32_t) x_u64;
v_left[i] = (double) left_u32;
v_right[i] = (double) right_u32;
}void int_adjust(
const bool decreasing,
const bool na_last,
const r_ssize size,
void* p_x
) {
const int direction = decreasing ? -1 : 1;
const uint32_t na_u32 = na_last ? UINT32_MAX : 0;
const int na_shift = na_last ? -1 : 0;
const int* p_x_int = (const int*) p_x;
uint32_t* p_x_u32 = (uint32_t*) p_x;
for (r_ssize i = 0; i < size; ++i) {
int elt = p_x_int[i];
if (elt == NA_INTEGER) {
p_x_u32[i] = na_u32;
continue;
}
elt = elt * direction + na_shift;
p_x_u32[i] = int_map_to_uint32(elt);
}
}r_obj* int_as_double(r_obj* x, bool* lossy) {
int* data = r_int_begin(x);
r_ssize n = r_length(x);
r_obj* out = KEEP(r_alloc_double(n));
double* out_data = r_dbl_begin(out);
for (r_ssize i = 0; i < n; ++i, ++data, ++out_data) {
int elt = *data;
*out_data = (elt == r_globals.na_int) ? r_globals.na_dbl : elt;
}
FREE(1);
return out;
}r_obj* int_as_logical(r_obj* x, bool* lossy) {
int* data = r_int_begin(x);
r_ssize n = r_length(x);
r_obj* out = KEEP(r_alloc_logical(n));
int* out_data = r_lgl_begin(out);
for (r_ssize i = 0; i < n; ++i, ++data, ++out_data) {
int elt = *data;
if (elt == r_globals.na_int) {
*out_data = r_globals.na_lgl;
continue;
}
if (elt != 0 && elt != 1) {
*lossy = true;
FREE(1);
return r_null;
}
*out_data = elt;
}
FREE(1);
return out;
}int int_cmp(int x, int y, const int direction, const int na_order) {
if (x == NA_INTEGER) {
if (y == NA_INTEGER) {
return 0;
} else {
return na_order;
}
}
if (y == NA_INTEGER) {
return -na_order;
}
int cmp = (x > y) - (x < y);
return cmp * direction;
}int int_compare_na_equal(int x, int y) {
return int_compare_scalar(x, y);
}int int_compare_scalar(int x, int y) {
return (x > y) - (x < y);
}uint8_t int_compute_skips(const uint32_t* p_x, r_ssize size, bool* p_skips) {
uint8_t radix_start = PASS_TO_RADIX(0, INT_MAX_RADIX_PASS);
uint8_t shift_start = radix_start * 8;
for (uint8_t i = 0; i < INT_MAX_RADIX_PASS; ++i) {
p_skips[i] = true;
}
uint8_t p_bytes[INT_MAX_RADIX_PASS];
const uint32_t elt0 = p_x[0];
// Get bytes of first element in MSD->LSD order.
// Placed in `p_bytes` in a way that aligns with the `pass` variable
for (uint8_t pass = 0, shift = shift_start;
pass < INT_MAX_RADIX_PASS;
++pass, shift += SHIFT_ADJUSTMENT) {
p_bytes[pass] = int_extract_uint32_byte(elt0, shift);
}
// Check to see which passes are skippable
for (r_ssize i = 1; i < size; ++i) {
uint8_t n_skips = INT_MAX_RADIX_PASS;
const uint32_t elt = p_x[i];
for (uint8_t pass = 0, shift = shift_start;
pass < INT_MAX_RADIX_PASS;
++pass, shift += SHIFT_ADJUSTMENT) {
bool skip = p_skips[pass];
if (skip) {
p_skips[pass] = (p_bytes[pass] == int_extract_uint32_byte(elt, shift));
} else {
--n_skips;
}
}
// No passes are skippable
if (n_skips == 0) {
break;
}
}
uint8_t pass = 0;
// Shift forward to the first pass with varying bytes
while (pass < INT_MAX_RADIX_PASS && p_skips[pass]) {
++pass;
}
return pass;
}uint32_t int_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return int_dict_hash_with(d, d, i);
}uint32_t int_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_int_equal_na_equal);
}bool int_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_int_is_incomplete(d->p_poly_vec->p_vec, i);
}static inline int int_equal_na_equal(int x, int y) {
return x == y;
}static inline int int_equal_na_propagate(int x, int y) {
if (int_is_missing(x) || int_is_missing(y)) {
return NA_LOGICAL;
} else {
return int_equal_na_equal(x, y);
}
}r_obj* int_filter_missing(r_obj* subscript, r_ssize n_missing) {
return int_filter(subscript, n_missing, r_globals.na_int);
}r_obj* int_filter_zero(r_obj* subscript, r_ssize n_zero) {
return int_filter(subscript, n_zero, 0);
}static inline uint32_t int_hash_scalar(int x) {
return uint32_hash(x);
}void int_incr(r_ssize size, int* p_x) {
for (r_ssize i = 0; i < size; ++i) {
p_x[i] = i + 1;
}
}bool int_is_missing(int x) {
return x == r_globals.na_int;
}static inline uint32_t int_map_to_uint32(int x) {
return ((uint32_t) x) ^ HEX_UINT32_SIGN_BIT;
}void int_order(
SEXP x,
bool decreasing,
bool na_last,
r_ssize size,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
const int* p_x = INTEGER_RO(x);
const enum vctrs_sortedness sortedness = int_sortedness(
p_x,
size,
decreasing,
na_last,
p_group_infos
);
// Handle sorted cases and set ordering to initialized
if (sortedness != VCTRS_SORTEDNESS_unsorted) {
int* p_o = p_order->p_data;
ord_resolve_sortedness(sortedness, size, p_o);
p_order->initialized = true;
return;
}
if (size <= ORDER_INSERTION_BOUNDARY) {
int* p_o = init_order(p_order);
void* p_x_chunk = init_lazy_raw(p_lazy_x_chunk);
r_memcpy(p_x_chunk, p_x, size * sizeof(*p_x));
int_adjust(decreasing, na_last, size, p_x_chunk);
int_order_insertion(size, p_x_chunk, p_o, p_group_infos);
return;
}
uint32_t range;
int x_min;
int_compute_range(p_x, size, &x_min, &range);
/*
* If in counting order range and on the first column / single vector,
* `p_o_aux` won't be used, so no need to initialize it.
*
* Also, `p_o` will be filled directly, so for performance we don't
* initialize its order.
*/
if (range < INT_ORDER_COUNTING_RANGE_BOUNDARY) {
const bool initialized = false;
int* p_o = p_order->p_data;
int* p_o_aux = NULL;
int_order_counting(
p_x,
size,
x_min,
range,
initialized,
decreasing,
na_last,
p_o,
p_o_aux,
p_group_infos
);
p_order->initialized = true;
return;
}
int* p_o = init_order(p_order);
int* p_o_aux = (int*) init_lazy_raw(p_lazy_o_aux);
uint32_t* p_x_aux = (uint32_t*) init_lazy_raw(p_lazy_x_aux);
uint8_t* p_bytes = (uint8_t*) init_lazy_raw(p_lazy_bytes);
r_ssize* p_counts = (r_ssize*) init_lazy_raw(p_lazy_counts);
r_memset(p_counts, 0, p_lazy_counts->size);
// Copy `x` so we can modify in place
void* p_x_chunk = init_lazy_raw(p_lazy_x_chunk);
r_memcpy(p_x_chunk, p_x, size * sizeof(*p_x));
int_adjust(decreasing, na_last, size, p_x_chunk);
int_order_radix(
size,
p_x_chunk,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts,
p_group_infos
);
}void int_order_chunk(
bool decreasing,
bool na_last,
r_ssize size,
int* p_o,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
void* p_x_chunk = p_lazy_x_chunk->p_data;
const enum vctrs_sortedness sortedness = int_sortedness(
p_x_chunk,
size,
decreasing,
na_last,
p_group_infos
);
if (sortedness != VCTRS_SORTEDNESS_unsorted) {
ord_resolve_sortedness_chunk(sortedness, size, p_o);
return;
}
if (size <= ORDER_INSERTION_BOUNDARY) {
int_adjust(decreasing, na_last, size, p_x_chunk);
int_order_insertion(size, p_x_chunk, p_o, p_group_infos);
return;
}
int* p_o_aux = (int*) init_lazy_raw(p_lazy_o_aux);
uint32_t range;
int x_min;
int_compute_range(p_x_chunk, size, &x_min, &range);
/*
* If in counting order range and on the second or higher column, we will
* need `p_o_aux` as working memory. At this point, `p_o` will have been
* initialized from ordering the first column.
*/
if (range < INT_ORDER_COUNTING_RANGE_BOUNDARY) {
const bool initialized = true;
int_order_counting(
p_x_chunk,
size,
x_min,
range,
initialized,
decreasing,
na_last,
p_o,
p_o_aux,
p_group_infos
);
return;
}
uint32_t* p_x_aux = (uint32_t*) init_lazy_raw(p_lazy_x_aux);
uint8_t* p_bytes = (uint8_t*) init_lazy_raw(p_lazy_bytes);
r_ssize* p_counts = (r_ssize*) init_lazy_raw(p_lazy_counts);
r_memset(p_counts, 0, p_lazy_counts->size);
int_adjust(decreasing, na_last, size, p_x_chunk);
int_order_radix(
size,
p_x_chunk,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts,
p_group_infos
);
}void int_order_insertion(
const r_ssize size,
uint32_t* p_x,
int* p_o,
struct group_infos* p_group_infos
) {
// Don't think this can occur, but safer this way
if (size == 0) {
return;
}
for (r_ssize i = 1; i < size; ++i) {
const uint32_t x_elt = p_x[i];
const int o_elt = p_o[i];
r_ssize j = i - 1;
while (j >= 0) {
const uint32_t x_cmp_elt = p_x[j];
if (x_elt >= x_cmp_elt) {
break;
}
int o_cmp_elt = p_o[j];
// Swap
p_x[j + 1] = x_cmp_elt;
p_o[j + 1] = o_cmp_elt;
// Next
--j;
}
// Place original elements in new location
// closer to start of the vector
p_x[j + 1] = x_elt;
p_o[j + 1] = o_elt;
}
// We've ordered a small chunk, we need to push at least one group size.
// Depends on the post-ordered results so we have to do this
// in a separate loop.
r_ssize group_size = 1;
uint32_t previous = p_x[0];
for (r_ssize i = 1; i < size; ++i) {
const uint32_t current = p_x[i];
// Continue the current group run
if (current == previous) {
++group_size;
continue;
}
// Push current run size and reset size tracker
groups_size_maybe_push(group_size, p_group_infos);
group_size = 1;
previous = current;
}
// Push final group run
groups_size_maybe_push(group_size, p_group_infos);
}void int_order_radix(
const r_ssize size,
uint32_t* p_x,
int* p_o,
uint32_t* p_x_aux,
int* p_o_aux,
uint8_t* p_bytes,
r_ssize* p_counts,
struct group_infos* p_group_infos
) {
bool p_skips[INT_MAX_RADIX_PASS];
uint8_t pass = int_compute_skips(p_x, size, p_skips);
// Skipped all passes - Happens when `x` is 1 value repeated
if (pass == INT_MAX_RADIX_PASS) {
groups_size_maybe_push(size, p_group_infos);
return;
}
int_order_radix_recurse(
size,
pass,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts,
p_skips,
p_group_infos
);
}r_obj* interval_order(r_obj* start,
r_obj* end,
r_obj* direction,
r_obj* na_value,
r_ssize size) {
// Put them in a data frame to compute joint ordering
r_obj* df = KEEP(r_new_list(2));
r_list_poke(df, 0, start);
r_list_poke(df, 1, end);
r_obj* df_names = r_new_character(2);
r_attrib_poke_names(df, df_names);
r_chr_poke(df_names, 0, r_str("start"));
r_chr_poke(df_names, 1, r_str("end"));
r_init_data_frame(df, size);
const bool nan_distinct = false;
r_obj* chr_proxy_collate = r_null;
r_obj* out = vec_order(
df,
direction,
na_value,
nan_distinct,
chr_proxy_collate
);
FREE(1);
return out;
}bool is_bare_data_frame(r_obj* x) {
return class_type(x) == VCTRS_CLASS_bare_data_frame;
}bool is_compact_condition(r_obj* x) {
return r_inherits(x, compact_condition_class_string);
}bool is_compact_rep(SEXP x) {
return r_inherits(x, compact_rep_class_string);
}bool is_compact_seq(SEXP x) {
return r_inherits(x, compact_seq_class_string);
}bool is_condition_index(r_obj* index) {
if (r_typeof(index) != R_TYPE_logical) {
return false;
}
if (has_dim(index)) {
return false;
}
if (r_is_object(index)) {
return false;
}
return true;
}bool is_data_frame(r_obj* x) {
return
r_typeof(x) == R_TYPE_list &&
class_type_is_data_frame(class_type(x));
}bool is_integer64(SEXP x) {
return TYPEOF(x) == REALSXP && Rf_inherits(x, "integer64");
}bool is_unique_names(r_obj* names) {
if (r_typeof(names) != R_TYPE_character) {
r_abort("`names` must be a character vector");
}
r_ssize n = r_length(names);
r_obj* const * v_names = r_chr_cbegin(names);
if (duplicated_any(names)) {
return false;
}
for (r_ssize i = 0; i < n; ++i) {
if (needs_suffix(v_names[i])) {
return false;
}
}
return true;
}bool lgl_any_na(SEXP x) {
R_xlen_t size = Rf_xlength(x);
const int* p_x = LOGICAL_RO(x);
for (R_xlen_t i = 0; i < size; ++i) {
if (p_x[i] == NA_LOGICAL) {
return true;
}
}
return false;
}r_obj* lgl_as_double(r_obj* x, bool* lossy) {
int* data = r_lgl_begin(x);
r_ssize n = r_length(x);
r_obj* out = KEEP(r_alloc_double(n));
double* out_data = r_dbl_begin(out);
for (r_ssize i = 0; i < n; ++i, ++data, ++out_data) {
int elt = *data;
*out_data = (elt == r_globals.na_lgl) ? r_globals.na_dbl : elt;
}
FREE(1);
return out;
}r_obj* lgl_as_integer(r_obj* x, bool* lossy) {
return Rf_coerceVector(x, INTSXP);
}r_obj* lgl_as_location(r_obj* subscript,
r_ssize n,
const struct location_opts* opts) {
r_ssize subscript_n = r_length(subscript);
if (subscript_n == n) {
bool na_propagate = false;
switch (opts->missing) {
case SUBSCRIPT_MISSING_PROPAGATE: na_propagate = true; break;
case SUBSCRIPT_MISSING_REMOVE: break;
case SUBSCRIPT_MISSING_ERROR: {
if (lgl_any_na(subscript)) {
stop_subscript_missing(subscript, opts);
}
break;
}
}
return r_lgl_which(subscript, na_propagate);
}
/* A single `TRUE` or `FALSE` index is recycled to the full vector
* size. This means `TRUE` is synonym for missing index (subscript.e. no
* subsetting) and `FALSE` is synonym for empty index.
*
* We could return the missing argument as sentinel to avoid
* materialising the index vector for the `TRUE` case but this would
* make `vec_as_location()` an option type just to optimise a rather
* uncommon case.
*/
if (subscript_n == 1) {
int elt = r_lgl_get(subscript, 0);
r_ssize recycle_size = n;
r_obj* out = r_null;
r_keep_loc out_shelter;
KEEP_HERE(out, &out_shelter);
if (elt == r_globals.na_lgl) {
switch (opts->missing) {
case SUBSCRIPT_MISSING_PROPAGATE: {
out = r_alloc_integer(n);
KEEP_AT(out, out_shelter);
r_int_fill(out, r_globals.na_int, n);
break;
}
case SUBSCRIPT_MISSING_REMOVE: {
out = r_copy(r_globals.empty_int);
KEEP_AT(out, out_shelter);
recycle_size = 0;
break;
}
case SUBSCRIPT_MISSING_ERROR: {
stop_subscript_missing(subscript, opts);
}
}
} else if (elt) {
out = r_alloc_integer(n);
KEEP_AT(out, out_shelter);
r_int_fill_seq(out, 1, n);
} else {
out = r_copy(r_globals.empty_int);
KEEP_AT(out, out_shelter);
recycle_size = 0;
}
r_obj* nms = KEEP(r_names(subscript));
if (nms != R_NilValue) {
r_obj* recycled_nms = r_alloc_character(recycle_size);
r_attrib_poke_names(out, recycled_nms);
r_chr_fill(recycled_nms, r_chr_get(nms, 0), recycle_size);
}
FREE(2);
return out;
}
r_obj* n_obj = KEEP(r_int(n));
stop_indicator_size(subscript, n_obj, opts);
r_stop_unreachable();
}int lgl_compare_na_equal(int x, int y) {
return int_compare_scalar(x, y);
}uint32_t lgl_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return lgl_dict_hash_with(d, d, i);
}uint32_t lgl_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_lgl_equal_na_equal);
}bool lgl_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_lgl_is_incomplete(d->p_poly_vec->p_vec, i);
}static inline int lgl_equal_na_equal(int x, int y) {
return x == y;
}static inline int lgl_equal_na_propagate(int x, int y) {
if (lgl_is_missing(x) || lgl_is_missing(y)) {
return NA_LOGICAL;
} else {
return lgl_equal_na_equal(x, y);
}
}static inline uint32_t lgl_hash_scalar(int x) {
return uint32_hash(x);
}bool lgl_is_missing(int x) {
return x == r_globals.na_int;
}bool lgl_is_unspecified(SEXP x) {
const r_ssize size = r_length(x);
if (size == 0) {
// We declare `logical()` to be <logical>, not <unspecified>
return false;
}
const int* p_x = r_lgl_cbegin(x);
for (r_ssize i = 0; i < size; ++i) {
if (p_x[i] != r_globals.na_lgl) {
return false;
}
}
return true;
}void lgl_order(
SEXP x,
bool decreasing,
bool na_last,
r_ssize size,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
int_order(
x,
decreasing,
na_last,
size,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
}void lgl_order_chunk(
bool decreasing,
bool na_last,
r_ssize size,
int* p_o,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
int_order_chunk(
decreasing,
na_last,
size,
p_o,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
}r_obj* list_assign(
r_obj* x,
r_obj* index,
r_obj* value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_BARRIER(r_obj*, r_list_cbegin, r_list_poke);
}r_ssize list_col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
COL_DETECT_MISSING(r_obj*, r_list_cbegin, list_is_missing);
}void list_col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_COL_DETECT_RUN_BOUNDS_BOOL(r_obj*, r_list_cbegin, list_equal_na_equal);
}r_obj* list_combine_for_list_unchop(
r_obj* xs,
r_obj* indices,
r_obj* ptype,
r_obj* name_spec,
const struct name_repair_opts* p_name_repair_opts,
struct vctrs_arg* p_xs_arg,
struct r_lazy error_call
) {
const enum s3_fallback s3_fallback = r_is_true(r_peek_option("vctrs:::base_c_in_progress")) ?
S3_FALLBACK_false :
S3_FALLBACK_true;
bool has_indices = indices != r_null;
struct vctrs_arg* p_indices_arg = vec_args.indices;
// If `!has_indices`, `list_combine()` will compute the size from the sizes of
// `xs` and will ignore whatever we put here.
r_ssize size = 0;
if (has_indices) {
// Sums the length of each `index` to compute the `size`
//
// This was the way that `list_unchop()` would compute the output size when
// `indices` were provided. In `list_combine()`, the `size` is explicitly
// required to account for a few edge cases and to work well with `default`.
//
// Note that `list_as_locations()` in `list_combine()` isn't allowed to
// change the `index` size, which is the only reason this works from a
// theoretical point of view.
obj_check_list(indices, p_indices_arg, error_call);
r_obj* const* v_indices = r_list_cbegin(indices);
r_ssize indices_size = vec_size(indices);
for (r_ssize i = 0; i < indices_size; ++i) {
size += r_length(v_indices[i]);
}
}
bool has_default = false;
r_obj* default_ = r_null;
struct vctrs_arg* p_default_arg = vec_args.empty;
enum list_combine_unmatched unmatched = LIST_COMBINE_UNMATCHED_default;
enum list_combine_multiple multiple = LIST_COMBINE_MULTIPLE_last;
const enum assignment_slice_value slice_xs = ASSIGNMENT_SLICE_VALUE_no;
const enum vctrs_index_style indices_style = VCTRS_INDEX_STYLE_location;
r_obj* out = KEEP(list_combine_impl(
xs,
has_indices,
indices,
indices_style,
size,
has_default,
default_,
unmatched,
multiple,
slice_xs,
ptype,
name_spec,
p_name_repair_opts,
p_xs_arg,
p_indices_arg,
p_default_arg,
error_call,
s3_fallback
));
if (vec_is_unspecified(out) && r_is_object(out)) {
// The following `list_c()` and `list_unchop()` cases historically return
// `NULL` because they don't have a `size` argument to maintain an invariant
// for. `list_combine()` returns `unspecified` for these, because there
// could be a `size > 0` argument supplied and we need to retain the size
// invariant. We rectify the difference here.
//
// ```
// vec_c()
// vec_c(NULL)
// list_unchop(list())
// list_unchop(list(), indices = list())
// list_unchop(list(NULL))
// list_unchop(list(NULL), indices = list(integer()))
// ```
//
// This is an ambiguous edge case that we've currently defined as also
// returning `NULL`. `list_combine()` returns `unspecified[2]` here, but
// that's clearer because `size` has to be explicitly provided.
//
// ```
// list_unchop(list(NULL), indices = list(1:2))
// ```
//
// We still want these cases to return `NA` even though they are technically
// "unspecified" outputs, so we explicitly check if the output is an S3 object
// as well, i.e. its an explicit `"vctrs_unspecified"` and not just a logical
// vector of `NA`s.
//
// ```
// vec_c(NA)
// list_unchop(list(NA), indices = list(1))
// ```
out = r_null;
}
FREE(1);
return out;
}r_obj* list_combine_for_vec_c(
r_obj* xs,
r_obj* ptype,
r_obj* name_spec,
const struct name_repair_opts* p_name_repair_opts,
struct vctrs_arg* p_xs_arg,
struct r_lazy error_call
) {
r_obj* indices = r_null;
return list_combine_for_list_unchop(
xs,
indices,
ptype,
name_spec,
p_name_repair_opts,
p_xs_arg,
error_call
);
}r_obj* list_combine_homogeneous_fallback(
r_obj* xs,
bool has_indices,
r_obj* indices,
enum vctrs_index_style indices_style,
r_ssize size,
bool has_default,
r_obj* default_,
enum list_combine_multiple multiple,
enum assignment_slice_value slice_xs,
r_obj* name_spec,
struct vctrs_arg* p_xs_arg,
struct vctrs_arg* p_default_arg,
struct r_lazy error_call
) {
return base_list_combine_fallback(
xs,
has_indices,
indices,
indices_style,
size,
has_default,
default_,
multiple,
slice_xs,
name_spec,
p_xs_arg,
p_default_arg,
error_call
);
}r_obj* list_combine_impl(
r_obj* xs,
bool has_indices,
r_obj* indices,
enum vctrs_index_style indices_style,
r_ssize size,
bool has_default,
r_obj* default_,
enum list_combine_unmatched unmatched,
enum list_combine_multiple multiple,
enum assignment_slice_value slice_xs,
r_obj* ptype,
r_obj* name_spec,
const struct name_repair_opts* p_name_repair_opts,
struct vctrs_arg* p_xs_arg,
struct vctrs_arg* p_indices_arg,
struct vctrs_arg* p_default_arg,
struct r_lazy error_call,
enum s3_fallback s3_fallback
) {
int n_protect = 0;
obj_check_list(xs, p_xs_arg, error_call);
r_obj* const* v_xs = r_list_cbegin(xs);
r_ssize xs_size = vec_size(xs);
// This is impossible with the exposed API, but let's sanity check
if (!has_indices) {
switch (multiple) {
case LIST_COMBINE_MULTIPLE_last: break;
case LIST_COMBINE_MULTIPLE_first: r_stop_internal("`multiple = 'first'` can't be set with sequential combination."); break;
default: r_stop_unreachable();
}
}
if (has_indices) {
// Apply size/type checking to `indices` before possibly early exiting from
// needing to apply a fallback
obj_check_list(indices, p_indices_arg, error_call);
vec_check_size(indices, xs_size, VCTRS_ALLOW_NULL_no, p_indices_arg, error_call);
}
// Sizes are reused by the sequential path when advancing the compact-seq index.
// It's more efficient to build them once even though it requires an allocation.
r_obj* xs_sizes = NULL;
r_ssize* v_xs_sizes = NULL;
if (!has_indices) {
// Infer `size` from `xs` for `vec_c()` and `list_unchop(indices = NULL)`
// sequential approach
size = 0;
xs_sizes = KEEP_N(r_alloc_raw(xs_size * sizeof(r_ssize)), &n_protect);
v_xs_sizes = r_raw_begin(xs_sizes);
for (r_ssize i = 0; i < xs_size; ++i) {
r_obj* x = v_xs[i];
r_ssize x_size = vec_size(x);
size += x_size;
v_xs_sizes[i] = x_size;
}
}
if (has_indices && indices_style == VCTRS_INDEX_STYLE_location) {
// Validate and convert `indices` if they exist.
//
// Note that we don't allow an individual `index` vector to change size
// during validation. This is the only reason we can "infer" the output
// size from the sum of the lengths of the `indices` before doing validation
// and conversion. In particular:
// - `NULL` indices become `integer()` (both size `0`).
// - We don't allow character or logical indices.
// - We don't allow negative or zero indices (these change the size).
// - We don't allow oob indices (makes no sense since we inferred the size from lengths).
// - Numeric `NA` propagates.
//
// Note that `compact_seq()` objects are valid `index` values for
// `list_combine()`. We have tests to ensure it can handle them!
//
// There is nothing to validate for condition indices, they are logical vectors
// where all 3 possible values are handled and we've already checked their sizes
// match `size` in `compute_indices_style()`.
const bool allow_compact = true;
indices = KEEP_N(list_as_locations(indices, size, r_null, allow_compact), &n_protect);
}
// Perform `unmatched` check
// (before fallback cases!)
switch (unmatched) {
case LIST_COMBINE_UNMATCHED_default: {
// Will use `default` in unmatched locations
break;
}
case LIST_COMBINE_UNMATCHED_error: {
if (default_ != r_null) {
r_abort_lazy_call(
error_call,
"Can't set %s when `unmatched = \"error\"`.",
vec_arg_format(p_default_arg)
);
}
if (!has_indices) {
r_stop_internal("`indices` should have been required if `unmatched` was set.");
}
check_any_unmatched(indices, indices_style, size, error_call);
break;
}
default: {
r_stop_unreachable();
}
}
ptype = KEEP_N(
ptype_common_with_default(
ptype,
xs,
has_default,
default_,
p_xs_arg,
p_default_arg,
error_call,
s3_fallback
),
&n_protect
);
if (needs_list_combine_common_class_fallback(ptype)) {
r_obj* out = list_combine_common_class_fallback(
xs,
has_indices,
indices,
indices_style,
size,
has_default,
default_,
multiple,
slice_xs,
ptype,
name_spec,
p_name_repair_opts,
p_xs_arg,
p_indices_arg,
p_default_arg,
error_call
);
FREE(n_protect);
return out;
}
if (needs_list_combine_homogeneous_fallback(xs, has_default, default_, ptype)) {
r_obj* out = list_combine_homogeneous_fallback(
xs,
has_indices,
indices,
indices_style,
size,
has_default,
default_,
multiple,
slice_xs,
name_spec,
p_xs_arg,
p_default_arg,
error_call
);
FREE(n_protect);
return out;
}
if (ptype == r_null) {
// Even when there are no inputs and we can't determine a `ptype`, the user
// will have supplied a `size`, so as an invariant we should return
// something with this `size`. Our size preserving identity type is
// `<unspecified[size]>`, so we use that.
//
// We catch `<unspecified[0]>` in `vec_c()` and `list_unchop()` and return
// `NULL` in those cases instead, because that is what they have historically
// returned and you can't supply `size` there, so this only happens in the
// empty input cases of those functions.
//
// Assuming `NULL` is roughly equivalent to `unspecified(0)`, this gives us:
//
// ```
// vec_c()
// #> NULL
// list_unchop(list(), indices = list())
// #> NULL
// list_combine(list(), indices = list(), size = 0)
// #> unspecified[0] # Consistent with size != 0 case.
// list_combine(list(), indices = list(), size = 5)
// #> unspecified[5] # Preserves size, good.
// ```
//
// The most theoretically correct thing may be to return `unspecified(0)`
// from `vec_c()` and `list_unchop()` as well, but we make a concious effort
// to avoid exposing this type to users when we can. Since those functions
// don't have the `size` invariant issue, `NULL` seems to be a good
// alternative.
// https://github.com/r-lib/vctrs/issues/1980
ptype = vctrs_shared_empty_uns;
}
const bool assign_names = !r_inherits(name_spec, "rlang_zap");
r_obj* xs_names = KEEP_N(r_names(xs), &n_protect);
const bool xs_is_named = xs_names != r_null && !is_data_frame(ptype);
r_keep_loc out_pi;
r_obj* out = vec_init(ptype, size);
KEEP_HERE(out, &out_pi);
++n_protect;
out = vec_proxy_recurse(out);
KEEP_AT(out, out_pi);
// - We own the `proxy` container
// - We own `proxy` recursively
// - We call `vec_proxy_recurse()` so must restore recursively
const struct vec_restore_opts restore_opts = {
.ownership = VCTRS_OWNERSHIP_deep,
.recursively_proxied = true
};
const struct vec_proxy_assign_opts proxy_assign_opts = {
.ownership = VCTRS_OWNERSHIP_deep,
.recursively_proxied = true,
.slice_value = slice_xs,
.index_style = indices_style,
.assign_names = assign_names,
.ignore_outer_names = true,
.call = error_call
};
r_keep_loc out_names_pi;
r_obj* out_names = r_null;
KEEP_HERE(out_names, &out_names_pi);
++n_protect;
r_ssize xs_i = 0;
struct vctrs_arg* p_x_arg = new_subscript_arg(
p_xs_arg,
xs_names,
xs_size,
&xs_i
);
KEEP_N(p_x_arg->shelter, &n_protect);
struct cast_opts cast_opts = {
.to = ptype,
.p_x_arg = p_x_arg,
.call = error_call,
.s3_fallback = s3_fallback
};
r_keep_loc x_pi;
r_obj* x = r_null;
KEEP_HERE(x, &x_pi);
++n_protect;
r_keep_loc index_pi;
r_obj* index = r_null;
KEEP_HERE(index, &index_pi);
++n_protect;
// For the sequential path
r_ssize start = 0;
int* v_index = NULL;
if (!has_indices) {
// Sequential path reuses the same compact sequence `index`
index = compact_seq(0, 0, true);
KEEP_AT(index, index_pi);
v_index = r_int_begin(index);
}
for (r_ssize i = 0; i < xs_size; ++i) {
switch (multiple) {
case LIST_COMBINE_MULTIPLE_last: xs_i = i; break;
case LIST_COMBINE_MULTIPLE_first: xs_i = xs_size - 1 - i; break;
default: r_stop_unreachable();
}
x = v_xs[xs_i];
if (x == r_null) {
continue;
}
r_ssize index_size;
// Advance `index`
if (has_indices) {
index = r_list_get(indices, xs_i);
index_size = vec_subscript_size(index);
} else {
index_size = v_xs_sizes[xs_i];
init_compact_seq(v_index, start, index_size, true);
}
// When we have `indices`, `x`'s size must be compatible with the `index`'s
// size. This is dependent on `slice_xs` and `indices_style`.
//
// When we don't have `indices`, we derive the index sizes from
// `x` itself so there is no reason to recheck the size.
//
// We don't actually recycle `x` because both `vec_proxy_assign_opts()` and
// `chr_assign()` efficiently recycle size 1 inputs.
if (has_indices) {
check_recyclable_against_index(
x,
index,
size,
slice_xs,
indices_style,
p_x_arg,
error_call
);
}
// Handle optional names assignment
if (assign_names) {
r_obj* outer = xs_is_named ? r_chr_get(xs_names, xs_i) : r_null;
r_obj* inner = KEEP(vec_names(x));
r_obj* x_names = KEEP(apply_name_spec(name_spec, outer, inner, index_size));
if (has_indices && x_names == r_null && out_names != r_null) {
// We don't have names on this element, but `out_names` will exist.
// Someone before us may have written to `out_names` at this `index` by
// providing an overlapping `index`, so we must clear that.
x_names = r_chrs.empty_string;
}
if (x_names != r_null) {
R_LAZY_ALLOC(out_names, out_names_pi, R_TYPE_character, size);
out_names = chr_assign(
out_names,
index,
x_names,
VCTRS_OWNERSHIP_deep,
slice_xs,
indices_style
);
KEEP_AT(out_names, out_names_pi);
}
FREE(2);
}
cast_opts.x = x;
x = vec_cast_opts(&cast_opts);
KEEP_AT(x, x_pi);
out = vec_proxy_assign_opts(out, index, x, &proxy_assign_opts);
KEEP_AT(out, out_pi);
if (!has_indices) {
start += index_size;
}
}
if (has_default) {
// `default` uses a slightly modified form of `proxy_assign_opts` and
// `cast_opts`
// - `default` is size 1 or size of the output, so uses
// `ASSIGNMENT_SLICE_VALUE_yes`.
// - `default`'s index is always built using a special compact condition
// vector, so uses `VCTRS_INDEX_STYLE_condition`.
// - `default` has its own special `p_default_arg`.
struct vec_proxy_assign_opts default_proxy_assign_opts = proxy_assign_opts;
default_proxy_assign_opts.index_style = VCTRS_INDEX_STYLE_condition;
default_proxy_assign_opts.slice_value = ASSIGNMENT_SLICE_VALUE_yes;
struct cast_opts default_cast_opts = cast_opts;
default_cast_opts.p_x_arg = p_default_arg;
// Compute `default` compact condition index
index = compute_default_index(indices, indices_style, size);
KEEP_AT(index, index_pi);
// `default` recycles against the output size, not the `index`
vec_check_recyclable(default_, size, VCTRS_ALLOW_NULL_no, p_default_arg, error_call);
// Handle optional names assignment
if (assign_names) {
// `outer` names don't exist, but `name_spec` could still `zap()` any `inner` names
r_obj* outer = r_null;
r_obj* inner = KEEP(vec_names(default_));
r_obj* x_names = KEEP(apply_name_spec(name_spec, outer, inner, size));
if (x_names != r_null) {
R_LAZY_ALLOC(out_names, out_names_pi, R_TYPE_character, size);
out_names = chr_assign(
out_names,
index,
x_names,
VCTRS_OWNERSHIP_deep,
default_proxy_assign_opts.slice_value,
default_proxy_assign_opts.index_style
);
KEEP_AT(out_names, out_names_pi);
}
FREE(2);
}
default_cast_opts.x = default_;
x = vec_cast_opts(&default_cast_opts);
KEEP_AT(x, x_pi);
out = vec_proxy_assign_opts(out, index, x, &default_proxy_assign_opts);
KEEP_AT(out, out_pi);
}
if (
s3_fallback == S3_FALLBACK_true &&
is_data_frame(out) &&
needs_df_list_combine_common_class_fallback(out)
) {
// Perform the common class fallback on any columns of the
// data frame that require it
df_list_combine_common_class_fallback(
out,
xs,
has_indices,
indices,
indices_style,
size,
has_default,
default_,
multiple,
slice_xs,
ptype,
name_spec,
p_name_repair_opts,
p_indices_arg,
error_call
);
}
out = vec_restore_opts(out, ptype, &restore_opts);
KEEP_AT(out, out_pi);
if (out_names != r_null) {
out_names = KEEP(vec_as_names(out_names, p_name_repair_opts));
out = vec_set_names(out, out_names, restore_opts.ownership);
FREE(1);
} else if (!assign_names) {
// FIXME: `vec_ptype2()` doesn't consistently zaps names, so `out`
// might have been initialised with names. This branch can be
// removed once #1020 is resolved.
out = vec_set_names(out, r_null, restore_opts.ownership);
}
FREE(n_protect);
return out;
}r_obj* list_detect_missing(r_obj* x) {
DETECT_MISSING(r_obj*, r_list_cbegin, list_is_missing);
}void list_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_DETECT_RUN_BOUNDS_BOOL(r_obj*, r_list_cbegin, list_equal_na_equal);
}uint32_t list_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return list_dict_hash_with(d, d, i);
}uint32_t list_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_list_equal_na_equal);
}bool list_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_list_is_incomplete(d->p_poly_vec->p_vec, i);
}r_obj* list_drop_empty(r_obj* x) {
if (!obj_is_list(x)) {
r_abort("`x` must be a list.");
}
r_ssize i = 0;
const r_ssize size = vec_size(x);
r_obj* const* v_x = r_list_cbegin(x);
// Locate first element to drop
for (; i < size; ++i) {
if (vec_size(v_x[i]) == 0) {
break;
}
}
if (i == size) {
// Nothing to drop
return x;
}
r_obj* keep = KEEP(r_alloc_logical(size));
int* v_keep = r_lgl_begin(keep);
for (r_ssize j = 0; j < i; ++j) {
// Keep everything before first element to drop
v_keep[j] = true;
}
// `i` should be dropped so handle that here
v_keep[i] = false;
++i;
for (; i < size; ++i) {
v_keep[i] = vec_size(v_x[i]) != 0;
}
r_obj* out = vec_slice(x, keep);
FREE(1);
return out;
}r_obj* list_encode_utf8(r_obj* x) {
bool owned = false;
r_keep_loc pi;
KEEP_HERE(x, &pi);
r_ssize size = r_length(x);
r_obj* const* p_x = r_list_cbegin(x);
for (r_ssize i = 0; i < size; ++i) {
r_obj* const elt_old = p_x[i];
r_obj* const elt_new = obj_encode_utf8(elt_old);
if (elt_old == elt_new) {
continue;
}
KEEP(elt_new);
if (!owned) {
x = r_clone(x);
KEEP_AT(x, pi);
p_x = r_list_cbegin(x);
owned = true;
}
r_list_poke(x, i, elt_new);
FREE(1);
}
FREE(1);
return x;
}static inline int list_equal_na_equal(SEXP x, SEXP y) {
return obj_equal_utf8(x, y);
}static inline int list_equal_na_propagate(SEXP x, SEXP y) {
if (list_is_missing(x) || list_is_missing(y)) {
return NA_LOGICAL;
} else {
return list_equal_na_equal(x, y);
}
}r_ssize list_first_missing(r_obj* x) {
FIRST_MISSING(r_obj*, r_list_cbegin, list_is_missing);
}SEXP list_first_non_null(SEXP xs, R_len_t* non_null_i) {
SEXP x = R_NilValue;
R_len_t n = Rf_length(xs);
R_len_t i = 0;
for (; i < n; ++i) {
x = VECTOR_ELT(xs, i);
if (x != R_NilValue) {
break;
}
}
if (non_null_i) {
*non_null_i = i;
}
return x;
}static inline void list_hash_fill_na_equal(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL(r_obj*, r_list_cbegin, list_hash_scalar);
}static inline void list_hash_fill_na_propagate(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL_NA_PROPAGATE(r_obj*, r_list_cbegin, list_hash_scalar, list_is_missing);
}static inline uint32_t list_hash_scalar(r_obj* x) {
return obj_hash(x);
}bool list_is_missing(r_obj* x) {
return x == r_null;
}void load_with_haystack(struct dictionary* d, R_len_t n_haystack) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: LOAD_WITH_HAYSTACK(nil_dict_hash_scalar); break;
case VCTRS_TYPE_logical: LOAD_WITH_HAYSTACK(lgl_dict_hash_scalar); break;
case VCTRS_TYPE_integer: LOAD_WITH_HAYSTACK(int_dict_hash_scalar); break;
case VCTRS_TYPE_double: LOAD_WITH_HAYSTACK(dbl_dict_hash_scalar); break;
case VCTRS_TYPE_complex: LOAD_WITH_HAYSTACK(cpl_dict_hash_scalar); break;
case VCTRS_TYPE_character: LOAD_WITH_HAYSTACK(chr_dict_hash_scalar); break;
case VCTRS_TYPE_raw: LOAD_WITH_HAYSTACK(raw_dict_hash_scalar); break;
case VCTRS_TYPE_list: LOAD_WITH_HAYSTACK(list_dict_hash_scalar); break;
case VCTRS_TYPE_dataframe: LOAD_WITH_HAYSTACK(df_dict_hash_scalar); break;
default: stop_unimplemented_vctrs_type("vec_match_loop", d->p_poly_vec->type);
}
}SEXP map(SEXP x, SEXP (*fn)(SEXP)) {
R_len_t n = Rf_length(x);
SEXP out = PROTECT(Rf_allocVector(VECSXP, n));
for (R_len_t i = 0; i < n; ++i) {
SET_VECTOR_ELT(out, i, fn(VECTOR_ELT(x, i)));
}
SEXP nms = PROTECT(Rf_getAttrib(x, R_NamesSymbol));
Rf_setAttrib(out, R_NamesSymbol, nms);
UNPROTECT(2);
return out;
}bool multiply_would_overflow(r_ssize x, r_ssize y) {
return (double) x * y > R_LEN_T_MAX;
}const char* name_repair_arg_as_c_string(enum name_repair_type type) {
switch (type) {
case NAME_REPAIR_none: return "none";
case NAME_REPAIR_minimal: return "minimal";
case NAME_REPAIR_unique: return "unique";
case NAME_REPAIR_universal: return "universal";
case NAME_REPAIR_check_unique: return "check_unique";
case NAME_REPAIR_custom: return "custom";
}
r_stop_unreachable();
}bool name_spec_is_inner(r_obj* name_spec) {
if (!r_is_string(name_spec)) {
return false;
}
const char* name_spec_c_string = r_chr_get_c_string(name_spec, 0);
return !strcmp(name_spec_c_string, "inner");
}r_obj* names_iota(r_ssize n) {
char buf[MAX_IOTA_SIZE];
r_obj* nms = r_chr_iota(n, buf, MAX_IOTA_SIZE, "...");
if (nms == r_null) {
r_abort("Too many names to repair.");
}
return nms;
}bool needs_list_combine_common_class_fallback(r_obj* ptype) {
if (!vec_is_common_class_fallback(ptype)) {
return false;
}
// Suboptimal: Prevent infinite recursion through `vctrs_vctr` method
r_obj* cls = r_attrib_get(ptype, syms_fallback_class);
cls = r_chr_get(cls, r_length(cls) - 1);
return cls != strings_vctrs_vctr;
}bool needs_list_combine_homogeneous_fallback(
r_obj* xs,
bool has_default,
r_obj* default_,
r_obj* ptype
) {
r_obj* first = list_first_non_null(xs, NULL);
if (first == r_null && has_default) {
// i.e. `list_combine(x = list(), default = foobar(1))`
first = default_;
}
if (!obj_is_vector(first, VCTRS_ALLOW_NULL_no)) {
return false;
}
// Never fall back for `vctrs_vctr` classes to avoid infinite
// recursion through `c.vctrs_vctr()`
if (r_inherits(first, "vctrs_vctr")) {
return false;
}
r_obj* ptype_class = KEEP(r_class(ptype));
if (!obj_has_class(first, ptype_class)) {
// Cheap test before consulting `vec_ptype2()` and `c()` methods
FREE(1);
return false;
}
bool out = !vec_implements_ptype2(first) &&
list_all_have_class(xs, ptype_class) &&
(has_default ? obj_has_class(default_, ptype_class) : true) &&
vec_implements_base_c(first);
FREE(1);
return out;
}static bool needs_suffix(r_obj* str) {
return
str == r_globals.na_str ||
str == strings_dots ||
str == strings_empty ||
is_dotdotint(r_str_c_string(str));
}inline void never_reached(const char* fn) {
Rf_error("Internal error in `%s()`: Reached the unreachable.", fn);
}struct vctrs_chop_indices* new_chop_indices(r_obj* x, r_obj* indices, r_obj* sizes) {
r_obj* shelter = KEEP(r_alloc_list(4));
r_obj* self = r_alloc_raw(sizeof(struct vctrs_chop_indices));
r_list_poke(shelter, 0, self);
struct vctrs_chop_indices* p_indices = r_raw_begin(self);
p_indices->shelter = shelter;
p_indices->indices = indices;
r_list_poke(p_indices->shelter, 1, p_indices->indices);
p_indices->has_indices = p_indices->indices != r_null;
p_indices->sizes = sizes;
r_list_poke(p_indices->shelter, 2, p_indices->sizes);
p_indices->has_sizes = p_indices->sizes != r_null;
if (p_indices->has_indices) {
p_indices->v_indices = r_list_cbegin(p_indices->indices);
p_indices->v_sizes = NULL;
p_indices->index = r_null;
r_list_poke(p_indices->shelter, 3, p_indices->index);
p_indices->p_index = NULL;
} else if (p_indices->has_sizes) {
p_indices->v_indices = NULL;
p_indices->v_sizes = r_int_cbegin(p_indices->sizes);
p_indices->index = compact_seq(0, 0, true);
r_list_poke(p_indices->shelter, 3, p_indices->index);
p_indices->p_index = r_int_begin(p_indices->index);
} else {
p_indices->v_indices = NULL;
p_indices->v_sizes = NULL;
p_indices->index = r_int(0);
r_list_poke(p_indices->shelter, 3, p_indices->index);
p_indices->p_index = r_int_begin(p_indices->index);
}
p_indices->loc = 0;
FREE(1);
return p_indices;
}r_obj* new_compact_condition(R_xlen_t size) {
if (size < 0) {
r_stop_internal("Negative `size` in `compact_condition()`.");
}
r_obj* out = KEEP(r_alloc_raw(size * sizeof(bool)));
r_attrib_poke_class(out, compact_condition_classes);
FREE(1);
return out;
}r_obj* new_compact_rownames(r_ssize n_rows) {
if (n_rows <= 0) {
return r_globals.empty_int;
}
r_obj* out = r_alloc_integer(2);
int* p_out = r_int_begin(out);
p_out[0] = r_globals.na_int;
p_out[1] = -n_rows;
return out;
}struct vctrs_arg new_counter_arg(struct vctrs_arg* parent,
struct arg_data_counter* data) {
return (struct vctrs_arg) {
.parent = parent,
.fill = &counter_arg_fill,
.data = (void*) data
};
}struct arg_data_counter new_counter_arg_data(struct vctrs_arg* p_parent,
r_ssize* i,
r_obj** names) {
return (struct arg_data_counter) {
.p_parent = p_parent,
.i = i,
.names = names
};
}struct counters* new_counters(r_obj* names,
struct vctrs_arg* p_curr_arg,
struct vctrs_arg* p_parent_arg) {
// This protects `shelter` and `names`
r_obj* shelter = KEEP(r_alloc_list(COUNTERS_SHELTER_N));
r_obj* data_shelter = r_alloc_raw(sizeof(struct counters));
r_list_poke(shelter, COUNTERS_SHELTER_data, data_shelter);
// `names` probably don't need to be protected, but we do so to be safe
// (We used to use splice boxes, and `names` needed to be protected then,
// but we no longer do as of #1578)
r_list_poke(shelter, COUNTERS_SHELTER_names, names);
struct counters* p_counters = r_raw_begin(data_shelter);
p_counters->shelter = shelter;
p_counters->curr = 0;
p_counters->next = 0;
p_counters->names = names;
p_counters->curr_counter_arg_data = new_counter_arg_data(p_parent_arg,
&p_counters->curr,
&p_counters->names);
p_counters->next_counter_arg_data = new_counter_arg_data(p_parent_arg,
&p_counters->next,
&p_counters->names);
p_counters->curr_counter = new_counter_arg(p_parent_arg, (void*) &p_counters->curr_counter_arg_data);
p_counters->next_counter = new_counter_arg(p_parent_arg, (void*) &p_counters->next_counter_arg_data);
p_counters->curr_arg = p_curr_arg;
p_counters->next_arg = (struct vctrs_arg*) &p_counters->next_counter;
FREE(1);
return p_counters;
}r_obj* new_data_frame(r_obj* x, r_ssize n) {
x = KEEP(r_clone_referenced(x));
init_data_frame(x, n);
FREE(1);
return x;
}static SEXP new_date(SEXP x) {
if (TYPEOF(x) != REALSXP) {
Rf_errorcall(R_NilValue, "`x` must be a double vector.");
}
SEXP names = PROTECT(r_names(x));
SEXP out = PROTECT(r_clone_referenced(x));
r_attrib_zap_all(out);
r_attrib_poke_names(out, names);
r_attrib_poke_class(out, classes_date);
UNPROTECT(2);
return out;
}static SEXP new_datetime(SEXP x, SEXP tzone) {
if (TYPEOF(x) != REALSXP) {
Rf_errorcall(R_NilValue, "`x` must be a double vector.");
}
// Convenience special case where we allow a
// null `tzone` to represent local time
if (tzone == R_NilValue) {
tzone = chrs_empty;
}
if (TYPEOF(tzone) != STRSXP) {
Rf_errorcall(R_NilValue, "`tzone` must be a character vector or `NULL`.");
}
SEXP names = PROTECT(r_names(x));
SEXP out = PROTECT(r_clone_referenced(x));
r_attrib_zap_all(out);
r_attrib_poke_names(out, names);
r_attrib_poke_class(out, classes_posixct);
r_attrib_poke(out, syms_tzone, tzone);
UNPROTECT(2);
return out;
}static inline struct df_short_circuit_info new_df_short_circuit_info(R_len_t size, bool lazy) {
SEXP row_known;
bool* p_row_known;
if (lazy) {
row_known = PROTECT(R_NilValue);
p_row_known = NULL;
} else {
row_known = PROTECT(Rf_allocVector(RAWSXP, size * sizeof(bool)));
p_row_known = (bool*) RAW(row_known);
// To begin with, no rows have a known comparison value
r_memset(p_row_known, false, size * sizeof(bool));
}
struct df_short_circuit_info info = {
.row_known = row_known,
.p_row_known = p_row_known,
.remaining = size,
.size = size
};
UNPROTECT(1);
return info;
}struct dictionary* new_dictionary(SEXP x) {
struct dictionary_opts opts = {
.partial = false,
.na_equal = true
};
return new_dictionary_opts(x, &opts);
}static struct dictionary* new_dictionary_opts(SEXP x, struct dictionary_opts* opts) {
int nprot = 0;
SEXP out = PROTECT_N(Rf_allocVector(RAWSXP, sizeof(struct dictionary)), &nprot);
struct dictionary* d = (struct dictionary*) RAW(out);
d->protect = out;
enum vctrs_type type = vec_proxy_typeof(x);
struct poly_vec* p_poly_vec = new_poly_vec(x, type);
KEEP_N(p_poly_vec->shelter, &nprot);
d->p_poly_vec = p_poly_vec;
d->used = 0;
if (opts->partial) {
d->key = NULL;
d->size = 0;
} else {
uint32_t size = dict_key_size(x);
d->key = (R_len_t*) R_alloc(size, sizeof(R_len_t));
for (uint32_t i = 0; i < size; ++i) {
d->key[i] = DICT_EMPTY;
}
d->size = size;
}
R_len_t n = vec_size(x);
if (n) {
d->hash = (uint32_t*) R_alloc(n, sizeof(uint32_t));
if (!(d->hash)) {
Rf_errorcall(R_NilValue, "Can't allocate hash lookup table. Please free memory.");
}
r_memset(d->hash, 0, n * sizeof(uint32_t));
vec_hash_fill(x, n, opts->na_equal, d->hash);
} else {
d->hash = NULL;
}
UNPROTECT(nprot);
return d;
}static struct dictionary* new_dictionary_params(SEXP x, bool partial, bool na_equal) {
struct dictionary_opts opts;
opts.partial = partial;
opts.na_equal = na_equal;
return new_dictionary_opts(x, &opts);
}struct dictionary* new_dictionary_partial(SEXP x) {
struct dictionary_opts opts = {
.partial = true,
.na_equal = true
};
return new_dictionary_opts(x, &opts);
}SEXP new_empty_factor(SEXP levels) {
if (TYPEOF(levels) != STRSXP) {
r_stop_internal("`level` must be a character vector.");
}
SEXP out = PROTECT(Rf_allocVector(INTSXP, 0));
Rf_setAttrib(out, R_LevelsSymbol, levels);
Rf_setAttrib(out, R_ClassSymbol, classes_factor);
UNPROTECT(1);
return out;
}SEXP new_empty_ordered(SEXP levels) {
SEXP out = PROTECT(Rf_allocVector(INTSXP, 0));
Rf_setAttrib(out, R_LevelsSymbol, levels);
Rf_setAttrib(out, R_ClassSymbol, classes_ordered);
UNPROTECT(1);
return out;
}r_obj* new_error_subscript_type(r_obj* subscript,
const struct subscript_opts* opts,
r_obj* body) {
r_obj* logical = subscript_type_action_chr(opts->logical);
r_obj* numeric = subscript_type_action_chr(opts->numeric);
r_obj* character = subscript_type_action_chr(opts->character);
subscript = KEEP(expr_protect(subscript));
r_obj* subscript_arg = KEEP(vctrs_arg(opts->subscript_arg));
r_obj* ffi_call = r_lazy_eval_protect(opts->call);
r_obj* syms[] = {
syms_i,
syms_subscript_arg,
syms_subscript_action,
syms_call,
syms_logical,
syms_numeric,
syms_character,
syms_body,
NULL
};
r_obj* args[] = {
subscript,
subscript_arg,
get_opts_action(opts),
ffi_call,
logical,
numeric,
character,
body,
NULL
};
r_obj* call = KEEP(r_call_n(syms_new_error_subscript_type, syms, args));
r_obj* out = r_eval(call, vctrs_ns_env);
FREE(3);
return out;
}struct group_info* new_group_info(void) {
SEXP self = PROTECT(r_new_raw(sizeof(struct group_info)));
struct group_info* p_group_info = (struct group_info*) RAW(self);
p_group_info->self = self;
p_group_info->data_size = 0;
p_group_info->data = r_globals.empty_int;
p_group_info->n_groups = 0;
p_group_info->max_group_size = 0;
UNPROTECT(1);
return p_group_info;
}struct group_infos* new_group_infos(struct group_info* p_group_info0,
struct group_info* p_group_info1,
r_ssize max_data_size,
bool force_groups,
bool ignore_groups) {
SEXP self = PROTECT(r_new_raw(sizeof(struct group_infos)));
struct group_infos* p_group_infos = (struct group_infos*) RAW(self);
SEXP p_p_group_info_data = PROTECT(r_new_raw(2 * sizeof(struct group_info*)));
struct group_info** p_p_group_info = (struct group_info**) RAW(p_p_group_info_data);
p_p_group_info[0] = p_group_info0;
p_p_group_info[1] = p_group_info1;
p_group_infos->self = self;
p_group_infos->p_p_group_info_data = p_p_group_info_data;
p_group_infos->p_p_group_info = p_p_group_info;
p_group_infos->max_data_size = max_data_size;
p_group_infos->current = 0;
p_group_infos->force_groups = force_groups;
p_group_infos->ignore_groups = ignore_groups;
UNPROTECT(2);
return p_group_infos;
}SEXP new_group_rle(SEXP g, SEXP l, R_len_t n) {
SEXP out = PROTECT(Rf_allocVector(VECSXP, 2));
SET_VECTOR_ELT(out, 0, g);
SET_VECTOR_ELT(out, 1, l);
SEXP names = PROTECT(Rf_allocVector(STRSXP, 2));
SET_STRING_ELT(names, 0, strings_group);
SET_STRING_ELT(names, 1, strings_length);
Rf_setAttrib(out, R_NamesSymbol, names);
SEXP n_groups = PROTECT(Rf_ScalarInteger(n));
Rf_setAttrib(out, syms_n, n_groups);
Rf_setAttrib(out, R_ClassSymbol, classes_vctrs_group_rle);
UNPROTECT(3);
return out;
}struct growable new_growable(SEXPTYPE type, int capacity) {
struct growable g;
g.x = Rf_allocVector(type, capacity);
g.type = type;
g.array = r_vec_unwrap(type, g.x);
g.n = 0;
g.capacity = capacity;
return g;
}struct vctrs_arg new_lazy_arg(struct r_lazy* arg) {
return (struct vctrs_arg) {
.parent = NULL,
.fill = &lazy_arg_fill,
.data = arg
};
}struct lazy_raw* new_lazy_raw(r_ssize size, size_t n_bytes) {
SEXP self = PROTECT(r_new_raw(sizeof(struct lazy_raw)));
struct lazy_raw* p_out = (struct lazy_raw*) RAW(self);
p_out->self = self;
p_out->data = R_NilValue;
p_out->size = size * n_bytes;
UNPROTECT(1);
return p_out;
}struct location_opts new_location_opts_assign(void) {
return (struct location_opts) {
.subscript_opts = new_subscript_opts_assign()
};
}struct order* new_order(r_ssize size) {
SEXP self = PROTECT(r_new_raw(sizeof(struct order)));
struct order* p_order = (struct order*) RAW(self);
SEXP data = PROTECT(Rf_allocVector(INTSXP, size));
int* p_data = INTEGER(data);
p_order->self = self;
p_order->data = data;
p_order->p_data = p_data;
p_order->size = size;
p_order->initialized = false;
UNPROTECT(2);
return p_order;
}struct poly_vec* new_poly_vec(r_obj* proxy, enum vctrs_type type) {
r_obj* shelter = KEEP(r_alloc_list(2));
r_obj* self = r_alloc_raw(sizeof(struct poly_vec));
r_list_poke(shelter, 0, self);
r_list_poke(shelter, 1, proxy);
struct poly_vec* p_poly_vec = r_raw_begin(self);
p_poly_vec->shelter = shelter;
p_poly_vec->vec = proxy;
p_poly_vec->type = type;
switch (type) {
case VCTRS_TYPE_null: init_nil_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_logical: init_lgl_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_integer: init_int_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_double: init_dbl_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_complex: init_cpl_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_character: init_chr_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_raw: init_raw_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_list: init_list_poly_vec(p_poly_vec); break;
case VCTRS_TYPE_dataframe: init_df_poly_vec(p_poly_vec); break;
default: stop_unimplemented_vctrs_type("new_poly_vec", type);
}
FREE(1);
return p_poly_vec;
}struct repair_error_info new_repair_error_info(struct name_repair_opts* p_opts) {
struct repair_error_info out;
out.shelter = r_new_list(4);
KEEP(out.shelter);
out.repair_arg = r_lazy_eval(p_opts->name_repair_arg);
r_list_poke(out.shelter, 0, out.repair_arg);
out.call = r_lazy_eval(p_opts->call);
r_list_poke(out.shelter, 1, out.call);
// If this is NULL, the `repair` value has been hard-coded by the
// frontend. Input errors are internal, and we provide no
// recommendation to fix user errors by providing a different value
// for `repair`.
if (out.repair_arg == r_null) {
out.input_error_repair_arg = chrs.repair;
r_list_poke(out.shelter, 2, out.input_error_repair_arg);
out.input_error_call = r_call(r_sym("vec_as_names"));
r_list_poke(out.shelter, 3, out.input_error_call);
} else {
out.input_error_repair_arg = r_lazy_eval(p_opts->name_repair_arg);
r_list_poke(out.shelter, 2, out.input_error_repair_arg);
out.input_error_call = r_lazy_eval(p_opts->call);
r_list_poke(out.shelter, 3, out.input_error_call);
}
FREE(1);
return out;
}struct vctrs_arg* new_subscript_arg_vec(struct vctrs_arg* parent,
r_obj* x,
r_ssize* p_i) {
r_obj* names = KEEP(vec_names(x));
struct vctrs_arg* p_arg = new_subscript_arg(parent,
names,
vec_size(x),
p_i);
FREE(1);
return p_arg;
}struct vctrs_arg new_wrapper_arg(struct vctrs_arg* parent,
const char* arg) {
return (struct vctrs_arg) {
.parent = parent,
.fill = &wrapper_arg_fill,
.data = (void*) arg
};
}uint32_t nil_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return nil_dict_hash_with(d, d, i);
}uint32_t nil_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_nil_equal_na_equal);
}bool nil_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_nil_is_incomplete(d->p_poly_vec->p_vec, i);
}r_obj* obj_attrib_encode_utf8(r_obj* x, bool owned) {
// `out` pointer may be updated in place by callback
r_obj* out = x;
r_keep_loc shelter;
KEEP_HERE(out, &shelter);
struct cb_data data = {
.p_out = &out,
.shelter = shelter,
.p_owned = &owned
};
r_attrib_map(x, obj_attrib_encode_utf8_cb, &data);
FREE(1);
return out;
}r_obj* obj_cast_subscript(r_obj* subscript,
const struct subscript_opts* opts,
ERR* err) {
struct vctrs_arg* p_subscript_arg = opts->subscript_arg;
struct r_lazy call = opts->call;
const enum s3_fallback s3_fallback = S3_FALLBACK_false;
struct cast_opts cast_opts = {
.x = subscript,
.to = r_null,
.p_x_arg = p_subscript_arg
};
cast_opts.to = r_globals.empty_lgl;
if (vec_is_coercible(
subscript,
cast_opts.to,
p_subscript_arg,
vec_args.empty,
call,
s3_fallback
)) {
return vec_cast_opts(&cast_opts);
}
cast_opts.to = r_globals.empty_int;
if (vec_is_coercible(
subscript,
cast_opts.to,
p_subscript_arg,
vec_args.empty,
call,
s3_fallback
)) {
return vec_cast_opts(&cast_opts);
}
cast_opts.to = r_globals.empty_chr;
if (vec_is_coercible(
subscript,
cast_opts.to,
p_subscript_arg,
vec_args.empty,
call,
s3_fallback
)) {
return vec_cast_opts(&cast_opts);
}
*err = new_error_subscript_type(subscript, opts, r_null);
return r_null;
}void obj_check_list(
r_obj* x,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
if (!obj_is_list(x)) {
stop_non_list_type(x, p_x_arg, call);
}
}void obj_check_vector(
r_obj* x,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
if (!obj_is_vector(x, allow_null)) {
stop_scalar_type(x, p_x_arg, call);
}
}r_obj* obj_encode_utf8(r_obj* x) {
r_obj* out;
switch (r_typeof(x)) {
case R_TYPE_character: out = chr_encode_utf8(x); break;
case R_TYPE_list: out = list_encode_utf8(x); break;
default: out = x; break;
}
if (r_attrib_has_any(out)) {
// Only `KEEP()` if there are attributes
KEEP(out);
// Pass down ownership to avoid a reclone if attributes change
bool owned = x != out;
out = obj_attrib_encode_utf8(out, owned);
FREE(1);
}
return out;
}bool obj_equal(r_obj* x, r_obj* y) {
x = KEEP(obj_encode_utf8(x));
y = KEEP(obj_encode_utf8(y));
const bool out = obj_equal_utf8(x, y);
FREE(2);
return out;
}uint32_t obj_hash(r_obj* x) {
uint32_t hash = sexp_hash(x);
if (r_attrib_has_any(x)) {
hash = hash_combine(hash, attrib_hash(x));
}
return hash;
}bool obj_is_list(r_obj* x) {
// Require `x` to be a list internally
if (r_typeof(x) != R_TYPE_list) {
return false;
}
// List arrays are not lists for vctrs purposes. We have pretty deep
// assumptions that if an object is a list, then `r_length(x) == vec_size(x)`.
// See `list_drop_empty()` and `list_combine()` for examples of
// implementations that would be broken if this wasn't true.
if (has_dim(x)) {
return false;
}
// Unclassed R_TYPE_list are lists
if (!r_is_object(x)) {
return true;
}
const enum vctrs_class_type type = class_type(x);
// Classed R_TYPE_list are only lists if the last class is explicitly `"list"`
// or if it is a bare "AsIs" type
return (type == VCTRS_CLASS_list) || (type == VCTRS_CLASS_bare_asis);
}bool obj_is_vector(r_obj* x, enum vctrs_allow_null allow_null) {
if (x == r_null) {
return allow_null_as_bool(allow_null);
}
struct vctrs_proxy_info info = vec_proxy_info(x);
return info.type != VCTRS_TYPE_scalar;
}static inline bool obj_vec_equal(r_obj* x, r_obj* y, enum r_type type) {
const r_ssize n = r_length(x);
// Length check
if (n != r_length(y)) {
return false;
}
// Attribute check
if (!obj_attrib_equal(x, y)) {
return false;
}
// Data check
switch (type) {
case R_TYPE_logical: OBJ_VEC_EQUAL(int, r_lgl_cbegin, lgl_equal_na_equal);
case R_TYPE_integer: OBJ_VEC_EQUAL(int, r_int_cbegin, int_equal_na_equal);
case R_TYPE_double: OBJ_VEC_EQUAL(double, r_dbl_cbegin, dbl_equal_na_equal);
case R_TYPE_character: OBJ_VEC_EQUAL(r_obj*, r_chr_cbegin, chr_equal_na_equal);
case R_TYPE_raw: OBJ_VEC_EQUAL(Rbyte, r_raw_cbegin, raw_equal_na_equal);
case R_TYPE_complex: OBJ_VEC_EQUAL(r_complex, r_cpl_cbegin, cpl_equal_na_equal);
case R_TYPE_list: OBJ_VEC_EQUAL(r_obj*, r_list_cbegin, list_equal_na_equal);
default: r_stop_unreachable();
}
}SEXP ord_as_character(SEXP x, struct vctrs_arg* x_arg) {
return fct_as_character(x, x_arg);
}r_obj* ord_ptype2(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
r_obj* x_levels = PROTECT(Rf_getAttrib(x, R_LevelsSymbol));
r_obj* y_levels = PROTECT(Rf_getAttrib(y, R_LevelsSymbol));
SEXP out;
if (ord_ptype2_validate(x_levels, y_levels, x, y, p_x_arg, p_y_arg)) {
out = new_empty_ordered(x_levels);
} else {
out = vec_ptype2_default(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
}
UNPROTECT(2);
return out;
}bool ord_ptype2_validate(
r_obj* x_levels,
r_obj* y_levels,
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg
) {
if (TYPEOF(x_levels) != STRSXP) {
stop_corrupt_ordered_levels(x, p_x_arg);
}
if (TYPEOF(y_levels) != STRSXP) {
stop_corrupt_ordered_levels(y, p_y_arg);
}
return obj_equal(x_levels, y_levels);
}void ord_resolve_sortedness(enum vctrs_sortedness sortedness,
r_ssize size,
int* p_o) {
switch (sortedness) {
case VCTRS_SORTEDNESS_sorted: int_incr(size, p_o); return;
case VCTRS_SORTEDNESS_reversed: ord_reverse(size, p_o); return;
case VCTRS_SORTEDNESS_unsorted: Rf_errorcall(R_NilValue, "Internal error: Unsorted case should be handled elsewhere.");
}
never_reached("ord_resolve_sortedness");
}void ord_resolve_sortedness_chunk(enum vctrs_sortedness sortedness,
r_ssize size,
int* p_o) {
switch (sortedness) {
case VCTRS_SORTEDNESS_sorted: return;
case VCTRS_SORTEDNESS_reversed: ord_reverse_chunk(size, p_o); return;
case VCTRS_SORTEDNESS_unsorted: Rf_errorcall(R_NilValue, "Internal error: Unsorted case should be handled elsewhere.");
}
never_reached("ord_resolve_sortedness_chunk");
}void ord_reverse(r_ssize size, int* p_o) {
const r_ssize half = size / 2;
for (r_ssize i = 0; i < half; ++i) {
r_ssize swap = size - 1 - i;
p_o[i] = swap + 1;
p_o[swap] = i + 1;
}
// Initialize center value if odd number
if (size % 2 != 0) {
p_o[half] = half + 1;
}
}void ord_reverse_chunk(r_ssize size, int* p_o) {
const r_ssize half = size / 2;
for (r_ssize i = 0; i < half; ++i) {
r_ssize swap = size - 1 - i;
const int temp = p_o[i];
p_o[i] = p_o[swap];
p_o[swap] = temp;
}
}r_obj* outer_names(r_obj* names, r_obj* outer, r_ssize n) {
if (outer == r_null) {
return names;
}
if (r_typeof(outer) != R_TYPE_string) {
r_stop_internal("`outer` must be a scalar string.");
}
if (outer == strings_empty || outer == r_globals.na_str) {
return names;
}
if (r_is_empty_names(names)) {
if (n == 1) {
return r_str_as_character(outer);
} else {
return r_seq_chr(r_str_c_string(outer), n);
}
} else {
return r_chr_paste_prefix(names, r_str_c_string(outer), "..");
}
}bool p_bool_any(const bool* v_x, r_ssize size) {
for (r_ssize i = 0; i < size; ++i) {
if (v_x[i]) {
return true;
}
}
return false;
}void p_bool_fill(bool* v_x, r_ssize size, bool value) {
for (r_ssize i = 0; i < size; ++i) {
v_x[i] = value;
}
}r_ssize p_bool_sum(const bool* v_x, r_ssize size) {
r_ssize out = 0;
for (r_ssize i = 0; i < size; ++i) {
out += v_x[i];
}
return out;
}r_obj* p_bool_which(const bool* v_x, r_ssize size) {
const r_ssize out_size = p_bool_sum(v_x, size);
r_obj* out = KEEP(r_alloc_integer(out_size));
int* v_out = r_int_begin(out);
for (r_ssize i = 0, j = 0; i < size && j < out_size; ++i) {
v_out[j] = i + 1;
j += v_x[i];
}
FREE(1);
return out;
}int p_chr_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(r_obj*, chr_compare_na_equal);
}bool p_chr_is_incomplete(const void* p_x, r_ssize i) {
return p_chr_is_missing(p_x, i);
}bool p_chr_is_missing(const void* p_x, r_ssize i) {
P_IS_MISSING(r_obj*, chr_is_missing);
}int p_col_compare_na_equal(
const void* p_x,
r_ssize i,
const void* p_y,
r_ssize j,
const enum vctrs_type type
) {
switch (type) {
case VCTRS_TYPE_null: return p_nil_compare_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_logical: return p_lgl_compare_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_integer: return p_int_compare_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_double: return p_dbl_compare_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_complex: return p_cpl_compare_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_character: return p_chr_compare_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_raw: return p_raw_compare_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_list: return p_list_compare_na_equal(p_x, i, p_y, j);
default: stop_unimplemented_vctrs_type("p_col_compare_na_equal", type);
}
}bool p_col_equal_na_equal(
const void* p_x,
r_ssize i,
const void* p_y,
r_ssize j,
const enum vctrs_type type
) {
switch (type) {
case VCTRS_TYPE_logical: return p_lgl_equal_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_integer: return p_int_equal_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_double: return p_dbl_equal_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_complex: return p_cpl_equal_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_character: return p_chr_equal_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_raw: return p_raw_equal_na_equal(p_x, i, p_y, j);
case VCTRS_TYPE_list: return p_list_equal_na_equal(p_x, i, p_y, j);
default: stop_unimplemented_vctrs_type("p_col_equal_na_equal", type);
}
}bool p_col_is_missing(
const void* p_x,
r_ssize i,
const enum vctrs_type type
) {
switch (type) {
case VCTRS_TYPE_logical: return p_lgl_is_missing(p_x, i);
case VCTRS_TYPE_integer: return p_int_is_missing(p_x, i);
case VCTRS_TYPE_double: return p_dbl_is_missing(p_x, i);
case VCTRS_TYPE_complex: return p_cpl_is_missing(p_x, i);
case VCTRS_TYPE_character: return p_chr_is_missing(p_x, i);
case VCTRS_TYPE_raw: return p_raw_is_missing(p_x, i);
case VCTRS_TYPE_list: return p_list_is_missing(p_x, i);
default: stop_unimplemented_vctrs_type("p_col_is_missing", type);
}
}bool p_cpl_is_incomplete(const void* p_x, r_ssize i) {
return p_cpl_is_missing(p_x, i);
}bool p_dbl_is_incomplete(const void* p_x, r_ssize i) {
return p_dbl_is_missing(p_x, i);
}bool p_df_is_incomplete(const void* p_x, r_ssize i) {
struct poly_df_data* p_x_data = (struct poly_df_data*) p_x;
enum vctrs_type* v_col_type = p_x_data->v_col_type;
const void** v_col_ptr = p_x_data->v_col_ptr;
r_ssize n_col = p_x_data->n_col;
// df-cols should already be flattened,
// so we only need missingness of each column, not completeness
for (r_ssize col = 0; col < n_col; ++col) {
if (p_col_is_missing(v_col_ptr[col], i, v_col_type[col])) {
return true;
}
}
return false;
}bool p_int_is_incomplete(const void* p_x, r_ssize i) {
return p_int_is_missing(p_x, i);
}bool p_lgl_is_incomplete(const void* p_x, r_ssize i) {
return p_lgl_is_missing(p_x, i);
}int p_list_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(r_obj*, list_compare_na_equal);
}bool p_list_is_incomplete(const void* p_x, r_ssize i) {
return p_list_is_missing(p_x, i);
}bool p_list_is_missing(const void* p_x, r_ssize i) {
P_IS_MISSING(r_obj*, list_is_missing);
}bool p_nesting_container_df_compare_fully_ge_na_equal(const void* x,
r_ssize i,
const void* y,
r_ssize j) {
// Checks if EVERY column of `x` is `>=` `y`.
// Assumes original input that `x` and `y` came from is ordered, and that
// `x` comes after `y` in terms of row location in that original input. This
// means that the first column of `x` is always `>=` the first column of `y`,
// so we can ignore it in the comparison.
// Iterates backwards to (ideally) maximize chance of hitting the fastest
// varying column.
// All columns are integer vectors (ranks).
const struct poly_df_data* x_data = (const struct poly_df_data*) x;
const struct poly_df_data* y_data = (const struct poly_df_data*) y;
const r_ssize n_col = x_data->n_col;
const void** v_x_col_ptr = x_data->v_col_ptr;
const void** v_y_col_ptr = y_data->v_col_ptr;
for (r_ssize col = n_col - 1; col > 0; --col) {
if (p_int_compare_na_equal(v_x_col_ptr[col], i, v_y_col_ptr[col], j) < 0) {
return false;
}
}
return true;
}int p_nil_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(r_obj*, nil_compare_na_equal);
}bool p_nil_is_incomplete(const void* p_x, r_ssize i) {
p_nil_is_missing(p_x, i);
}bool p_raw_is_incomplete(const void* p_x, r_ssize i) {
return p_raw_is_missing(p_x, i);
}bool p_raw_is_missing(const void* p_x, r_ssize i) {
P_IS_MISSING(unsigned char, raw_is_missing);
}void parse_condition(r_obj* condition, r_ssize n_cols, enum vctrs_ops* v_ops) {
if (r_typeof(condition) != R_TYPE_character) {
r_abort("`condition` must be a character vector.");
}
r_obj* const* v_condition = r_chr_cbegin(condition);
r_ssize size_condition = vec_size(condition);
if (size_condition == 1) {
const char* elt = r_str_c_string(v_condition[0]);
enum vctrs_ops op = parse_condition_one(elt);
for (r_ssize i = 0; i < n_cols; ++i) {
v_ops[i] = op;
}
return;
}
if (size_condition == n_cols) {
for (r_ssize i = 0; i < n_cols; ++i) {
const char* elt = r_str_c_string(v_condition[i]);
v_ops[i] = parse_condition_one(elt);
}
return;
}
r_abort(
"`condition` must be length 1, or the same "
"length as the number of columns of the input."
);
}enum vctrs_ops parse_condition_one(const char* condition) {
if (!strcmp(condition, "==")) { return VCTRS_OPS_eq; }
if (!strcmp(condition, ">")) { return VCTRS_OPS_gt; }
if (!strcmp(condition, ">=")) { return VCTRS_OPS_gte; }
if (!strcmp(condition, "<")) { return VCTRS_OPS_lt; }
if (!strcmp(condition, "<=")) { return VCTRS_OPS_lte; }
r_abort("`condition` must only contain \"==\", \">\", \">=\", \"<\", or \"<=\".");
}void parse_direction(SEXP x, bool* p_down, bool* p_leading) {
if (TYPEOF(x) != STRSXP || Rf_length(x) == 0) {
stop_bad_direction();
}
const char* str = CHAR(STRING_ELT(x, 0));
if (!strcmp(str, "down")) {
*p_down = true;
*p_leading = false;
return;
}
if (!strcmp(str, "up")) {
*p_down = false;
*p_leading = false;
return;
}
if (!strcmp(str, "downup")) {
*p_down = true;
*p_leading = true;
return;
}
if (!strcmp(str, "updown")) {
*p_down = false;
*p_leading = true;
return;
}
stop_bad_direction();
never_reached("parse_direction");
}int parse_direction_one(SEXP x) {
if (x == NA_STRING) {
Rf_errorcall(R_NilValue, "`direction` can't be missing.");
}
const char* c_x = CHAR(x);
if (!strcmp(c_x, "asc")) return 0;
if (!strcmp(c_x, "desc")) return 1;
Rf_errorcall(
R_NilValue,
"`direction` must contain only \"asc\" or \"desc\"."
);
}int parse_max_fill(r_obj* x) {
if (x == R_NilValue) {
return INFINITE_FILL;
}
x = KEEP(vec_cast(x,
r_globals.empty_int,
vec_args.max_fill,
vec_args.empty,
r_lazy_null));
if (!r_is_positive_number(x)) {
r_abort("`max_fill` must be `NULL` or a single positive integer.");
}
int out = r_int_get(x, 0);
FREE(1);
return out;
}enum vctrs_interval_missing parse_missing(r_obj* missing) {
if (!r_is_string(missing)) {
r_abort("`missing` must be a string.");
}
const char* c_missing = r_chr_get_c_string(missing, 0);
if (!strcmp(c_missing, "group")) return VCTRS_INTERVAL_MISSING_group;
if (!strcmp(c_missing, "drop")) return VCTRS_INTERVAL_MISSING_drop;
r_abort("`missing` must be either \"group\" or \"drop\".");
}SEXP parse_na_value(SEXP na_value) {
// Don't care about length here, checked later
if (TYPEOF(na_value) != STRSXP) {
Rf_errorcall(R_NilValue, "`na_value` must be a character vector.");
}
R_len_t size = Rf_length(na_value);
const SEXP* p_na_value = STRING_PTR_RO(na_value);
SEXP na_largest = PROTECT(Rf_allocVector(LGLSXP, size));
int* p_na_largest = LOGICAL(na_largest);
for (R_len_t i = 0; i < size; ++i) {
p_na_largest[i] = parse_na_value_one(p_na_value[i]);
}
UNPROTECT(1);
return na_largest;
}int parse_na_value_one(SEXP x) {
if (x == NA_STRING) {
Rf_errorcall(R_NilValue, "`na_value` can't be missing.");
}
const char* c_x = CHAR(x);
if (!strcmp(c_x, "largest")) return 1;
if (!strcmp(c_x, "smallest")) return 0;
Rf_errorcall(
R_NilValue,
"`na_value` must contain only \"largest\" or \"smallest\"."
);
}bool parse_nan_distinct(SEXP nan_distinct) {
if (TYPEOF(nan_distinct) != LGLSXP) {
Rf_errorcall(R_NilValue, "`nan_distinct` must be a logical vector.");
}
if (Rf_length(nan_distinct) != 1) {
Rf_errorcall(R_NilValue, "`nan_distinct` must be length 1.");
}
int c_nan_distinct = LOGICAL_RO(nan_distinct)[0];
if (c_nan_distinct == NA_LOGICAL) {
Rf_errorcall(R_NilValue, "`nan_distinct` can't be missing.");
}
return (bool) c_nan_distinct;
}bool plus_would_overflow(r_ssize x, r_ssize y) {
return x > R_LEN_T_MAX - y;
}poly_binary_int_fn* poly_p_compare_na_equal(enum vctrs_type type) {
switch (type) {
case VCTRS_TYPE_null: return p_nil_compare_na_equal;
case VCTRS_TYPE_logical: return p_lgl_compare_na_equal;
case VCTRS_TYPE_integer: return p_int_compare_na_equal;
case VCTRS_TYPE_double: return p_dbl_compare_na_equal;
case VCTRS_TYPE_complex: return p_cpl_compare_na_equal;
case VCTRS_TYPE_character: return p_chr_compare_na_equal;
case VCTRS_TYPE_raw: return p_raw_compare_na_equal;
case VCTRS_TYPE_list: return p_list_compare_na_equal;
case VCTRS_TYPE_dataframe: return p_df_compare_na_equal;
default: stop_unimplemented_vctrs_type("poly_p_compare_na_equal", type);
}
}poly_unary_bool_fn* poly_p_is_missing(enum vctrs_type type) {
switch (type) {
case VCTRS_TYPE_null: return p_nil_is_missing;
case VCTRS_TYPE_logical: return p_lgl_is_missing;
case VCTRS_TYPE_integer: return p_int_is_missing;
case VCTRS_TYPE_double: return p_dbl_is_missing;
case VCTRS_TYPE_complex: return p_cpl_is_missing;
case VCTRS_TYPE_character: return p_chr_is_missing;
case VCTRS_TYPE_raw: return p_raw_is_missing;
case VCTRS_TYPE_list: return p_list_is_missing;
case VCTRS_TYPE_dataframe: return p_df_is_missing;
default: stop_unimplemented_vctrs_type("poly_p_is_missing", type);
}
}SEXP posixct_as_date(SEXP x, bool* lossy) {
SEXP ct = PROTECT(datetime_validate(x));
SEXP tzone = PROTECT(tzone_get(ct));
SEXP lt = PROTECT(posixct_as_posixlt_impl(ct, tzone));
SEXP out = posixt_as_date(ct, lt, lossy);
UNPROTECT(3);
return out;
}SEXP posixct_as_posixct(SEXP x, SEXP to) {
SEXP tzone = PROTECT(tzone_get(to));
SEXP out = posixct_as_posixct_impl(x, tzone);
UNPROTECT(1);
return out;
}static SEXP posixct_as_posixct_impl(SEXP x, SEXP tzone) {
x = PROTECT(datetime_validate(x));
SEXP out = datetime_rezone(x, tzone);
UNPROTECT(1);
return out;
}SEXP posixct_as_posixlt(SEXP x, SEXP to) {
SEXP tzone = PROTECT(tzone_get(to));
SEXP out = posixct_as_posixlt_impl(x, tzone);
UNPROTECT(1);
return out;
}static SEXP posixct_as_posixlt_impl(SEXP x, SEXP tzone) {
return r_as_posixlt(x, tzone);
}SEXP posixlt_as_date(SEXP x, bool* lossy) {
SEXP lt = x;
SEXP tzone = PROTECT(tzone_get(lt));
SEXP ct = PROTECT(posixlt_as_posixct_impl(lt, tzone));
SEXP out = posixt_as_date(ct, lt, lossy);
UNPROTECT(2);
return out;
}SEXP posixlt_as_posixct(SEXP x, SEXP to) {
SEXP tzone = PROTECT(tzone_get(to));
SEXP out = posixlt_as_posixct_impl(x, tzone);
UNPROTECT(1);
return out;
}static SEXP posixlt_as_posixct_impl(SEXP x, SEXP tzone) {
SEXP x_tzone = PROTECT(tzone_get(x));
x = PROTECT(r_as_posixct(x, x_tzone));
SEXP out = posixct_as_posixct_impl(x, tzone);
UNPROTECT(2);
return out;
}SEXP proxy_apply_chr_proxy_collate(SEXP proxy, SEXP chr_proxy_collate) {
if (chr_proxy_collate == r_null) {
return proxy;
}
chr_proxy_collate = PROTECT(r_as_function(chr_proxy_collate, "chr_proxy_collate"));
SEXP out;
switch (vec_proxy_typeof(proxy)) {
case VCTRS_TYPE_character: out = chr_apply(proxy, chr_proxy_collate); break;
case VCTRS_TYPE_dataframe: out = df_apply(proxy, chr_proxy_collate); break;
default: out = proxy;
}
UNPROTECT(1);
return out;
}r_obj* proxy_detect_missing(r_obj* proxy) {
const enum vctrs_type type = vec_proxy_typeof(proxy);
switch (type) {
case VCTRS_TYPE_logical: return lgl_detect_missing(proxy);
case VCTRS_TYPE_integer: return int_detect_missing(proxy);
case VCTRS_TYPE_double: return dbl_detect_missing(proxy);
case VCTRS_TYPE_complex: return cpl_detect_missing(proxy);
case VCTRS_TYPE_raw: return raw_detect_missing(proxy);
case VCTRS_TYPE_character: return chr_detect_missing(proxy);
case VCTRS_TYPE_list: return list_detect_missing(proxy);
case VCTRS_TYPE_dataframe: return df_detect_missing(proxy);
case VCTRS_TYPE_null: return r_globals.empty_lgl;
case VCTRS_TYPE_scalar: stop_scalar_type(proxy, vec_args.empty, r_lazy_null);
default: stop_unimplemented_vctrs_type("vec_detect_missing", type);
}
r_stop_unreachable();
}r_ssize proxy_first_missing(r_obj* proxy) {
const enum vctrs_type type = vec_proxy_typeof(proxy);
switch (type) {
case VCTRS_TYPE_logical: return lgl_first_missing(proxy);
case VCTRS_TYPE_integer: return int_first_missing(proxy);
case VCTRS_TYPE_double: return dbl_first_missing(proxy);
case VCTRS_TYPE_complex: return cpl_first_missing(proxy);
case VCTRS_TYPE_raw: return raw_first_missing(proxy);
case VCTRS_TYPE_character: return chr_first_missing(proxy);
case VCTRS_TYPE_list: return list_first_missing(proxy);
case VCTRS_TYPE_dataframe: return df_first_missing(proxy);
case VCTRS_TYPE_null: return 0;
case VCTRS_TYPE_scalar: stop_scalar_type(proxy, vec_args.empty, r_lazy_null);
default: stop_unimplemented_vctrs_type("vec_first_missing", type);
}
r_stop_unreachable();
}r_obj* ptype_common_with_default(
r_obj* ptype,
r_obj* xs,
bool has_default,
r_obj* default_,
struct vctrs_arg* p_xs_arg,
struct vctrs_arg* p_default_arg,
struct r_lazy error_call,
enum s3_fallback s3_fallback
) {
if (ptype != r_null) {
// Performs scalar checks and whatnot
return vec_ptype_final(ptype, vec_args.ptype, error_call);
}
// Okay `ptype` is `NULL`. We determine it from `xs` and `default`.
// Use only `xs` and `p_xs_arg` first for best errors.
// Not finalising `ptype` yet in case we need to incorporate `default`!
ptype = KEEP(vec_ptype_common(
xs,
ptype,
PTYPE_FINALISE_false,
s3_fallback,
p_xs_arg,
error_call
));
// Now incorporate `default` and `p_default_arg` if required
if (has_default) {
int _;
ptype = vec_ptype2(
ptype,
default_,
vec_args.empty,
p_default_arg,
error_call,
s3_fallback,
&_
);
}
KEEP(ptype);
// Now finalise after incorporating `default`
ptype = KEEP(vec_ptype_finalise(ptype));
FREE(3);
return ptype;
}int qsort_int_compare_scalar(const void* x, const void* y) {
return int_compare_scalar(*((int*) x), *((int*) y));
}r_ssize r__dyn_increment(struct r_dyn_array* p_arr) {
r_ssize loc = p_arr->count++;
if (p_arr->count > p_arr->capacity) {
r_ssize new_capacity = r_ssize_mult(p_arr->capacity, p_arr->growth_factor);
r_dyn_resize(p_arr, new_capacity);
}
return loc;
}r_obj* r_alloc_character(r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(R_TYPE_character, n);
#else
return Rf_allocVector(R_TYPE_character, n);
#endif
}r_obj* r_alloc_complex(r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(R_TYPE_complex, n);
#else
return Rf_allocVector(R_TYPE_complex, n);
#endif
}r_obj* r_alloc_df_list(r_ssize n_rows,
r_obj* names,
const enum r_type* v_types,
r_ssize types_size) {
r_obj* out = KEEP(r_alloc_list(types_size));
if (r_typeof(names) != R_TYPE_character) {
r_abort("`names` must be a character vector.");
}
if (r_length(names) != types_size) {
r_abort("`names` must match the number of columns.");
}
r_attrib_poke_names(out, names);
for (r_ssize i = 0; i < types_size; ++i) {
// A nil type stands for no column allocation
enum r_type type = v_types[i];
if (type != R_TYPE_null) {
r_obj* col = r_alloc_vector(type, n_rows);
r_list_poke(out, i, col);
}
}
FREE(1);
return out;
}r_obj* r_alloc_double(r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(R_TYPE_double, n);
#else
return Rf_allocVector(R_TYPE_double, n);
#endif
}r_obj* r_alloc_empty_environment(r_obj* parent) {
// Non-hashed environment.
// Very fast and useful when you aren't getting/setting from the result.
#if R_VERSION >= R_Version(4, 1, 0)
const int hash = 0;
const int size = 0; // Not used when `hash = 0`
return R_NewEnv(parent, hash, size);
#else
r_obj* env = Rf_allocSExp(R_TYPE_environment);
SET_ENCLOS(env, parent);
return env;
#endif
}r_obj* r_alloc_environment(r_ssize size, r_obj* parent) {
#if R_VERSION < R_Version(4, 1, 0)
parent = parent ? parent : r_envs.empty;
r_node_poke_car(new_env__parent_node, parent);
size = size ? size : 29;
r_node_poke_car(new_env__size_node, r_int(size));
r_obj* env = r_eval(new_env_call, r_envs.base);
// Free for gc
r_node_poke_car(new_env__parent_node, r_null);
return env;
#else
const int hash = 1;
return R_NewEnv(parent, hash, size);
#endif
}r_obj* r_alloc_integer(r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(R_TYPE_integer, n);
#else
return Rf_allocVector(R_TYPE_integer, n);
#endif
}r_obj* r_alloc_list(r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(R_TYPE_list, n);
#else
return Rf_allocVector(R_TYPE_list, n);
#endif
}r_obj* r_alloc_logical(r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(R_TYPE_logical, n);
#else
return Rf_allocVector(R_TYPE_logical, n);
#endif
}r_obj* r_alloc_raw(r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(R_TYPE_raw, n);
#else
return Rf_allocVector(R_TYPE_raw, n);
#endif
}bool r_arg_as_bool(r_obj* x, const char* arg) {
if (!r_is_bool(x)) {
r_abort("`%s` must be `TRUE` or `FALSE`.", arg);
}
return r_lgl_get(x, 0);
}int r_arg_as_int(r_obj* x, const char* arg) {
if (!r_is_int(x)) {
r_abort("`%s` must be a single integer value.", arg);
}
return r_int_get(x, 0);
}SEXP r_as_data_frame(SEXP x) {
if (is_bare_data_frame(x)) {
return x;
} else {
return vctrs_dispatch1(syms_as_data_frame2, fns_as_data_frame2, syms_x, x);
}
}static SEXP r_as_date(SEXP x) {
return vctrs_dispatch1(syms_as_date, fns_as_date, syms_x, x);
}r_obj* r_as_function(r_obj* x, const char* arg) {
switch (r_typeof(x)) {
case R_TYPE_closure:
case R_TYPE_builtin:
case R_TYPE_special:
return x;
case R_TYPE_call:
if (r_node_car(x) == r_syms.tilde && r_node_cddr(x) == r_null) {
r_obj* env = r_attrib_get(x, r_syms.dot_environment);
if (env == r_null) {
r_abort("Can't transform formula to function because it doesn't have an environment.");
}
return r_new_function(rlang_formula_formals, r_node_cadr(x), env);
}
// else fallthrough;
default:
r_abort("Can't convert `%s` to a function", arg);
}
}int r_as_int(r_obj* x) {
return r_arg_as_int(x, "x");
}static SEXP r_as_posixct(SEXP x, SEXP tzone) {
return vctrs_dispatch2(syms_as_posixct, fns_as_posixct, syms_x, x, syms_tz, tzone);
}static SEXP r_as_posixlt(SEXP x, SEXP tzone) {
return vctrs_dispatch2(syms_as_posixlt, fns_as_posixlt, syms_x, x, syms_tz, tzone);
}void r_attrib_clone_from(r_obj* to, r_obj* from) {
SHALLOW_DUPLICATE_ATTRIB(to, from);
}static r_obj* r_attrib_get_cb(r_obj* tag, r_obj* val, void* data) {
if (tag == *(r_obj**) data) {
return val;
}
return NULL;
}bool r_attrib_has_any(r_obj* x) {
return ANY_ATTRIB(x);
}r_obj* r_attrib_map(r_obj* x, r_attrib_map_fn* fn, void* data) {
return R_mapAttrib(x, fn, data);
}void r_attrib_zap_all(r_obj* x) {
CLEAR_ATTRIB(x);
}int r_bool_as_int(SEXP x) {
if (!r_is_bool(x)) {
Rf_errorcall(R_NilValue, "Input must be a single `TRUE` or `FALSE`.");
}
return LOGICAL(x)[0];
}const char* r_c_str_format_error_arg(const char* x) {
r_obj* ffi_x = KEEP(r_chr(x));
const char* out = r_format_error_arg(ffi_x);
FREE(1);
return out;
}r_obj* r_chr(const char* c_string) {
r_obj* out = KEEP(r_alloc_character(1));
r_chr_poke(out, 0, r_str(c_string));
FREE(1);
return out;
}r_obj* const * r_chr_cbegin(r_obj* x) {
return STRING_PTR_RO(x);
}static SEXP r_chr_date_as_posixct(SEXP x, SEXP tzone) {
return vctrs_dispatch2(syms_chr_date_as_posixct, fns_chr_date_as_posixct, syms_x, x, syms_tzone, tzone);
}static SEXP r_chr_date_as_posixlt(SEXP x, SEXP tzone) {
return vctrs_dispatch2(syms_chr_date_as_posixlt, fns_chr_date_as_posixlt, syms_x, x, syms_tzone, tzone);
}void r_chr_fill(r_obj* chr, r_obj* value, r_ssize n) {
for (r_ssize i = 0; i < n; ++i) {
r_chr_poke(chr, i, value);
}
}r_obj* r_chr_get(r_obj* x, r_ssize i) {
return STRING_ELT(x, i);
}const char* r_chr_get_c_string(r_obj* x, r_ssize i) {
return CHAR(r_chr_get(x, i));
}bool r_chr_has_string(SEXP x, SEXP str) {
R_len_t n = Rf_length(x);
const SEXP* xp = STRING_PTR_RO(x);
for (R_len_t i = 0; i < n; ++i, ++xp) {
if (*xp == str) {
return true;
}
}
return false;
}int r_chr_max_len(SEXP x) {
R_len_t n = Rf_length(x);
SEXP const* p = STRING_PTR_RO(x);
int max = 0;
for (R_len_t i = 0; i < n; ++i, ++p) {
int len = strlen(CHAR(*p));
max = len > max ? len : max;
}
return max;
}r_obj* r_chr_n(const char* const * strings, r_ssize n) {
r_obj* out = KEEP(r_alloc_character(n));
for (r_ssize i = 0; i < n; ++i) {
r_chr_poke(out, i, r_str(strings[i]));
}
FREE(1);
return out;
}void r_chr_poke(r_obj* x, r_ssize i, r_obj* y) {
SET_STRING_ELT(x, i, y);
}r_obj* r_class(r_obj* x) {
return r_attrib_get(x, r_syms.class_);
}r_obj* r_clone(r_obj* x) {
return Rf_shallow_duplicate(x);
}SEXP r_clone_referenced(SEXP x) {
if (MAYBE_REFERENCED(x)) {
return Rf_shallow_duplicate(x);
} else {
return x;
}
}void r_cnd_signal(r_obj* cnd) {
r_eval_with_x(cnd_signal_call, cnd, r_envs.base);
}r_obj* r_copy(r_obj* x) {
return Rf_duplicate(x);
}r_complex* r_cpl_begin(r_obj* x) {
return COMPLEX(x);
}const r_complex* r_cpl_cbegin(r_obj* x) {
return (const r_complex*) COMPLEX(x);
}static SEXP r_date_as_character(SEXP x) {
return vctrs_dispatch1(syms_date_as_character, fns_date_as_character, syms_x, x);
}r_obj* r_dbl(double x) {
return Rf_ScalarReal(x);
}double* r_dbl_begin(r_obj* x) {
return REAL(x);
}const double* r_dbl_cbegin(r_obj* x) {
return (const double*) REAL(x);
}double r_dbl_get(r_obj* x, r_ssize i) {
return REAL(x)[i];
}r_obj* r_dim(r_obj* x) {
return r_attrib_get(x, r_syms.dim);
}r_obj* r_dim_names(r_obj* x) {
return r_attrib_get(x, r_syms.dim_names);
}int r_dyn_int_get(struct r_dyn_array* p_vec, r_ssize i) {
return ((const int*) p_vec->v_data_const)[i];
}void r_dyn_int_poke(struct r_dyn_array* p_vec, r_ssize i, int value) {
((int*) p_vec->v_data)[i] = value;
}void r_dyn_int_push_back(struct r_dyn_array* p_vec, int elt) {
r_ssize loc = r__dyn_increment(p_vec);
r_dyn_int_poke(p_vec, loc, elt);
}void* r_dyn_last(struct r_dyn_array* p_arr) {
return r_dyn_pointer(p_arr, p_arr->count - 1);
}void r_dyn_list_poke(struct r_dyn_array* p_vec, r_ssize i, r_obj* value) {
r_list_poke(p_vec->data, i, value);
}void r_dyn_list_push_back(struct r_dyn_array* p_vec, r_obj* elt) {
KEEP(elt);
r_ssize loc = r__dyn_increment(p_vec);
r_dyn_list_poke(p_vec, loc, elt);
FREE(1);
}void* r_dyn_pointer(struct r_dyn_array* p_arr, r_ssize i) {
if (p_arr->barrier_set) {
r_abort("Can't take mutable pointer of barrier vector.");
}
r_ssize offset = i * p_arr->elt_byte_size;
return ((unsigned char*) p_arr->v_data) + offset;
}void r_dyn_push_back(struct r_dyn_array* p_arr,
const void* p_elt) {
r_ssize loc = r__dyn_increment(p_arr);
if (p_arr->barrier_set) {
r_obj* value = *((r_obj* const *) p_elt);
p_arr->barrier_set(p_arr->data, loc, value);
} else if (p_elt) {
r_memcpy(r_dyn_last(p_arr), p_elt, p_arr->elt_byte_size);
} else {
r_memset(r_dyn_last(p_arr), 0, p_arr->elt_byte_size);
}
}r_obj* r_dyn_unwrap(struct r_dyn_array* p_arr) {
if (p_arr->type == R_TYPE_raw) {
return r_raw_resize(p_arr->data, p_arr->count * p_arr->elt_byte_size);
} else {
return r_vec_resize0(p_arr->type, p_arr->data, p_arr->count);
}
}void r_env_bind(r_obj* env, r_obj* sym, r_obj* value) {
// See rchk concerns in https://github.com/r-lib/rlang/commit/28ce7b01
KEEP(value);
Rf_defineVar(sym, value, env);
FREE(1);
}enum r_env_binding_type r_env_binding_type(r_obj* env, r_obj* sym) {
#if RLANG_HAS_R_BINDING_API
switch (R_GetBindingType(sym, env)) {
case R_BindingTypeUnbound: return R_ENV_BINDING_TYPE_unbound;
case R_BindingTypeValue: return R_ENV_BINDING_TYPE_value;
case R_BindingTypeMissing: return R_ENV_BINDING_TYPE_missing;
case R_BindingTypeDelayed: return R_ENV_BINDING_TYPE_delayed;
case R_BindingTypeForced: return R_ENV_BINDING_TYPE_forced;
case R_BindingTypeActive: return R_ENV_BINDING_TYPE_active;
}
r_stop_unreachable();
#else
// Active binding check must come first since `r_env_find()` triggers them
if (R_BindingIsActive(sym, env)) {
return R_ENV_BINDING_TYPE_active;
}
r_obj* value = env_find(env, sym);
if (value == R_UnboundValue) {
return R_ENV_BINDING_TYPE_unbound;
}
if (value == r_missing_arg) {
return R_ENV_BINDING_TYPE_missing;
}
if (r_typeof(value) == R_TYPE_promise) {
bool forced;
rlang_promise_unwrap(value, &forced);
if (forced) {
return R_ENV_BINDING_TYPE_forced;
}
return R_ENV_BINDING_TYPE_delayed;
}
return R_ENV_BINDING_TYPE_value;
#endif
}r_obj* r_env_get(r_obj* env, r_obj* sym) {
enum r_env_binding_type type = r_env_binding_type(env, sym);
if (type == R_ENV_BINDING_TYPE_unbound) {
r_abort("object '%s' not found", r_sym_c_string(sym));
}
if (type == R_ENV_BINDING_TYPE_missing) {
return r_missing_arg;
}
#if R_VERSION >= R_Version(4, 5, 0)
return R_getVar(sym, env, FALSE);
#else
r_obj* value = env_find(env, sym);
if (r_typeof(value) == R_TYPE_dots) {
return value;
}
// Handles value, delayed, forced, and active bindings
return Rf_eval(sym, env);
#endif
}r_obj* r_eval(r_obj* expr, r_obj* env) {
return Rf_eval(expr, env);
}r_obj* r_exec_mask_n(r_obj* fn_sym,
r_obj* fn,
const struct r_pair* args,
int n,
r_obj* parent) {
r_obj* mask = KEEP(r_alloc_environment(n + 1, parent));
r_obj* call = KEEP(r_exec_mask_n_call_poke(fn_sym, fn, args, n, mask));
r_obj* out = r_eval(call, mask);
FREE(2);
return out;
}r_obj* r_exec_n(r_obj* fn_sym,
r_obj* fn,
const struct r_pair* args,
int n,
r_obj* env) {
r_obj* call = KEEP(r_exec_mask_n_call_poke(fn_sym, fn, args, n, env));
r_obj* out = r_eval(call, env);
FREE(1);
return out;
}r_obj* r_expr_protect(r_obj* x) {
switch (r_typeof(x)) {
case R_TYPE_symbol:
case R_TYPE_call:
case R_TYPE_promise:
return r_call2(quote_prim, x);
default:
return x;
}
}r_obj* r_fn_body(r_obj* fn) {
return R_ClosureExpr(fn);
}r_obj* r_fn_env(r_obj* fn) {
#if R_VERSION >= R_Version(4, 5, 0)
return R_ClosureEnv(fn);
#else
return CLOENV(fn);
#endif
}r_obj* r_fn_formals(r_obj* fn) {
#if R_VERSION >= R_Version(4, 5, 0)
return R_ClosureFormals(fn);
#else
return FORMALS(fn);
#endif
}bool r_inherits(r_obj* x, const char* tag) {
return Rf_inherits(x, tag);
}void r_init_data_frame(r_obj* x, r_ssize n_rows) {
init_compact_rownames(x, n_rows);
r_attrib_poke(x, r_syms.class_, r_classes.data_frame);
}void r_init_library_arg(void) {
r_arg_match = (int (*)(r_obj*, r_obj*, struct r_lazy, struct r_lazy))
r_peek_c_callable("rlang", "rlang_arg_match_2");
}void r_init_library_call(void) {
quote_prim = r_base_ns_get("quote");
}void r_init_library_cnd(void) {
msg_call = r_parse("message(x)");
r_preserve(msg_call);
wng_call = r_parse("warning(x, call. = FALSE)");
r_preserve(wng_call);
err_call = r_parse("rlang::abort(x)");
r_preserve(err_call);
cnd_signal_call = r_parse("rlang::cnd_signal(x)");
r_preserve(cnd_signal_call);
// Silence "'noreturn' attribute does not apply to types warning".
// It seems like GCC doesn't handle attributes in casts so we need
// to cast through a typedef.
// https://stackoverflow.com/questions/9441262/function-pointer-to-attribute-const-function
typedef r_no_return void (*r_stop_internal_t)(const char*,
int,
r_obj*,
const char* fmt,
...);
r_stop_internal = (r_stop_internal_t) R_GetCCallable("rlang", "rlang_stop_internal2");
r_format_error_arg = (const char* (*)(r_obj*)) r_peek_c_callable("rlang", "rlang_format_error_arg");
r_obj_type_friendly_full = (const char* (*)(r_obj*, bool, bool)) r_peek_c_callable("rlang", "rlang_obj_type_friendly_full");
}void r_init_library_dyn_array(void) {
r_preserve_global(dyn_array_class = r_chr("rlang_dyn_array"));
}void r_init_library_env(void) {
#if R_VERSION < R_Version(4, 1, 0)
new_env_call = r_parse_eval("as.call(list(new.env, TRUE, NULL, NULL))", r_envs.base);
r_preserve(new_env_call);
new_env__parent_node = r_node_cddr(new_env_call);
new_env__size_node = r_node_cdr(new_env__parent_node);
#endif
missing_prim = r_parse_eval("missing", r_envs.base);
env2list_call = r_parse("as.list.environment(x, all.names = TRUE)");
r_preserve(env2list_call);
list2env_call = r_parse("list2env(x, envir = NULL, parent = y, hash = TRUE)");
r_preserve(list2env_call);
exists_call = r_parse("exists(y, envir = x, inherits = z)");
r_preserve(exists_call);
remove_call = r_parse("remove(list = y, envir = x, inherits = z)");
r_preserve(remove_call);
r_methods_ns_env = r_parse_eval("asNamespace('methods')", r_envs.base);
}void r_init_library_eval(void) {
r_lazy_missing_arg = (struct r_lazy) { .x = r_missing_arg, .env = r_null };
}void r_init_library_fn(void) {
const char* formals_code = "formals(function(..., .x = ..1, .y = ..2, . = ..1) NULL)";
rlang_formula_formals = r_parse_eval(formals_code, r_envs.base);
r_preserve_global(rlang_formula_formals);
}void r_init_library_obj(r_obj* ns) {
p_precious_dict = r_new_dict(PRECIOUS_DICT_INIT_SIZE);
KEEP(p_precious_dict->shelter);
r_env_bind(ns,
r_sym(".__rlang_lib_precious_dict__."),
p_precious_dict->shelter);
FREE(1);
// The Microsoft C library doesn't implement the hexadecimal
// formatter correctly
const char* null_addr = r_str_c_string(r_obj_address(r_null));
if (null_addr[0] != '0' || null_addr[1] != 'x') {
obj_address_formatter = "0x%p";
}
r_obj_encode_utf8 = (r_obj* (*)(r_obj*)) r_peek_c_callable("rlang", "rlang_obj_encode_utf8");
as_label_call = r_parse("as_label(x)");
r_preserve_global(as_label_call);
}void r_init_library_quo(void) {
r_quo_get_expr = (r_obj* (*)(r_obj*)) r_peek_c_callable("rlang", "rlang_quo_get_expr");
r_quo_set_expr = (r_obj* (*)(r_obj*, r_obj*)) r_peek_c_callable("rlang", "rlang_quo_set_expr");
r_quo_get_env = (r_obj* (*)(r_obj*)) r_peek_c_callable("rlang", "rlang_quo_get_env");
r_quo_set_env = (r_obj* (*)(r_obj*, r_obj*)) r_peek_c_callable("rlang", "rlang_quo_set_env");
}void r_init_library_session(void) {
is_installed_call = r_parse("requireNamespace(x, quietly = TRUE)");
r_preserve(is_installed_call);
has_colour_call = r_parse("crayon::has_color()");
r_preserve(has_colour_call);
}void r_init_library_stack(void) {
// `sys.frame(sys.nframe())` doesn't work because `sys.nframe()`
// returns the number of the frame in which evaluation occurs. It
// doesn't return the number of frames on the stack. So we'd need
// to evaluate it in the last frame on the stack which is what we
// are looking for to begin with. We use instead this workaround:
// Call `sys.frame()` from a closure to push a new frame on the
// stack, and use negative indexing to get the previous frame.
r_obj* current_frame_body = KEEP(r_parse("sys.frame(-1)"));
r_obj* current_frame_fn = KEEP(r_new_function(r_null, current_frame_body, r_envs.base));
peek_frame_call = r_new_call(current_frame_fn, r_null);
r_preserve(peek_frame_call);
FREE(2);
sys_frame_call = generate_sys_call("sys.frame", &sys_frame_n_addr);
sys_call_call = generate_sys_call("sys.call", &sys_call_n_addr);
caller_env_call = r_parse("parent.frame()");
r_preserve_global(caller_env_call);
}void r_init_library_sym(void) {
r_sym_as_utf8_character = (r_obj* (*)(r_obj*)) r_peek_c_callable("rlang", "rlang_sym_as_character");
r_sym_as_utf8_string = (r_obj* (*)(r_obj*)) r_peek_c_callable("rlang", "rlang_sym_as_string");
}void r_init_library_vendor(void) {
r_xxh3_64bits = (uint64_t (*)(const void*, size_t)) r_peek_c_callable("rlang", "rlang_xxh3_64bits");
}void r_init_rlang_ns_env(void) {
rlang_ns_env = r_ns_env("rlang");
}r_obj* r_int(int x) {
return Rf_ScalarInteger(x);
}int* r_int_begin(r_obj* x) {
return INTEGER(x);
}const int* r_int_cbegin(r_obj* x) {
return (const int*) INTEGER(x);
}void r_int_fill(SEXP x, int value, R_len_t n) {
r_p_int_fill(INTEGER(x), value, n);
}void r_int_fill_seq(SEXP x, int start, R_len_t n) {
int* data = INTEGER(x);
for (R_len_t i = 0; i < n; ++i, ++data, ++start) {
*data = start;
}
}int r_int_get(r_obj* x, r_ssize i) {
return INTEGER(x)[i];
}bool r_is_bool(r_obj* x) {
return
r_typeof(x) == R_TYPE_logical &&
r_length(x) == 1 &&
r_lgl_get(x, 0) != r_globals.na_lgl;
}bool r_is_empty_names(SEXP x) {
if (TYPEOF(x) != STRSXP) {
if (x == R_NilValue) {
return true;
} else {
return false;
}
}
R_len_t n = Rf_length(x);
const SEXP* p = STRING_PTR_RO(x);
for (R_len_t i = 0; i < n; ++i, ++p) {
SEXP elt = *p;
if (elt != NA_STRING && elt != strings_empty) {
return false;
}
}
return true;
}bool r_is_function(r_obj* x) {
switch (r_typeof(x)) {
case R_TYPE_closure:
case R_TYPE_builtin:
case R_TYPE_special:
return true;
default:
return false;
}
}bool r_is_int(r_obj* x) {
return
r_typeof(x) == R_TYPE_integer &&
r_length(x) == 1 &&
r_int_get(x, 0) != r_globals.na_int;
}bool r_is_minimal_names(SEXP x) {
if (TYPEOF(x) != STRSXP) {
return false;
}
R_len_t n = Rf_length(x);
const SEXP* p = STRING_PTR_RO(x);
for (R_len_t i = 0; i < n; ++i, ++p) {
SEXP elt = *p;
if (elt == NA_STRING || elt == strings_empty) {
return false;
}
}
return true;
}bool r_is_number(SEXP x) {
return TYPEOF(x) == INTSXP &&
Rf_length(x) == 1 &&
INTEGER(x)[0] != NA_INTEGER;
}bool r_is_object(r_obj* x) {
return Rf_isObject(x);
}bool r_is_positive_number(SEXP x) {
return r_is_number(x) && INTEGER(x)[0] > 0;
}static inline bool r_is_s4(SEXP x) {
return Rf_isS4(x);
}bool r_is_scalar_logical(r_obj* x) {
return r_typeof(x) == R_TYPE_logical && r_length(x) == 1;
}bool r_is_string(r_obj* x) {
return
r_typeof(x) == R_TYPE_character &&
r_length(x) == 1 &&
r_chr_get(x, 0) != R_NaString;
}r_ssize r_length(r_obj* x) {
return Rf_xlength(x);
}r_obj* r_lgl(bool x) {
return Rf_ScalarLogical(x);
}int* r_lgl_begin(r_obj* x) {
return LOGICAL(x);
}const int* r_lgl_cbegin(r_obj* x) {
return (const int*) LOGICAL(x);
}void r_lgl_fill(SEXP x, int value, R_len_t n) {
r_p_lgl_fill(LOGICAL(x), value, n);
}int r_lgl_get(r_obj* x, r_ssize i) {
return LOGICAL(x)[i];
}r_ssize r_lgl_sum(r_obj* x, bool na_true) {
if (r_typeof(x) != R_TYPE_logical) {
r_abort("Internal error: Excepted logical vector in `r_lgl_sum()`");
}
const r_ssize n = r_length(x);
const int* v_x = r_lgl_cbegin(x);
// This can't overflow since `sum` is necessarily smaller or equal
// to the vector length expressed in `r_ssize`
r_ssize sum = 0;
if (na_true) {
for (r_ssize i = 0; i < n; ++i) {
sum += (bool) v_x[i];
}
} else {
for (r_ssize i = 0; i < n; ++i) {
sum += (v_x[i] == 1);
}
}
return sum;
}r_obj* const * r_list_cbegin(r_obj* x) {
#if (R_VERSION >= R_Version(4, 5, 0))
return VECTOR_PTR_RO(x);
#else
return ((r_obj* const *) DATAPTR_RO(x));
#endif
}r_obj* r_list_get(r_obj* x, r_ssize i) {
return VECTOR_ELT(x, i);
}void r_list_poke(r_obj* x, r_ssize i, r_obj* y) {
SET_VECTOR_ELT(x, i, y);
}void r_mark_shared(r_obj* x) {
MARK_NOT_MUTABLE(x);
}void r_memcpy(void* dest, const void* src, size_t count) {
if (count) {
memcpy(dest, src, count);
}
}void r_memset(void* dest, int value, size_t count) {
if (count) {
memset(dest, value, count);
}
}r_obj* r_names(r_obj* x) {
return r_attrib_get(x, r_syms.names);
}SEXP r_new_character(R_len_t n) {
return Rf_allocVector(STRSXP, n);
}struct r_dyn_array* r_new_dyn_vector(enum r_type type,
r_ssize capacity) {
r_obj* shelter = KEEP(r_alloc_list(2));
r_attrib_poke_class(shelter, dyn_array_class);
r_obj* vec_raw = r_alloc_raw(sizeof(struct r_dyn_array));
r_list_poke(shelter, 0, vec_raw);
r_obj* vec_data = r_alloc_vector(type, capacity);
r_list_poke(shelter, 1, vec_data);
struct r_dyn_array* p_vec = r_raw_begin(vec_raw);
p_vec->shelter = shelter;
p_vec->count = 0;
p_vec->capacity = capacity;
p_vec->growth_factor = R_DYN_ARRAY_GROWTH_FACTOR;
p_vec->type = type;
p_vec->elt_byte_size = r_vec_elt_sizeof0(type);
p_vec->data = vec_data;
switch (type) {
case R_TYPE_character:
p_vec->v_data = NULL;
p_vec->barrier_set = &r_chr_poke;
break;
case R_TYPE_list:
p_vec->v_data = NULL;
p_vec->barrier_set = &r_list_poke;
break;
default:
p_vec->barrier_set = NULL;
p_vec->v_data = r_vec_begin0(type, vec_data);
break;
}
p_vec->v_data_const = r_vec_cbegin0(type, vec_data);
FREE(1);
return p_vec;
}r_obj* r_new_function(r_obj* formals, r_obj* body, r_obj* env) {
#if R_VERSION >= R_Version(4, 5, 0)
return R_mkClosure(formals, body, env);
#else
SEXP fn = Rf_allocSExp(R_TYPE_closure);
SET_FORMALS(fn, formals);
SET_BODY(fn, body);
SET_CLOENV(fn, env);
return fn;
#endif
}SEXP r_new_integer(R_len_t n) {
return Rf_allocVector(INTSXP, n);
}SEXP r_new_list(R_len_t n) {
return Rf_allocVector(VECSXP, n);
}SEXP r_new_logical(R_len_t n) {
return Rf_allocVector(LGLSXP, n);
}r_obj* r_new_node(r_obj* car, r_obj* cdr) {
return Rf_cons(car, cdr);
}SEXP r_new_raw(R_len_t n) {
return Rf_allocVector(RAWSXP, n);
}SEXP r_new_shared_character(const char* name) {
SEXP out = Rf_mkString(name);
R_PreserveObject(out);
MARK_NOT_MUTABLE(out);
return out;
}SEXP r_new_shared_vector(SEXPTYPE type, R_len_t n) {
SEXP out = Rf_allocVector(type, n);
R_PreserveObject(out);
MARK_NOT_MUTABLE(out);
return out;
}struct r_vector_bool* r_new_vector_bool(r_ssize n) {
r_obj* shelter = KEEP(r_alloc_list(2));
r_obj* vec = r_alloc_raw(sizeof(struct r_vector_bool));
r_list_poke(shelter, 0, vec);
r_obj* data = r_alloc_raw(n * sizeof(bool));
r_list_poke(shelter, 1, data);
struct r_vector_bool* p_vec = r_raw_begin(vec);
p_vec->shelter = shelter;
p_vec->data = data;
p_vec->v_data = r_raw_begin(data);
p_vec->n = n;
FREE(1);
return p_vec;
}static inline r_obj* r_node_cadr(r_obj* x) { return CADR(x); }static inline r_obj* r_node_car(r_obj* x) { return CAR(x); }static inline r_obj* r_node_cddr(r_obj* x) { return CDDR(x); }static inline r_obj* r_node_cdr(r_obj* x) { return CDR(x); }static inline void r_node_poke_car(r_obj* x, r_obj* newcar) { SETCAR(x, newcar); }static inline void r_node_poke_cdr(r_obj* x, r_obj* newcdr) { SETCDR(x, newcdr); }static inline void r_node_poke_tag(r_obj* x, r_obj* tag) { SET_TAG(x, tag); }static inline r_obj* r_node_tag(r_obj* x) { return TAG(x); }r_obj* r_ns_env(const char* pkg) {
r_obj* pkg_str = KEEP(r_chr(pkg));
r_obj* ns = R_FindNamespace(pkg_str);
FREE(1);
return ns;
}r_obj* r_obj_address(r_obj* x) {
static char buf[1000];
snprintf(buf, 1000, obj_address_formatter, (void*) x);
return Rf_mkChar(buf);
}void r_obj_print(r_obj* x) {
Rf_PrintValue(x);
}const char* r_obj_type_friendly(r_obj* x) {
return r_obj_type_friendly_full(x, true, false);
}r_obj* r_parse(const char* str) {
r_obj* str_ = KEEP(r_chr(str));
ParseStatus status;
r_obj* out = KEEP(R_ParseVector(str_, -1, &status, r_null));
if (status != PARSE_OK) {
abort_parse(str_, "Parsing failed");
}
if (r_length(out) != 1) {
abort_parse(str_, "Expected a single expression");
}
out = r_list_get(out, 0);
FREE(2);
return out;
}r_obj* r_parse_eval(const char* str, r_obj* env) {
r_obj* out = r_eval(KEEP(r_parse(str)), env);
FREE(1);
return out;
}r_void_fn r_peek_c_callable(const char* pkg, const char* callable) {
return R_GetCCallable(pkg, callable);
}r_obj* r_peek_frame(void) {
return r_eval(peek_frame_call, r_envs.base);
}r_obj* r_peek_option(const char* name) {
return Rf_GetOption1(Rf_install(name));
}SEXP r_protect(SEXP x) {
return Rf_lang2(fns_quote, x);
}void* r_raw_begin(r_obj* x) {
return RAW(x);
}const void* r_raw_cbegin(r_obj* x) {
return (const void*) RAW(x);
}r_obj* r_seq_chr(const char* prefix, r_ssize n) {
int total_len = 24 + strlen(prefix) + 1;
R_CheckStack2(total_len);
char buf[total_len];
return r_chr_iota(n, buf, total_len, prefix);
}r_ssize r_ssize_max(r_ssize x, r_ssize y) {
return (y < x) ? x : y;
}r_ssize r_ssize_min(r_ssize x, r_ssize y) {
return (y < x) ? y : x;
}r_ssize r_ssize_mult(r_ssize x, r_ssize y) {
if (x > 0) {
if (y > 0) {
if (x > (R_SSIZE_MAX / y)) {
goto error;
}
} else {
if (y < (R_SSIZE_MIN / x)) {
goto error;
}
}
} else {
if (y > 0) {
if (x < (R_SSIZE_MIN / y)) {
goto error;
}
} else {
if ( (x != 0) && (y < (R_SSIZE_MAX / x))) {
goto error;
}
}
}
return x * y;
error:
r_stop_internal("Result too large for an `r_ssize`.");
}r_obj* r_str(const char* c_string) {
return Rf_mkCharCE(c_string, CE_UTF8);
}r_obj* r_str_as_character(r_obj* x) {
return Rf_ScalarString(x);
}const char* r_str_c_string(r_obj* str) {
return CHAR(str);
}r_obj* r_sym(const char* c_string) {
return Rf_install(c_string);
}const char* r_sym_c_string(r_obj* sym) {
return CHAR(PRINTNAME(sym));
}r_obj* r_sym_string(r_obj* sym) {
return PRINTNAME(sym);
}ERR r_try_catch(void (*fn)(void*),
void* fn_data,
SEXP cnd_sym,
void (*hnd)(void*),
void* hnd_data) {
struct r_try_catch_data data = {
.fn = fn,
.fn_data = fn_data,
.cnd_sym = cnd_sym,
.hnd = hnd,
.hnd_data = hnd_data,
.err = NULL
};
SEXP xptr = PROTECT(R_MakeExternalPtr(&data, R_NilValue, R_NilValue));
SEXP hnd_fn = PROTECT(try_catch_hnd(xptr));
SEXP syms[3] = {
syms_data,
cnd_sym,
NULL
};
SEXP args[3] = {
xptr,
hnd_fn,
NULL
};
SEXP call = PROTECT(r_call_n(syms_try_catch_impl, syms, args));
Rf_eval(call, vctrs_ns_env);
UNPROTECT(3);
return data.err;
}enum r_type r_typeof(r_obj* x) {
return (enum r_type) TYPEOF(x);
}void* r_vec_begin0(enum r_type type, r_obj* x) {
switch (type) {
case R_TYPE_logical: return r_lgl_begin(x);
case R_TYPE_integer: return r_int_begin(x);
case R_TYPE_double: return r_dbl_begin(x);
case R_TYPE_complex: return r_cpl_begin(x);
case R_TYPE_raw: return r_raw_begin(x);
default: r_stop_unimplemented_type(type);
}
}const void* r_vec_cbegin0(enum r_type type, r_obj* x) {
switch (type) {
case R_TYPE_logical: return r_lgl_cbegin(x);
case R_TYPE_integer: return r_int_cbegin(x);
case R_TYPE_double: return r_dbl_cbegin(x);
case R_TYPE_complex: return r_cpl_cbegin(x);
case R_TYPE_raw: return r_raw_cbegin(x);
case R_TYPE_character: return r_chr_cbegin(x);
case R_TYPE_list: return r_list_cbegin(x);
default: r_stop_unimplemented_type(type);
}
}int r_vec_elt_sizeof0(enum r_type type) {
switch (type) {
case R_TYPE_logical: return sizeof(int);
case R_TYPE_integer: return sizeof(int);
case R_TYPE_double: return sizeof(double);
case R_TYPE_complex: return sizeof(r_complex);
case R_TYPE_raw: return sizeof(char);
case R_TYPE_character: return sizeof(r_obj*);
case R_TYPE_list: return sizeof(r_obj*);
default: r_stop_unimplemented_type(type);
}
}r_obj* r_vec_resize0(enum r_type type, r_obj* x, r_ssize new_size) {
switch (type) {
case R_TYPE_logical: return r_lgl_resize(x, new_size);
case R_TYPE_integer: return r_int_resize(x, new_size);
case R_TYPE_double: return r_dbl_resize(x, new_size);
case R_TYPE_complex: return r_cpl_resize(x, new_size);
case R_TYPE_raw: return r_raw_resize(x, new_size);
case R_TYPE_character: return r_chr_resize(x, new_size);
case R_TYPE_list: return r_list_resize(x, new_size);
default: r_stop_unimplemented_type(type);
}
}static inline void* r_vec_unwrap(SEXPTYPE type, SEXP x) {
switch (type) {
case INTSXP: return (void*) INTEGER(x);
default: stop_unimplemented_type("r_vec_unwrap", type);
}
}bool* r_vector_bool_begin(struct r_vector_bool* p_vec) {
return p_vec->v_data;
}const bool* r_vector_bool_cbegin(struct r_vector_bool* p_vec) {
return (const bool*) p_vec->v_data;
}r_ssize r_vector_bool_length(struct r_vector_bool* p_vec) {
return p_vec->n;
}r_ssize raw_col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
COL_DETECT_MISSING(unsigned char, r_uchar_cbegin, raw_is_missing);
}void raw_detect_complete(SEXP x, R_len_t size, int* p_out) {
VEC_DETECT_COMPLETE(unsigned char, RAW_RO, raw_is_missing);
}r_obj* raw_detect_missing(r_obj* x) {
DETECT_MISSING(unsigned char, r_uchar_cbegin, raw_is_missing);
}uint32_t raw_dict_hash_scalar(struct dictionary* d, R_len_t i) {
return raw_dict_hash_with(d, d, i);
}uint32_t raw_dict_hash_with(struct dictionary* d, struct dictionary* x, R_len_t i) {
DICT_HASH_WITH(p_raw_equal_na_equal);
}bool raw_dict_is_incomplete(struct dictionary* d, R_len_t i) {
return dict_hash_is_missing(d, i) && p_raw_is_incomplete(d->p_poly_vec->p_vec, i);
}static inline int raw_equal_na_equal(Rbyte x, Rbyte y) {
return x == y;
}static inline int raw_equal_na_propagate(Rbyte x, Rbyte y) {
return raw_equal_na_equal(x, y);
}r_ssize raw_first_missing(r_obj* x) {
FIRST_MISSING(unsigned char, r_uchar_cbegin, raw_is_missing);
}static inline uint32_t raw_hash_scalar(Rbyte x) {
return uint32_hash(x);
}bool raw_is_missing(unsigned char x) {
return false;
}r_ssize rownames_size(r_obj* rn) {
switch (rownames_type(rn)) {
case ROWNAMES_TYPE_identifiers:
case ROWNAMES_TYPE_automatic:
return r_length(rn);
case ROWNAMES_TYPE_automatic_compact:
return compact_rownames_length(rn);
}
never_reached("rownames_size");
}SEXP s3_bare_class(SEXP x) {
switch (TYPEOF(x)) {
case NILSXP: return chrs_null;
case LGLSXP: return chrs_logical;
case INTSXP: return chrs_integer;
case REALSXP: return chrs_double;
case CPLXSXP: return chrs_complex;
case STRSXP: return chrs_character;
case RAWSXP: return chrs_raw;
case VECSXP: return chrs_list;
case EXPRSXP: return chrs_expression;
case CLOSXP:
case SPECIALSXP:
case BUILTINSXP: return chrs_function;
default: stop_unimplemented_vctrs_type("base_dispatch_class_str", vec_typeof(x));
}
}SEXP s3_class_find_method(const char* generic, SEXP cls, SEXP table) {
// Avoid corrupt objects where `x` passes `r_is_object()`, but the class is NULL
if (cls == R_NilValue) {
return R_NilValue;
}
SEXP const* p_cls = STRING_PTR_RO(cls);
int n_cls = Rf_length(cls);
for (int i = 0; i < n_cls; ++i) {
SEXP method = s3_get_method(generic, CHAR(p_cls[i]), table);
if (method != R_NilValue) {
return method;
}
}
return R_NilValue;
}enum s3_fallback s3_fallback_from_opts(r_obj* opts) {
return (enum s3_fallback) r_int_get(r_list_get(opts, 0), 0);
}SEXP s3_find_method(const char* generic, SEXP x, SEXP table) {
if (!r_is_object(x)) {
return R_NilValue;
}
SEXP cls = PROTECT(Rf_getAttrib(x, R_ClassSymbol));
SEXP method = s3_class_find_method(generic, cls, table);
UNPROTECT(1);
return method;
}SEXP s3_get_method(const char* generic, const char* cls, SEXP table) {
SEXP sym = s3_paste_method_sym(generic, cls);
return s3_sym_get_method(sym, table);
}static inline SEXP s3_get_table(SEXP env) {
if (r_env_has(env, syms_s3_methods_table)) {
return r_env_get(env, syms_s3_methods_table);
} else {
return r_null;
}
}SEXP s4_class_find_method(SEXP cls, SEXP table) {
// Avoid corrupt objects where `x` passes `r_is_object()`, but the class is NULL
if (cls == R_NilValue) {
return R_NilValue;
}
SEXP const* p_class = STRING_PTR_RO(cls);
int n_class = Rf_length(cls);
for (int i = 0; i < n_class; ++i) {
SEXP method = s4_get_method(CHAR(p_class[i]), table);
if (method != R_NilValue) {
return method;
}
}
return R_NilValue;
}SEXP s4_find_method(SEXP x, SEXP table) {
if (!r_is_s4(x)) {
return R_NilValue;
}
SEXP cls = PROTECT(Rf_getAttrib(x, R_ClassSymbol));
SEXP out = s4_class_find_method(cls, table);
UNPROTECT(1);
return out;
}r_obj* set_names_dispatch(r_obj* x, r_obj* names) {
return vctrs_dispatch2(syms_set_names_dispatch, fns_set_names_dispatch,
syms_x, x,
syms_names, names);
}r_obj* set_rownames_dispatch(r_obj* x, r_obj* names) {
return vctrs_dispatch2(syms_set_rownames_dispatch, fns_set_rownames_dispatch,
syms_x, x,
syms_names, names);
}static inline uint32_t sexp_hash(r_obj* x) {
switch (TYPEOF(x)) {
// `NULL`
case NILSXP: return 0;
// Atomics
case LGLSXP: return lgl_hash(x);
case INTSXP: return int_hash(x);
case REALSXP: return dbl_hash(x);
case CPLXSXP: return cpl_hash(x);
case RAWSXP: return raw_hash(x);
case STRSXP: return chr_hash(x);
case VECSXP: return list_hash(x);
// Expressions
case EXPRSXP: return expr_hash(x);
// Node-like
case DOTSXP:
case LANGSXP:
case LISTSXP:
case BCODESXP: return node_hash(x);
// Functions
case CLOSXP: return fn_hash(x);
// Pointer based hashing
case SYMSXP:
case SPECIALSXP:
case BUILTINSXP:
case ENVSXP:
case EXTPTRSXP: return uint64_hash((uintptr_t) x);
default: Rf_errorcall(R_NilValue, "Unsupported type %s", Rf_type2char(TYPEOF(x)));
}
}r_obj* shaped_as_df_col(r_obj* x, r_obj* outer) {
// If packed, store array as a column
if (outer != strings_empty) {
return x;
}
// If unpacked, transform to data frame first. We repair names
// after unpacking and concatenation.
r_obj* out = KEEP(r_as_data_frame(x));
// Remove names if they were repaired by `as.data.frame()`
if (colnames(x) == r_null) {
r_attrib_poke_names(out, r_null);
}
FREE(1);
return out;
}bool should_finalise(enum ptype_finalise finalise) {
return finalise == PTYPE_FINALISE_true;
}r_obj* size2_common(
r_obj* x,
r_obj* y,
struct counters* counters,
void* data
) {
struct size_common_reduce_opts* reduce_opts = data;
const r_ssize x_size = reduce_opts->current_size;
const r_ssize y_size = vec_size_params(y, counters->next_arg, reduce_opts->call);
int left = -1;
r_obj* out = vec_size2_impl(
x,
y,
x_size,
y_size,
counters->curr_arg,
counters->next_arg,
reduce_opts->call,
&left
);
if (!left) {
counters_shift(counters);
reduce_opts->current_size = y_size;
}
return out;
}size_t size_round_power_2(size_t size) {
size_t out = 1;
while (out < size) {
out <<= 1;
}
return out;
}r_obj* slice_names(r_obj* names, r_obj* subscript) {
if (names == r_null) {
return names;
} else {
// Ensures `NA_integer_` subscripts utilize `""` as the name
return chr_names_slice(names, subscript, VCTRS_MATERIALIZE_false);
}
}r_obj* slice_rownames(r_obj* names, r_obj* subscript) {
if (names == r_null) {
return names;
}
names = KEEP(chr_slice(names, subscript, VCTRS_MATERIALIZE_false));
// Rownames can't contain `NA` or duplicates
names = vec_as_unique_names(names, true);
FREE(1);
return names;
}void stop_bad_direction(void) {
r_abort("`direction` must be one of \"down\", \"up\", \"downup\", or \"updown\".");
}void stop_combine_unmatched(r_obj* loc, struct r_lazy error_call) {
r_obj* syms[3] = {
syms_loc,
syms_call,
NULL
};
r_obj* args[3] = {
loc,
KEEP(r_lazy_eval_protect(error_call)),
NULL
};
r_obj* ffi_call = KEEP(r_call_n(syms_stop_combine_unmatched, syms, args));
Rf_eval(ffi_call, vctrs_ns_env);
never_reached("stop_combine_unmatched");
}void stop_corrupt_factor_levels(SEXP x, struct vctrs_arg* arg) {
SEXP call = PROTECT(Rf_lang3(Rf_install("stop_corrupt_factor_levels"),
PROTECT(r_protect(x)),
PROTECT(vctrs_arg(arg))));
Rf_eval(call, vctrs_ns_env);
never_reached("stop_corrupt_factor_levels");
}void stop_corrupt_ordered_levels(SEXP x, struct vctrs_arg* arg) {
SEXP call = PROTECT(Rf_lang3(Rf_install("stop_corrupt_ordered_levels"),
PROTECT(r_protect(x)),
PROTECT(vctrs_arg(arg))));
Rf_eval(call, vctrs_ns_env);
never_reached("stop_corrupt_ordered_levels");
}void stop_incompatible_size(r_obj* x,
r_obj* y,
r_ssize x_size,
r_ssize y_size,
struct vctrs_arg* x_arg,
struct vctrs_arg* y_arg,
struct r_lazy call) {
r_obj* syms[8] = {
syms_x,
syms_y,
syms_x_size,
syms_y_size,
syms_x_arg,
syms_y_arg,
r_syms.call,
NULL
};
r_obj* args[8] = {
KEEP(r_protect(x)),
KEEP(r_protect(y)),
KEEP(r_int(x_size)),
KEEP(r_int(y_size)),
KEEP(vctrs_arg(x_arg)),
KEEP(vctrs_arg(y_arg)),
KEEP(r_lazy_eval_protect(call)),
NULL
};
r_obj* ffi_call = KEEP(r_call_n(syms_stop_incompatible_size,
syms,
args));
r_eval(ffi_call, vctrs_ns_env);
r_stop_unreachable();
}void stop_indicator_size(r_obj* i,
r_obj* n,
const struct location_opts* opts) {
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask5(r_sym("stop_indicator_size"),
syms_i, i,
syms_n, n,
syms_subscript_action, get_opts_action(&opts->subscript_opts),
syms_subscript_arg, arg,
syms_call, call);
r_stop_unreachable();
}static void stop_large_name(void) {
r_abort("Can't tidy up name because it is too large.");
}void stop_location_negative(r_obj* i,
const struct location_opts* opts) {
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask4(r_sym("stop_location_negative"),
syms_i, i,
syms_subscript_action, get_opts_action(&opts->subscript_opts),
syms_subscript_arg, arg,
syms_call, call);
r_stop_unreachable();
}void stop_location_negative_missing(r_obj* i,
const struct location_opts* opts) {
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask4(r_sym("stop_location_negative_missing"),
syms_i, i,
syms_subscript_arg, arg,
syms_call, call,
syms_subscript_action, get_opts_action(&opts->subscript_opts));
r_stop_unreachable();
}void stop_location_negative_positive(r_obj* i,
const struct location_opts* opts) {
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask4(r_sym("stop_location_negative_positive"),
syms_i, i,
syms_subscript_arg, arg,
syms_call, call,
syms_subscript_action, get_opts_action(&opts->subscript_opts));
r_stop_unreachable();
}void stop_location_oob_non_consecutive(r_obj* i,
r_ssize size,
const struct location_opts* opts) {
r_obj* size_obj = KEEP(r_int(size));
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask5(r_sym("stop_location_oob_non_consecutive"),
syms_i, i,
syms_size, size_obj,
syms_subscript_action, get_opts_action(&opts->subscript_opts),
syms_subscript_arg, arg,
syms_call, call);
FREE(1);
r_stop_unreachable();
}void stop_location_zero(r_obj* i,
const struct location_opts* opts) {
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask4(r_sym("stop_location_zero"),
syms_i, i,
syms_subscript_action, get_opts_action(&opts->subscript_opts),
syms_subscript_arg, arg,
syms_call, call);
r_stop_unreachable();
}void stop_name_repair(struct name_repair_opts* p_opts) {
struct repair_error_info info = new_repair_error_info(p_opts);
KEEP(info.shelter);
r_abort_call(info.input_error_call,
"%s must be a string or a function. See `?vctrs::vec_as_names`.",
r_format_error_arg(info.input_error_repair_arg));
}void stop_non_list_type(
r_obj* x,
struct vctrs_arg* arg,
struct r_lazy call
) {
r_eval_with_xyz(KEEP(r_parse("stop_non_list_type(x, y, z)")),
x,
KEEP(vctrs_arg(arg)),
KEEP(r_lazy_eval(call)),
vctrs_ns_env);
r_stop_unreachable();
}void stop_recycle_incompatible_size(r_ssize x_size,
r_ssize size,
struct vctrs_arg* x_arg,
struct r_lazy call) {
r_obj* syms[5] = {
r_sym("x_size"),
r_sym("size"),
r_sym("x_arg"),
syms_call,
NULL
};
r_obj* args[5] = {
KEEP(r_int(x_size)),
KEEP(r_int(size)),
KEEP(vctrs_arg(x_arg)),
KEEP(r_lazy_eval_protect(call)),
NULL
};
r_obj* stop_call = KEEP(r_call_n(r_sym("stop_recycle_incompatible_size"), syms, args));
r_eval(stop_call, vctrs_ns_env);
never_reached("stop_recycle_incompatible_size");
}void stop_rep_each_times_missing(r_ssize i, struct r_lazy call, struct vctrs_arg* p_times_arg) {
r_abort_lazy_call(call,
"%s can't be missing. Location %i is missing.",
vec_arg_format(p_times_arg),
i);
}void stop_rep_each_times_negative(r_ssize i, struct r_lazy call, struct vctrs_arg* p_times_arg) {
r_abort_lazy_call(call,
"%s must be a vector of positive numbers. Location %i is negative.",
vec_arg_format(p_times_arg),
i);
}void stop_rep_each_times_oob(int times, r_ssize i, struct r_lazy call, struct vctrs_arg* p_times_arg) {
r_abort_lazy_call(
call,
"%s must be less than %i, not %i. ",
"Location %i is too large.",
vec_arg_format(p_times_arg),
R_LEN_T_MAX,
times,
i
);
}void stop_rep_size_oob(struct r_lazy call) {
r_abort_lazy_call(
call,
"Long vectors are not yet supported. "
"Requested output size must be less than %i.",
R_LEN_T_MAX
);
}void stop_rep_times_missing(struct r_lazy call, struct vctrs_arg* p_times_arg) {
r_abort_lazy_call(call,
"%s can't be missing.",
vec_arg_format(p_times_arg));
}void stop_rep_times_negative(struct r_lazy call, struct vctrs_arg* p_times_arg) {
r_abort_lazy_call(call,
"%s must be a positive number.",
vec_arg_format(p_times_arg));
}void stop_rep_times_oob(int times, struct r_lazy call, struct vctrs_arg* p_times_arg) {
r_abort_lazy_call(
call,
"%s must be less than %i, not %i.",
vec_arg_format(p_times_arg),
R_LEN_T_MAX,
times
);
}void stop_rep_times_size(struct r_lazy call,
struct vctrs_arg* p_times_arg) {
r_abort_lazy_call(call,
"%s must be a single number.",
vec_arg_format(p_times_arg));
}void stop_subscript_empty(r_obj* i,
const struct location_opts* opts) {
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask2(r_sym("stop_subscript_empty"),
syms_i, i,
syms_call, call);
r_stop_unreachable();
}void stop_subscript_missing(r_obj* i,
const struct location_opts* opts) {
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask2(r_sym("stop_subscript_missing"),
syms_i, i,
syms_call, call);
r_stop_unreachable();
}void stop_subscript_negative_oob_location(r_obj* i,
r_ssize size,
const struct location_opts* opts) {
struct location_opts error_opts = *opts;
error_opts.subscript_opts.action = SUBSCRIPT_ACTION_NEGATE;
stop_subscript_oob_location(i, size, &error_opts);
}void stop_subscript_oob_location(r_obj* i,
r_ssize size,
const struct location_opts* opts) {
r_obj* size_obj = KEEP(r_int(size));
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask6(r_sym("stop_subscript_oob"),
syms_i, i,
syms_subscript_type, chrs_numeric,
syms_size, size_obj,
syms_subscript_action, get_opts_action(&opts->subscript_opts),
syms_subscript_arg, arg,
syms_call, call);
r_stop_unreachable();
}void stop_subscript_oob_name(r_obj* i,
r_obj* names,
const struct location_opts* opts) {
r_obj* arg = KEEP(vctrs_arg(opts->subscript_opts.subscript_arg));
r_obj* call = KEEP(r_lazy_eval(opts->subscript_opts.call));
vctrs_eval_mask6(r_sym("stop_subscript_oob"),
syms_i, i,
syms_subscript_type, chrs_character,
syms_names, names,
syms_subscript_action, get_opts_action(&opts->subscript_opts),
syms_subscript_arg, arg,
syms_call, call);
r_stop_unreachable();
}static inline r_obj* str_as_utf8(r_obj* x) {
return Rf_mkCharCE(Rf_translateCharUTF8(x), CE_UTF8);
}int str_cmp(
const char* x,
const char* y,
const int direction
) {
// Same pointer
// In our research it seems like `strcmp()` doesn't optimize this check,
// since it would be rare for most `strcmp()` usage. But for R's interned
// strings it definitely matters for us.
if (x == y) {
return 0;
} else {
return direction * strcmp(x, y);
}
} int str_cmp_maybe_na(
SEXP x,
SEXP y,
const char* x_string,
const char* y_string,
const int direction,
const int na_order
) {
// Same pointer - including `NA`s
if (x == y) {
return 0;
}
if (x == NA_STRING) {
return na_order;
}
if (y == NA_STRING) {
return -na_order;
}
return direction * strcmp(x_string, y_string);
}bool str_ge(
const char* x,
const char* y,
const int direction
) {
return str_cmp(x, y, direction) >= 0;
}static inline bool str_is_ascii_or_utf8(r_obj* x) {
#if (R_VERSION >= R_Version(4, 5, 0))
return Rf_charIsASCII(x) || (Rf_getCharCE(x) == CE_UTF8) || (x == r_globals.na_str);
#else
const int mask_ascii = 8;
const int mask_utf8 = 64;
const int levels = LEVELS(x);
return (levels & mask_ascii) || (levels & mask_utf8) || (x == r_globals.na_str);
#endif
}static inline SEXP subscript_type_action_chr(enum subscript_type_action action) {
switch (action) {
case SUBSCRIPT_TYPE_ACTION_CAST: return chrs_cast;
case SUBSCRIPT_TYPE_ACTION_ERROR: return chrs_error;
}
never_reached("subscript_type_action_chr");
}ptrdiff_t suffix_pos(const char* name) {
int n = strlen(name);
const char* suffix_end = NULL;
int in_dots = 0;
bool in_digits = false;
for (const char* ptr = name + n - 1; ptr >= name; --ptr) {
char c = *ptr;
if (in_digits) {
if (c == '.') {
in_digits = false;
in_dots = 1;
continue;
}
if (isdigit(c)) {
continue;
}
goto done;
}
switch (in_dots) {
case 0:
if (isdigit(c)) {
in_digits = true;
continue;
}
goto done;
case 1:
case 2:
if (c == '.') {
++in_dots;
continue;
}
goto done;
case 3:
suffix_end = ptr + 1;
if (isdigit(c)) {
in_dots = 0;
in_digits = true;
continue;
}
goto done;
default:
r_stop_internal("Unexpected state.");
}}
done:
if (suffix_end) {
return suffix_end - name;
} else {
return -1;
}
}SEXP tib_cast(const struct cast_opts* opts) {
SEXP out = PROTECT(df_cast_opts(opts));
Rf_setAttrib(out, R_ClassSymbol, classes_tibble);
UNPROTECT(1);
return out;
}r_obj* tib_ptype2(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
r_obj* out = KEEP(df_ptype2(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback
));
r_attrib_poke_class(out, classes_tibble);
FREE(1);
return out;
}bool times_is_oob(int times) {
return times > R_LEN_T_MAX;
}static inline SEXP try_catch_hnd(SEXP ptr) {
SEXP call = PROTECT(Rf_lang2(syms_try_catch_hnd, ptr));
SEXP out = Rf_eval(call, vctrs_ns_env);
UNPROTECT(1);
return out;
}static bool tzone_equal(SEXP x_tzone, SEXP y_tzone) {
// Equal objects?
if (x_tzone == y_tzone) {
return true;
}
// Equal CHARSXPs?
SEXP x_string = STRING_ELT(x_tzone, 0);
SEXP y_string = STRING_ELT(y_tzone, 0);
if (x_string == y_string) {
return true;
}
// Equal C char?
const char* x_tzone_char = CHAR(x_string);
const char* y_tzone_char = CHAR(y_string);
return !strcmp(x_tzone_char, y_tzone_char);
}static inline bool tzone_is_local(SEXP tzone) {
return STRING_ELT(tzone, 0) == strings_empty;
}static SEXP tzone_union(SEXP x_tzone, SEXP y_tzone) {
if (tzone_is_local(x_tzone)) {
return y_tzone;
} else {
return x_tzone;
}
}r_obj* vctrs_arg(struct vctrs_arg* arg) {
if (!arg) {
return chrs_empty;
}
r_ssize next_size = DEFAULT_ARG_BUF_SIZE;
r_ssize size;
r_obj* buf_holder = KEEP(r_null);
char* buf;
do {
size = next_size;
FREE(1);
buf_holder = KEEP(r_alloc_raw(size));
buf = (char*) r_raw_begin(buf_holder);
// Reallocate a larger buffer at the next iteration if the current
// buffer turns out too small
next_size *= 1.5;
} while (fill_arg_buffer(arg, buf, 0, size) < 0);
r_obj* out = r_chr(buf);
FREE(1);
return out;
}void vctrs_count_loop(struct dictionary* d, R_len_t n, int* p_count) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VCTRS_COUNT_LOOP(nil_dict_hash_scalar); break;
case VCTRS_TYPE_logical: VCTRS_COUNT_LOOP(lgl_dict_hash_scalar); break;
case VCTRS_TYPE_integer: VCTRS_COUNT_LOOP(int_dict_hash_scalar); break;
case VCTRS_TYPE_double: VCTRS_COUNT_LOOP(dbl_dict_hash_scalar); break;
case VCTRS_TYPE_complex: VCTRS_COUNT_LOOP(cpl_dict_hash_scalar); break;
case VCTRS_TYPE_character: VCTRS_COUNT_LOOP(chr_dict_hash_scalar); break;
case VCTRS_TYPE_raw: VCTRS_COUNT_LOOP(raw_dict_hash_scalar); break;
case VCTRS_TYPE_list: VCTRS_COUNT_LOOP(list_dict_hash_scalar); break;
case VCTRS_TYPE_dataframe: VCTRS_COUNT_LOOP(df_dict_hash_scalar); break;
default: stop_unimplemented_vctrs_type("vctrs_count_loop", d->p_poly_vec->type);
}
}SEXP vctrs_date_validate(SEXP x) {
return date_validate(x);
}SEXP vctrs_datetime_validate(SEXP x) {
return datetime_validate(x);
}SEXP vctrs_detect_complete(SEXP x) {
return vec_detect_complete(x);
}SEXP vctrs_dim(SEXP x) {
return vec_dim(x);
}SEXP vctrs_dim_n(SEXP x) {
return r_int(vec_dim_n(x));
}SEXP vctrs_duplicated_any(SEXP x) {
bool out = duplicated_any(x);
return Rf_ScalarLogical(out);
}void vctrs_duplicated_loop(struct dictionary* d, R_len_t n, uint32_t* p_hashes, int* p_out) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VCTRS_DUPLICATED_LOOP(nil_dict_hash_scalar); break;
case VCTRS_TYPE_logical: VCTRS_DUPLICATED_LOOP(lgl_dict_hash_scalar); break;
case VCTRS_TYPE_integer: VCTRS_DUPLICATED_LOOP(int_dict_hash_scalar); break;
case VCTRS_TYPE_double: VCTRS_DUPLICATED_LOOP(dbl_dict_hash_scalar); break;
case VCTRS_TYPE_complex: VCTRS_DUPLICATED_LOOP(cpl_dict_hash_scalar); break;
case VCTRS_TYPE_character: VCTRS_DUPLICATED_LOOP(chr_dict_hash_scalar); break;
case VCTRS_TYPE_raw: VCTRS_DUPLICATED_LOOP(raw_dict_hash_scalar); break;
case VCTRS_TYPE_list: VCTRS_DUPLICATED_LOOP(list_dict_hash_scalar); break;
case VCTRS_TYPE_dataframe: VCTRS_DUPLICATED_LOOP(df_dict_hash_scalar); break;
default: stop_unimplemented_vctrs_type("vctrs_duplicated_loop", d->p_poly_vec->type);
}
}SEXP vctrs_eval_mask_n(SEXP fn, SEXP* syms, SEXP* args) {
return vctrs_eval_mask_n_impl(R_NilValue, fn, syms, args, vctrs_ns_env);
}static SEXP vctrs_eval_mask_n_impl(SEXP fn_sym, SEXP fn, SEXP* syms, SEXP* args, SEXP env) {
SEXP mask = PROTECT(r_alloc_empty_environment(env));
if (fn_sym != R_NilValue) {
Rf_defineVar(fn_sym, fn, mask);
fn = fn_sym;
}
SEXP body = PROTECT(r_call_n(fn, syms, syms));
SEXP call_fn = PROTECT(r_new_function(R_NilValue, body, mask));
SEXP call = PROTECT(Rf_lang1(call_fn));
while (*syms) {
Rf_defineVar(*syms, *args, mask);
++syms; ++args;
}
SEXP out = Rf_eval(call, env);
UNPROTECT(4);
return out;
}SEXP vctrs_fast_c(SEXP x, SEXP y) {
SEXPTYPE x_type = TYPEOF(x);
if (x_type != TYPEOF(y)) {
Rf_error("`x` and `y` must have the same types.");
}
switch (x_type) {
case STRSXP: return chr_c(x, y);
default: stop_unimplemented_type("vctrs_fast_c", x_type);
}
}SEXP vctrs_field_get(SEXP x, SEXP index) {
check_rcrd(x);
return vctrs_list_get(x, index);
}SEXP vctrs_field_set(SEXP x, SEXP index, SEXP value) {
check_rcrd(x);
if (!obj_is_vector(value, VCTRS_ALLOW_NULL_no)) {
Rf_errorcall(R_NilValue, "Invalid value: not a vector.");
}
if (vec_size(value) != vec_size(x)) {
Rf_errorcall(R_NilValue, "Invalid value: incorrect length.");
}
return vctrs_list_set(x, index, value);
}SEXP vctrs_fields(SEXP x) {
check_rcrd(x);
return Rf_getAttrib(x, R_NamesSymbol);
}SEXP vctrs_fill_missing(SEXP x, SEXP direction, SEXP max_fill) {
bool down;
bool leading;
parse_direction(direction, &down, &leading);
int c_max_fill = parse_max_fill(max_fill);
return vec_fill_missing(x, down, leading, c_max_fill);
}void vctrs_group_id_loop(struct dictionary* d, R_len_t n, int* p_out) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VCTRS_GROUP_ID_LOOP(nil_dict_hash_scalar); break;
case VCTRS_TYPE_logical: VCTRS_GROUP_ID_LOOP(lgl_dict_hash_scalar); break;
case VCTRS_TYPE_integer: VCTRS_GROUP_ID_LOOP(int_dict_hash_scalar); break;
case VCTRS_TYPE_double: VCTRS_GROUP_ID_LOOP(dbl_dict_hash_scalar); break;
case VCTRS_TYPE_complex: VCTRS_GROUP_ID_LOOP(cpl_dict_hash_scalar); break;
case VCTRS_TYPE_character: VCTRS_GROUP_ID_LOOP(chr_dict_hash_scalar); break;
case VCTRS_TYPE_raw: VCTRS_GROUP_ID_LOOP(raw_dict_hash_scalar); break;
case VCTRS_TYPE_list: VCTRS_GROUP_ID_LOOP(list_dict_hash_scalar); break;
case VCTRS_TYPE_dataframe: VCTRS_GROUP_ID_LOOP(df_dict_hash_scalar); break;
default: stop_unimplemented_vctrs_type("vctrs_group_id_loop", d->p_poly_vec->type);
}
}R_len_t vctrs_group_rle_loop(struct dictionary* d, R_len_t n, int* p_g, int* p_l) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VCTRS_GROUP_RLE_LOOP(nil_dict_hash_scalar, p_nil_equal_na_equal); break;
case VCTRS_TYPE_logical: VCTRS_GROUP_RLE_LOOP(lgl_dict_hash_scalar, p_lgl_equal_na_equal); break;
case VCTRS_TYPE_integer: VCTRS_GROUP_RLE_LOOP(int_dict_hash_scalar, p_int_equal_na_equal); break;
case VCTRS_TYPE_double: VCTRS_GROUP_RLE_LOOP(dbl_dict_hash_scalar, p_dbl_equal_na_equal); break;
case VCTRS_TYPE_complex: VCTRS_GROUP_RLE_LOOP(cpl_dict_hash_scalar, p_cpl_equal_na_equal); break;
case VCTRS_TYPE_character: VCTRS_GROUP_RLE_LOOP(chr_dict_hash_scalar, p_chr_equal_na_equal); break;
case VCTRS_TYPE_raw: VCTRS_GROUP_RLE_LOOP(raw_dict_hash_scalar, p_raw_equal_na_equal); break;
case VCTRS_TYPE_list: VCTRS_GROUP_RLE_LOOP(list_dict_hash_scalar, p_list_equal_na_equal); break;
case VCTRS_TYPE_dataframe: VCTRS_GROUP_RLE_LOOP(df_dict_hash_scalar, p_df_equal_na_equal); break;
default: stop_unimplemented_vctrs_type("vctrs_group_rle_loop", d->p_poly_vec->type);
}
}SEXP vctrs_has_dim(SEXP x) {
return r_lgl(has_dim(x));
}void vctrs_id_loop(struct dictionary* d, R_len_t n, int* p_out) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VCTRS_ID_LOOP(nil_dict_hash_scalar); break;
case VCTRS_TYPE_logical: VCTRS_ID_LOOP(lgl_dict_hash_scalar); break;
case VCTRS_TYPE_integer: VCTRS_ID_LOOP(int_dict_hash_scalar); break;
case VCTRS_TYPE_double: VCTRS_ID_LOOP(dbl_dict_hash_scalar); break;
case VCTRS_TYPE_complex: VCTRS_ID_LOOP(cpl_dict_hash_scalar); break;
case VCTRS_TYPE_character: VCTRS_ID_LOOP(chr_dict_hash_scalar); break;
case VCTRS_TYPE_raw: VCTRS_ID_LOOP(raw_dict_hash_scalar); break;
case VCTRS_TYPE_list: VCTRS_ID_LOOP(list_dict_hash_scalar); break;
case VCTRS_TYPE_dataframe: VCTRS_ID_LOOP(df_dict_hash_scalar); break;
default: stop_unimplemented_vctrs_type("vctrs_id_loop", d->p_poly_vec->type);
}
}SEXP vctrs_implements_ptype2(SEXP x) {
return r_lgl(vec_implements_ptype2(x));
}void vctrs_init_bind(r_obj* ns) {
syms_vec_cbind_frame_ptype = r_sym("vec_cbind_frame_ptype");
fns_vec_cbind_frame_ptype = r_env_get(ns, syms_vec_cbind_frame_ptype);
}void vctrs_init_cast(r_obj* ns) {
syms.vec_default_cast = r_sym("vec_default_cast");
}void vctrs_init_data(r_obj* ns) {
syms_vec_proxy = r_sym("vec_proxy");
syms_vec_proxy_equal = r_sym("vec_proxy_equal");
syms_vec_proxy_equal_array = r_sym("vec_proxy_equal.array");
syms_vec_proxy_compare = r_sym("vec_proxy_compare");
syms_vec_proxy_compare_array = r_sym("vec_proxy_compare.array");
syms_vec_proxy_order = r_sym("vec_proxy_order");
syms_vec_proxy_order_array = r_sym("vec_proxy_order.array");
fns_vec_proxy_equal_array = r_env_get(ns, syms_vec_proxy_equal_array);
fns_vec_proxy_compare_array = r_env_get(ns, syms_vec_proxy_compare_array);
fns_vec_proxy_order_array = r_env_get(ns, syms_vec_proxy_order_array);
}void vctrs_init_dictionary(SEXP ns) {
args_needles = new_wrapper_arg(NULL, "needles");
args_haystack = new_wrapper_arg(NULL, "haystack");
}void vctrs_init_globals(r_obj* ns) {
size_t n_strings = sizeof(struct lazy_calls) / sizeof(struct r_lazy);
size_t n_lazy_calls = sizeof(struct strings) / sizeof(r_obj*);
size_t n_globals = n_strings + n_lazy_calls;
globals_shelter = r_new_dyn_vector(R_TYPE_list, n_globals);
r_preserve(globals_shelter->shelter);
// Symbols -----------------------------------------------------------
syms.arg = r_sym("arg");
syms.condition_arg = r_sym("condition_arg");
syms.conditions_arg = r_sym("conditions_arg");
syms.default_arg = r_sym("default_arg");
syms.dot_arg = r_sym(".arg");
syms.dot_call = r_sym(".call");
syms.dot_error_arg = r_sym(".error_arg");
syms.dot_error_call = r_sym(".error_call");
syms.false_arg = r_sym("false_arg");
syms.from_arg = r_sym("from_arg");
syms.haystack_arg = r_sym("haystack_arg");
syms.missing_arg = r_sym("missing_arg");
syms.indices_arg = r_sym("indices_arg");
syms.needles_arg = r_sym("needles_arg");
syms.recurse = r_sym("recurse");
syms.repair_arg = r_sym("repair_arg");
syms.times_arg = r_sym("times_arg");
syms.to_arg = r_sym("to_arg");
syms.true_arg = r_sym("true_arg");
syms.value_arg = r_sym("value_arg");
syms.values_arg = r_sym("values_arg");
syms.x_arg = r_sym("x_arg");
syms.y_arg = r_sym("y_arg");
// Strings and characters --------------------------------------------
INIT_STRING(AsIs);
INIT_STRING(repair);
INIT_STRING(location);
INIT_STRING(condition);
// Args --------------------------------------------------------------
INIT_ARG2(dot_name_repair, ".name_repair");
INIT_ARG2(dot_ptype, ".ptype");
INIT_ARG2(dot_size, ".size");
INIT_ARG2(empty, "");
INIT_ARG(i);
INIT_ARG(max_fill);
INIT_ARG(n);
INIT_ARG(value);
INIT_ARG(x);
INIT_ARG(y);
INIT_ARG(indices);
INIT_ARG(sizes);
INIT_ARG(ptype);
INIT_ARG(size);
// Lazy args ---------------------------------------------------------
INIT_LAZY_ARG_2(dot_name_repair, ".name_repair");
// Calls -------------------------------------------------------------
INIT_CALL(vec_assign);
INIT_CALL(vec_assign_seq);
INIT_CALL(vec_init);
INIT_CALL(vec_ptype_finalise);
INIT_CALL(vec_recycle);
INIT_CALL(vec_size);
}void vctrs_init_interval(r_obj* ns) {
args_start_ = new_wrapper_arg(NULL, "start");
args_end_ = new_wrapper_arg(NULL, "end");
args_lower_ = new_wrapper_arg(NULL, "lower");
args_upper_ = new_wrapper_arg(NULL, "upper");
}r_obj* vctrs_init_library(r_obj* ns) {
r_init_library(ns);
vctrs_init_bind(ns);
vctrs_init_cast(ns);
vctrs_init_data(ns);
vctrs_init_dictionary(ns);
vctrs_init_interval(ns);
vctrs_init_match(ns);
vctrs_init_names(ns);
vctrs_init_proxy_restore(ns);
vctrs_init_slice(ns);
vctrs_init_slice_assign(ns);
vctrs_init_subscript(ns);
vctrs_init_subscript_loc(ns);
vctrs_init_ptype(ns);
vctrs_init_ptype2(ns);
vctrs_init_ptype2_dispatch(ns);
vctrs_init_rep(ns);
vctrs_init_type_data_frame(ns);
vctrs_init_type_date_time(ns);
vctrs_init_type_info(ns);
vctrs_init_unspecified(ns);
vctrs_init_utils(ns);
vctrs_init_globals(ns);
return r_null;
}void vctrs_init_match(r_obj* ns) {
args_incomplete_ = new_wrapper_arg(NULL, "incomplete");
args_no_match_ = new_wrapper_arg(NULL, "no_match");
args_remaining_ = new_wrapper_arg(NULL, "remaining");
}void vctrs_init_names(r_obj* ns) {
syms_set_rownames_dispatch = r_sym("set_rownames_dispatch");
syms_set_names_dispatch = r_sym("set_names_dispatch");
syms_as_universal_names = r_sym("as_universal_names");
syms_check_unique_names = r_sym("validate_unique");
fns_set_rownames_dispatch = r_env_get(ns, syms_set_rownames_dispatch);
fns_set_names_dispatch = r_env_get(ns, syms_set_names_dispatch);
fns_as_universal_names = r_env_get(ns, syms_as_universal_names);
fns_check_unique_names = r_env_get(ns, syms_check_unique_names);
syms_glue_as_name_spec = r_sym("glue_as_name_spec");
fns_glue_as_name_spec = r_env_get(ns, syms_glue_as_name_spec);
syms_internal_spec = r_sym("_spec");
name_spec_inner = r_chr("inner");
r_preserve(name_spec_inner);
unique_repair_default_opts.type = NAME_REPAIR_unique;
unique_repair_default_opts.fn = r_null;
unique_repair_default_opts.quiet = false;
unique_repair_silent_opts.type = NAME_REPAIR_unique;
unique_repair_silent_opts.fn = r_null;
unique_repair_silent_opts.quiet = true;
no_repair_opts.type = NAME_REPAIR_none;
no_repair_opts.fn = r_null;
no_repair_opts.quiet = true;
}void vctrs_init_proxy_restore(r_obj* ns) {
syms_vec_restore_dispatch = r_sym("vec_restore_dispatch");
fns_vec_restore_dispatch = r_eval(syms_vec_restore_dispatch, ns);
}void vctrs_init_ptype(r_obj* ns) {
syms_vec_ptype = r_sym("vec_ptype");
}void vctrs_init_ptype2(r_obj* ns) { }void vctrs_init_ptype2_dispatch(r_obj* ns) {
syms_vec_ptype2_default = r_sym("vec_default_ptype2");
}void vctrs_init_rep(r_obj* ns) { }void vctrs_init_slice(r_obj* ns) {
syms.vec_slice_altrep = r_sym("vec_slice_altrep");
syms.vec_slice_dispatch_integer64 = r_sym("vec_slice_dispatch_integer64");
syms.vec_slice_fallback = r_sym("vec_slice_fallback");
syms.vec_slice_fallback_integer64 = r_sym("vec_slice_fallback_integer64");
fns.vec_slice_altrep = r_eval(syms.vec_slice_altrep, ns);
fns.vec_slice_dispatch_integer64 = r_eval(syms.vec_slice_dispatch_integer64, ns);
fns.vec_slice_fallback = r_eval(syms.vec_slice_fallback, ns);
fns.vec_slice_fallback_integer64 = r_eval(syms.vec_slice_fallback_integer64, ns);
}void vctrs_init_slice_assign(r_obj* ns) {
syms_vec_assign_fallback = r_sym("vec_assign_fallback");
fns_vec_assign_fallback = r_eval(syms_vec_assign_fallback, ns);
}void vctrs_init_subscript(r_obj* ns) {
syms_new_error_subscript_type = r_sym("new_error_subscript_type");
syms_new_dbl_cast_subscript_body = r_sym("new_cnd_bullets_subscript_lossy_cast");
syms_lossy_err = r_sym("lossy_err");
fns_cnd_body_subscript_dim = r_eval(r_sym("cnd_body_subscript_dim"), ns);
}void vctrs_init_subscript_loc(r_obj* ns) { }void vctrs_init_type_data_frame(r_obj* ns) {
syms_df_lossy_cast = r_sym("df_lossy_cast");
fns_df_lossy_cast = r_eval(syms_df_lossy_cast, ns);
}void vctrs_init_type_date_time(SEXP ns) {
syms_tz = Rf_install("tz");
syms_as_date = Rf_install("as.Date");
syms_as_posixct = Rf_install("as.POSIXct");
syms_as_posixlt = Rf_install("as.POSIXlt");
syms_date_as_character = Rf_install("date_as_character");
syms_chr_date_as_posixct = Rf_install("chr_date_as_posixct");
syms_chr_date_as_posixlt = Rf_install("chr_date_as_posixlt");
fns_as_date = r_env_get(R_BaseEnv, syms_as_date);
fns_as_posixct = r_env_get(R_BaseEnv, syms_as_posixct);
fns_as_posixlt = r_env_get(R_BaseEnv, syms_as_posixlt);
fns_date_as_character = r_env_get(ns, syms_date_as_character);
fns_chr_date_as_posixct = r_env_get(ns, syms_chr_date_as_posixct);
fns_chr_date_as_posixlt = r_env_get(ns, syms_chr_date_as_posixlt);
}void vctrs_init_type_info(r_obj* ns) {
}void vctrs_init_unspecified(SEXP ns) {
{
vctrs_unspecified_class = Rf_allocVector(STRSXP, 1);
R_PreserveObject(vctrs_unspecified_class);
SET_STRING_ELT(vctrs_unspecified_class, 0, Rf_mkChar("vctrs_unspecified"));
}
vctrs_shared_empty_uns = vec_unspecified(0);
R_PreserveObject(vctrs_shared_empty_uns);
MARK_NOT_MUTABLE(vctrs_shared_empty_uns);
syms_vec_ptype_finalise_dispatch = r_sym("vec_ptype_finalise_dispatch");
fns_vec_ptype_finalise_dispatch = r_eval(syms_vec_ptype_finalise_dispatch, ns);
}void vctrs_init_utils(SEXP ns) {
vctrs_ns_env = ns;
vctrs_debug_verbose = r_is_true(Rf_GetOption1(Rf_install("vctrs:::debug")));
vctrs_method_table = r_env_get(ns, Rf_install(".__S3MethodsTable__."));
base_method_table = r_env_get(R_BaseNamespace, Rf_install(".__S3MethodsTable__."));
s4_c_method_table = r_parse_eval("environment(methods::getGeneric('c'))$.MTable", R_GlobalEnv);
R_PreserveObject(s4_c_method_table);
vctrs_shared_empty_str = Rf_mkString("");
R_PreserveObject(vctrs_shared_empty_str);
// Holds the CHARSXP objects because unlike symbols they can be
// garbage collected
strings2 = r_new_shared_vector(STRSXP, 25);
strings_dots = Rf_mkChar("...");
SET_STRING_ELT(strings2, 0, strings_dots);
strings_empty = Rf_mkChar("");
SET_STRING_ELT(strings2, 1, strings_empty);
strings_date = Rf_mkChar("Date");
SET_STRING_ELT(strings2, 2, strings_date);
strings_posixct = Rf_mkChar("POSIXct");
SET_STRING_ELT(strings2, 3, strings_posixct);
strings_posixlt = Rf_mkChar("POSIXlt");
SET_STRING_ELT(strings2, 4, strings_posixlt);
strings_posixt = Rf_mkChar("POSIXt");
SET_STRING_ELT(strings2, 5, strings_posixt);
strings_none = Rf_mkChar("none");
SET_STRING_ELT(strings2, 6, strings_none);
strings_minimal = Rf_mkChar("minimal");
SET_STRING_ELT(strings2, 7, strings_minimal);
strings_unique = Rf_mkChar("unique");
SET_STRING_ELT(strings2, 8, strings_unique);
strings_universal = Rf_mkChar("universal");
SET_STRING_ELT(strings2, 9, strings_universal);
strings_check_unique = Rf_mkChar("check_unique");
SET_STRING_ELT(strings2, 10, strings_check_unique);
strings_unique_quiet = Rf_mkChar("unique_quiet");
SET_STRING_ELT(strings2, 23, strings_unique_quiet);
strings_universal_quiet = Rf_mkChar("universal_quiet");
SET_STRING_ELT(strings2, 24, strings_universal_quiet);
strings_key = Rf_mkChar("key");
SET_STRING_ELT(strings2, 11, strings_key);
strings_loc = Rf_mkChar("loc");
SET_STRING_ELT(strings2, 12, strings_loc);
strings_val = Rf_mkChar("val");
SET_STRING_ELT(strings2, 13, strings_val);
strings_group = Rf_mkChar("group");
SET_STRING_ELT(strings2, 14, strings_group);
strings_length = Rf_mkChar("length");
SET_STRING_ELT(strings2, 15, strings_length);
strings_factor = Rf_mkChar("factor");
SET_STRING_ELT(strings2, 16, strings_factor);
strings_ordered = Rf_mkChar("ordered");
SET_STRING_ELT(strings2, 17, strings_ordered);
strings_list = Rf_mkChar("list");
SET_STRING_ELT(strings2, 18, strings_list);
strings_vctrs_vctr = Rf_mkChar("vctrs_vctr");
SET_STRING_ELT(strings2, 19, strings_vctrs_vctr);
strings_times = Rf_mkChar("times");
SET_STRING_ELT(strings2, 20, strings_times);
strings_needles = Rf_mkChar("needles");
SET_STRING_ELT(strings2, 21, strings_needles);
strings_haystack = Rf_mkChar("haystack");
SET_STRING_ELT(strings2, 22, strings_haystack);
classes_data_frame = r_new_shared_vector(STRSXP, 1);
strings_data_frame = Rf_mkChar("data.frame");
SET_STRING_ELT(classes_data_frame, 0, strings_data_frame);
classes_factor = r_new_shared_vector(STRSXP, 1);
SET_STRING_ELT(classes_factor, 0, strings_factor);
classes_ordered = r_new_shared_vector(STRSXP, 2);
SET_STRING_ELT(classes_ordered, 0, strings_ordered);
SET_STRING_ELT(classes_ordered, 1, strings_factor);
classes_date = r_new_shared_vector(STRSXP, 1);
SET_STRING_ELT(classes_date, 0, strings_date);
classes_posixct = r_new_shared_vector(STRSXP, 2);
SET_STRING_ELT(classes_posixct, 0, strings_posixct);
SET_STRING_ELT(classes_posixct, 1, strings_posixt);
chrs_subset = r_new_shared_character("subset");
chrs_extract = r_new_shared_character("extract");
chrs_assign = r_new_shared_character("assign");
chrs_rename = r_new_shared_character("rename");
chrs_remove = r_new_shared_character("remove");
chrs_negate = r_new_shared_character("negate");
chrs_null = r_new_shared_character("NULL");
chrs_logical = r_new_shared_character("logical");
chrs_integer = r_new_shared_character("integer");
chrs_double = r_new_shared_character("double");
chrs_complex = r_new_shared_character("complex");
chrs_character = r_new_shared_character("character");
chrs_raw = r_new_shared_character("raw");
chrs_list = r_new_shared_character("list");
chrs_expression = r_new_shared_character("expression");
chrs_numeric = r_new_shared_character("numeric");
chrs_function = r_new_shared_character("function");
chrs_empty = r_new_shared_character("");
chrs_cast = r_new_shared_character("cast");
chrs_error = r_new_shared_character("error");
chrs_combine = r_new_shared_character("combine");
chrs_convert = r_new_shared_character("convert");
chrs_asc = r_new_shared_character("asc");
chrs_desc = r_new_shared_character("desc");
chrs_largest = r_new_shared_character("largest");
chrs_smallest = r_new_shared_character("smallest");
chrs_which = r_new_shared_character("which");
classes_tibble = r_new_shared_vector(STRSXP, 3);
strings_tbl_df = Rf_mkChar("tbl_df");
SET_STRING_ELT(classes_tibble, 0, strings_tbl_df);
strings_tbl = Rf_mkChar("tbl");
SET_STRING_ELT(classes_tibble, 1, strings_tbl);
SET_STRING_ELT(classes_tibble, 2, strings_data_frame);
classes_vctrs_group_rle = r_new_shared_vector(STRSXP, 3);
SET_STRING_ELT(classes_vctrs_group_rle, 0, Rf_mkChar("vctrs_group_rle"));
SET_STRING_ELT(classes_vctrs_group_rle, 1, Rf_mkChar("vctrs_rcrd"));
SET_STRING_ELT(classes_vctrs_group_rle, 2, Rf_mkChar("vctrs_vctr"));
vctrs_shared_empty_date = r_new_shared_vector(REALSXP, 0);
Rf_setAttrib(vctrs_shared_empty_date, R_ClassSymbol, classes_date);
vctrs_shared_na_cpl.i = NA_REAL;
vctrs_shared_na_cpl.r = NA_REAL;
vctrs_shared_missing_lgl = r_new_shared_vector(LGLSXP, 1);
LOGICAL(vctrs_shared_missing_lgl)[0] = NA_LOGICAL;
vctrs_shared_missing_int = r_new_shared_vector(INTSXP, 1);
INTEGER(vctrs_shared_missing_int)[0] = NA_INTEGER;
vctrs_shared_missing_dbl = r_new_shared_vector(REALSXP, 1);
REAL(vctrs_shared_missing_dbl)[0] = NA_REAL;
vctrs_shared_missing_cpl = r_new_shared_vector(CPLXSXP, 1);
COMPLEX(vctrs_shared_missing_cpl)[0] = vctrs_shared_na_cpl;
// No actual `NA` value for raw, but we always use `0`
vctrs_shared_missing_raw = r_new_shared_vector(RAWSXP, 1);
RAW(vctrs_shared_missing_raw)[0] = 0;
vctrs_shared_missing_chr = r_new_shared_vector(STRSXP, 1);
SET_STRING_ELT(vctrs_shared_missing_chr, 0, NA_STRING);
vctrs_shared_missing_list = r_new_shared_vector(VECSXP, 1);
SET_VECTOR_ELT(vctrs_shared_missing_list, 0, R_NilValue);
vctrs_shared_zero_int = r_new_shared_vector(INTSXP, 1);
INTEGER(vctrs_shared_zero_int)[0] = 0;
syms_i = Rf_install("i");
syms_j = Rf_install("j");
syms_n = Rf_install("n");
syms_x = Rf_install("x");
syms_y = Rf_install("y");
syms_x_size = Rf_install("x_size");
syms_y_size = Rf_install("y_size");
syms_to = Rf_install("to");
syms_dots = Rf_install("...");
syms_bracket = Rf_install("[");
syms_x_arg = Rf_install("x_arg");
syms_y_arg = Rf_install("y_arg");
syms_to_arg = Rf_install("to_arg");
syms_times_arg = Rf_install("times_arg");
syms_subscript_arg = Rf_install("subscript_arg");
syms_needles_arg = Rf_install("needles_arg");
syms_haystack_arg = Rf_install("haystack_arg");
syms_out = Rf_install("out");
syms_value = Rf_install("value");
syms_quiet = Rf_install("quiet");
syms_dot_name_spec = Rf_install(".name_spec");
syms_outer = Rf_install("outer");
syms_inner = Rf_install("inner");
syms_tilde = Rf_install("~");
syms_dot_environment = Rf_install(".Environment");
syms_ptype = Rf_install("ptype");
syms_missing = R_MissingArg;
syms_size = Rf_install("size");
syms_subscript_action = Rf_install("subscript_action");
syms_subscript_type = Rf_install("subscript_type");
syms_repair = Rf_install("repair");
syms_tzone = Rf_install("tzone");
syms_data = Rf_install("data");
syms_try_catch_impl = Rf_install("try_catch_impl");
syms_try_catch_hnd = Rf_install("try_catch_hnd");
syms_vctrs_error_incompatible_type = Rf_install("vctrs_error_incompatible_type");
syms_vctrs_error_cast_lossy = Rf_install("vctrs_error_cast_lossy");
syms_cnd_signal = Rf_install("cnd_signal");
syms_logical = Rf_install("logical");
syms_numeric = Rf_install("numeric");
syms_character = Rf_install("character");
syms_body = Rf_install("body");
syms_parent = Rf_install("parent");
syms_s3_methods_table = Rf_install(".__S3MethodsTable__.");
syms_from_dispatch = Rf_install("vctrs:::from_dispatch");
syms_s3_fallback = Rf_install("vctrs:::s3_fallback");
syms_stop_incompatible_type = Rf_install("stop_incompatible_type");
syms_stop_incompatible_size = Rf_install("stop_incompatible_size");
syms_stop_assert_size = Rf_install("stop_assert_size");
syms_stop_matches_overflow = Rf_install("stop_matches_overflow");
syms_stop_matches_nothing = Rf_install("stop_matches_nothing");
syms_stop_matches_remaining = Rf_install("stop_matches_remaining");
syms_stop_matches_incomplete = Rf_install("stop_matches_incomplete");
syms_stop_matches_multiple = Rf_install("stop_matches_multiple");
syms_warn_matches_multiple = Rf_install("warn_matches_multiple");
syms_stop_matches_relationship_one_to_one = Rf_install("stop_matches_relationship_one_to_one");
syms_stop_matches_relationship_one_to_many = Rf_install("stop_matches_relationship_one_to_many");
syms_stop_matches_relationship_many_to_one = Rf_install("stop_matches_relationship_many_to_one");
syms_warn_matches_relationship_many_to_many = Rf_install("warn_matches_relationship_many_to_many");
syms_stop_combine_unmatched = Rf_install("stop_combine_unmatched");
syms_action = Rf_install("action");
syms_vctrs_common_class_fallback = Rf_install(c_strs_vctrs_common_class_fallback);
syms_fallback_class = Rf_install("fallback_class");
syms_abort = Rf_install("abort");
syms_message = Rf_install("message");
syms_chr_proxy_collate = Rf_install("chr_proxy_collate");
syms_actual = Rf_install("actual");
syms_required = Rf_install("required");
syms_call = Rf_install("call");
syms_dot_call = Rf_install(".call");
syms_which = Rf_install("which");
syms_slice_value = Rf_install("slice_value");
syms_index_style = Rf_install("index_style");
syms_loc = Rf_install("loc");
fns_bracket = r_env_get(R_BaseEnv, syms_bracket);
fns_quote = r_env_get(R_BaseEnv, Rf_install("quote"));
fns_names = r_env_get(R_BaseEnv, Rf_install("names"));
new_env_call = r_parse_eval("as.call(list(new.env, TRUE, NULL, NULL))", R_BaseEnv);
R_PreserveObject(new_env_call);
new_env__parent_node = CDDR(new_env_call);
new_env__size_node = CDR(new_env__parent_node);
rlang_sym_as_character = (SEXP (*)(SEXP)) R_GetCCallable("rlang", "rlang_sym_as_character");
syms_as_data_frame2 = Rf_install("as.data.frame2");
syms_colnames = Rf_install("colnames");
fns_as_data_frame2 = r_env_get(ns, syms_as_data_frame2);
fns_colnames = r_env_get(R_BaseEnv, syms_colnames);
compact_seq_class_string = "vctrs_compact_seq";
compact_seq_classes = Rf_allocVector(STRSXP, 1);
R_PreserveObject(compact_seq_classes);
SET_STRING_ELT(compact_seq_classes, 0, Rf_mkChar(compact_seq_class_string));
compact_rep_class_string = "vctrs_compact_rep";
compact_rep_classes = Rf_allocVector(STRSXP, 1);
R_PreserveObject(compact_rep_classes);
SET_STRING_ELT(compact_rep_classes, 0, Rf_mkChar(compact_rep_class_string));
compact_condition_class_string = "vctrs_compact_condition";
compact_condition_classes = Rf_allocVector(STRSXP, 1);
R_PreserveObject(compact_condition_classes);
SET_STRING_ELT(compact_condition_classes, 0, Rf_mkChar(compact_condition_class_string));
rlang_result_names = Rf_allocVector(STRSXP, 2);
R_PreserveObject(rlang_result_names);
SET_STRING_ELT(rlang_result_names, 0, Rf_mkChar("ok"));
SET_STRING_ELT(rlang_result_names, 1, Rf_mkChar("err"));
rlang_result_class = Rf_allocVector(STRSXP, 1);
R_PreserveObject(rlang_result_class);
SET_STRING_ELT(rlang_result_class, 0, Rf_mkChar("rlang_result"));
// We assume the following in `union vctrs_dbl_indicator`
VCTRS_ASSERT(sizeof(double) == sizeof(int64_t));
VCTRS_ASSERT(sizeof(double) == 2 * sizeof(int));
// We assume the following in `vec_order()`
VCTRS_ASSERT(sizeof(int) == sizeof(int32_t));
VCTRS_ASSERT(sizeof(double) == sizeof(int64_t));
}r_obj* vctrs_is_altrep(r_obj* x) {
return r_lgl(ALTREP(x));
}SEXP vctrs_is_unspecified(SEXP x) {
return Rf_ScalarLogical(vec_is_unspecified(x));
}r_obj* vctrs_list_drop_empty(r_obj* x) {
return list_drop_empty(x);
}SEXP vctrs_locate_complete(SEXP x) {
return vec_locate_complete(x);
}void vctrs_n_distinct_loop(struct dictionary* d, R_len_t n) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VCTRS_N_DISTINCT_LOOP(nil_dict_hash_scalar); break;
case VCTRS_TYPE_logical: VCTRS_N_DISTINCT_LOOP(lgl_dict_hash_scalar); break;
case VCTRS_TYPE_integer: VCTRS_N_DISTINCT_LOOP(int_dict_hash_scalar); break;
case VCTRS_TYPE_double: VCTRS_N_DISTINCT_LOOP(dbl_dict_hash_scalar); break;
case VCTRS_TYPE_complex: VCTRS_N_DISTINCT_LOOP(cpl_dict_hash_scalar); break;
case VCTRS_TYPE_character: VCTRS_N_DISTINCT_LOOP(chr_dict_hash_scalar); break;
case VCTRS_TYPE_raw: VCTRS_N_DISTINCT_LOOP(raw_dict_hash_scalar); break;
case VCTRS_TYPE_list: VCTRS_N_DISTINCT_LOOP(list_dict_hash_scalar); break;
case VCTRS_TYPE_dataframe: VCTRS_N_DISTINCT_LOOP(df_dict_hash_scalar); break;
default: stop_unimplemented_vctrs_type("vctrs_n_distinct_loop", d->p_poly_vec->type);
}
}SEXP vctrs_n_fields(SEXP x) {
check_rcrd(x);
return Rf_ScalarInteger(Rf_length(x));
}SEXP vctrs_new_date(SEXP x) {
return new_date(x);
}SEXP vctrs_new_datetime(SEXP x, SEXP tzone) {
return new_datetime(x, tzone);
}SEXP vctrs_order(
SEXP x,
SEXP direction,
SEXP na_value,
SEXP nan_distinct,
SEXP chr_proxy_collate
) {
bool c_nan_distinct = parse_nan_distinct(nan_distinct);
return vec_order(x, direction, na_value, c_nan_distinct, chr_proxy_collate);
}SEXP vctrs_s3_find_method(SEXP generic, SEXP x, SEXP table) {
return s3_find_method(r_chr_get_c_string(generic, 0), x, table);
}SEXP vctrs_slice_complete(SEXP x) {
return vec_slice_complete(x);
}SEXP vctrs_try_catch_callback(SEXP ptr, SEXP cnd) {
struct r_try_catch_data* data = (struct r_try_catch_data*) R_ExternalPtrAddr(ptr);
if (cnd == R_NilValue) {
if (data->fn) {
data->fn(data->fn_data);
}
} else {
data->err = cnd;
if (data->hnd) {
data->hnd(data->hnd_data);
}
}
return R_NilValue;
}r_obj* vctrs_typeof(r_obj* x, r_obj* dispatch) {
enum vctrs_type type;
if (r_lgl_get(dispatch, 0)) {
type = vec_proxy_info(x).type;
} else {
type = vec_typeof(x);
}
return r_chr(vec_type_as_str(type));
}void vctrs_unique_loc_loop(struct dictionary* d, struct growable* g, R_len_t n) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VCTRS_UNIQUE_LOC_LOOP(nil_dict_hash_with); break;
case VCTRS_TYPE_logical: VCTRS_UNIQUE_LOC_LOOP(lgl_dict_hash_with); break;
case VCTRS_TYPE_integer: VCTRS_UNIQUE_LOC_LOOP(int_dict_hash_with); break;
case VCTRS_TYPE_double: VCTRS_UNIQUE_LOC_LOOP(dbl_dict_hash_with); break;
case VCTRS_TYPE_complex: VCTRS_UNIQUE_LOC_LOOP(cpl_dict_hash_with); break;
case VCTRS_TYPE_character: VCTRS_UNIQUE_LOC_LOOP(chr_dict_hash_with); break;
case VCTRS_TYPE_raw: VCTRS_UNIQUE_LOC_LOOP(raw_dict_hash_with); break;
case VCTRS_TYPE_list: VCTRS_UNIQUE_LOC_LOOP(list_dict_hash_with); break;
case VCTRS_TYPE_dataframe: VCTRS_UNIQUE_LOC_LOOP(df_dict_hash_with); break;
default: stop_unimplemented_vctrs_type("vctrs_unique_loc_loop", d->p_poly_vec->type);
}
}SEXP vctrs_unspecified(SEXP n) {
if (Rf_length(n) != 1) {
Rf_errorcall(R_NilValue, "`n` must be a single number");
}
if (TYPEOF(n) != INTSXP) {
n = vec_cast(n,
r_globals.empty_int,
vec_args.empty,
vec_args.empty,
r_lazy_null);
}
int len = INTEGER(n)[0];
return vec_unspecified(len);
}r_obj* vctrs_validate_minimal_names(r_obj* names, r_obj* n_) {
r_ssize n = -1;
if (r_typeof(n_) == R_TYPE_integer) {
if (r_length(n_) != 1) {
r_stop_internal("`n` must be a single number.");
}
n = r_int_get(n_, 0);
}
vec_validate_minimal_names(names, n, r_lazy_null);
return names;
}r_obj* vctrs_validate_name_repair_arg(r_obj* arg) {
struct name_repair_opts opts = new_name_repair_opts(arg,
r_lazy_null,
true,
r_lazy_null);
if (opts.type == NAME_REPAIR_custom) {
return opts.fn;
} else if (r_length(arg) != 1) {
return r_str_as_character(r_str(name_repair_arg_as_c_string(opts.type)));
} else {
return arg;
}
}bool vec_any_missing(r_obj* x) {
return vec_first_missing(x) != vec_size(x);
}const char* vec_arg_format(struct vctrs_arg* p_arg) {
r_obj* arg = KEEP(vctrs_arg(p_arg));
const char* out = r_format_error_arg(arg);
FREE(1);
return out;
}static inline struct vctrs_arg vec_as_arg(SEXP x) {
if (x == R_NilValue) {
return *vec_args.empty;
}
if (!r_is_string(x)) {
Rf_errorcall(R_NilValue, "Argument tag must be a string.");
}
return new_wrapper_arg(NULL, r_chr_get_c_string(x, 0));
}r_obj* vec_as_location_opts(r_obj* subscript,
r_ssize n,
r_obj* names,
const struct location_opts* opts) {
ERR err = NULL;
subscript = vec_as_subscript_opts(subscript, &opts->subscript_opts, &err);
KEEP2(subscript, err);
if (err) {
r_cnd_signal(err);
r_stop_unreachable();
}
r_obj* out = r_null;
switch (r_typeof(subscript)) {
case R_TYPE_null: out = r_globals.empty_int; break;
case R_TYPE_logical: out = lgl_as_location(subscript, n, opts); break;
case R_TYPE_integer: out = int_as_location(subscript, n, opts); break;
case R_TYPE_double: out = dbl_as_location(subscript, n, opts); break;
case R_TYPE_character: out = chr_as_location(subscript, names, opts); break;
default: r_stop_unimplemented_type(r_typeof(subscript));
}
FREE(2);
return out;
}r_obj* vec_as_names(r_obj* names, const struct name_repair_opts* opts) {
if (!opts) {
return names;
}
switch (opts->type) {
case NAME_REPAIR_none: return names;
case NAME_REPAIR_minimal: return ffi_as_minimal_names(names);
case NAME_REPAIR_unique: return vec_as_unique_names(names, opts->quiet);
case NAME_REPAIR_universal: return vec_as_universal_names(names, opts->quiet);
case NAME_REPAIR_check_unique: return check_unique_names(names, opts);
case NAME_REPAIR_custom: return vec_as_custom_names(names, opts);
}
r_stop_unreachable();
}r_ssize vec_as_short_length(r_obj* n,
struct vctrs_arg* p_arg,
struct r_lazy call) {
r_ssize out = vec_as_ssize(n, p_arg, call);
if (out < 0) {
r_abort_lazy_call(call,
"%s must be a positive number or zero.",
vec_arg_format(p_arg));
}
if (out > INT_MAX) {
// Ideally we'd mention long vector support in an info bullets
r_abort_lazy_call(call,
"%s is too large a number and long vectors are not supported.",
vec_arg_format(p_arg));
}
return out;
}r_obj* vec_as_subscript_opts(r_obj* subscript,
const struct subscript_opts* opts,
ERR* err) {
if (vec_dim_n(subscript) != 1) {
*err = new_error_subscript_type(subscript, opts, fns_cnd_body_subscript_dim);
return r_null;
}
r_keep_loc subscript_pi;
KEEP_HERE(subscript, &subscript_pi);
r_obj* orig_names = KEEP(r_names(subscript));
switch (r_typeof(subscript)) {
case R_TYPE_null:
if (opts->numeric == SUBSCRIPT_TYPE_ACTION_CAST) {
subscript = r_globals.empty_int;
}
break;
case R_TYPE_symbol:
if (opts->character == SUBSCRIPT_TYPE_ACTION_CAST) {
subscript = rlang_sym_as_character(subscript);
}
break;
default:
break;
}
KEEP_AT(subscript, subscript_pi);
if (!obj_is_vector(subscript, VCTRS_ALLOW_NULL_no)) {
*err = new_error_subscript_type(subscript, opts, r_null);
FREE(2);
return r_null;
}
if (r_is_object(subscript)) {
subscript = obj_cast_subscript(subscript, opts, err);
} else if (r_typeof(subscript) == R_TYPE_double) {
subscript = dbl_cast_subscript(subscript, opts, err);
}
KEEP_AT(subscript, subscript_pi);
if (*err) {
FREE(2);
return r_null;
}
// Coerce unspecified vectors to integer only if logical indices are
// not allowed
if (opts->logical == SUBSCRIPT_TYPE_ACTION_ERROR && vec_is_unspecified(subscript)) {
struct vctrs_arg* arg = opts->subscript_arg;
if (opts->numeric == SUBSCRIPT_TYPE_ACTION_CAST) {
subscript = vec_cast(subscript,
r_globals.empty_int,
arg,
NULL,
r_lazy_null);
} else {
subscript = vec_cast(subscript,
r_globals.empty_chr,
arg,
NULL,
r_lazy_null);
}
}
KEEP_AT(subscript, subscript_pi);
enum subscript_type_action action = SUBSCRIPT_TYPE_ACTION_ERROR;
switch (r_typeof(subscript)) {
case R_TYPE_logical: action = opts->logical; break;
case R_TYPE_integer: action = opts->numeric; break;
case R_TYPE_character: action = opts->character; break;
default: break;
}
if (action == SUBSCRIPT_TYPE_ACTION_ERROR) {
*err = new_error_subscript_type(subscript, opts, r_null);
FREE(2);
return r_null;
}
if (orig_names != r_null) {
// FIXME: Handle names in cast methods
subscript = r_clone_referenced(subscript);
KEEP_AT(subscript, subscript_pi);
r_attrib_poke_names(subscript, orig_names);
}
FREE(2);
return subscript;
}r_obj* vec_as_unique_names(r_obj* names, bool quiet) {
if (is_unique_names(names) && !any_has_suffix(names)) {
return names;
} else {
return(as_unique_names_impl(names, quiet));
}
}r_obj* vec_as_universal_names(r_obj* names, bool quiet) {
r_obj* quiet_obj = KEEP(r_lgl(quiet));
r_obj* out = vctrs_dispatch2(syms_as_universal_names, fns_as_universal_names,
syms_names, names,
syms_quiet, quiet_obj);
FREE(1);
return out;
}r_obj* vec_assign_fallback(
r_obj* x,
r_obj* index,
r_obj* value,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
r_obj* ffi_slice_value;
switch (slice_value) {
case ASSIGNMENT_SLICE_VALUE_no: ffi_slice_value = r_false; break;
case ASSIGNMENT_SLICE_VALUE_yes: ffi_slice_value = r_true; break;
default: r_stop_unreachable();
}
r_obj* ffi_index_style;
switch (index_style) {
case VCTRS_INDEX_STYLE_location: ffi_index_style = chrs.location; break;
case VCTRS_INDEX_STYLE_condition: ffi_index_style = chrs.condition; break;
default: r_stop_unreachable();
}
return vctrs_dispatch5(syms_vec_assign_fallback, fns_vec_assign_fallback,
syms_x, x,
syms_i, index,
syms_slice_value, ffi_slice_value,
syms_index_style, ffi_index_style,
syms_value, value);
}r_obj* vec_assign_opts(r_obj* x,
r_obj* index,
r_obj* value,
const struct vec_assign_opts* p_opts) {
if (x == r_null) {
return r_null;
}
struct r_lazy call = r_lazy_is_null(p_opts->call) ? lazy_calls.vec_assign : p_opts->call;
struct vctrs_arg* x_arg = r_lazy_is_null(p_opts->call) ? vec_args.x : p_opts->x_arg;
struct vctrs_arg* value_arg = r_lazy_is_null(p_opts->call) ? vec_args.value : p_opts->value_arg;
obj_check_vector(x, VCTRS_ALLOW_NULL_no, x_arg, call);
obj_check_vector(value, VCTRS_ALLOW_NULL_no, value_arg, call);
const r_ssize x_size = vec_size(x);
// Determine index style. Logical condition indices follow an optimized path.
enum vctrs_index_style index_style =
(is_condition_index(index) && r_length(index) == x_size) ?
VCTRS_INDEX_STYLE_condition :
VCTRS_INDEX_STYLE_location;
if (index_style == VCTRS_INDEX_STYLE_location) {
// Validate and convert to integer locations with `vec_as_location()`
r_obj* x_names = KEEP(vec_names(x));
const struct location_opts location_opts = new_location_opts_assign();
index = vec_as_location_opts(
index,
x_size,
x_names,
&location_opts
);
FREE(1);
}
KEEP(index);
// We won't be proxying recursively
const bool recursively_proxied = false;
struct vec_proxy_assign_opts assign_opts = {
.assign_names = p_opts->assign_names,
.ignore_outer_names = p_opts->ignore_outer_names,
.call = call,
.x_arg = x_arg,
.value_arg = value_arg,
.index_style = index_style,
.slice_value = p_opts->slice_value,
.ownership = p_opts->ownership,
.recursively_proxied = recursively_proxied
};
struct vec_restore_opts restore_opts = {
.ownership = p_opts->ownership,
.recursively_proxied = recursively_proxied
};
// Cast `value` and check that it can recycle
value = KEEP(vec_cast(value, x, assign_opts.value_arg, assign_opts.x_arg, assign_opts.call));
check_recyclable_against_index(
value,
index,
x_size,
assign_opts.slice_value,
assign_opts.index_style,
assign_opts.value_arg,
assign_opts.call
);
r_obj* proxy = KEEP(vec_proxy(x));
proxy = KEEP(vec_proxy_assign_opts(proxy, index, value, &assign_opts));
r_obj* out = vec_restore_opts(proxy, x, &restore_opts);
FREE(4);
return out;
}SEXP vec_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
switch (vec_proxy_typeof(proxy)) {
case VCTRS_TYPE_logical: return lgl_assign_shaped(proxy, index, value, ownership, slice_value, index_style);
case VCTRS_TYPE_integer: return int_assign_shaped(proxy, index, value, ownership, slice_value, index_style);
case VCTRS_TYPE_double: return dbl_assign_shaped(proxy, index, value, ownership, slice_value, index_style);
case VCTRS_TYPE_complex: return cpl_assign_shaped(proxy, index, value, ownership, slice_value, index_style);
case VCTRS_TYPE_character: return chr_assign_shaped(proxy, index, value, ownership, slice_value, index_style);
case VCTRS_TYPE_raw: return raw_assign_shaped(proxy, index, value, ownership, slice_value, index_style);
case VCTRS_TYPE_list: return list_assign_shaped(proxy, index, value, ownership, slice_value, index_style);
default: stop_unimplemented_vctrs_type("vec_assign_shaped", vec_proxy_typeof(proxy));
}
}static inline SEXP vec_bare_dim(SEXP x) {
return r_dim(x);
}static inline R_len_t vec_bare_dim_n(SEXP x) {
return Rf_length(vec_bare_dim(x));
}enum vctrs_type vec_base_typeof(r_obj* x, bool proxied) {
switch (r_typeof(x)) {
// Atomic types are always vectors
case R_TYPE_null: return VCTRS_TYPE_null;
case R_TYPE_logical: return VCTRS_TYPE_logical;
case R_TYPE_integer: return VCTRS_TYPE_integer;
case R_TYPE_double: return VCTRS_TYPE_double;
case R_TYPE_complex: return VCTRS_TYPE_complex;
case R_TYPE_character: return VCTRS_TYPE_character;
case R_TYPE_raw: return VCTRS_TYPE_raw;
case R_TYPE_list:
// Bare lists and data frames are vectors
if (!r_is_object(x)) return VCTRS_TYPE_list;
if (is_data_frame(x)) return VCTRS_TYPE_dataframe;
// S3 lists are only vectors if they are proxied
if (proxied || r_inherits(x, "list")) return VCTRS_TYPE_list;
// fallthrough
default: return VCTRS_TYPE_scalar;
}
}r_obj* vec_c(
r_obj* xs,
r_obj* ptype,
r_obj* name_spec,
const struct name_repair_opts* name_repair,
struct vctrs_arg* p_error_arg,
struct r_lazy error_call
) {
return list_combine_for_vec_c(
xs,
ptype,
name_spec,
name_repair,
p_error_arg,
error_call
);
}r_obj* vec_cast_common(r_obj* xs,
r_obj* to,
struct vctrs_arg* p_arg,
struct r_lazy call) {
return vec_cast_common_params(xs,
to,
S3_FALLBACK_false,
p_arg,
call);
}r_obj* vec_cast_common_opts(r_obj* xs,
r_obj* to,
const struct cast_common_opts* opts) {
r_obj* type = KEEP(vec_ptype_common(
xs,
to,
PTYPE_FINALISE_DEFAULT,
opts->s3_fallback,
opts->p_arg,
opts->call
));
const r_ssize xs_size = r_length(xs);
r_obj* xs_names = KEEP(r_names(xs));
r_obj* const* v_xs = r_list_cbegin(xs);
r_obj* out = KEEP(r_alloc_list(xs_size));
r_attrib_poke_names(out, xs_names);
r_ssize i = 0;
struct vctrs_arg* p_x_arg = new_subscript_arg(
opts->p_arg,
xs_names,
xs_size,
&i
);
KEEP(p_x_arg->shelter);
for (; i < xs_size; ++i) {
r_obj* elt = v_xs[i];
struct cast_opts cast_opts = {
.x = elt,
.to = type,
.p_x_arg = p_x_arg,
.call = opts->call,
.s3_fallback = opts->s3_fallback
};
r_list_poke(out, i, vec_cast_opts(&cast_opts));
}
FREE(4);
return out;
}r_obj* vec_cast_default(r_obj* x,
r_obj* to,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_to_arg,
struct r_lazy call,
enum s3_fallback s3_fallback) {
return vec_cast_default_full(x, to, p_x_arg, p_to_arg, call, s3_fallback, false);
}r_obj* vec_cast_default_full(r_obj* x,
r_obj* to,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_to_arg,
struct r_lazy call,
enum s3_fallback s3_fallback,
bool from_dispatch) {
r_obj* ffi_s3_fallback = KEEP(r_int(s3_fallback));
r_obj* ffi_x_arg = KEEP(vctrs_arg(p_x_arg));
r_obj* ffi_to_arg = KEEP(vctrs_arg(p_to_arg));
r_obj* ffi_call = KEEP(r_lazy_eval(call));
r_obj* out = vctrs_eval_mask7(syms.vec_default_cast,
syms_x, x,
syms_to, to,
syms_x_arg, ffi_x_arg,
syms_to_arg, ffi_to_arg,
syms_call, ffi_call,
syms_from_dispatch, r_lgl(from_dispatch),
syms_s3_fallback, ffi_s3_fallback);
FREE(4);
return out;
}r_obj* vec_cast_dispatch_native(const struct cast_opts* opts,
enum vctrs_type x_type,
enum vctrs_type to_type,
bool* lossy) {
r_obj* x = opts->x;
r_obj* to = opts->to;
struct vctrs_arg* x_arg = opts->p_x_arg;
struct vctrs_arg* to_arg = opts->p_to_arg;
int dir = 0;
enum vctrs_type2_s3 type2_s3 = vec_typeof2_s3_impl(x, to, x_type, to_type, &dir);
switch (type2_s3) {
case VCTRS_TYPE2_S3_character_bare_factor:
if (dir == 0) {
return chr_as_factor(x, to, lossy, to_arg);
} else {
return fct_as_character(x, x_arg);
}
case VCTRS_TYPE2_S3_character_bare_ordered:
if (dir == 0) {
return chr_as_ordered(x, to, lossy, to_arg);
} else {
return ord_as_character(x, x_arg);
}
case VCTRS_TYPE2_S3_bare_factor_bare_factor:
return fct_as_factor(x, to, lossy, x_arg, to_arg);
case VCTRS_TYPE2_S3_bare_ordered_bare_ordered:
return ord_as_ordered(opts);
case VCTRS_TYPE2_S3_bare_date_bare_posixct:
if (dir == 0) {
return date_as_posixct(x, to);
} else {
return posixct_as_date(x, lossy);
}
case VCTRS_TYPE2_S3_bare_date_bare_posixlt:
if (dir == 0) {
return date_as_posixlt(x, to);
} else {
return posixlt_as_date(x, lossy);
}
case VCTRS_TYPE2_S3_bare_posixct_bare_posixlt:
if (dir == 0) {
return posixct_as_posixlt(x, to);
} else {
return posixlt_as_posixct(x, to);
}
case VCTRS_TYPE2_S3_bare_date_bare_date:
return date_as_date(x);
case VCTRS_TYPE2_S3_bare_posixct_bare_posixct:
return posixct_as_posixct(x, to);
case VCTRS_TYPE2_S3_bare_posixlt_bare_posixlt:
return posixlt_as_posixlt(x, to);
case VCTRS_TYPE2_S3_dataframe_bare_tibble:
if (dir == 0) {
return tib_cast(opts);
} else {
return df_cast_opts(opts);
}
case VCTRS_TYPE2_S3_bare_tibble_bare_tibble:
return tib_cast(opts);
default:
return r_null;
}
}r_obj* vec_cast_e(const struct cast_opts* opts,
ERR* err) {
struct cast_err_data data = {
.opts = opts,
.out = r_null
};
*err = r_try_catch(&vec_cast_e_cb,
&data,
syms_vctrs_error_incompatible_type,
NULL,
NULL);
return data.out;
}void vec_cast_e_cb(void* data_) {
struct cast_err_data* data = (struct cast_err_data*) data_;
data->out = vec_cast_opts(data->opts);
}r_obj* vec_cast_switch_native(const struct cast_opts* opts,
enum vctrs_type x_type,
enum vctrs_type to_type,
bool* lossy) {
r_obj* x = opts->x;
int dir = 0;
enum vctrs_type2 type2 = vec_typeof2_impl(x_type, to_type, &dir);
switch (type2) {
case VCTRS_TYPE2_logical_logical:
case VCTRS_TYPE2_integer_integer:
case VCTRS_TYPE2_double_double:
case VCTRS_TYPE2_complex_complex:
case VCTRS_TYPE2_raw_raw:
case VCTRS_TYPE2_character_character:
case VCTRS_TYPE2_list_list:
return x;
case VCTRS_TYPE2_logical_integer:
if (dir == 0) {
return lgl_as_integer(x, lossy);
} else {
return int_as_logical(x, lossy);
}
case VCTRS_TYPE2_logical_double:
if (dir == 0) {
return lgl_as_double(x, lossy);
} else {
return dbl_as_logical(x, lossy);
}
case VCTRS_TYPE2_integer_double:
if (dir == 0) {
return int_as_double(x, lossy);
} else {
return dbl_as_integer(x, lossy);
}
case VCTRS_TYPE2_dataframe_dataframe:
return df_cast_opts(opts);
default:
break;
}
return r_null;
}void vec_check_size(
r_obj* x,
r_ssize size,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
if (!vec_is_size(x, size, allow_null, p_x_arg, call)) {
const r_ssize x_size = vec_size_params(x, p_x_arg, call);
stop_assert_size(x_size, size, p_x_arg, call);
}
}r_obj* vec_chop(r_obj* x, r_obj* indices, r_obj* sizes) {
const r_ssize n = vec_size(x);
r_obj* names = KEEP(vec_names(x));
if (indices != r_null && sizes != r_null) {
r_abort_lazy_call(r_lazy_null, "Can't supply both `indices` and `sizes`.");
}
if (indices != r_null) {
const bool allow_compact = false;
indices = list_as_locations(indices, n, names, allow_compact);
}
KEEP(indices);
if (sizes != r_null) {
sizes = vec_as_chop_sizes(sizes, n);
}
KEEP(sizes);
r_obj* out = vec_chop_unsafe(x, indices, sizes);
FREE(3);
return out;
}r_obj* vec_chop_base(r_obj* x,
struct vctrs_proxy_info info,
struct vctrs_chop_indices* p_indices) {
if (vec_requires_fallback(x, info)) {
// Fallback to `[` if the class doesn't implement a proxy. This is
// to be maximally compatible with existing classes.
if (info.type == VCTRS_TYPE_scalar) {
r_abort_lazy_call(r_lazy_null, "Can't slice a scalar");
}
if (has_dim(x)) {
return chop_fallback_shaped(x, p_indices);
} else {
return chop_fallback(x, p_indices);
}
}
switch (info.type) {
case VCTRS_TYPE_logical:
case VCTRS_TYPE_integer:
case VCTRS_TYPE_double:
case VCTRS_TYPE_complex:
case VCTRS_TYPE_character:
case VCTRS_TYPE_raw:
case VCTRS_TYPE_list: {
if (has_dim(x)) {
return chop_shaped(x, info, p_indices);
} else {
return chop(x, info, p_indices);
}
}
case VCTRS_TYPE_dataframe: {
return chop_df(x, info, p_indices);
}
default:
obj_check_vector(x, VCTRS_ALLOW_NULL_no, vec_args.empty, r_lazy_null);
stop_unimplemented_vctrs_type("vec_chop_base", info.type);
}
}r_obj* vec_chop_unsafe(r_obj* x, r_obj* indices, r_obj* sizes) {
struct vctrs_proxy_info info = vec_proxy_info(x);
KEEP(info.inner);
struct vctrs_chop_indices* p_indices = new_chop_indices(x, indices, sizes);
KEEP(p_indices->shelter);
r_obj* out = vec_chop_base(x, info, p_indices);
FREE(2);
return out;
}static inline SEXP vec_clone_referenced(SEXP x, const enum vctrs_ownership ownership) {
switch (ownership) {
case VCTRS_OWNERSHIP_foreign: return r_clone_referenced(x);
case VCTRS_OWNERSHIP_shallow: return x;
case VCTRS_OWNERSHIP_deep: return x;
default: r_stop_unreachable();
}
}size_t vec_compute_n_bytes_lazy_counts(
SEXP x,
const enum vctrs_type type
) {
switch (type) {
case VCTRS_TYPE_integer:
case VCTRS_TYPE_logical:
return INT_MAX_RADIX_PASS;
case VCTRS_TYPE_double:
case VCTRS_TYPE_complex:
return DBL_MAX_RADIX_PASS;
case VCTRS_TYPE_character:
return 0;
case VCTRS_TYPE_dataframe:
return df_compute_n_bytes_lazy_counts(x);
default:
Rf_errorcall(R_NilValue, "This type is not supported by `vec_order()`.");
}
}size_t vec_compute_n_bytes_lazy_raw(
SEXP x,
const enum vctrs_type type
) {
switch (type) {
case VCTRS_TYPE_integer:
case VCTRS_TYPE_logical:
return sizeof(int);
case VCTRS_TYPE_double:
return sizeof(double);
case VCTRS_TYPE_complex:
// Complex types will be split into two double vectors
return sizeof(double);
case VCTRS_TYPE_character:
// Both `SEXP` and `const char*` are written to the working memory.
// Should be the same size (8 bytes), both are pointers, but be defensive.
return sizeof(SEXP) > sizeof(const char*) ? sizeof(SEXP) : sizeof(const char*);
case VCTRS_TYPE_dataframe:
return df_compute_n_bytes_lazy_raw(x);
default:
Rf_errorcall(R_NilValue, "This type is not supported by `vec_order()`.");
}
}void vec_detect_complete_switch(SEXP x, R_len_t size, int* p_out) {
switch (vec_proxy_typeof(x)) {
case VCTRS_TYPE_logical: lgl_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_integer: int_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_double: dbl_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_complex: cpl_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_character: chr_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_raw: raw_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_list: list_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_dataframe: df_detect_complete(x, size, p_out); break;
case VCTRS_TYPE_null: break;
case VCTRS_TYPE_scalar: stop_scalar_type(x, vec_args.empty, r_lazy_null);
default: stop_unimplemented_vctrs_type("vec_detect_complete", vec_proxy_typeof(x));
}
}r_obj* vec_df_restore(r_obj* x,
r_obj* to,
const struct vec_restore_opts* p_opts) {
r_obj* out = KEEP(vec_bare_df_restore(x, to, p_opts));
out = vec_restore_dispatch(out, to);
FREE(1);
return out;
}static inline SEXP vec_dim(SEXP x) {
SEXP dim = vec_bare_dim(x);
if (dim == R_NilValue) {
dim = r_int(Rf_length(x));
}
return dim;
}static inline R_len_t vec_dim_n(SEXP x) {
SEXP dim = vec_bare_dim(x);
if (dim == R_NilValue) {
return 1;
}
return Rf_length(dim);
}void vec_fill_missing_down(const int* p_na, r_ssize size, bool leading, int* p_loc) {
r_ssize loc = 0;
if (leading) {
// Increment `loc` to the first non-missing value
for (r_ssize i = 0; i < size; ++i) {
if (!p_na[i]) {
loc = i;
break;
}
}
// Back-fill with first non-missing value
for (r_ssize i = loc - 1; i >= 0; --i) {
p_loc[i] = loc + 1;
}
}
for (r_ssize i = loc; i < size; ++i) {
if (!p_na[i]) {
loc = i;
}
p_loc[i] = loc + 1;
}
}void vec_fill_missing_down_with_max_fill(const int* p_na, r_ssize size, bool leading, int max_fill, int* p_loc) {
r_ssize loc = 0;
if (leading) {
// Increment `loc` to the first non-missing value
for (r_ssize i = 0; i < size; ++i) {
if (!p_na[i]) {
loc = i;
break;
}
}
// Back-fill with first non-missing value with a max_fill
r_ssize n_fill = 0;
for (r_ssize i = loc - 1; i >= 0; --i) {
if (n_fill == max_fill) {
p_loc[i] = i + 1;
} else {
p_loc[i] = loc + 1;
++n_fill;
}
}
}
r_ssize n_fill = 0;
for (r_ssize i = loc; i < size; ++i) {
if (!p_na[i]) {
loc = i;
n_fill = 0;
p_loc[i] = i + 1;
continue;
}
if (n_fill == max_fill) {
p_loc[i] = i + 1;
} else {
p_loc[i] = loc + 1;
++n_fill;
}
}
}void vec_fill_missing_up(const int* p_na, r_ssize size, bool leading, int* p_loc) {
r_ssize loc = size - 1;
if (leading) {
// Decrement `loc` to the last non-missing value
for (r_ssize i = size - 1; i >= 0; --i) {
if (!p_na[i]) {
loc = i;
break;
}
}
// Forward-fill with last non-missing value
for (r_ssize i = loc + 1; i < size; ++i) {
p_loc[i] = loc + 1;
}
}
for (r_ssize i = loc; i >= 0; --i) {
if (!p_na[i]) {
loc = i;
}
p_loc[i] = loc + 1;
}
}void vec_fill_missing_up_with_max_fill(const int* p_na, r_ssize size, bool leading, int max_fill, int* p_loc) {
r_ssize loc = size - 1;
if (leading) {
// Decrement `loc` to the last non-missing value
for (r_ssize i = size - 1; i >= 0; --i) {
if (!p_na[i]) {
loc = i;
break;
}
}
// Forward-fill with last non-missing value with a max_fill
r_ssize n_fill = 0;
for (r_ssize i = loc + 1; i < size; ++i) {
if (n_fill == max_fill) {
p_loc[i] = i + 1;
} else {
p_loc[i] = loc + 1;
++n_fill;
}
}
}
r_ssize n_fill = 0;
for (r_ssize i = loc; i >= 0; --i) {
if (!p_na[i]) {
loc = i;
n_fill = 0;
p_loc[i] = i + 1;
continue;
}
if (n_fill == max_fill) {
p_loc[i] = i + 1;
} else {
p_loc[i] = loc + 1;
++n_fill;
}
}
}bool vec_implements_base_c(r_obj* x) {
if (!r_is_object(x)) {
return false;
}
if (r_is_s4(x)) {
return s4_find_method(x, s4_c_method_table) != r_null;
} else {
return s3_find_method("c", x, base_method_table) != r_null;
}
}bool vec_implements_ptype2(SEXP x) {
switch (vec_typeof(x)) {
case VCTRS_TYPE_scalar:
return false;
case VCTRS_TYPE_s3: {
SEXP method_sym = R_NilValue;
SEXP method = s3_find_method_xy("vec_ptype2", x, x, vctrs_method_table, &method_sym);
if (method != R_NilValue) {
return true;
}
method = s3_find_method2("vec_ptype2", x, vctrs_method_table, &method_sym);
return method != R_NilValue;
}
default:
return true;
}
}SEXP vec_in(
SEXP needles,
SEXP haystack,
bool na_equal,
struct vctrs_arg* p_needles_arg,
struct vctrs_arg* p_haystack_arg,
struct r_lazy call
) {
int nprot = 0;
int _;
SEXP type = vec_ptype2(
needles,
haystack,
p_needles_arg,
p_haystack_arg,
call,
S3_FALLBACK_false,
&_
);
PROTECT_N(type, &nprot);
type = PROTECT_N(vec_ptype_finalise(type), &nprot);
needles = vec_cast_params(
needles,
type,
p_needles_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
PROTECT_N(needles, &nprot);
haystack = vec_cast_params(
haystack,
type,
p_haystack_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
PROTECT_N(haystack, &nprot);
needles = PROTECT_N(vec_proxy_equal(needles), &nprot);
needles = PROTECT_N(obj_encode_utf8(needles), &nprot);
haystack = PROTECT_N(vec_proxy_equal(haystack), &nprot);
haystack = PROTECT_N(obj_encode_utf8(haystack), &nprot);
R_len_t n_haystack = vec_size(haystack);
R_len_t n_needle = vec_size(needles);
struct dictionary* d = new_dictionary_params(haystack, false, na_equal);
PROTECT_DICT(d, &nprot);
// Load dictionary with haystack
load_with_haystack(d, n_haystack);
struct dictionary* d_needles = new_dictionary_params(needles, true, na_equal);
PROTECT_DICT(d_needles, &nprot);
// Locate needles
SEXP out = PROTECT_N(Rf_allocVector(LGLSXP, n_needle), &nprot);
int* p_out = LOGICAL(out);
if (na_equal) {
vec_in_loop(p_out, d, d_needles, n_needle);
} else {
vec_in_loop_propagate(p_out, d, d_needles, n_needle);
}
UNPROTECT(nprot);
return out;
}void vec_in_loop(
int* p_out,
struct dictionary* d,
struct dictionary* d_needles,
R_len_t n_needle
) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_IN_LOOP(nil_dict_hash_with); break;
case VCTRS_TYPE_logical: VEC_IN_LOOP(lgl_dict_hash_with); break;
case VCTRS_TYPE_integer: VEC_IN_LOOP(int_dict_hash_with); break;
case VCTRS_TYPE_double: VEC_IN_LOOP(dbl_dict_hash_with); break;
case VCTRS_TYPE_complex: VEC_IN_LOOP(cpl_dict_hash_with); break;
case VCTRS_TYPE_character: VEC_IN_LOOP(chr_dict_hash_with); break;
case VCTRS_TYPE_raw: VEC_IN_LOOP(raw_dict_hash_with); break;
case VCTRS_TYPE_list: VEC_IN_LOOP(list_dict_hash_with); break;
case VCTRS_TYPE_dataframe: VEC_IN_LOOP(df_dict_hash_with); break;
default: stop_unimplemented_vctrs_type("vec_in_loop", d->p_poly_vec->type);
}
}void vec_in_loop_propagate(
int* p_out,
struct dictionary* d,
struct dictionary* d_needles,
R_len_t n_needle
) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_IN_LOOP_PROPAGATE(nil_dict_hash_with, nil_dict_is_incomplete); break;
case VCTRS_TYPE_logical: VEC_IN_LOOP_PROPAGATE(lgl_dict_hash_with, lgl_dict_is_incomplete); break;
case VCTRS_TYPE_integer: VEC_IN_LOOP_PROPAGATE(int_dict_hash_with, int_dict_is_incomplete); break;
case VCTRS_TYPE_double: VEC_IN_LOOP_PROPAGATE(dbl_dict_hash_with, dbl_dict_is_incomplete); break;
case VCTRS_TYPE_complex: VEC_IN_LOOP_PROPAGATE(cpl_dict_hash_with, cpl_dict_is_incomplete); break;
case VCTRS_TYPE_character: VEC_IN_LOOP_PROPAGATE(chr_dict_hash_with, chr_dict_is_incomplete); break;
case VCTRS_TYPE_raw: VEC_IN_LOOP_PROPAGATE(raw_dict_hash_with, raw_dict_is_incomplete); break;
case VCTRS_TYPE_list: VEC_IN_LOOP_PROPAGATE(list_dict_hash_with, list_dict_is_incomplete); break;
case VCTRS_TYPE_dataframe: VEC_IN_LOOP_PROPAGATE(df_dict_hash_with, df_dict_is_incomplete); break;
default: stop_unimplemented_vctrs_type("vec_in_loop_propagate", d->p_poly_vec->type);
}
}r_obj* vec_init(r_obj* x, r_ssize n) {
obj_check_vector(x, VCTRS_ALLOW_NULL_no, vec_args.x, lazy_calls.vec_init);
if (n < 0) {
r_abort_lazy_call(lazy_calls.vec_init,
"%s must be a positive integer.",
r_c_str_format_error_arg("n"));
}
r_obj* i = KEEP(compact_rep(r_globals.na_int, n));
r_obj* out = vec_slice_unsafe(x, i);
FREE(1);
return out;
}r_obj* vec_invoke_coerce_method(r_obj* method_sym, r_obj* method,
r_obj* x_sym, r_obj* x,
r_obj* y_sym, r_obj* y,
r_obj* x_arg_sym, r_obj* x_arg,
r_obj* y_arg_sym, r_obj* y_arg,
struct r_lazy lazy_call,
enum s3_fallback s3_fallback) {
r_obj* call = KEEP(r_lazy_eval(lazy_call));
if (s3_fallback != S3_FALLBACK_false) {
r_obj* ffi_s3_fallback = KEEP(r_int(s3_fallback));
r_obj* out = vctrs_dispatch6(method_sym, method,
x_sym, x,
y_sym, y,
x_arg_sym, x_arg,
y_arg_sym, y_arg,
syms_call, call,
syms_s3_fallback, ffi_s3_fallback);
FREE(2);
return out;
} else {
r_obj* out = vctrs_dispatch5(method_sym, method,
x_sym, x,
y_sym, y,
x_arg_sym, x_arg,
y_arg_sym, y_arg,
syms_call, call);
FREE(1);
return out;
}
}bool vec_is_coercible(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
ERR err = NULL;
vec_is_coercible_e(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback,
&err
);
return !err;
}void vec_is_coercible_e(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback,
ERR* err
) {
struct is_coercible_data data = {
.x = x,
.y = y,
.p_x_arg = p_x_arg,
.p_y_arg = p_y_arg,
.call = call,
.s3_fallback = s3_fallback,
.out = r_null
};
*err = r_try_catch(&vec_is_coercible_cb,
&data,
syms_vctrs_error_incompatible_type,
NULL,
NULL);
}bool vec_is_recyclable(
r_obj* x,
r_ssize size,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
const r_ssize x_size = vec_size_params(x, p_x_arg, call);
if (x_size == size || x_size == 1) {
return true;
}
if (allow_null_as_bool(allow_null) && x == r_null) {
return true;
}
return false;
}static r_obj* vec_is_restored_cb(r_obj* tag, r_obj* _value, void* _data) {
if (tag == r_syms.names) {
// Keep iterating
return NULL;
} else {
// Restored!
return R_NilValue;
}
}bool vec_is_size(
r_obj* x,
r_ssize size,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
const r_ssize x_size = vec_size_params(x, p_x_arg, call);
if (x_size == size) {
return true;
}
if (allow_null_as_bool(allow_null) && x == r_null) {
return true;
}
return false;
}bool vec_is_unspecified(SEXP x) {
if (r_typeof(x) != R_TYPE_logical) {
// Both `<vctrs_unspecified>` and `<vector-of-NA>` must be logical
return false;
}
if (has_dim(x)) {
// Disallow arrays from being unspecified
return false;
}
// If it is classed, that class must be `<vctrs_unspecified>`, otherwise check
// for all `NA`s. Notably, core attributes like `names` and extraneous
// attributes are allowed on `x`, and it is still considered unspecified.
if (r_is_object(x)) {
return r_inherits(x, "vctrs_unspecified");
} else {
return lgl_is_unspecified(x);
}
}SEXP vec_locate_complete(SEXP x) {
SEXP where = PROTECT(vec_detect_complete(x));
SEXP out = r_lgl_which(where, false);
UNPROTECT(1);
return out;
}r_obj* vec_locate_run_bounds(r_obj* x, enum vctrs_run_bound which, struct r_lazy error_call) {
struct r_vector_bool* p_where = vec_detect_run_bounds_bool(x, which, error_call);
KEEP(p_where->shelter);
const bool* v_where = r_vector_bool_cbegin(p_where);
const r_ssize size = r_vector_bool_length(p_where);
r_ssize n = 0;
for (r_ssize i = 0; i < size; ++i) {
n += v_where[i];
}
r_obj* out = KEEP(r_alloc_integer(n));
int* v_out = r_int_begin(out);
r_ssize j = compute_iter_loc(n, which);
r_ssize loc = compute_iter_loc(size, which);
const r_ssize step = compute_iter_step(which);
// First/last value are always the final bound locations
// (depending on `which`), so `j` won't ever write to OOB locations
for (r_ssize i = 0; i < size; ++i) {
v_out[j] = loc + 1;
j += step * v_where[loc];
loc += step;
}
FREE(2);
return out;
}SEXP vec_match(SEXP needles, SEXP haystack) {
return vec_match_params(needles, haystack, true, NULL, NULL, r_lazy_null);
}void vec_match_loop(
int* p_out,
struct dictionary* d,
struct dictionary* d_needles,
R_len_t n_needle
) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_MATCH_LOOP(nil_dict_hash_with); break;
case VCTRS_TYPE_logical: VEC_MATCH_LOOP(lgl_dict_hash_with); break;
case VCTRS_TYPE_integer: VEC_MATCH_LOOP(int_dict_hash_with); break;
case VCTRS_TYPE_double: VEC_MATCH_LOOP(dbl_dict_hash_with); break;
case VCTRS_TYPE_complex: VEC_MATCH_LOOP(cpl_dict_hash_with); break;
case VCTRS_TYPE_character: VEC_MATCH_LOOP(chr_dict_hash_with); break;
case VCTRS_TYPE_raw: VEC_MATCH_LOOP(raw_dict_hash_with); break;
case VCTRS_TYPE_list: VEC_MATCH_LOOP(list_dict_hash_with); break;
case VCTRS_TYPE_dataframe: VEC_MATCH_LOOP(df_dict_hash_with); break;
default: stop_unimplemented_vctrs_type("vec_match_loop", d->p_poly_vec->type);
}
}void vec_match_loop_propagate(
int* p_out,
struct dictionary* d,
struct dictionary* d_needles,
R_len_t n_needle
) {
switch (d->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_MATCH_LOOP_PROPAGATE(nil_dict_hash_with, nil_dict_is_incomplete); break;
case VCTRS_TYPE_logical: VEC_MATCH_LOOP_PROPAGATE(lgl_dict_hash_with, lgl_dict_is_incomplete); break;
case VCTRS_TYPE_integer: VEC_MATCH_LOOP_PROPAGATE(int_dict_hash_with, int_dict_is_incomplete); break;
case VCTRS_TYPE_double: VEC_MATCH_LOOP_PROPAGATE(dbl_dict_hash_with, dbl_dict_is_incomplete); break;
case VCTRS_TYPE_complex: VEC_MATCH_LOOP_PROPAGATE(cpl_dict_hash_with, cpl_dict_is_incomplete); break;
case VCTRS_TYPE_character: VEC_MATCH_LOOP_PROPAGATE(chr_dict_hash_with, chr_dict_is_incomplete); break;
case VCTRS_TYPE_raw: VEC_MATCH_LOOP_PROPAGATE(raw_dict_hash_with, raw_dict_is_incomplete); break;
case VCTRS_TYPE_list: VEC_MATCH_LOOP_PROPAGATE(list_dict_hash_with, list_dict_is_incomplete); break;
case VCTRS_TYPE_dataframe: VEC_MATCH_LOOP_PROPAGATE(df_dict_hash_with, df_dict_is_incomplete); break;
default: stop_unimplemented_vctrs_type("vec_match_loop_propagate", d->p_poly_vec->type);
}
}r_obj* vec_names(r_obj* x) {
return vec_names_impl(x, false);
}void vec_order_base_switch(
SEXP x,
bool decreasing,
bool na_last,
bool nan_distinct,
r_ssize size,
const enum vctrs_type type,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
switch (type) {
case VCTRS_TYPE_integer: {
int_order(
x,
decreasing,
na_last,
size,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_logical: {
lgl_order(
x,
decreasing,
na_last,
size,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_double: {
dbl_order(
x,
decreasing,
na_last,
nan_distinct,
size,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_complex: {
cpl_order(
x,
decreasing,
na_last,
nan_distinct,
size,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_character: {
chr_order(
x,
decreasing,
na_last,
size,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_group_infos
);
break;
}
case VCTRS_TYPE_dataframe: {
Rf_errorcall(R_NilValue, "Internal error: Data frames should have been handled by now");
}
default: {
Rf_errorcall(R_NilValue, "This type is not supported by `vec_order()`.");
}
}
}void vec_order_chunk_switch(
bool decreasing,
bool na_last,
bool nan_distinct,
r_ssize size,
const enum vctrs_type type,
int* p_o,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
switch (type) {
case VCTRS_TYPE_integer: {
int_order_chunk(
decreasing,
na_last,
size,
p_o,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_logical: {
lgl_order_chunk(
decreasing,
na_last,
size,
p_o,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_double: {
dbl_order_chunk(
decreasing,
na_last,
nan_distinct,
size,
p_o,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_complex: {
// Complex types are run in two passes, once over real then over imaginary
dbl_order_chunk(
decreasing,
na_last,
nan_distinct,
size,
p_o,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_character: {
chr_order_chunk(
decreasing,
na_last,
size,
p_o,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
break;
}
case VCTRS_TYPE_dataframe: {
Rf_errorcall(R_NilValue, "Internal error: df-cols should have already been flattened.");
break;
}
default: {
Rf_errorcall(R_NilValue, "This type is not supported by `vec_order()`");
}
}
}SEXP vec_order_expand_args(
SEXP x,
SEXP decreasing,
SEXP na_largest
) {
SEXP args = PROTECT(r_new_list(2));
SET_VECTOR_ELT(args, 0, decreasing);
SET_VECTOR_ELT(args, 1, na_largest);
// Don't check length here. These might be vectorized if `x` is a data frame.
if (TYPEOF(decreasing) != LGLSXP) {
Rf_errorcall(R_NilValue, "Internal error: `decreasing` must be logical");
}
if (lgl_any_na(decreasing)) {
Rf_errorcall(R_NilValue, "Internal error: `decreasing` can't contain missing values.");
}
if (TYPEOF(na_largest) != LGLSXP) {
Rf_errorcall(R_NilValue, "Internal error: `na_largest` must be logical");
}
if (lgl_any_na(na_largest)) {
Rf_errorcall(R_NilValue, "Internal error: `na_largest` can't contain missing values.");
}
if (is_data_frame(x)) {
args = df_expand_args(x, args);
UNPROTECT(1);
return args;
}
if (r_length(decreasing) != 1) {
Rf_errorcall(R_NilValue, "`direction` must be a single value when `x` is not a data frame.");
}
if (r_length(na_largest) != 1) {
Rf_errorcall(R_NilValue, "`na_value` must be a single value when `x` is not a data frame.");
}
UNPROTECT(1);
return args;
}SEXP vec_order_info(
SEXP x,
SEXP direction,
SEXP na_value,
bool nan_distinct,
SEXP chr_proxy_collate
) {
const bool group_sizes = true;
return vec_order_info_impl(x, direction, na_value, nan_distinct, chr_proxy_collate, group_sizes);
}void vec_order_switch(
SEXP x,
SEXP decreasing,
SEXP na_last,
bool nan_distinct,
r_ssize size,
const enum vctrs_type type,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
if (type == VCTRS_TYPE_dataframe) {
df_order(
x,
decreasing,
na_last,
nan_distinct,
size,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
return;
}
if (r_length(decreasing) != 1) {
Rf_errorcall(
R_NilValue,
"Internal error: Size of decreasing != 1, but "
"`vec_order_expand_args()` didn't catch it."
);
}
if (r_length(na_last) != 1) {
Rf_errorcall(
R_NilValue,
"Internal error: Size of na_last != 1, but "
"`vec_order_expand_args()` didn't catch it."
);
}
bool c_decreasing = LOGICAL(decreasing)[0];
bool c_na_last = LOGICAL(na_last)[0];
vec_order_base_switch(
x,
c_decreasing,
c_na_last,
nan_distinct,
size,
type,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
}r_obj* vec_pall(
r_obj* xs,
enum vec_parallel_missing missing,
r_ssize size,
struct vctrs_arg* p_xs_arg,
struct r_lazy error_call
) {
return vec_parallel(xs, missing, size, p_xs_arg, error_call, VEC_PARALLEL_VARIANT_all);
}void vec_pall_fill(const int* v_x, enum vec_parallel_missing missing, r_ssize size, int* v_out) {
switch (missing) {
case VEC_PARALLEL_MISSING_na: vec_pall_fill_missing_as_na(v_x, size, v_out); break;
case VEC_PARALLEL_MISSING_false: vec_pall_fill_missing_as_false(v_x, size, v_out); break;
case VEC_PARALLEL_MISSING_true: vec_pall_fill_missing_as_true(v_x, size, v_out); break;
default: r_stop_unreachable();
}
}void vec_pall_fill_missing_as_false(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
const int elt_out = v_out[i];
const int elt_x = v_x[i];
v_out[i] = elt_out && (elt_x == 1);
}
}void vec_pall_fill_missing_as_na(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
const int elt_out = v_out[i];
const int elt_x = v_x[i];
const bool any_false = !elt_out || !elt_x;
const bool equal = elt_out == elt_x;
v_out[i] = !any_false * (equal * elt_out + !equal * r_globals.na_lgl);
}
}void vec_pall_fill_missing_as_true(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
const int elt_out = v_out[i];
const int elt_x = v_x[i];
v_out[i] = elt_out && elt_x;
}
}r_obj* vec_pany(
r_obj* xs,
enum vec_parallel_missing missing,
r_ssize size,
struct vctrs_arg* p_xs_arg,
struct r_lazy error_call
) {
return vec_parallel(xs, missing, size, p_xs_arg, error_call, VEC_PARALLEL_VARIANT_any);
}void vec_pany_fill(const int* v_x, enum vec_parallel_missing missing, r_ssize size, int* v_out) {
switch (missing) {
case VEC_PARALLEL_MISSING_na: vec_pany_fill_missing_as_na(v_x, size, v_out); break;
case VEC_PARALLEL_MISSING_false: vec_pany_fill_missing_as_false(v_x, size, v_out); break;
case VEC_PARALLEL_MISSING_true: vec_pany_fill_missing_as_true(v_x, size, v_out); break;
default: r_stop_unreachable();
}
}void vec_pany_fill_missing_as_false(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
const int elt_out = v_out[i];
const int elt_x = v_x[i];
v_out[i] = elt_out || (elt_x == 1);
}
}void vec_pany_fill_missing_as_na(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
const int elt_out = v_out[i];
const int elt_x = v_x[i];
const bool any_true = (elt_out == 1) || (elt_x == 1);
const bool equal = elt_out == elt_x;
v_out[i] = any_true + !any_true * (equal * elt_out + !equal * r_globals.na_lgl);
}
}void vec_pany_fill_missing_as_true(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
const int elt_out = v_out[i];
const int elt_x = v_x[i];
v_out[i] = elt_out || elt_x;
}
}void vec_parallel_init(const int* v_x, enum vec_parallel_missing missing, r_ssize size, int* v_out) {
switch (missing) {
case VEC_PARALLEL_MISSING_na: vec_parallel_init_missing_as_na(v_x, size, v_out); break;
case VEC_PARALLEL_MISSING_false: vec_parallel_init_missing_as_false(v_x, size, v_out); break;
case VEC_PARALLEL_MISSING_true: vec_parallel_init_missing_as_true(v_x, size, v_out); break;
default: r_stop_unreachable();
}
}void vec_parallel_init_missing_as_false(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
const int elt = v_x[i];
v_out[i] = (elt != r_globals.na_lgl) * elt;
}
}void vec_parallel_init_missing_as_na(const int* v_x, r_ssize size, int* v_out) {
r_memcpy(v_out, v_x, sizeof(*v_out) * size);
}void vec_parallel_init_missing_as_true(const int* v_x, r_ssize size, int* v_out) {
for (r_ssize i = 0; i < size; ++i) {
v_out[i] = (bool) v_x[i];
}
}SEXP vec_posixct_restore(SEXP x, SEXP to, const enum vctrs_ownership ownership) {
SEXP out = PROTECT(vec_restore_default(x, to, ownership));
out = datetime_validate(out);
UNPROTECT(1);
return out;
}SEXP vec_posixlt_restore(SEXP x, SEXP to, const enum vctrs_ownership ownership) {
SEXP out = PROTECT(vec_restore_default(x, to, ownership));
out = datetime_validate_tzone(out);
UNPROTECT(1);
return out;
}r_obj* vec_proxy(r_obj* x) {
return vec_proxy_2(x, false);
}r_obj* vec_proxy_2(r_obj* x, bool recurse) {
switch (vec_typeof(x)) {
case VCTRS_TYPE_s3: {
r_obj* x_proxy_method = KEEP(vec_proxy_method(x));
r_obj* out = KEEP(vec_proxy_invoke(x, x_proxy_method));
if (recurse && is_data_frame(out)) {
out = df_proxy_recurse(out);
}
FREE(2);
return out;
}
// Avoid `KEEP()` in the most common paths (data frames and unclassed atomics)
case VCTRS_TYPE_dataframe: {
return recurse ? df_proxy_recurse(x) : x;
}
default:
return x;
}
}r_obj* vec_proxy_compare_impl(r_obj* x) {
VEC_PROXY_KIND_IMPL(vec_proxy_compare_method, vec_proxy_compare_invoke);
}r_obj* vec_proxy_compare_invoke(r_obj* x, r_obj* method) {
return vec_proxy_invoke_impl(x, method, syms_vec_proxy_compare, &vec_proxy_equal_impl);
}r_obj* vec_proxy_compare_method(r_obj* x) {
return vec_proxy_method_impl(x, "vec_proxy_compare", fns_vec_proxy_compare_array);
}r_obj* vec_proxy_equal_impl(r_obj* x) {
VEC_PROXY_KIND_IMPL(vec_proxy_equal_method, vec_proxy_equal_invoke);
}r_obj* vec_proxy_equal_invoke(r_obj* x, r_obj* method) {
return vec_proxy_invoke_impl(x, method, syms_vec_proxy_equal, vec_proxy);
}r_obj* vec_proxy_equal_method(r_obj* x) {
return vec_proxy_method_impl(x, "vec_proxy_equal", fns_vec_proxy_equal_array);
}struct vctrs_proxy_info vec_proxy_info(r_obj* x) {
struct vctrs_proxy_info info;
// Avoid `KEEP(x_proxy_method)` if not required! This does help with
// performance, since this is called in such a tight loop.
//
// `vec_proxy_method()` itself may also return `r_null`
r_obj* x_proxy_method = r_is_object(x) ? vec_proxy_method(x) : r_null;
if (x_proxy_method == r_null) {
info.inner = x;
info.type = vec_base_typeof(x, false);
info.had_proxy_method = false;
} else {
KEEP(x_proxy_method);
info.inner = KEEP(vec_proxy_invoke(x, x_proxy_method));
info.type = vec_base_typeof(info.inner, true);
info.had_proxy_method = true;
FREE(2);
}
return info;
}r_obj* vec_proxy_invoke(r_obj* x, r_obj* method) {
if (method == r_null) {
return x;
} else {
return vctrs_dispatch1(syms_vec_proxy, method,
syms_x, x);
}
}r_obj* vec_proxy_invoke_impl(r_obj* x,
r_obj* method,
r_obj* vec_proxy_sym,
r_obj* (*vec_proxy_impl_fn)(r_obj*)) {
if (method != r_null) {
return vctrs_dispatch1(vec_proxy_sym, method, syms_x, x);
}
/* Fallback on S3 objects with no proxy */
if (vec_typeof(x) == VCTRS_TYPE_s3) {
return vec_proxy_impl_fn(x);
} else {
return x;
}
}r_obj* vec_proxy_method(r_obj* x) {
return s3_find_method("vec_proxy", x, vctrs_method_table);
}r_obj* vec_proxy_method_impl(r_obj* x, const char* generic, r_obj* fn_proxy_array) {
r_obj* cls = KEEP(s3_get_class(x));
r_obj* method = s3_class_find_method(generic, cls, vctrs_method_table);
if (method != r_null) {
FREE(1);
return method;
}
/* FIXME: Stopgap check for bare arrays */
/* which equality functions don't handle well */
if (vec_dim_n(x) > 1) {
FREE(1);
return fn_proxy_array;
}
FREE(1);
return r_null;
}r_obj* vec_proxy_names(r_obj* x) {
return vec_names_impl(x, true);
}r_obj* vec_proxy_order_impl(r_obj* x) {
VEC_PROXY_KIND_IMPL(vec_proxy_order_method, vec_proxy_order_invoke);
}r_obj* vec_proxy_order_invoke(r_obj* x, r_obj* method) {
return vec_proxy_invoke_impl(x, method, syms_vec_proxy_order, &vec_proxy_compare_impl);
}r_obj* vec_proxy_order_method(r_obj* x) {
return vec_proxy_method_impl(x, "vec_proxy_order", fns_vec_proxy_order_array);
}r_obj* vec_proxy_set_names(r_obj* x, r_obj* names, const enum vctrs_ownership ownership) {
return vec_set_names_impl(x, names, true, ownership);
}enum vctrs_type vec_proxy_typeof(r_obj* x) {
return vec_base_typeof(x, true);
}r_obj* vec_proxy_unwrap(r_obj* x) {
if (r_typeof(x) == R_TYPE_list && r_length(x) == 1 && is_data_frame(x)) {
x = vec_proxy_unwrap(r_list_get(x, 0));
}
return x;
}r_obj* vec_ptype(r_obj* x, struct vctrs_arg* x_arg, struct r_lazy call) {
switch (vec_typeof(x)) {
case VCTRS_TYPE_null: return r_null;
case VCTRS_TYPE_unspecified: return vctrs_shared_empty_uns;
case VCTRS_TYPE_logical: return vec_ptype_slice(x, r_globals.empty_lgl);
case VCTRS_TYPE_integer: return vec_ptype_slice(x, r_globals.empty_int);
case VCTRS_TYPE_double: return vec_ptype_slice(x, r_globals.empty_dbl);
case VCTRS_TYPE_complex: return vec_ptype_slice(x, r_globals.empty_cpl);
case VCTRS_TYPE_character: return vec_ptype_slice(x, r_globals.empty_chr);
case VCTRS_TYPE_raw: return vec_ptype_slice(x, r_globals.empty_raw);
case VCTRS_TYPE_list: return vec_ptype_slice(x, r_globals.empty_list);
case VCTRS_TYPE_dataframe: return df_ptype(x, true);
case VCTRS_TYPE_s3: return s3_ptype(x, x_arg, call);
case VCTRS_TYPE_scalar: stop_scalar_type(x, x_arg, call);
}
r_stop_unreachable();
}r_obj* vec_ptype2(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback,
int* left
) {
return vec_ptype2_impl(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback,
left,
true
);
}r_obj* vec_ptype2_default(r_obj* x,
r_obj* y,
struct vctrs_arg* x_arg,
struct vctrs_arg* y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback) {
return vec_ptype2_default_full(x, y, x_arg, y_arg, call, s3_fallback, false);
}r_obj* vec_ptype2_default_full(r_obj* x,
r_obj* y,
struct vctrs_arg* x_arg,
struct vctrs_arg* y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback,
bool from_dispatch) {
r_obj* ffi_s3_fallback = KEEP(r_int(s3_fallback));
r_obj* ffi_x_arg = KEEP(vctrs_arg(x_arg));
r_obj* ffi_y_arg = KEEP(vctrs_arg(y_arg));
r_obj* ffi_call = KEEP(r_lazy_eval(call));
r_obj* out = vctrs_eval_mask7(syms_vec_ptype2_default,
syms_x, x,
syms_y, y,
syms_x_arg, ffi_x_arg,
syms_y_arg, ffi_y_arg,
syms_call, ffi_call,
syms_from_dispatch, r_lgl(from_dispatch),
syms_s3_fallback, ffi_s3_fallback);
FREE(4);
return out;
}r_obj* vec_ptype2_dispatch_native(
r_obj* x,
r_obj* y,
enum vctrs_type x_type,
enum vctrs_type y_type,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback,
int* left
) {
enum vctrs_type2_s3 type2_s3 = vec_typeof2_s3_impl(x, y, x_type, y_type, left);
switch (type2_s3) {
case VCTRS_TYPE2_S3_character_bare_factor:
case VCTRS_TYPE2_S3_character_bare_ordered:
return r_globals.empty_chr;
case VCTRS_TYPE2_S3_bare_factor_bare_factor:
return fct_ptype2(
x,
y,
p_x_arg,
p_y_arg
);
case VCTRS_TYPE2_S3_bare_ordered_bare_ordered:
return ord_ptype2(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
case VCTRS_TYPE2_S3_bare_date_bare_date:
return vctrs_shared_empty_date;
case VCTRS_TYPE2_S3_bare_date_bare_posixct:
case VCTRS_TYPE2_S3_bare_date_bare_posixlt:
return date_datetime_ptype2(x, y);
case VCTRS_TYPE2_S3_bare_posixct_bare_posixct:
case VCTRS_TYPE2_S3_bare_posixct_bare_posixlt:
case VCTRS_TYPE2_S3_bare_posixlt_bare_posixlt:
return datetime_datetime_ptype2(x, y);
case VCTRS_TYPE2_S3_dataframe_bare_tibble:
case VCTRS_TYPE2_S3_bare_tibble_bare_tibble:
return tib_ptype2(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
default:
return r_null;
}
}r_obj* vec_ptype2_switch_native(
r_obj* x,
r_obj* y,
enum vctrs_type x_type,
enum vctrs_type y_type,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback,
int* left
) {
enum vctrs_type2 type2 = vec_typeof2_impl(x_type, y_type, left);
switch (type2) {
case VCTRS_TYPE2_null_null:
return r_null;
case VCTRS_TYPE2_logical_logical:
return vec_shaped_ptype(r_globals.empty_lgl, x, y, p_x_arg, p_y_arg);
case VCTRS_TYPE2_logical_integer:
case VCTRS_TYPE2_integer_integer:
return vec_shaped_ptype(r_globals.empty_int, x, y, p_x_arg, p_y_arg);
case VCTRS_TYPE2_logical_double:
case VCTRS_TYPE2_integer_double:
case VCTRS_TYPE2_double_double:
return vec_shaped_ptype(r_globals.empty_dbl, x, y, p_x_arg, p_y_arg);
case VCTRS_TYPE2_integer_complex:
case VCTRS_TYPE2_double_complex:
case VCTRS_TYPE2_complex_complex:
return vec_shaped_ptype(r_globals.empty_cpl, x, y, p_x_arg, p_y_arg);
case VCTRS_TYPE2_character_character:
return vec_shaped_ptype(r_globals.empty_chr, x, y, p_x_arg, p_y_arg);
case VCTRS_TYPE2_raw_raw:
return vec_shaped_ptype(r_globals.empty_raw, x, y, p_x_arg, p_y_arg);
case VCTRS_TYPE2_list_list:
return vec_shaped_ptype(r_globals.empty_list, x, y, p_x_arg, p_y_arg);
case VCTRS_TYPE2_dataframe_dataframe:
return df_ptype2(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
default:
return vec_ptype2_dispatch_s3(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
}
}r_obj* vec_ptype_common(
r_obj* dots,
r_obj* ptype,
enum ptype_finalise finalise,
enum s3_fallback s3_fallback,
struct vctrs_arg* p_arg,
struct r_lazy call
) {
int n_prot = 0;
r_obj* out;
if (ptype != r_null) {
out = KEEP_N(vec_ptype(ptype, vec_args.dot_ptype, call), &n_prot);
} else {
if (r_is_true(r_peek_option("vctrs.no_guessing"))) {
r_abort_lazy_call(r_lazy_null, "strict mode is activated; you must supply complete `.ptype`.");
}
struct ptype_common_reduce_opts reduce_opts = {
.call = call,
.s3_fallback = s3_fallback
};
out = KEEP_N(
reduce(
r_null,
vec_args.empty,
p_arg,
dots,
&ptype2_common,
&reduce_opts
),
&n_prot
);
}
if (should_finalise(finalise)) {
out = KEEP_N(vec_ptype_finalise(out), &n_prot);
}
FREE(n_prot);
return out;
}r_obj* vec_ptype_finalise(r_obj* x) {
if (x == r_null) {
return x;
}
struct r_lazy call = lazy_calls.vec_ptype_finalise;
if (!r_is_object(x)) {
obj_check_vector(x, VCTRS_ALLOW_NULL_no, vec_args.x, call);
return x;
}
if (vec_is_unspecified(x)) {
return vec_ptype_finalise_unspecified(x);
}
obj_check_vector(x, VCTRS_ALLOW_NULL_no, vec_args.x, call);
switch (class_type(x)) {
case VCTRS_CLASS_bare_tibble:
case VCTRS_CLASS_bare_data_frame:
return bare_df_map(x, &vec_ptype_finalise);
case VCTRS_CLASS_data_frame:
return df_map(x, &vec_ptype_finalise);
case VCTRS_CLASS_none:
r_stop_internal("Non-S3 classes should have returned by now.");
default:
return vec_ptype_finalise_dispatch(x);
}
}r_obj* vec_ptype_finalise_dispatch(r_obj* x) {
return vctrs_dispatch1(
syms_vec_ptype_finalise_dispatch, fns_vec_ptype_finalise_dispatch,
syms_x, x
);
}r_obj* vec_ptype_finalise_unspecified(r_obj* x) {
r_ssize size = r_length(x);
if (size == 0) {
return r_globals.empty_lgl;
}
r_obj* out = KEEP(r_alloc_logical(size));
r_lgl_fill(out, r_globals.na_lgl, size);
FREE(1);
return out;
}r_obj* vec_ptype_invoke(r_obj* x, r_obj* method) {
return vctrs_dispatch1(syms_vec_ptype, method, syms_x, x);
}r_obj* vec_ptype_method(r_obj* x) {
r_obj* cls = KEEP(s3_get_class(x));
r_obj* method = s3_class_find_method("vec_ptype", cls, vctrs_method_table);
FREE(1);
return method;
}r_obj* vec_ptype_or_s3_fallback(
r_obj* x,
struct vctrs_arg* p_x_arg,
enum vctrs_type x_type,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
if (s3_fallback == S3_FALLBACK_true && x_type == VCTRS_TYPE_s3) {
int _;
return vec_ptype2(
x,
x,
p_x_arg,
p_x_arg,
r_lazy_null,
s3_fallback,
&_
);
}
return vec_ptype(x, p_x_arg, call);
}r_obj* vec_ptype_slice(r_obj* x, r_obj* empty) {
if (r_attrib_has_any(x)) {
// Slicing preserves attributes
return vec_slice(x, r_null);
} else {
return empty;
}
}r_obj* vec_recycle(
r_obj* x,
r_ssize size,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
if (x == r_null) {
return r_null;
}
r_ssize n_x = vec_size(x);
if (n_x == size) {
return x;
}
if (n_x == 1L) {
r_obj* i = KEEP(compact_rep(1, size));
r_obj* out = vec_slice_unsafe(x, i);
FREE(1);
return out;
}
stop_recycle_incompatible_size(n_x, size, p_x_arg, call);
}r_obj* vec_recycle_common(
r_obj* xs,
r_ssize size,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
if (size < 0) {
return xs;
}
r_obj* const* v_xs = r_list_cbegin(xs);
r_obj* xs_names = KEEP(r_names(xs));
const r_ssize xs_size = r_length(xs);
r_ssize xs_index = 0;
struct vctrs_arg* p_x_arg = new_subscript_arg(
p_xs_arg,
xs_names,
xs_size,
&xs_index
);
KEEP(p_x_arg->shelter);
// If all elements are of size `size`, there is nothing to do
// and we can avoid an allocation
for (r_ssize i = 0; i < xs_size; ++i) {
r_obj* x = v_xs[i];
if (!vec_is_size(x, size, VCTRS_ALLOW_NULL_yes, p_x_arg, call)) {
break;
}
++xs_index;
}
if (xs_index == xs_size) {
FREE(2);
return xs;
}
// Otherwise we need a new list
r_obj* out = KEEP(r_alloc_list(xs_size));
r_attrib_poke_names(out, xs_names);
// Copy over everything before `xs_index`
for (r_ssize i = 0; i < xs_index; ++i) {
r_obj* x = v_xs[i];
r_list_poke(out, i, x);
}
// Recycle everything at and after `xs_index`
for (r_ssize i = xs_index; i < xs_size; ++i) {
r_obj* x = v_xs[i];
r_list_poke(out, i, vec_recycle(x, size, p_x_arg, call));
++xs_index;
}
FREE(3);
return out;
}r_obj* vec_recycle_fallback(r_obj* x,
r_ssize size,
struct vctrs_arg* x_arg,
struct r_lazy call) {
if (x == r_null) {
return r_null;
}
r_ssize x_size = vec_size(x);
if (x_size == size) {
return x;
}
if (x_size == 1) {
r_obj* subscript = KEEP(r_alloc_integer(size));
r_int_fill(subscript, 1, size);
r_obj* out = vec_slice_fallback(x, subscript);
FREE(1);
return out;
}
stop_recycle_incompatible_size(x_size, size, x_arg, call);
}r_obj* vec_recycle_xs_fallback(
r_obj* xs,
r_obj* indices,
struct vctrs_arg* p_xs_arg,
struct r_lazy error_call
) {
r_ssize xs_size = vec_size(xs);
r_obj* xs_names = KEEP(r_names(xs));
xs = KEEP(r_clone_referenced(xs));
r_ssize i = 0;
struct vctrs_arg* p_x_arg = new_subscript_arg(
p_xs_arg,
xs_names,
xs_size,
&i
);
KEEP(p_x_arg->shelter);
r_obj* const* v_xs = r_list_cbegin(xs);
r_obj* const* v_indices = r_list_cbegin(indices);
for (; i < xs_size; ++i) {
r_obj* x = v_xs[i];
r_ssize index_size = r_length(v_indices[i]);
r_list_poke(xs, i, vec_recycle_fallback(x, index_size, p_x_arg, error_call));
}
FREE(3);
return xs;
}r_obj* vec_rep(r_obj* x,
int times,
struct r_lazy error_call,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_times_arg) {
check_rep_times(times, error_call, p_times_arg);
if (times == 1) {
return x;
}
const r_ssize times_ = (r_ssize) times;
const r_ssize x_size = vec_size(x);
if (x_size == 1) {
return vec_recycle(x, times_, p_x_arg, error_call);
}
if (multiply_would_overflow(x_size, times_)) {
stop_rep_size_oob(error_call);
};
const r_ssize size = x_size * times_;
r_obj* subscript = KEEP(r_alloc_integer(size));
int* v_subscript = r_int_begin(subscript);
r_ssize k = 0;
for (r_ssize i = 0; i < times_; ++i) {
for (r_ssize j = 1; j <= x_size; ++j, ++k) {
v_subscript[k] = j;
}
}
r_obj* out = vec_slice_unsafe(x, subscript);
FREE(1);
return out;
}r_obj* vec_rep_each_uniform(r_obj* x,
int times,
struct r_lazy error_call,
struct vctrs_arg* p_times_arg) {
check_rep_each_times(times, 1, error_call, p_times_arg);
const r_ssize times_ = (r_ssize) times;
const r_ssize x_size = vec_size(x);
if (multiply_would_overflow(x_size, times_)) {
stop_rep_size_oob(error_call);
};
const r_ssize size = x_size * times_;
r_obj* subscript = KEEP(r_alloc_integer(size));
int* v_subscript = r_int_begin(subscript);
r_ssize k = 0;
for (r_ssize i = 1; i <= x_size; ++i) {
for (r_ssize j = 0; j < times_; ++j, ++k) {
v_subscript[k] = i;
}
}
r_obj* out = vec_slice_unsafe(x, subscript);
FREE(1);
return out;
}bool vec_requires_fallback(r_obj* x, struct vctrs_proxy_info info) {
return r_is_object(x) &&
!info.had_proxy_method &&
info.type != VCTRS_TYPE_dataframe;
}static r_obj* vec_restore_collect_cb(r_obj* tag, r_obj* value, void* data) {
struct vec_restore_collect_data* p_data = (struct vec_restore_collect_data*) data;
if (tag == r_syms.names) {
p_data->names = value;
return NULL;
}
if (tag == r_syms.dim) {
p_data->dim = value;
return NULL;
}
if (tag == r_syms.dim_names) {
p_data->dim_names = value;
return NULL;
}
if (tag == r_syms.row_names) {
p_data->row_names = value;
return NULL;
}
return NULL;
}r_obj* vec_restore_dispatch(r_obj* x, r_obj* to) {
return vctrs_dispatch2(syms_vec_restore_dispatch, fns_vec_restore_dispatch,
syms_x, x,
syms_to, to);
}r_obj* vec_restore_opts(
r_obj* x,
r_obj* to,
const struct vec_restore_opts* p_opts
) {
enum vctrs_class_type to_type = class_type(to);
switch (to_type) {
case VCTRS_CLASS_bare_factor:
case VCTRS_CLASS_bare_ordered:
case VCTRS_CLASS_none: return vec_restore_default(x, to, p_opts->ownership);
case VCTRS_CLASS_bare_date: return vec_date_restore(x, to, p_opts->ownership);
case VCTRS_CLASS_bare_posixct: return vec_posixct_restore(x, to, p_opts->ownership);
case VCTRS_CLASS_bare_posixlt: return vec_posixlt_restore(x, to, p_opts->ownership);
case VCTRS_CLASS_bare_data_frame:
case VCTRS_CLASS_bare_tibble: return vec_bare_df_restore(x, to, p_opts);
case VCTRS_CLASS_data_frame: return vec_df_restore(x, to, p_opts);
default:
if (p_opts->recursively_proxied && is_data_frame(x)) {
return vec_df_restore(x, to, p_opts);
} else {
return vec_restore_dispatch(x, to);
}
}
}r_obj* vec_run_sizes(r_obj* x, struct r_lazy error_call) {
struct r_vector_bool* p_ends = vec_detect_run_bounds_bool(x, VCTRS_RUN_BOUND_end, error_call);
KEEP(p_ends->shelter);
const bool* v_ends = r_vector_bool_cbegin(p_ends);
const r_ssize size = r_vector_bool_length(p_ends);
r_ssize n = 0;
for (r_ssize i = 0; i < size; ++i) {
n += v_ends[i];
}
r_obj* out = KEEP(r_alloc_integer(n));
int* v_out = r_int_begin(out);
r_ssize j = 0;
int count = 1;
for (r_ssize i = 0; i < size; ++i) {
const bool end = v_ends[i];
v_out[j] = count;
j += end;
count = !end * count + 1;
}
FREE(2);
return out;
}r_obj* vec_set_df_rownames(r_obj* x, r_obj* names, bool proxy, const enum vctrs_ownership ownership) {
if (names == r_null) {
if (rownames_type(df_rownames(x)) != ROWNAMES_TYPE_identifiers) {
return(x);
}
x = KEEP(vec_clone_referenced(x, ownership));
init_compact_rownames(x, vec_size(x));
FREE(1);
return x;
}
// Repair row names silently
if (!proxy) {
names = vec_as_names(names, p_unique_repair_silent_opts);
}
KEEP(names);
x = KEEP(vec_clone_referenced(x, ownership));
r_attrib_poke(x, r_syms.row_names, names);
FREE(2);
return x;
}void vec_set_difference_loop(
struct dictionary* x_dict,
struct dictionary* y_dict,
r_ssize x_size,
r_ssize y_size,
bool* v_marked
) {
switch (x_dict->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_SET_DIFFERENCE_LOOP(nil_dict_hash_scalar, nil_dict_hash_with); break;
case VCTRS_TYPE_logical: VEC_SET_DIFFERENCE_LOOP(lgl_dict_hash_scalar, lgl_dict_hash_with); break;
case VCTRS_TYPE_integer: VEC_SET_DIFFERENCE_LOOP(int_dict_hash_scalar, int_dict_hash_with); break;
case VCTRS_TYPE_double: VEC_SET_DIFFERENCE_LOOP(dbl_dict_hash_scalar, dbl_dict_hash_with); break;
case VCTRS_TYPE_complex: VEC_SET_DIFFERENCE_LOOP(cpl_dict_hash_scalar, cpl_dict_hash_with); break;
case VCTRS_TYPE_character: VEC_SET_DIFFERENCE_LOOP(chr_dict_hash_scalar, chr_dict_hash_with); break;
case VCTRS_TYPE_raw: VEC_SET_DIFFERENCE_LOOP(raw_dict_hash_scalar, raw_dict_hash_with); break;
case VCTRS_TYPE_list: VEC_SET_DIFFERENCE_LOOP(list_dict_hash_scalar, list_dict_hash_with); break;
case VCTRS_TYPE_dataframe: VEC_SET_DIFFERENCE_LOOP(df_dict_hash_scalar, df_dict_hash_with); break;
default: stop_unimplemented_vctrs_type("vec_set_difference_loop", x_dict->p_poly_vec->type);
}
}void vec_set_intersect_loop(
struct dictionary* x_dict,
struct dictionary* y_dict,
r_ssize x_size,
r_ssize y_size,
bool* v_marked
) {
switch (x_dict->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_SET_INTERSECT_LOOP(nil_dict_hash_scalar, nil_dict_hash_with); break;
case VCTRS_TYPE_logical: VEC_SET_INTERSECT_LOOP(lgl_dict_hash_scalar, lgl_dict_hash_with); break;
case VCTRS_TYPE_integer: VEC_SET_INTERSECT_LOOP(int_dict_hash_scalar, int_dict_hash_with); break;
case VCTRS_TYPE_double: VEC_SET_INTERSECT_LOOP(dbl_dict_hash_scalar, dbl_dict_hash_with); break;
case VCTRS_TYPE_complex: VEC_SET_INTERSECT_LOOP(cpl_dict_hash_scalar, cpl_dict_hash_with); break;
case VCTRS_TYPE_character: VEC_SET_INTERSECT_LOOP(chr_dict_hash_scalar, chr_dict_hash_with); break;
case VCTRS_TYPE_raw: VEC_SET_INTERSECT_LOOP(raw_dict_hash_scalar, raw_dict_hash_with); break;
case VCTRS_TYPE_list: VEC_SET_INTERSECT_LOOP(list_dict_hash_scalar, list_dict_hash_with); break;
case VCTRS_TYPE_dataframe: VEC_SET_INTERSECT_LOOP(df_dict_hash_scalar, df_dict_hash_with); break;
default: stop_unimplemented_vctrs_type("vec_set_intersect_loop", x_dict->p_poly_vec->type);
}
}r_obj* vec_set_names(r_obj* x, r_obj* names, const enum vctrs_ownership ownership) {
return vec_set_names_impl(x, names, false, ownership);
}r_obj* vec_set_rownames(r_obj* x, r_obj* names, bool proxy, const enum vctrs_ownership ownership) {
if (!proxy && r_is_object(x)) {
return set_rownames_dispatch(x, names);
}
r_obj* dim_names = r_attrib_get(x, r_syms.dim_names);
// Early exit when no new row names and no existing row names
if (names == r_null) {
if (dim_names == r_null || r_list_get(dim_names, 0) == r_null) {
return x;
}
}
// Okay, now protect `dim_names`
KEEP(dim_names);
x = KEEP(vec_clone_referenced(x, ownership));
if (dim_names == r_null) {
dim_names = KEEP(r_alloc_list(vec_dim_n(x)));
} else {
// Also clone attribute
dim_names = KEEP(r_clone(dim_names));
}
r_list_poke(dim_names, 0, names);
r_attrib_poke(x, r_syms.dim_names, dim_names);
FREE(3);
return x;
}struct r_ssize_pair vec_set_symmetric_difference_loop(
struct dictionary* x_dict,
struct dictionary* y_dict,
r_ssize x_size,
r_ssize y_size,
bool* v_x_marked,
bool* v_y_marked
) {
switch (x_dict->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(nil_dict_hash_scalar, nil_dict_hash_with); break;
case VCTRS_TYPE_logical: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(lgl_dict_hash_scalar, lgl_dict_hash_with); break;
case VCTRS_TYPE_integer: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(int_dict_hash_scalar, int_dict_hash_with); break;
case VCTRS_TYPE_double: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(dbl_dict_hash_scalar, dbl_dict_hash_with); break;
case VCTRS_TYPE_complex: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(cpl_dict_hash_scalar, cpl_dict_hash_with); break;
case VCTRS_TYPE_character: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(chr_dict_hash_scalar, chr_dict_hash_with); break;
case VCTRS_TYPE_raw: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(raw_dict_hash_scalar, raw_dict_hash_with); break;
case VCTRS_TYPE_list: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(list_dict_hash_scalar, list_dict_hash_with); break;
case VCTRS_TYPE_dataframe: VEC_SET_SYMMETRIC_DIFFERENCE_LOOP(df_dict_hash_scalar, df_dict_hash_with); break;
default: stop_unimplemented_vctrs_type("vec_set_symmetric_difference_loop", x_dict->p_poly_vec->type);
}
}r_obj* vec_shape_broadcast(
r_obj* x,
r_obj* to,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_to_arg,
struct r_lazy call
) {
r_obj* ffi_x_arg = KEEP(vctrs_arg(p_x_arg));
r_obj* ffi_to_arg = KEEP(vctrs_arg(p_to_arg));
r_obj* ffi_call = KEEP(r_lazy_eval(call));
r_obj* out = vctrs_eval_mask5(
r_sym("shape_broadcast"),
r_syms.x,
x,
r_sym("to"),
to,
syms.x_arg,
ffi_x_arg,
syms.to_arg,
ffi_to_arg,
r_syms.call,
ffi_call
);
FREE(3);
return out;
}static inline R_len_t vec_shape_elem_n(const int* p_dim, const R_len_t dim_n) {
R_len_t shape_elem_n = 1;
for (int i = 1; i < dim_n; ++i) {
shape_elem_n *= p_dim[i];
}
return shape_elem_n;
}r_obj* vec_shaped_ptype(
r_obj* ptype,
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg
) {
r_obj* shape = vec_shape2(x, y, p_x_arg, p_y_arg);
if (shape == r_null) {
return ptype;
}
// Only `KEEP()` if we have to
KEEP(shape);
ptype = KEEP(r_clone_referenced(ptype));
r_attrib_poke_dim(ptype, shape);
FREE(2);
return ptype;
}r_ssize vec_size(r_obj* x) {
return vec_size_params(x, vec_args.x, lazy_calls.vec_size);
}r_obj* vec_size2_impl(
r_obj* x,
r_obj* y,
r_ssize x_size,
r_ssize y_size,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
int* left
) {
// `NULL` handling rules:
// - If `x` and `y` are `NULL`, do nothing
// - If `x` is `NULL`, use `y`
// - If `y` is `NULL`, use `x`
//
// The first rule is important to ensure that this works
// `vec_size_common(NULL, .absent = 5L)`
if (x == r_null) {
if (y == r_null) {
*left = -1;
return x;
} else {
*left = 0;
return y;
}
}
if (y == r_null) {
if (x == r_null) {
r_stop_unreachable();
} else {
*left = 1;
return x;
}
}
// Now apply common size rules
// - Same size, use `x`
// - Size 1 `x`, use `y`
// - Size 1 `y`, use `x`
if (x_size == y_size) {
*left = -1;
return x;
}
if (x_size == 1) {
*left = 0;
return y;
}
if (y_size == 1) {
*left = 1;
return x;
}
stop_incompatible_size(
x,
y,
x_size,
y_size,
p_x_arg,
p_y_arg,
call
);
}r_ssize vec_size_params(
r_obj* x,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
struct vctrs_proxy_info info = vec_proxy_info(x);
KEEP(info.inner);
r_obj* data = info.inner;
r_ssize size;
switch (info.type) {
case VCTRS_TYPE_null:
size = 0;
break;
case VCTRS_TYPE_logical:
case VCTRS_TYPE_integer:
case VCTRS_TYPE_double:
case VCTRS_TYPE_complex:
case VCTRS_TYPE_character:
case VCTRS_TYPE_raw:
case VCTRS_TYPE_list:
size = vec_raw_size(data);
break;
case VCTRS_TYPE_dataframe:
size = df_size(data);
break;
default:
stop_scalar_type(x, p_x_arg, call);
}
FREE(1);
return size;
}r_obj* vec_slice_base(enum vctrs_type type,
r_obj* x,
r_obj* subscript,
enum vctrs_materialize materialize) {
switch (type) {
case VCTRS_TYPE_logical: return lgl_slice(x, subscript, materialize);
case VCTRS_TYPE_integer: return int_slice(x, subscript, materialize);
case VCTRS_TYPE_double: return dbl_slice(x, subscript, materialize);
case VCTRS_TYPE_complex: return cpl_slice(x, subscript, materialize);
case VCTRS_TYPE_character: return chr_slice(x, subscript, materialize);
case VCTRS_TYPE_raw: return raw_slice(x, subscript, materialize);
case VCTRS_TYPE_list: return list_slice(x, subscript, materialize);
default: stop_unimplemented_vctrs_type("vec_slice_base", type);
}
}SEXP vec_slice_complete(SEXP x) {
SEXP loc = PROTECT(vec_locate_complete(x));
// Skip `vec_as_location()` in `vec_slice()`
SEXP out = vec_slice_unsafe(x, loc);
UNPROTECT(1);
return out;
}r_obj* vec_slice_dispatch(r_obj* x, r_obj* subscript) {
// TODO - Remove once bit64 is updated on CRAN. Special casing integer64
// objects to ensure correct slicing with `NA_integer_`.
if (is_integer64(x)) {
return vctrs_dispatch2(syms.vec_slice_dispatch_integer64, fns.vec_slice_dispatch_integer64,
syms_x, x,
syms_i, subscript);
}
return vctrs_dispatch2(syms_bracket, fns_bracket,
syms_x, x,
syms_i, subscript);
}r_obj* vec_slice_fallback(r_obj* x, r_obj* subscript) {
// TODO - Remove once bit64 is updated on CRAN. Special casing integer64
// objects to ensure correct slicing with `NA_integer_`.
if (is_integer64(x)) {
return vctrs_dispatch2(syms.vec_slice_fallback_integer64, fns.vec_slice_fallback_integer64,
syms_x, x,
syms_i, subscript);
}
return vctrs_dispatch2(syms.vec_slice_fallback, fns.vec_slice_fallback,
syms_x, x,
syms_i, subscript);
}r_obj* vec_slice_opts(r_obj* x,
r_obj* i,
const struct vec_slice_opts* opts) {
obj_check_vector(x, VCTRS_ALLOW_NULL_no, opts->x_arg, opts->call);
r_obj* names = KEEP(vec_names(x));
i = KEEP(vec_as_location_ctxt(i,
vec_size(x),
names,
opts->i_arg,
opts->call));
r_obj* out = vec_slice_unsafe(x, i);
FREE(2);
return out;
}SEXP vec_slice_shaped_base(enum vctrs_type type,
SEXP x,
SEXP index,
struct strides_info* p_info) {
switch (type) {
case VCTRS_TYPE_logical: return lgl_slice_shaped(x, index, p_info);
case VCTRS_TYPE_integer: return int_slice_shaped(x, index, p_info);
case VCTRS_TYPE_double: return dbl_slice_shaped(x, index, p_info);
case VCTRS_TYPE_complex: return cpl_slice_shaped(x, index, p_info);
case VCTRS_TYPE_character: return chr_slice_shaped(x, index, p_info);
case VCTRS_TYPE_raw: return raw_slice_shaped(x, index, p_info);
case VCTRS_TYPE_list: return list_slice_shaped(x, index, p_info);
default: stop_unimplemented_vctrs_type("vec_slice_shaped_base", type);
}
}r_obj* vec_slice_xs_fallback(
r_obj* xs,
r_obj* indices,
r_ssize size,
struct vctrs_arg* p_xs_arg,
struct r_lazy error_call
) {
r_ssize xs_size = vec_size(xs);
r_obj* xs_names = KEEP(r_names(xs));
xs = KEEP(r_clone_referenced(xs));
r_ssize i = 0;
struct vctrs_arg* p_x_arg = new_subscript_arg(
p_xs_arg,
xs_names,
xs_size,
&i
);
KEEP(p_x_arg->shelter);
r_obj* const* v_xs = r_list_cbegin(xs);
r_obj* const* v_indices = r_list_cbegin(indices);
for (; i < xs_size; ++i) {
r_obj* x = v_xs[i];
r_obj* index = v_indices[i];
const r_ssize x_size = vec_size(x);
const r_ssize index_size = r_length(index);
if (x_size == 1) {
// Recycle "up" to the size of the index
x = vec_recycle_fallback(x, index_size, p_x_arg, error_call);
} else if (x_size == size) {
// Slice "down" to the size of the index
x = vec_slice_fallback(x, index);
} else {
// `x` is the wrong size, error
vec_check_recyclable(x, size, VCTRS_ALLOW_NULL_no, p_x_arg, error_call);
}
r_list_poke(xs, i, x);
}
FREE(3);
return xs;
}static inline SEXP vec_steps(const int* p_index, const R_len_t index_n) {
SEXP steps = PROTECT(Rf_allocVector(INTSXP, index_n));
int* p_steps = INTEGER(steps);
// Indices come in 1-based
int index_previous = 1;
for (R_len_t i = 0; i < index_n; ++i) {
const int index_current = p_index[i];
if (index_current == NA_INTEGER) {
p_steps[i] = NA_INTEGER;
continue;
}
p_steps[i] = index_current - index_previous;
index_previous = index_current;
}
UNPROTECT(1);
return steps;
}static inline SEXP vec_strides(const int* p_dim, const R_len_t shape_n) {
SEXP strides = PROTECT(Rf_allocVector(INTSXP, shape_n));
int* p_strides = INTEGER(strides);
int stride = 1;
for (int i = 0; i < shape_n; ++i) {
stride *= p_dim[i];
p_strides[i] = stride;
}
UNPROTECT(1);
return strides;
}R_len_t vec_subscript_size(SEXP x) {
if (is_compact_rep(x)) {
return r_int_get(x, 1);
} else if (is_compact_seq(x)) {
return r_int_get(x, 1);
} else if (is_compact_condition(x)) {
return compact_condition_size(x);
} else {
return vec_size(x);
}
}const char* vec_type_as_str(enum vctrs_type type) {
switch (type) {
case VCTRS_TYPE_null: return "null";
case VCTRS_TYPE_unspecified: return "unspecified";
case VCTRS_TYPE_logical: return "logical";
case VCTRS_TYPE_integer: return "integer";
case VCTRS_TYPE_double: return "double";
case VCTRS_TYPE_complex: return "complex";
case VCTRS_TYPE_character: return "character";
case VCTRS_TYPE_raw: return "raw";
case VCTRS_TYPE_list: return "list";
case VCTRS_TYPE_dataframe: return "dataframe";
case VCTRS_TYPE_s3: return "s3";
case VCTRS_TYPE_scalar: return "scalar";
}
never_reached("vec_type_as_str");
}enum vctrs_type vec_typeof(r_obj* x) {
// Check for unspecified vectors before `vec_base_typeof()` which
// allows vectors of `NA` to pass through as `VCTRS_TYPE_logical`
if (vec_is_unspecified(x)) {
return VCTRS_TYPE_unspecified;
}
if (!r_is_object(x) || r_class(x) == r_null) {
return vec_base_typeof(x, false);
}
// Bare data frames are treated as a base atomic type. Subclasses of
// data frames are treated as S3 to give them a chance to be proxied
// or implement their own methods for cast, type2, etc.
if (is_bare_data_frame(x)) {
return VCTRS_TYPE_dataframe;
}
return VCTRS_TYPE_s3;
}enum vctrs_type2 vec_typeof2(r_obj* x, r_obj* y) {
int _;
return vec_typeof2_impl(vec_typeof(x), vec_typeof(y), &_);
}enum vctrs_type2_s3 vec_typeof2_s3(r_obj* x, r_obj* y) {
int _;
return vec_typeof2_s3_impl(x, y, vec_typeof(x), vec_typeof(y), &_);
}enum vctrs_type2_s3 vec_typeof2_s3_impl2(r_obj* x,
r_obj* y,
enum vctrs_type type_y,
int* left) {
switch (class_type(x)) {
case VCTRS_CLASS_bare_factor: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_S3_null_bare_factor;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_S3_unspecified_bare_factor;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_S3_logical_bare_factor;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_S3_integer_bare_factor;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_S3_double_bare_factor;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_S3_complex_bare_factor;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_S3_character_bare_factor;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_S3_raw_bare_factor;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_S3_list_bare_factor;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_S3_dataframe_bare_factor;
case VCTRS_TYPE_scalar: *left = 1; return VCTRS_TYPE2_S3_scalar_bare_factor;
case VCTRS_TYPE_s3: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = -1; return VCTRS_TYPE2_S3_bare_factor_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_bare_factor_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_bare_factor_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_bare_factor_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_bare_factor_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_bare_factor_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_bare_factor_unknown;
}
}}
}
case VCTRS_CLASS_bare_ordered: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_S3_null_bare_ordered;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_S3_unspecified_bare_ordered;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_S3_logical_bare_ordered;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_S3_integer_bare_ordered;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_S3_double_bare_ordered;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_S3_complex_bare_ordered;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_S3_character_bare_ordered;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_S3_raw_bare_ordered;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_S3_list_bare_ordered;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_S3_dataframe_bare_ordered;
case VCTRS_TYPE_scalar: *left = 1; return VCTRS_TYPE2_S3_scalar_bare_ordered;
case VCTRS_TYPE_s3: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 1; return VCTRS_TYPE2_S3_bare_factor_bare_ordered;
case VCTRS_CLASS_bare_ordered: *left = -1; return VCTRS_TYPE2_S3_bare_ordered_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_bare_ordered_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_bare_ordered_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_bare_ordered_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_bare_ordered_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_bare_ordered_unknown;
}
}}
}
case VCTRS_CLASS_bare_date: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_S3_null_bare_date;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_S3_unspecified_bare_date;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_S3_logical_bare_date;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_S3_integer_bare_date;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_S3_double_bare_date;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_S3_complex_bare_date;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_S3_character_bare_date;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_S3_raw_bare_date;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_S3_list_bare_date;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_S3_dataframe_bare_date;
case VCTRS_TYPE_scalar: *left = 1; return VCTRS_TYPE2_S3_scalar_bare_date;
case VCTRS_TYPE_s3: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 1; return VCTRS_TYPE2_S3_bare_factor_bare_date;
case VCTRS_CLASS_bare_ordered: *left = 1; return VCTRS_TYPE2_S3_bare_ordered_bare_date;
case VCTRS_CLASS_bare_date: *left = -1; return VCTRS_TYPE2_S3_bare_date_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_bare_date_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_bare_date_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_bare_date_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_bare_date_unknown;
}
}}
}
case VCTRS_CLASS_bare_posixct: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_S3_null_bare_posixct;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_S3_unspecified_bare_posixct;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_S3_logical_bare_posixct;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_S3_integer_bare_posixct;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_S3_double_bare_posixct;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_S3_complex_bare_posixct;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_S3_character_bare_posixct;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_S3_raw_bare_posixct;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_S3_list_bare_posixct;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_S3_dataframe_bare_posixct;
case VCTRS_TYPE_scalar: *left = 1; return VCTRS_TYPE2_S3_scalar_bare_posixct;
case VCTRS_TYPE_s3: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 1; return VCTRS_TYPE2_S3_bare_factor_bare_posixct;
case VCTRS_CLASS_bare_ordered: *left = 1; return VCTRS_TYPE2_S3_bare_ordered_bare_posixct;
case VCTRS_CLASS_bare_date: *left = 1; return VCTRS_TYPE2_S3_bare_date_bare_posixct;
case VCTRS_CLASS_bare_posixct: *left = -1; return VCTRS_TYPE2_S3_bare_posixct_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_bare_posixct_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_bare_posixct_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_bare_posixct_unknown;
}
}}
}
case VCTRS_CLASS_bare_posixlt: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_S3_null_bare_posixlt;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_S3_unspecified_bare_posixlt;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_S3_logical_bare_posixlt;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_S3_integer_bare_posixlt;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_S3_double_bare_posixlt;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_S3_complex_bare_posixlt;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_S3_character_bare_posixlt;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_S3_raw_bare_posixlt;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_S3_list_bare_posixlt;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_S3_dataframe_bare_posixlt;
case VCTRS_TYPE_scalar: *left = 1; return VCTRS_TYPE2_S3_scalar_bare_posixlt;
case VCTRS_TYPE_s3: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 1; return VCTRS_TYPE2_S3_bare_factor_bare_posixlt;
case VCTRS_CLASS_bare_ordered: *left = 1; return VCTRS_TYPE2_S3_bare_ordered_bare_posixlt;
case VCTRS_CLASS_bare_date: *left = 1; return VCTRS_TYPE2_S3_bare_date_bare_posixlt;
case VCTRS_CLASS_bare_posixct: *left = 1; return VCTRS_TYPE2_S3_bare_posixct_bare_posixlt;
case VCTRS_CLASS_bare_posixlt: *left = -1; return VCTRS_TYPE2_S3_bare_posixlt_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_bare_posixlt_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_bare_posixlt_unknown;
}
}}
}
case VCTRS_CLASS_bare_tibble: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_S3_null_bare_tibble;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_S3_unspecified_bare_tibble;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_S3_logical_bare_tibble;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_S3_integer_bare_tibble;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_S3_double_bare_tibble;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_S3_complex_bare_tibble;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_S3_character_bare_tibble;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_S3_raw_bare_tibble;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_S3_list_bare_tibble;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_S3_dataframe_bare_tibble;
case VCTRS_TYPE_scalar: *left = 1; return VCTRS_TYPE2_S3_scalar_bare_tibble;
case VCTRS_TYPE_s3: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 1; return VCTRS_TYPE2_S3_bare_factor_bare_tibble;
case VCTRS_CLASS_bare_ordered: *left = 1; return VCTRS_TYPE2_S3_bare_ordered_bare_tibble;
case VCTRS_CLASS_bare_date: *left = 1; return VCTRS_TYPE2_S3_bare_date_bare_tibble;
case VCTRS_CLASS_bare_posixct: *left = 1; return VCTRS_TYPE2_S3_bare_posixct_bare_tibble;
case VCTRS_CLASS_bare_posixlt: *left = 1; return VCTRS_TYPE2_S3_bare_posixlt_bare_tibble;
case VCTRS_CLASS_bare_tibble: *left = -1; return VCTRS_TYPE2_S3_bare_tibble_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_bare_tibble_unknown;
}
}}
}
default: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_S3_null_unknown;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_S3_unspecified_unknown;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_S3_logical_unknown;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_S3_integer_unknown;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_S3_double_unknown;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_S3_complex_unknown;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_S3_character_unknown;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_S3_raw_unknown;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_S3_list_unknown;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_S3_dataframe_unknown;
case VCTRS_TYPE_scalar: *left = 1; return VCTRS_TYPE2_S3_scalar_unknown;
case VCTRS_TYPE_s3: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 1; return VCTRS_TYPE2_S3_bare_factor_unknown;
case VCTRS_CLASS_bare_ordered: *left = 1; return VCTRS_TYPE2_S3_bare_ordered_unknown;
case VCTRS_CLASS_bare_date: *left = 1; return VCTRS_TYPE2_S3_bare_date_unknown;
case VCTRS_CLASS_bare_posixct: *left = 1; return VCTRS_TYPE2_S3_bare_posixct_unknown;
case VCTRS_CLASS_bare_posixlt: *left = 1; return VCTRS_TYPE2_S3_bare_posixlt_unknown;
case VCTRS_CLASS_bare_tibble: *left = 1; return VCTRS_TYPE2_S3_bare_tibble_unknown;
default: *left = -1; return VCTRS_TYPE2_S3_unknown_unknown;
}
}}
}}
r_stop_unreachable();
}SEXP vec_unique(SEXP x) {
SEXP index = PROTECT(vctrs_unique_loc(x));
SEXP out = vec_slice_unsafe(x, index);
UNPROTECT(1);
return out;
}r_obj* vec_unique_names_impl(r_obj* names, r_ssize n, bool quiet) {
r_obj* out;
if (names == r_null) {
out = KEEP(names_iota(n));
if (!quiet) {
describe_repair(names, out);
}
} else {
out = KEEP(vec_as_unique_names(names, quiet));
}
FREE(1);
return(out);
}SEXP vec_unspecified(R_len_t n) {
SEXP out = PROTECT(Rf_allocVector(LGLSXP, n));
r_lgl_fill(out, NA_LOGICAL, n);
r_attrib_poke_class(out, vctrs_unspecified_class);
UNPROTECT(1);
return out;
}void vec_validate_minimal_names(r_obj* names, r_ssize n, struct r_lazy call) {
if (names == r_null) {
r_abort_lazy_call(call, "Names repair functions can't return `NULL`.");
}
if (r_typeof(names) != R_TYPE_character) {
r_abort_lazy_call(call, "Names repair functions must return a character vector.");
}
if (n >= 0 && r_length(names) != n) {
r_abort_lazy_call(call,
"Repaired names have length %d instead of length %d.",
r_length(names),
n);
}
if (r_chr_has_string(names, r_globals.na_str)) {
r_abort_lazy_call(call, "Names repair functions can't return `NA` values.");
}
}function: t(null & 'I36265, *{ shelter : any_sexp ; type : c(0..4) | c(99) ; name_repair_arg : { x : any_sexp ; env : any_sexp } ; fn : any_sexp ; quiet : c_bool ; call : { x : any_sexp ; env : any_sexp } }, { x : any_sexp ; env : any_sexp }) --> null & 'I36265
argument: t((lgl[^(int \ 0)]<> | env<...> | externalptr<...> | lang<...> | list<...> | vec<...> | vec0<> | arrow<...>) & 'I36252, *{ shelter : any_sexp ; type : c(0..4) | c(99) ; name_repair_arg : { x : any_sexp ; env : any_sexp } ; fn : any_sexp ; quiet : c_bool ; call : { x : any_sexp ; env : any_sexp } } & 'I36253, 'I36254 & { x : any_sexp ; env : any_sexp })r_obj* as_df_row(r_obj* x,
struct name_repair_opts* name_repair,
struct r_lazy error_call) {
if (vec_is_unspecified(x) && r_names(x) == r_null) {
return x;
} else {
return as_df_row_impl(x, name_repair, error_call);
}
}function: ref('I38314) --> 'I38314
argument: any --> anyenum vctrs_run_bound as_run_bound(r_obj* which, struct r_lazy error_call) {
struct r_lazy error_arg = { .x = chrs_which, .env = r_null };
r_obj* values = KEEP(r_alloc_character(2));
r_chr_poke(values, 0, r_str("start"));
r_chr_poke(values, 1, r_str("end"));
const int match = r_arg_match(which, values, error_arg, error_call);
enum vctrs_run_bound out;
switch (match) {
case 0: out = VCTRS_RUN_BOUND_start; break;
case 1: out = VCTRS_RUN_BOUND_end; break;
default: r_stop_internal("Unknown `which` value.");
}
FREE(1);
return out;
}function: t(lgl) --> *c_int_na argument: t(any_sexp)
r_obj* as_unique_names_impl(r_obj* names, bool quiet) {
r_ssize n = r_length(names);
r_obj* new_names = KEEP(r_clone(names));
r_obj* const * v_new_names = r_chr_cbegin(new_names);
for (r_ssize i = 0; i < n; ++i) {
r_obj* elt = v_new_names[i];
// Set `NA` and dots values to "" so they get replaced by `...n`
// later on
if (needs_suffix(elt)) {
elt = strings_empty;
r_chr_poke(new_names, i, elt);
continue;
}
// Strip `...n` suffixes
const char* nm = r_str_c_string(elt);
int pos = suffix_pos(nm);
if (pos >= 0) {
elt = Rf_mkCharLenCE(nm, pos, Rf_getCharCE(elt));
r_chr_poke(new_names, i, elt);
continue;
}
}
// Append all duplicates with a suffix
r_obj* dups = KEEP(vctrs_duplicated(new_names));
const int* dups_ptr = r_lgl_cbegin(dups);
for (r_ssize i = 0; i < n; ++i) {
r_obj* elt = v_new_names[i];
if (elt != strings_empty && !dups_ptr[i]) {
continue;
}
const char* name = r_str_c_string(elt);
int size = strlen(name);
int buf_size = size + MAX_IOTA_SIZE;
R_CheckStack2(buf_size);
char buf[buf_size];
buf[0] = '\0';
r_memcpy(buf, name, size);
int remaining = buf_size - size;
int needed = snprintf(buf + size, remaining, "...%d", (int) i + 1);
if (needed >= remaining) {
stop_large_name();
}
r_chr_poke(new_names, i, Rf_mkCharLenCE(buf, size + needed, Rf_getCharCE(elt)));
}
if (!quiet) {
describe_repair(names, new_names);
}
FREE(2);
return new_names;
}function: t(any_sexp, *t(any_sexp, any_sexp, *c_void) --> any_sexp, *c_void) --> any_sexp argument: t(any_sexp & 'I2925, t(any_sexp, any_sexp, *c_void) --> any_sexp, *c_false)
static inline uint32_t attrib_hash(r_obj* x) {
uint32_t hash = 0;
r_attrib_map(x, attrib_hash_cb, &hash);
return hash;
}name: obj_hash
static inline r_obj* attrib_hash_cb(r_obj* tag, r_obj* value, void* data) {
uint32_t* p_hash = (uint32_t*) data;
*p_hash = hash_combine(*p_hash, obj_hash(tag));
*p_hash = hash_combine(*p_hash, obj_hash(value));
// Return C `NULL` to continue iteration through the attributes
return NULL;
}function: ref('I14517) --> 'I14517
argument: t({ 'I14515 }, t(any_sexp) --> any_sexp & t('I14515) --> empty) | t({ 'I14516 & 'I14515 }, t(any_sexp) --> any_sexp & t('I14515) | t('I14516) --> any) -> any_sexpSEXP bare_df_map(SEXP df, SEXP (*fn)(SEXP)) {
SEXP out = PROTECT(map(df, fn));
// Shallow ownership over `out` because `map()` generates a fresh
// list. We only care about "restoring" that bare list to the type of `df`,
// not the columns, so not recursive.
struct vec_restore_opts opts = {
.ownership = VCTRS_OWNERSHIP_shallow,
.recursively_proxied = false
};
out = vec_bare_df_restore(out, df, &opts);
UNPROTECT(1);
return out;
}name: vec_c
r_obj* build_fallback_index(r_obj* indices, r_ssize size, struct r_lazy error_call) {
const struct name_repair_opts name_repair_opts = {
.type = NAME_REPAIR_none,
.fn = r_null,
.call = error_call
};
r_obj* index = KEEP(vec_c(
indices,
r_globals.empty_int,
name_spec_inner,
&name_repair_opts,
vec_args.indices,
error_call
));
const int* v_index = r_int_cbegin(index);
// Not necessarily same as `size`!
//
// ```
// local_c_foobar()
// list_combine(
// list(foobar("a"), NULL, foobar("b")),
// indices = list(2, 3, 1),
// size = 3
// )
// ```
//
// Implies `size` of 3 but `NULL` causes the `3`
// index to get dropped, so `index_size` is `2`.
const r_ssize index_size = r_length(index);
r_obj* locations = KEEP(r_alloc_integer(size));
int* v_locations = r_int_begin(locations);
// Initialize with missing to handle locations that are never selected
for (r_ssize i = 0; i < size; ++i) {
v_locations[i] = r_globals.na_int;
}
// At each index location, put the order value, note that results in "last
// wins" behavior when multiple indices overwrite the same location
for (r_ssize i = 0; i < index_size; ++i) {
const int elt = v_index[i];
if (elt != r_globals.na_int) {
v_locations[elt - 1] = i + 1;
}
}
FREE(2);
return locations;
}function: t(raw) --> *c_bool argument: t(any_sexp)
void check_any_unmatched(
r_obj* indices,
enum vctrs_index_style indices_style,
r_ssize size,
struct r_lazy error_call
) {
r_obj* default_index = KEEP(compute_default_index(indices, indices_style, size));
const bool* v_default_index = compact_condition_cbegin(default_index);
if (p_bool_any(v_default_index, size)) {
r_obj* loc = KEEP(compact_condition_materialize_location(default_index));
stop_combine_unmatched(loc, error_call);
}
FREE(1);
}function: t(vec[^int('I36146)]) --> c_int & c_int_na('I36146) & t(p(chr) | vec[^int('I36146)]) --> c_int
argument: t(list & 'I36141)r_obj* chop_df(r_obj* x,
struct vctrs_proxy_info info,
struct vctrs_chop_indices* p_indices) {
r_obj* proxy = info.inner;
r_obj* const* v_proxy = r_list_cbegin(proxy);
const r_ssize n_cols = r_length(proxy);
r_obj* col_names = KEEP(r_names(proxy));
r_obj* row_names = KEEP(df_rownames(proxy));
const bool has_row_names = r_typeof(row_names) == R_TYPE_character;
const r_ssize out_size = indices_out_size(p_indices, proxy);
r_obj* out = KEEP(r_alloc_list(out_size));
r_obj* const* v_out = r_list_cbegin(out);
// Pre-load the `out` container with empty bare data frames
for (r_ssize i = 0; i < out_size; ++i) {
r_obj* elt = r_alloc_list(n_cols);
r_list_poke(out, i, elt);
r_attrib_poke_names(elt, col_names);
r_obj* index = indices_next(p_indices);
const r_ssize size = vec_subscript_size(index);
init_data_frame(elt, size);
if (has_row_names) {
r_obj* elt_row_names = slice_rownames(row_names, index);
r_attrib_poke(elt, r_syms.row_names, elt_row_names);
}
}
r_obj* indices = p_indices->indices;
r_obj* sizes = p_indices->sizes;
// Chop each column according to the indices, and then assign the results
// into the appropriate data frame column in the `out` list
for (r_ssize i = 0; i < n_cols; ++i) {
r_obj* col = v_proxy[i];
r_obj* col_chopped = KEEP(vec_chop_unsafe(col, indices, sizes));
r_obj* const* v_col_chopped = r_list_cbegin(col_chopped);
for (r_ssize j = 0; j < out_size; ++j) {
r_obj* elt = v_out[j];
r_list_poke(elt, i, v_col_chopped[j]);
}
FREE(1);
}
// Each data frame container is owned by us.
// Columns aren't necessarily owned by us, but that
// doesn't matter because we don't recursively restore.
// `vec_proxy_info()` doesn't recursively proxy.
const struct vec_restore_opts elt_restore_opts = {
.ownership = VCTRS_OWNERSHIP_shallow,
.recursively_proxied = false
};
// Restore each data frame
for (r_ssize i = 0; i < out_size; ++i) {
r_obj* elt = v_out[i];
elt = vec_restore_opts(elt, x, &elt_restore_opts);
r_list_poke(out, i, elt);
}
FREE(3);
return out;
}function: t(env) --> env argument: t(any_sexp)
r_obj* chop_fallback(r_obj* x, struct vctrs_chop_indices* p_indices) {
// Evaluate in a child of the global environment to allow dispatch
// to custom functions. We define `[` to point to its base
// definition to ensure consistent look-up. This is the same logic
// as in `vctrs_dispatch_n()`, reimplemented here to allow repeated
// evaluations in a loop.
r_obj* env = KEEP(r_alloc_empty_environment(r_envs.global));
r_env_bind(env, syms_x, x);
// Construct call with symbols, not values, for performance.
// TODO - Remove once bit64 is updated on CRAN. Special casing integer64
// objects to ensure correct slicing with `NA_integer_`.
r_obj* call;
if (is_integer64(x)) {
call = KEEP(r_call3(syms.vec_slice_dispatch_integer64, syms_x, syms_i));
r_env_bind(env, syms.vec_slice_dispatch_integer64, fns.vec_slice_dispatch_integer64);
} else {
call = KEEP(r_call3(syms_bracket, syms_x, syms_i));
r_env_bind(env, syms_bracket, fns_bracket);
}
// Sliced `elt` comes from R, so is foreign. Technically not proxied at all,
// so "restoring" is a bit of a hack, but we only restore if it looks like the
// `[` result is missing attributes.
struct vec_restore_opts elt_restore_opts = {
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
const r_ssize out_size = indices_out_size(p_indices, x);
r_obj* out = KEEP(r_alloc_list(out_size));
for (r_ssize i = 0; i < out_size; ++i) {
r_obj* index = indices_next(p_indices);
index = KEEP(vec_subscript_materialize(index));
// Update `i` binding with the new index value
r_env_bind(env, syms_i, index);
r_obj* elt = KEEP(r_eval(call, env));
if (!vec_is_restored(elt, x)) {
// No guarantee that we own `elt` here
elt = vec_restore_opts(elt, x, &elt_restore_opts);
}
r_list_poke(out, i, elt);
FREE(2);
}
FREE(3);
return out;
}function: t({ 'I36036 }, c_int) --> 'I36036
argument: t(p(chr) | sym | attr_any, c_false)r_obj* chop_shaped(r_obj* x,
struct vctrs_proxy_info info,
struct vctrs_chop_indices* p_indices) {
r_obj* proxy = info.inner;
const enum vctrs_type type = info.type;
r_obj* dim_names = KEEP(r_dim_names(proxy));
r_obj* row_names = r_null;
if (dim_names != r_null) {
row_names = r_list_get(dim_names, 0);
}
const r_ssize out_size = indices_out_size(p_indices, proxy);
r_obj* out = KEEP(r_alloc_list(out_size));
// Treat each `elt` as owned (we also poke its dim names)
// `vec_proxy_info()` doesn't recursively proxy.
const struct vec_restore_opts elt_restore_opts = {
.ownership = VCTRS_OWNERSHIP_shallow,
.recursively_proxied = false
};
for (r_ssize i = 0; i < out_size; ++i) {
r_obj* index = indices_next(p_indices);
r_obj* elt = KEEP(vec_slice_shaped(type, proxy, index));
if (dim_names != r_null) {
if (row_names != r_null) {
// Required to slice row names to the right size before poking to avoid
// erroring on the dimnames length check in `Rf_setAttrib()`
r_obj* new_dim_names = KEEP(r_clone(dim_names));
r_obj* new_row_names = slice_names(row_names, index);
r_list_poke(new_dim_names, 0, new_row_names);
r_attrib_poke_dim_names(elt, new_dim_names);
FREE(1);
} else {
r_attrib_poke_dim_names(elt, dim_names);
}
}
elt = vec_restore_opts(elt, x, &elt_restore_opts);
r_list_poke(out, i, elt);
FREE(1);
}
FREE(2);
return out;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> any argument: t(chr | null)
SEXP chr_as_factor(SEXP x, SEXP to, bool* lossy, struct vctrs_arg* to_arg) {
SEXP levels = PROTECT(Rf_getAttrib(to, R_LevelsSymbol));
if (TYPEOF(levels) != STRSXP) {
stop_corrupt_factor_levels(to, to_arg);
}
SEXP out;
// When `to` has no levels, it is treated as a template and the
// levels come from `x`
if (vec_size(levels) == 0) {
out = chr_as_factor_from_self(x, false);
} else {
out = chr_as_factor_impl(x, levels, lossy, false);
}
UNPROTECT(1);
return out;
}function: t(int, any_sexp) --> () argument: t(any_sexp, any_sexp)
static SEXP chr_as_factor_from_self(SEXP x, bool ordered) {
SEXP levels = PROTECT(vec_unique(x));
levels = PROTECT(remove_na_levels(levels));
// `NA` values in `x` correctly become `NA` values in the result
SEXP out = PROTECT(vec_match(x, levels));
if (ordered) {
init_ordered(out, levels);
} else {
init_factor(out, levels);
}
UNPROTECT(3);
return out;
}function: t(^int) --> *c_int & t(int) --> *c_int_na argument: t(any_sexp)
static SEXP chr_as_factor_impl(SEXP x, SEXP levels, bool* lossy, bool ordered) {
SEXP out = PROTECT(vec_match(x, levels));
const int* p_out = INTEGER(out);
R_len_t size = vec_size(x);
const SEXP* p_x = STRING_PTR_RO(x);
// Detect lossy no-matches, but allow `NA` values from `x`
for (R_len_t i = 0; i < size; ++i) {
if (p_out[i] == NA_INTEGER && p_x[i] != NA_STRING) {
*lossy = true;
UNPROTECT(1);
return R_NilValue;
}
}
if (ordered) {
init_ordered(out, levels);
} else {
init_factor(out, levels);
}
UNPROTECT(1);
return out;
}function: t(null | vec, null, c_int) --> ^int0 & t(null | vec, vec['I22909], c_int) --> ^int['I22909]
argument: t('I22877 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym), any_sexp & 'I22876, c_int_na)r_obj* chr_as_location(r_obj* subscript,
r_obj* names,
const struct location_opts* opts) {
if (names == R_NilValue) {
r_abort("Can't use character names to index an unnamed vector.");
}
if (r_typeof(names) != R_TYPE_character) {
r_abort("`names` must be a character vector.");
}
bool remove_missing = false;
r_obj* matched = KEEP(Rf_match(names, subscript, r_globals.na_int));
r_attrib_poke_names(matched, r_names(subscript));
r_ssize n = r_length(matched);
int* p = r_int_begin(matched);
r_obj* const * ip = r_chr_cbegin(subscript);
for (r_ssize k = 0; k < n; ++k) {
const r_obj* elt = ip[k];
if (elt == r_strs.empty) {
// `""` never matches, even if `names` contains a `""` name
stop_subscript_empty(subscript, opts);
}
if (elt == r_globals.na_str) {
// `NA_character_` never matches, even if `names` contains a missing name
p[k] = r_globals.na_int;
switch (opts->missing) {
case SUBSCRIPT_MISSING_PROPAGATE: continue;
case SUBSCRIPT_MISSING_REMOVE: remove_missing = true; continue;
case SUBSCRIPT_MISSING_ERROR: stop_subscript_missing(subscript, opts);
}
}
if (p[k] == r_globals.na_int) {
stop_subscript_oob_name(subscript, names, opts);
}
}
if (remove_missing) {
if (opts->missing != SUBSCRIPT_MISSING_REMOVE) {
r_stop_internal("`missing = 'remove'` must be set if `n_missing > 0`.");
}
r_obj* not_missing = KEEP(vec_detect_complete(matched));
matched = KEEP(vec_slice(matched, not_missing));
FREE(2);
}
KEEP(matched);
FREE(2);
return matched;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> any argument: t(chr | null)
SEXP chr_as_ordered(SEXP x, SEXP to, bool* lossy, struct vctrs_arg* to_arg) {
SEXP levels = PROTECT(Rf_getAttrib(to, R_LevelsSymbol));
if (TYPEOF(levels) != STRSXP) {
stop_corrupt_ordered_levels(to, to_arg);
}
SEXP out;
// When `to` has no levels, it is treated as a template and the
// levels come from `x`
if (vec_size(levels) == 0) {
out = chr_as_factor_from_self(x, true);
} else {
out = chr_as_factor_impl(x, levels, lossy, true);
}
UNPROTECT(1);
return out;
}name: ASSIGN_BARRIER_SHAPED
static inline SEXP chr_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_BARRIER_SHAPED(SEXP, STRING_PTR_RO, SET_STRING_ELT);
}name: VEC_DETECT_COMPLETE
void chr_detect_complete(SEXP x, R_len_t size, int* p_out) {
VEC_DETECT_COMPLETE(SEXP, STRING_PTR_RO, chr_is_missing);
}function: ( ) --> *any argument: ()
r_obj* chr_encode_utf8(r_obj* x) {
r_ssize size = r_length(x);
r_ssize start = chr_find_encoding_start(x, size);
if (size == start) {
return x;
}
x = KEEP(r_clone(x));
r_obj* const* p_x = r_chr_cbegin(x);
const void* vmax = vmaxget();
for (r_ssize i = start; i < size; ++i) {
r_obj* const elt = p_x[i];
if (!str_is_ascii_or_utf8(elt)) {
r_chr_poke(x, i, str_as_utf8(elt));
}
}
vmaxset(vmax);
FREE(1);
return x;
}name: EQUAL
SEXP chr_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
EQUAL(SEXP, STRING_PTR_RO, chr_equal_na_equal, chr_equal_na_propagate);
}name: SLICE_BARRIER
r_obj* chr_names_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE_BARRIER(R_TYPE_character, r_chr_cbegin, r_chr_poke, r_strs.empty);
}function: t(any, *p(chr), *c_string) --> { x : any ; y : c_int_na }
argument: t(c_int_na & 'I11596, *any_sexp, *c_string)void chr_order_chunk(
bool decreasing,
bool na_last,
r_ssize size,
int* p_o,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
SEXP* p_x_chunk_sexp = (SEXP*) p_lazy_x_chunk->p_data;
const enum vctrs_sortedness sortedness = chr_sortedness(
p_x_chunk_sexp,
size,
decreasing,
na_last,
p_group_infos
);
if (sortedness != VCTRS_SORTEDNESS_unsorted) {
ord_resolve_sortedness_chunk(sortedness, size, p_o);
return;
}
const char** p_x_aux = (const char**) init_lazy_raw(p_lazy_x_aux);
// Extract out `CHAR()` string pointers and `Rf_length()` string sizes,
// skipping missings along the way, but returning the count of them and
// the max string size
const struct r_ssize_int_pair pair = chr_extract_without_missings(
size,
p_x_chunk_sexp,
p_x_aux
);
const r_ssize n_missing = pair.x;
const int max_string_size = pair.y;
if (n_missing != 0) {
// If there are missings, handle them by pushing their ordering to the front
// (or back, depending on `na_last`) of `p_o`
int* p_o_aux = init_lazy_raw(p_lazy_o_aux);
chr_handle_missings(
size,
n_missing,
na_last,
p_x_chunk_sexp,
p_o,
p_o_aux
);
size -= n_missing;
p_o = na_last ? p_o : (p_o + n_missing);
}
// Now forget about `p_x_chunk_sexp` and swap `p_x_aux` with `p_x_chunk`
// to get back to the "standard" definition of these pointers
//p_x_chunk_sexp = NULL;
const char** p_x_chunk = (const char**) p_lazy_x_chunk->p_data;
SWAP(const char**, p_x_chunk, p_x_aux);
if (!na_last && n_missing != 0) {
// Push `!na_last` group before sorting
groups_size_maybe_push(n_missing, p_group_infos);
}
if (size <= ORDER_INSERTION_BOUNDARY) {
chr_order_insertion(
size,
decreasing,
p_x_chunk,
p_o,
p_group_infos
);
} else {
int* p_o_aux = (int*) init_lazy_raw(p_lazy_o_aux);
uint8_t* p_bytes = (uint8_t*) init_lazy_raw(p_lazy_bytes);
chr_order_radix(
size,
decreasing,
max_string_size,
p_x_chunk,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_group_infos
);
}
if (na_last && n_missing != 0) {
// Push `na_last` group after sorting
groups_size_maybe_push(n_missing, p_group_infos);
}
}name: chr_order_radix_recurse
void chr_order_radix_recurse(
const r_ssize size,
const bool decreasing,
const int pass,
const int max_string_size,
const char** p_x,
int* p_o,
const char** p_x_aux,
int* p_o_aux,
uint8_t* p_bytes,
struct group_infos* p_group_infos
) {
// Exit as fast as possible if we are below the insertion order boundary
if (size <= ORDER_INSERTION_BOUNDARY) {
chr_order_insertion(
size,
decreasing,
p_x,
p_o,
p_group_infos
);
return;
}
const int next_pass = pass + 1;
// Fast check to see if all bytes within this group are the same. If so, skip
// this `pass` since we learned nothing. Unlike with other methods, it is useful
// to do this check before the histogram because with strings there is often a
// long common prefix, and it is faster to skip past that as quickly as possible,
// avoiding the jumpiness of histogramming.
if (chr_all_same_byte(p_x, size)) {
if (next_pass == max_string_size) {
// If we are already at the last pass, we are done
groups_size_maybe_push(size, p_group_infos);
} else {
// Otherwise, advance `p_x` to the next byte and immediately recurse using
// the same `size` since the group size hasn't changed
for (r_ssize i = 0; i < size; ++i) {
++p_x[i];
}
chr_order_radix_recurse(
size,
decreasing,
next_pass,
max_string_size,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_group_infos
);
}
return;
}
// We don't carry along `p_counts` from an up front allocation since
// the strings have variable length
r_ssize p_counts[UINT8_MAX_SIZE] = { 0 };
// Histogram
//
// Histogramming strings is very special!
//
// Note that R strings never contain a nul terminator of `\0`, which is byte
// `0`, in the string itself. However, all R strings end with a nul terminator
// since they are C style strings.
//
// We utilize this fact when histogramming. If we hit a string of "ab" on
// `pass = 2` then it will extract the nul terminator `\0` as byte `0` and
// will therefore bucket all `"ab"` strings together. Then the check for
// `nul_terminator_i` will detect this, keeping us from over recursing on
// `"ab"` and indexing past the nul terminator!
//
// This trick avoids needing to track the string size alongside the string
// pointer. We just need the `max_string_size` of the total number of times to
// recurse, and the algorithm automatically stops early on shorter strings.
//
// We also advance the `char*` returned by `p_x[i]` to the next byte right
// after we access it, for use by the next `pass`. This actually makes
// `chr_order_insertion()` and `chr_all_same_byte()` a little simpler, because
// we've already taken care of advancing past all the bytes that we know are
// all the same. For strings like `"ab"` in the example above, this can advance
// us past the `\0` nul terminator, but we will never access that location.
for (r_ssize i = 0; i < size; ++i) {
const uint8_t byte = (uint8_t) *p_x[i];
++p_x[i];
p_bytes[i] = byte;
++p_counts[byte];
}
r_ssize cumulative = 0;
// Handle decreasing/increasing by altering the order in which
// counts are accumulated
const int direction = decreasing ? -1 : 1;
r_ssize j = decreasing ? UINT8_MAX_SIZE - 1 : 0;
// Accumulate counts, skip zeros
for (uint16_t i = 0; i < UINT8_MAX_SIZE; ++i) {
r_ssize count = p_counts[j];
if (count == 0) {
j += direction;
continue;
}
// Insert current cumulative value, then increment
p_counts[j] = cumulative;
cumulative += count;
j += direction;
}
// Place into auxiliary arrays in the correct order
for (r_ssize i = 0; i < size; ++i) {
const uint8_t byte = p_bytes[i];
const r_ssize loc = p_counts[byte]++;
p_o_aux[loc] = p_o[i];
p_x_aux[loc] = p_x[i];
}
// Copy back into `p_o` because our output is `p_o`, but recognize that we can
// just swap the auxiliary data related to `x` to achieve the same idea there
r_memcpy(p_o, p_o_aux, size * sizeof(*p_o_aux));
SWAP(const char**, p_x, p_x_aux);
// Cumulative counts will be in reverse order if we were decreasing. We
// reverse them to put them in the correct order for cumulative count diffing.
// This works nicely because `UINT8_MAX_SIZE` is even.
if (decreasing) {
for (uint16_t i = 0; i < UINT8_MAX_SIZE_HALVED; ++i) {
const r_ssize front = p_counts[i];
const r_ssize back = p_counts[UINT8_MAX_SIZE - 1 - i];
p_counts[i] = back;
p_counts[UINT8_MAX_SIZE - 1 - i] = front;
}
}
const uint16_t nul_terminator_i = decreasing ? UINT8_MAX_SIZE - 1 : 0;
r_ssize last_cumulative_count = 0;
// Recurse on subgroups as required
for (uint16_t i = 0; last_cumulative_count < size && i < UINT8_MAX_SIZE; ++i) {
const r_ssize cumulative_count = p_counts[i];
if (!cumulative_count) {
continue;
}
// Set to zero to clear for subsequent groups
p_counts[i] = 0;
// Diff the accumulated counts to get the radix group size
const r_ssize group_size = cumulative_count - last_cumulative_count;
last_cumulative_count = cumulative_count;
if (group_size == 1) {
groups_size_maybe_push(1, p_group_infos);
++p_x;
++p_o;
continue;
}
// If `i` is pointing to the `\0` byte bucket, we are done with this group.
// `\0` is the end of string marker, so all strings in this bucket are the
// same and we can't recurse further into them, otherwise we'd index OOB
// (see the test that mentions `\0`). Happens with `c("abc", "abd", "a",
// "a")` where after the first pass we haven't learned anything, and after
// the second pass two of the strings are on `\0`. We avoid indexing OOB on
// a third pass by exiting early when we see the `\0` group.
// `chr_all_same()` would also catch this, but this check is faster and
// clearer.
if (i == nul_terminator_i) {
groups_size_maybe_push(group_size, p_group_infos);
p_x += group_size;
p_o += group_size;
continue;
}
// If we've made it to the end of the string, finalize the group.
// We can get here with `c("xyz", "xyz", "xyx")` where we need the
// last byte to break the tie, but we end up with a group size of 2.
if (next_pass == max_string_size) {
groups_size_maybe_push(group_size, p_group_infos);
p_x += group_size;
p_o += group_size;
continue;
}
// If the upcoming subgroup is all the same string, we are done. This is a
// very useful performance optimization for cases like `c("abcd", "def",
// "abcd")` where after the first pass we have two groups, but every string
// within each group is already the same so we don't need to continue
// recursing.
if (chr_all_same(p_x, group_size)) {
groups_size_maybe_push(group_size, p_group_infos);
p_x += group_size;
p_o += group_size;
continue;
}
// Order next byte of this subgroup
chr_order_radix_recurse(
group_size,
decreasing,
next_pass,
max_string_size,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_group_infos
);
p_x += group_size;
p_o += group_size;
}
}name: SLICE_BARRIER
r_obj* chr_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE_BARRIER(R_TYPE_character, r_chr_cbegin, r_chr_poke, r_globals.na_str);
}name: SLICE_BARRIER_SHAPED
static SEXP chr_slice_shaped(SEXP x, SEXP index, struct strides_info* p_info) {
SLICE_BARRIER_SHAPED(STRSXP, SEXP, STRING_PTR_RO, SET_STRING_ELT, NA_STRING);
}name: vec_ptype
r_obj* col_ptype(r_obj* x) {
return vec_ptype(x, vec_args.empty, r_lazy_null);
}function: t(list) --> *any_sexp
argument: t('I24073 & (p(chr) | vec[^int('I24087)]))r_obj* compute_default_index(
r_obj* indices,
enum vctrs_index_style indices_style,
r_ssize size
) {
const r_ssize indices_size = r_length(indices);
r_obj* const* v_indices = r_list_cbegin(indices);
r_obj* out = KEEP(new_compact_condition(size));
bool* v_out = compact_condition_begin(out);
// Initialize mark everything as unmatched
p_bool_fill(v_out, size, true);
// Unmark matched locations according to the index style
switch (indices_style) {
case VCTRS_INDEX_STYLE_location: {
for (r_ssize i = 0; i < indices_size; ++i) {
r_obj* index = v_indices[i];
if (is_compact_seq(index)) {
const int* v_index = r_int_cbegin(index);
const r_ssize start = v_index[0];
const r_ssize size = v_index[1];
const r_ssize step = v_index[2];
r_ssize loc = start;
for (r_ssize j = 0; j < size; ++j) {
v_out[loc] = false;
loc += step;
}
} else {
const r_ssize size = r_length(index);
const int* v_index = r_int_cbegin(index);
for (r_ssize j = 0; j < size; ++j) {
const int loc = v_index[j];
if (loc != r_globals.na_int) {
// If not `NA`, mark location as matched by at least 1 index
v_out[loc - 1] = false;
}
}
}
}
break;
}
case VCTRS_INDEX_STYLE_condition: {
for (r_ssize i = 0; i < indices_size; ++i) {
r_obj* index = v_indices[i];
const int* v_index = r_lgl_cbegin(index);
for (r_ssize j = 0; j < size; ++j) {
const int elt = v_index[j];
// If `TRUE`, mark location as matched by at least 1 index.
// Specially optimized to be branchless, which does greatly help.
v_out[j] &= (elt != 1);
}
}
break;
}
default: {
r_stop_unreachable();
}
}
FREE(1);
return out;
}function: ref('I12763) --> 'I12763
argument: any --> anyr_obj* compute_nesting_container_ids(r_obj* x,
const int* v_order,
const int* v_group_sizes,
const int* v_outer_group_sizes,
r_ssize size,
r_ssize n_groups,
bool has_outer_group_sizes) {
if (!is_data_frame(x)) {
r_stop_internal("`x` must be a data frame.");
}
int n_prot = 0;
const r_ssize n_cols = r_length(x);
r_obj* out = KEEP_N(r_alloc_list(2), &n_prot);
r_obj* container_ids = r_alloc_integer(size);
r_list_poke(out, 0, container_ids);
int* v_container_ids = r_int_begin(container_ids);
r_obj* n_container_ids = r_alloc_integer(1);
r_list_poke(out, 1, n_container_ids);
int* p_n_container_ids = r_int_begin(n_container_ids);
// Initialize ids to 0, which is always our first container id value.
// This means we start with 1 container.
r_memset(v_container_ids, 0, size * sizeof(int));
*p_n_container_ids = 1;
if (size == 0) {
// Algorithm requires at least 1 row
FREE(n_prot);
return out;
}
if (n_cols == 1) {
// If there is only 1 column, `x` is in increasing order already when
// ordered by `v_order`.
// If `v_outer_group_sizes` were supplied, within each group `x` will
// be in increasing order (since the single `x` column is the one that
// broke any ties), and that is all that is required.
FREE(n_prot);
return out;
}
struct r_dyn_array* p_prev_rows = r_new_dyn_vector(R_TYPE_integer, 10000);
KEEP_N(p_prev_rows->shelter, &n_prot);
struct poly_vec* p_poly_x = new_poly_vec(x, VCTRS_TYPE_dataframe);
KEEP_N(p_poly_x->shelter, &n_prot);
const void* v_x = p_poly_x->p_vec;
// Will be used if `has_outer_group_sizes` is `true`
r_ssize loc_outer_group_sizes = 0;
r_ssize loc_next_outer_group_start = 0;
r_ssize loc_group_start = 0;
for (r_ssize i = 0; i < n_groups; ++i) {
if (has_outer_group_sizes && loc_next_outer_group_start == loc_group_start) {
// Start of a new outer group. Clear all stored previous rows.
p_prev_rows->count = 0;
loc_next_outer_group_start += v_outer_group_sizes[loc_outer_group_sizes];
++loc_outer_group_sizes;
}
const r_ssize group_size = v_group_sizes[i];
const int cur_row = v_order[loc_group_start] - 1;
int container_id = 0;
int n_container_ids_group = p_prev_rows->count;
for (; container_id < n_container_ids_group; ++container_id) {
const int prev_row = r_dyn_int_get(p_prev_rows, container_id);
if (p_nesting_container_df_compare_fully_ge_na_equal(v_x, cur_row, v_x, prev_row)) {
// Current row is fully greater than or equal to previous row.
// Meaning it is not a new `container_id`, and it falls in the current container.
break;
}
}
if (container_id == n_container_ids_group) {
// New `container_id` for this outer group, which we add to the end
r_dyn_push_back(p_prev_rows, &cur_row);
++n_container_ids_group;
if (n_container_ids_group > *p_n_container_ids) {
// `p_prev_rows` is reset for each outer group,
// so we have to keep a running overall count
*p_n_container_ids = n_container_ids_group;
}
} else {
// Update stored row location to the current row,
// since the current row is greater than or equal to it
r_dyn_int_poke(p_prev_rows, container_id, cur_row);
}
for (r_ssize j = 0; j < group_size; ++j) {
v_container_ids[v_order[loc_group_start] - 1] = container_id;
++loc_group_start;
}
}
FREE(n_prot);
return out;
}name: ASSIGN
r_obj* cpl_assign(
r_obj* x,
r_obj* index,
r_obj* value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN(Rcomplex, COMPLEX, COMPLEX_RO);
}name: ASSIGN_SHAPED
static inline SEXP cpl_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_SHAPED(Rcomplex, COMPLEX, COMPLEX_RO);
}name: COL_DETECT_MISSING
r_ssize cpl_col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
COL_DETECT_MISSING(r_complex, r_cpl_cbegin, cpl_is_missing);
}name: VEC_COL_DETECT_RUN_BOUNDS_BOOL
void cpl_col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_COL_DETECT_RUN_BOUNDS_BOOL(Rcomplex, r_cpl_cbegin, cpl_equal_na_equal);
}function: ref('I35268) --> 'I35268
argument: any --> anyint cpl_compare_na_equal(Rcomplex x, Rcomplex y) {
r_stop_internal("Can't compare complex types.");
}name: VEC_DETECT_COMPLETE
void cpl_detect_complete(SEXP x, R_len_t size, int* p_out) {
VEC_DETECT_COMPLETE(Rcomplex, COMPLEX_RO, cpl_is_missing);
}name: DETECT_MISSING
r_obj* cpl_detect_missing(r_obj* x) {
DETECT_MISSING(r_complex, r_cpl_cbegin, cpl_is_missing);
}name: Rcomplex
void cpl_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_DETECT_RUN_BOUNDS_BOOL(Rcomplex, r_cpl_cbegin, cpl_equal_na_equal);
}name: EQUAL
SEXP cpl_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
EQUAL(Rcomplex, COMPLEX_RO, cpl_equal_na_equal, cpl_equal_na_propagate);
}function: t(c_true, c_true) --> c_true & t(c_false, c_false) | t(c_false, c_true) | t(c_true, c_false) --> c_false argument: t(c_int_na, c_int_na)
static inline int cpl_equal_na_propagate(Rcomplex x, Rcomplex y) {
int real_equal = dbl_equal_na_propagate(x.r, y.r);
int imag_equal = dbl_equal_na_propagate(x.i, y.i);
if (real_equal == NA_LOGICAL || imag_equal == NA_LOGICAL) {
return NA_LOGICAL;
} else {
return real_equal && imag_equal;
}
}name: FIRST_MISSING
r_ssize cpl_first_missing(r_obj* x) {
FIRST_MISSING(r_complex, r_cpl_cbegin, cpl_is_missing);
}name: HASH
static inline uint32_t cpl_hash(r_obj* x) {
HASH(r_complex, r_cpl_cbegin, cpl_hash_scalar);
}name: HASH_FILL
static inline void cpl_hash_fill_na_equal(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL(r_complex, r_cpl_cbegin, cpl_hash_scalar);
}name: HASH_FILL_NA_PROPAGATE
static inline void cpl_hash_fill_na_propagate(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL_NA_PROPAGATE(r_complex, r_cpl_cbegin, cpl_hash_scalar, cpl_is_missing);
}function: t({ i : c_double ; r : c_double ..}) --> any
argument: t(s({ r: c_double, i: c_double }))void cpl_order(
SEXP x,
bool decreasing,
bool na_last,
bool nan_distinct,
r_ssize size,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
// We treat complex as a two column data frame, so we have to use group
// information for at least the first column.
// - If a complex atomic vector is used, `ignore_groups` will be true unless
// the user also requested group information.
// - If the first column of a df is a complex column, `ignore_groups` will
// be false.
bool reset_ignore_groups = false;
if (p_group_infos->ignore_groups) {
p_group_infos->ignore_groups = false;
reset_ignore_groups = true;
}
const Rcomplex* p_x_cpl = COMPLEX_RO(x);
// When a complex column is present,
// `lazy_x_chunk` and `lazy_x_aux` are created to have the
// size of a double vector.
double* p_x_chunk_dbl = (double*) init_lazy_raw(p_lazy_x_chunk);
// Handle the real portion first
for (r_ssize i = 0; i < size; ++i) {
p_x_chunk_dbl[i] = cpl_normalise_missing(p_x_cpl[i]).r;
}
/*
* Call double ordering algorithm on real section.
*
* In this case, both `p_x_chunk_dbl` and `p_lazy_x_chunk` are passed through,
* but we set `copy = false` which tells `dbl_order_impl()` not to copy
* the input (`p_x_chunk_dbl`) over to the chunk vector of (`p_lazy_x_chunk`).
* It has already been done when we extracted the real section.
*/
dbl_order_impl(
p_x_chunk_dbl,
decreasing,
na_last,
nan_distinct,
size,
false,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
// Ordering will now be initialized
int* p_o = p_order->p_data;
// Reset `ignore_groups` for the second pass if we don't need to track groups.
// This happens if an atomic complex vector is passed in and the user
// hasn't requested group information.
if (reset_ignore_groups) {
p_group_infos->ignore_groups = true;
}
// Get the number of group chunks from the first pass
struct group_info* p_group_info_pre = groups_current(p_group_infos);
r_ssize n_groups = p_group_info_pre->n_groups;
// If there were no ties, we are completely done
if (n_groups == size) {
return;
}
// Swap to other group info to prepare for the imaginary section
groups_swap(p_group_infos);
// Fill with the imaginary portion.
// Uses updated ordering to place it in sequential order.
for (r_ssize i = 0; i < size; ++i) {
const int loc = p_o[i] - 1;
p_x_chunk_dbl[i] = cpl_normalise_missing(p_x_cpl[loc]).i;
}
// Iterate over the group chunks from the first pass
for (r_ssize group = 0; group < n_groups; ++group) {
r_ssize group_size = p_group_info_pre->p_data[group];
// Fast handling of simplest case
if (group_size == 1) {
++p_x_chunk_dbl;
++p_o;
groups_size_maybe_push(1, p_group_infos);
continue;
}
dbl_order_chunk_impl(
decreasing,
na_last,
nan_distinct,
group_size,
p_x_chunk_dbl,
p_o,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
p_x_chunk_dbl += group_size;
p_o += group_size;
}
}name: SLICE
r_obj* cpl_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE(R_TYPE_complex, r_complex, r_cpl_begin, r_cpl_cbegin, r_globals.na_cpl);
}name: SLICE_SHAPED
static SEXP cpl_slice_shaped(SEXP x, SEXP index, struct strides_info* p_info) {
SLICE_SHAPED(CPLXSXP, Rcomplex, COMPLEX, COMPLEX_RO, vctrs_shared_na_cpl);
}function: t('I36873 & (p(chr) | vec), c_int_na | c_double) --> 'I36873 & (p(chr) | vec)
argument: t(any_sexp, 'I36863)r_obj* data_frame(r_obj* x,
r_ssize size,
const struct name_repair_opts* p_name_repair_opts,
struct r_lazy error_call) {
const bool unpack = true;
r_obj* out = KEEP(df_list(x, size, unpack, p_name_repair_opts, error_call));
out = new_data_frame(out, size);
FREE(1);
return out;
}function: t(chr, any_sexp & 'I27196) --> any_sexp & 'I27196 argument: t(any_sexp, any_sexp)
SEXP datetime_datetime_ptype2(SEXP x, SEXP y) {
SEXP x_tzone = PROTECT(tzone_get(x));
SEXP y_tzone = PROTECT(tzone_get(y));
// Never allocates
SEXP tzone = tzone_union(x_tzone, y_tzone);
SEXP out = new_empty_datetime(tzone);
UNPROTECT(2);
return out;
}function: t(chr, chr) --> c_bool argument: t(any_sexp, any_sexp & 'I16572)
static SEXP datetime_rezone(SEXP x, SEXP tzone) {
SEXP x_tzone = PROTECT(tzone_get(x));
if (tzone_equal(x_tzone, tzone)) {
UNPROTECT(1);
return x;
}
SEXP out = PROTECT(r_clone_referenced(x));
Rf_setAttrib(out, syms_tzone, tzone);
UNPROTECT(2);
return out;
}function: t(v(dbl & 'I5818) & 'I5817) --> v(dbl & 'I5818) & 'I5817 & t(v(int & 'I5818) & 'I5817) --> p(dbl) argument: t(attr_any | 'I5805)
static SEXP datetime_validate(SEXP x) {
x = PROTECT(datetime_validate_tzone(x));
x = PROTECT(datetime_validate_type(x));
UNPROTECT(2);
return x;
}function: t(c_false, c_false, any, c_null, *c_int_na) | t(c_true, c_false, any, c_null, *c_int_na) --> () argument: t(c_bool & 'I10073, c_bool & 'I10074, 'I10076, *c_double, *c_int_na)
void dbl_adjust(
const bool decreasing,
const bool na_last,
const bool nan_distinct,
const r_ssize size,
void* p_x
) {
double* p_x_dbl = (double*) p_x;
uint64_t* p_x_u64 = (uint64_t*) p_x;
if (nan_distinct) {
dbl_adjust_nan_distinct(decreasing, na_last, size, p_x_dbl, p_x_u64);
} else {
dbl_adjust_nan_identical(decreasing, na_last, size, p_x_dbl, p_x_u64);
}
}name: ASSIGN
r_obj* dbl_assign(
r_obj* x,
r_obj* index,
r_obj* value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN(double, REAL, REAL_RO);
}name: ASSIGN_SHAPED
static inline SEXP dbl_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_SHAPED(double, REAL, REAL_RO);
}name: COL_DETECT_MISSING
r_ssize dbl_col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
COL_DETECT_MISSING(double, r_dbl_cbegin, dbl_is_missing);
}name: VEC_COL_DETECT_RUN_BOUNDS_BOOL
void dbl_col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_COL_DETECT_RUN_BOUNDS_BOOL(double, r_dbl_cbegin, dbl_equal_na_equal);
}name: VEC_DETECT_COMPLETE
void dbl_detect_complete(SEXP x, R_len_t size, int* p_out) {
VEC_DETECT_COMPLETE(double, REAL_RO, dbl_is_missing);
}name: DETECT_MISSING
r_obj* dbl_detect_missing(r_obj* x) {
DETECT_MISSING(double, r_dbl_cbegin, dbl_is_missing);
}name: double
void dbl_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_DETECT_RUN_BOUNDS_BOOL(double, r_dbl_cbegin, dbl_equal_na_equal);
}name: EQUAL
SEXP dbl_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
EQUAL(double, REAL_RO, dbl_equal_na_equal, dbl_equal_na_propagate);
}name: UINT8_MAX
uint8_t dbl_extract_uint64_byte(uint64_t x, uint8_t shift) {
return (x >> shift) & UINT8_MAX;
}name: FIRST_MISSING
r_ssize dbl_first_missing(r_obj* x) {
FIRST_MISSING(double, r_dbl_cbegin, dbl_is_missing);
}name: HASH
static inline uint32_t dbl_hash(r_obj* x) {
HASH(double, r_dbl_cbegin, dbl_hash_scalar);
}name: HASH_FILL
static inline void dbl_hash_fill_na_equal(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL(double, r_dbl_cbegin, dbl_hash_scalar);
}name: HASH_FILL_NA_PROPAGATE
static inline void dbl_hash_fill_na_propagate(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL_NA_PROPAGATE(double, r_dbl_cbegin, dbl_hash_scalar, dbl_is_missing);
}function: t({ ;; `I67 }, 'I10000) --> { d : 'I10000 ;; `I67 }
argument: t(any, 'I9990)uint64_t dbl_map_to_uint64(double x) {
// Catch `-0` vs `0`
if (x == 0) {
x = 0;
}
// Reinterpret as uint64_t without changing bytes
d_u64.d = x;
d_u64.u64 = dbl_flip_uint64(d_u64.u64);
return d_u64.u64;
}name: UINT8_MAX_SIZE
void dbl_order_radix_recurse(
const r_ssize size,
const uint8_t pass,
uint64_t* p_x,
int* p_o,
uint64_t* p_x_aux,
int* p_o_aux,
uint8_t* p_bytes,
r_ssize* p_counts,
bool* p_skips,
struct group_infos* p_group_infos
) {
// Exit as fast as possible if we are below the insertion order boundary
if (size <= ORDER_INSERTION_BOUNDARY) {
dbl_order_insertion(size, p_x, p_o, p_group_infos);
return;
}
// Skip passes where our up front check told us that all bytes were the same
uint8_t next_pass = pass + 1;
r_ssize* p_counts_next_pass = p_counts + UINT8_MAX_SIZE;
while (next_pass < DBL_MAX_RADIX_PASS && p_skips[next_pass]) {
++next_pass;
p_counts_next_pass += UINT8_MAX_SIZE;
}
const uint8_t radix = PASS_TO_RADIX(pass, DBL_MAX_RADIX_PASS);
const uint8_t shift = radix * 8;
uint8_t byte = 0;
// Histogram
for (r_ssize i = 0; i < size; ++i) {
const uint64_t x_elt = p_x[i];
byte = dbl_extract_uint64_byte(x_elt, shift);
p_bytes[i] = byte;
++p_counts[byte];
}
// Fast check to see if all bytes were the same.
// If so, skip this `pass` since we learned nothing.
// No need to accumulate counts and iterate over chunks,
// we know all others are zero.
if (p_counts[byte] == size) {
// Reset count for other group chunks
p_counts[byte] = 0;
if (next_pass == DBL_MAX_RADIX_PASS) {
// If we are already at the last pass, we are done
groups_size_maybe_push(size, p_group_infos);
} else {
// Otherwise, recurse on next byte using the same `size` since
// the group size hasn't changed
dbl_order_radix_recurse(
size,
next_pass,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts_next_pass,
p_skips,
p_group_infos
);
}
return;
}
r_ssize cumulative = 0;
// Accumulate counts, skip zeros
for (uint16_t i = 0; i < UINT8_MAX_SIZE; ++i) {
r_ssize count = p_counts[i];
if (count == 0) {
continue;
}
// Replace with `cumulative` first, then bump `cumulative`.
// `p_counts` now represents starting locations for each radix group.
p_counts[i] = cumulative;
cumulative += count;
}
// Place into auxiliary arrays in the correct order, then copy back over
for (r_ssize i = 0; i < size; ++i) {
const uint8_t byte = p_bytes[i];
const r_ssize loc = p_counts[byte]++;
p_o_aux[loc] = p_o[i];
p_x_aux[loc] = p_x[i];
}
// Copy back over
r_memcpy(p_o, p_o_aux, size * sizeof(*p_o_aux));
r_memcpy(p_x, p_x_aux, size * sizeof(*p_x_aux));
r_ssize last_cumulative_count = 0;
// Recurse on subgroups as required
for (uint16_t i = 0; last_cumulative_count < size && i < UINT8_MAX_SIZE; ++i) {
const r_ssize cumulative_count = p_counts[i];
if (!cumulative_count) {
continue;
}
p_counts[i] = 0;
// Diff the accumulated counts to get the radix group size
const r_ssize group_size = cumulative_count - last_cumulative_count;
last_cumulative_count = cumulative_count;
if (group_size == 1) {
groups_size_maybe_push(1, p_group_infos);
++p_x;
++p_o;
continue;
}
// Can get here in the case of ties, like c(1, 1), which have a
// `group_size` of 2 in the last radix, but there is nothing left to
// compare so we are done.
if (next_pass == DBL_MAX_RADIX_PASS) {
groups_size_maybe_push(group_size, p_group_infos);
p_x += group_size;
p_o += group_size;
continue;
}
// Order next byte of this subgroup
dbl_order_radix_recurse(
group_size,
next_pass,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts_next_pass,
p_skips,
p_group_infos
);
p_x += group_size;
p_o += group_size;
}
}name: SLICE
r_obj* dbl_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE(R_TYPE_double, double, r_dbl_begin, r_dbl_cbegin, r_globals.na_dbl);
}name: SLICE_SHAPED
static SEXP dbl_slice_shaped(SEXP x, SEXP index, struct strides_info* p_info) {
SLICE_SHAPED(REALSXP, double, REAL, REAL_RO, NA_REAL);
}function: t(any_sexp, env) --> any argument: t(null, any_sexp)
void describe_repair(r_obj* old_names, r_obj* new_names) {
r_obj* call = KEEP(r_call3(r_sym("describe_repair"),
old_names,
new_names));
r_eval(call, vctrs_ns_env);
// To reset visibility when called from a `.External2()`
r_eval(r_null, r_envs.empty);
FREE(1);
}function: t(list) --> *any_sexp
argument: t('I8326 & (p(chr) | vec[^int('I8330)]))SEXP df_apply(SEXP x, SEXP chr_proxy_collate) {
const r_ssize n_cols = r_length(x);
const SEXP* v_x = VECTOR_PTR_RO(x);
r_ssize i = 0;
for (; i < n_cols; ++i) {
SEXP col = v_x[i];
if (vec_proxy_typeof(col) == VCTRS_TYPE_character) {
break;
}
}
if (i == n_cols) {
// No character columns
return x;
}
SEXP out = PROTECT(r_clone_referenced(x));
for (; i < n_cols; ++i) {
SEXP col = v_x[i];
if (vec_proxy_typeof(col) != VCTRS_TYPE_character) {
continue;
}
col = chr_apply(col, chr_proxy_collate);
SET_VECTOR_ELT(out, i, col);
}
UNPROTECT(1);
return out;
}function: t(^int) --> *c_int & t(int) --> *c_int_na argument: t(any_sexp)
r_obj* df_cast_match(const struct cast_opts* opts,
r_obj* x_names,
r_obj* to_names) {
r_obj* x = opts->x;
r_obj* to = opts->to;
r_obj* to_dups_pos = KEEP(vec_match(to_names, x_names));
int* to_dups_pos_data = r_int_begin(to_dups_pos);
r_ssize to_len = r_length(to_dups_pos);
r_obj* out = KEEP(r_alloc_list(to_len));
r_attrib_poke(out, r_syms.names, to_names);
r_ssize size = df_size(x);
r_ssize common_len = 0;
r_ssize i = 0;
r_ssize x_arg_loc = 0;
struct vctrs_arg* named_x_arg = new_subscript_arg(opts->p_x_arg, x_names, r_length(x_names), &x_arg_loc);
KEEP(named_x_arg->shelter);
struct vctrs_arg* named_to_arg = new_subscript_arg(opts->p_to_arg, to_names, to_len, &i);
KEEP(named_to_arg->shelter);
for (; i < to_len; ++i) {
r_ssize pos = to_dups_pos_data[i];
if (pos == r_globals.na_int) {
r_obj* to_col = r_list_get(to, i);
// FIXME: Need to initialise the vector because we currently use
// `vec_assign()` in `vec_rbind()` before falling back. Attach
// an attribute to recognise unspecified vectors in
// `base_c_invoke()`.
if (opts->s3_fallback && vec_is_common_class_fallback(to_col)) {
r_obj* col = KEEP(vec_init(to_col, size));
r_attrib_poke(col, r_sym("vctrs:::unspecified"), r_true);
r_list_poke(out, i, col);
FREE(1);
} else {
r_obj* col = vec_init(to_col, size);
r_list_poke(out, i, col);
}
} else {
--pos; // 1-based index
++common_len;
x_arg_loc = pos;
struct cast_opts col_opts = {
.x = r_list_get(x, pos),
.to = r_list_get(to, i),
.p_x_arg = named_x_arg,
.p_to_arg = named_to_arg,
.call = opts->call,
.s3_fallback = opts->s3_fallback
};
r_obj* col = vec_cast_opts(&col_opts);
r_list_poke(out, i, col);
}
}
// Restore data frame size before calling `vec_restore()`. `x` and
// `to` might not have any columns to compute the original size.
init_data_frame(out, size);
r_attrib_poke(out, r_syms.row_names, df_rownames(x));
r_ssize extra_len = r_length(x) - common_len;
if (extra_len) {
r_obj* ffi_x_arg = KEEP(vctrs_arg(opts->p_x_arg));
r_obj* ffi_to_arg = KEEP(vctrs_arg(opts->p_to_arg));
r_obj* ffi_call = KEEP(r_lazy_eval(opts->call));
out = vctrs_dispatch6(syms_df_lossy_cast, fns_df_lossy_cast,
syms_out, out,
syms_x, x,
syms_to, to,
syms_x_arg, ffi_x_arg,
syms_to_arg, ffi_to_arg,
syms_call, ffi_call);
FREE(3);
}
FREE(4);
return out;
}function: t({ 'I8544 }, c_int) --> 'I8544
argument: t('I8531 & (p(chr) | vec[^int('I8536)]), c_false)size_t df_compute_n_bytes_lazy_counts(SEXP x) {
r_ssize n_cols = r_length(x);
size_t multiplier = 0;
for (r_ssize i = 0; i < n_cols; ++i) {
SEXP col = VECTOR_ELT(x, i);
const enum vctrs_type type = vec_proxy_typeof(col);
size_t col_multiplier = vec_compute_n_bytes_lazy_counts(col, type);
if (col_multiplier > multiplier) {
multiplier = col_multiplier;
}
}
return multiplier;
}function: t({ 'I8364 }, c_int) --> 'I8364
argument: t('I8351 & (p(chr) | vec[^int('I8356)]), c_false)size_t df_compute_n_bytes_lazy_raw(SEXP x) {
r_ssize n_cols = r_length(x);
size_t multiplier = 0;
for (r_ssize i = 0; i < n_cols; ++i) {
SEXP col = VECTOR_ELT(x, i);
const enum vctrs_type type = vec_proxy_typeof(col);
size_t col_multiplier = vec_compute_n_bytes_lazy_raw(col, type);
if (col_multiplier > multiplier) {
multiplier = col_multiplier;
}
}
return multiplier;
}function: t({ 'I4734 }, c_int) --> 'I4734
argument: t('I4722 & (p(chr) | vec[^int('I4726)]), c_false)int df_decreasing_expansion(SEXP x) {
r_ssize n_cols = r_length(x);
int out = 0;
// Accumulate the expansion factors of the cols of the df-col
for (r_ssize i = 0; i < n_cols; ++i) {
SEXP col = VECTOR_ELT(x, i);
out += vec_decreasing_expansion(col);
}
return out;
}function: t(list) --> *any_sexp
argument: t('I22656 & (p(chr) | vec[^int('I22662)]))void df_detect_complete(SEXP x, R_len_t size, int* p_out) {
r_ssize n_cols = r_length(x);
const SEXP* p_x = VECTOR_PTR_RO(x);
for (r_ssize i = 0; i < n_cols; ++i) {
col_detect_complete_switch(p_x[i], size, p_out);
}
}function: t(list) --> *any_sexp
argument: t('I32135 & (p(chr) | vec<> & vec[^int('I32142)]))r_obj* df_detect_missing(r_obj* x) {
int n_prot = 0;
const r_ssize n_col = r_length(x);
const r_ssize size = vec_size(x);
r_obj* const* v_x = r_list_cbegin(x);
// A location vector to track rows where we still need to check for missing
// values. After we iterate through all columns, `v_loc` points to the missing
// rows.
r_ssize loc_size = size;
r_obj* loc_shelter = KEEP_N(r_alloc_raw(loc_size * sizeof(r_ssize)), &n_prot);
r_ssize* v_loc = (r_ssize*) r_raw_begin(loc_shelter);
for (r_ssize i = 0; i < loc_size; ++i) {
v_loc[i] = i;
}
for (r_ssize i = 0; i < n_col; ++i) {
r_obj* col = v_x[i];
loc_size = col_detect_missing(col, v_loc, loc_size);
// If all rows have at least one non-missing value, break
if (loc_size == 0) {
break;
}
}
r_obj* out = KEEP_N(r_new_logical(size), &n_prot);
int* v_out = r_lgl_begin(out);
r_p_lgl_fill(v_out, 0, size);
for (r_ssize i = 0; i < loc_size; ++i) {
const r_ssize loc = v_loc[i];
v_out[loc] = 1;
}
FREE(n_prot);
return out;
}function: t('I39072, c_true) --> { size : 'I39072 ; row_known : null ; p_row_known : c_null ; remaining : 'I39072 }
argument: t((c_int & c_int_na('I39051)) & 'I39034, c_false)SEXP df_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
int nprot = 0;
SEXP out = PROTECT_N(r_new_logical(size), &nprot);
int* p_out = LOGICAL(out);
// Initialize to "equality" value
// and only change if we learn that it differs
for (R_len_t i = 0; i < size; ++i) {
p_out[i] = 1;
}
struct df_short_circuit_info info = new_df_short_circuit_info(size, false);
struct df_short_circuit_info* p_info = &info;
PROTECT_DF_SHORT_CIRCUIT_INFO(p_info, &nprot);
R_len_t n_col = Rf_length(x);
if (n_col != Rf_length(y)) {
Rf_errorcall(R_NilValue, "`x` and `y` must have the same number of columns");
}
void (*vec_equal_col)(SEXP, SEXP, bool, bool, int*, struct df_short_circuit_info*);
if (na_equal) {
vec_equal_col = vec_equal_col_na_equal;
} else {
vec_equal_col = vec_equal_col_na_propagate;
}
const SEXP* p_x = VECTOR_PTR_RO(x);
const SEXP* p_y = VECTOR_PTR_RO(y);
for (R_len_t i = 0; i < n_col; ++i) {
vec_equal_col(p_x[i], p_y[i], x_recycles, y_recycles, p_out, p_info);
if (p_info->remaining == 0) {
break;
}
}
UNPROTECT(nprot);
return out;
}function: t(list) --> *any_sexp
argument: t('I1588 & (p(chr) | vec[^int('I1593)]))r_ssize df_flat_width(r_obj* x) {
r_ssize n = r_length(x);
r_ssize out = n;
r_obj* const * v_x = r_list_cbegin(x);
for (r_ssize i = 0; i < n; ++i) {
r_obj* col = v_x[i];
if (is_data_frame(col)) {
out = out + df_flat_width(col) - 1;
}
}
return out;
}function: t(c_int & c_int_na('I1741)) --> chr[^int('I1741)]
argument: tuple1r_obj* df_flatten(r_obj* x) {
struct flatten_info info = df_flatten_info(x);
if (!info.flatten) {
return x;
}
r_obj* out = KEEP(r_alloc_list(info.width));
r_obj* out_names = KEEP(r_alloc_character(info.width));
r_attrib_poke_names(out, out_names);
df_flatten_loop(x, out, out_names, 0);
init_data_frame(out, df_size(x));
FREE(2);
return out;
}function: t(list) --> *any_sexp
argument: t('I1598 & (p(chr) | vec[^int('I1603)]))struct flatten_info df_flatten_info(r_obj* x) {
bool flatten = false;
r_ssize n = r_length(x);
r_ssize width = n;
r_obj* const * v_x = r_list_cbegin(x);
for (r_ssize i = 0; i < n; ++i) {
r_obj* col = v_x[i];
if (is_data_frame(col)) {
flatten = true;
width = width + df_flat_width(col) - 1;
}
}
return (struct flatten_info){flatten, width};
}function: t({ 'I1652 }, c_int) --> 'I1652
argument: t('I1630 & (p(chr) | vec[^int('I1641)]), c_false)r_ssize df_flatten_loop(r_obj* x,
r_obj* out,
r_obj* out_names,
r_ssize counter) {
r_ssize n = r_length(x);
r_obj* x_names = KEEP(r_names(x));
for (r_ssize i = 0; i < n; ++i) {
r_obj* col = r_list_get(x, i);
if (is_data_frame(col)) {
counter = df_flatten_loop(col, out, out_names, counter);
} else {
r_list_poke(out, counter, col);
r_chr_poke(out_names, counter, r_chr_get(x_names, i));
++counter;
}
}
FREE(1);
return counter;
}function: t(list) --> *any_sexp
argument: t('I2954 & (p(chr) | vec[^int('I2961)]))static inline void df_hash_fill(r_obj* x, r_ssize size, bool na_equal, uint32_t* v_out) {
const r_ssize n_col = r_length(x);
r_obj* const* v_x = r_list_cbegin(x);
for (r_ssize i = 0; i < n_col; ++i) {
vec_hash_fill(v_x[i], size, na_equal, v_out);
}
}function: ref('I36818) --> 'I36818
argument: any --> anyr_obj* df_list(r_obj* x,
r_ssize size,
bool unpack,
const struct name_repair_opts* p_name_repair_opts,
struct r_lazy error_call) {
if (r_typeof(x) != R_TYPE_list) {
r_stop_internal("`x` must be a list.");
}
x = KEEP(vec_recycle_common(x, size, vec_args.empty, error_call));
r_ssize n_cols = r_length(x);
// Unnamed columns are auto-named with `""`
if (r_names(x) == r_null) {
r_obj* names = KEEP(r_new_character(n_cols));
r_attrib_poke_names(x, names);
FREE(1);
}
x = KEEP(df_list_drop_null(x));
if (unpack) {
x = df_list_unpack(x);
}
KEEP(x);
r_obj* names = KEEP(r_names(x));
names = KEEP(vec_as_names(names, p_name_repair_opts));
r_attrib_poke_names(x, names);
FREE(5);
return x;
}function: ref('I26806) --> 'I26806
argument: any --> anyvoid df_list_combine_common_class_fallback(
r_obj* out,
r_obj* xs,
bool has_indices,
r_obj* indices,
enum vctrs_index_style indices_style,
r_ssize size,
bool has_default,
r_obj* default_,
enum list_combine_multiple multiple,
enum assignment_slice_value slice_xs,
r_obj* ptype,
r_obj* name_spec,
const struct name_repair_opts* p_name_repair_opts,
struct vctrs_arg* p_indices_arg,
struct r_lazy error_call
) {
int n_protect = 0;
r_ssize n_cols = r_length(out);
r_obj* ptype_orig = ptype;
if (!is_data_frame(ptype)) {
ptype = KEEP_N(vec_proxy(ptype), &n_protect);
if (!is_data_frame(ptype)) {
r_stop_internal("Expected fallback target to have a df proxy.");
}
}
if (r_length(ptype) != n_cols ||
r_typeof(out) != R_TYPE_list ||
r_typeof(ptype) != R_TYPE_list) {
r_stop_internal("`ptype` and `out` must be lists of the same length.");
}
for (r_ssize i = 0; i < n_cols; ++i) {
r_obj* col = r_list_get(out, i);
r_obj* ptype_col = r_list_get(ptype, i);
if (is_data_frame(col) && needs_df_list_combine_common_class_fallback(ptype_col)) {
// Recurse into df-cols
r_obj* out_col = r_list_get(out, i);
r_obj* xs_col = KEEP(list_pluck(xs, i));
r_obj* default_col = has_default ? r_list_get(default_, i) : r_null;
df_list_combine_common_class_fallback(
out_col,
xs_col,
has_indices,
indices,
indices_style,
size,
has_default,
default_col,
multiple,
slice_xs,
ptype_col,
name_spec,
p_name_repair_opts,
p_indices_arg,
error_call
);
FREE(1);
} else if (needs_list_combine_common_class_fallback(ptype_col)) {
r_obj* xs_col = KEEP(list_pluck(xs, i));
r_obj* default_col = has_default ? r_list_get(default_, i) : r_null;
struct vctrs_arg* p_xs_col_arg = vec_args.empty;
struct vctrs_arg* p_default_col_arg = vec_args.empty;
r_obj* out_col = list_combine_common_class_fallback(
xs_col,
has_indices,
indices,
indices_style,
size,
has_default,
default_col,
multiple,
slice_xs,
ptype_col,
name_spec,
p_name_repair_opts,
p_xs_col_arg,
p_indices_arg,
p_default_col_arg,
error_call
);
r_list_poke(out, i, out_col);
if (vec_size(out_col) != size) {
r_stop_internal(
"`c()` method returned a vector of unexpected size %d instead of %d.",
vec_size(out_col),
size
);
}
// Remove fallback vector from the ptype so it doesn't get in
// the way of restoration later on
r_list_poke(ptype_orig, i, vec_ptype_final(out_col, vec_args.empty, error_call));
FREE(1);
}
}
FREE(n_protect);
}function: t({ 'I36797 }, c_int) --> 'I36797
argument: t('I36775 & (p(chr) | vec[^int('I36784)]), c_false)r_obj* df_list_drop_null(r_obj* x) {
r_ssize n_cols = r_length(x);
r_ssize count = 0;
for (r_ssize i = 0; i < n_cols; ++i) {
count += r_list_get(x, i) == r_null;
}
if (count == 0) {
return x;
}
r_obj* names = KEEP(r_names(x));
r_obj* const * p_names = r_chr_cbegin(names);
r_ssize n_out = n_cols - count;
r_obj* out = KEEP(r_alloc_list(n_out));
r_obj* out_names = KEEP(r_alloc_character(n_out));
r_ssize out_i = 0;
for (r_ssize i = 0; i < n_cols; ++i) {
r_obj* col = r_list_get(x, i);
if (col != r_null) {
r_list_poke(out, out_i, col);
r_chr_poke(out_names, out_i, p_names[i]);
++out_i;
}
}
r_attrib_poke_names(out, out_names);
FREE(3);
return out;
}function: t(chr) --> *p(chr) argument: t(any_sexp)
r_obj* df_list_unpack(r_obj* x) {
r_obj* names = KEEP(r_names(x));
r_obj* const * p_names = r_chr_cbegin(names);
bool any_needs_unpack = false;
r_ssize n_cols = r_length(x);
r_ssize i = 0;
for (; i < n_cols; ++i) {
// Only unpack unnamed data frames
if (p_names[i] != strings_empty) {
continue;
}
r_obj* col = r_list_get(x, i);
if (is_data_frame(col)) {
any_needs_unpack = true;
break;
}
}
if (!any_needs_unpack) {
FREE(1);
return x;
}
r_obj* unpack = KEEP(r_new_logical(n_cols));
int* p_unpack = LOGICAL(unpack);
for (r_ssize j = 0; j < n_cols; ++j) {
p_unpack[j] = 0;
}
r_ssize width = i;
for (; i < n_cols; ++i) {
// Only unpack unnamed data frames
if (p_names[i] != strings_empty) {
++width;
continue;
}
r_obj* col = r_list_get(x, i);
if (is_data_frame(col)) {
width += r_length(col);
p_unpack[i] = 1;
} else {
++width;
}
}
r_obj* out = KEEP(r_new_list(width));
r_obj* out_names = KEEP(r_new_character(width));
r_ssize loc = 0;
// Unpack loop
for (r_ssize i = 0; i < n_cols; ++i) {
if (!p_unpack[i]) {
r_list_poke(out, loc, r_list_get(x, i));
r_chr_poke(out_names, loc, p_names[i]);
++loc;
continue;
}
r_obj* col = r_list_get(x, i);
r_obj* col_names = KEEP(r_names(col));
if (r_typeof(col_names) != R_TYPE_character) {
r_stop_internal(
"Encountered corrupt data frame. "
"Data frames must have character column names."
);
}
r_obj* const * p_col_names = r_chr_cbegin(col_names);
r_ssize col_i = 0;
r_ssize stop = loc + r_length(col);
for (; loc < stop; ++loc, ++col_i) {
r_list_poke(out, loc, r_list_get(col, col_i));
r_chr_poke(out_names, loc, p_col_names[col_i]);
}
loc = stop;
FREE(1);
}
r_attrib_poke_names(out, out_names);
FREE(4);
return out;
}function: ref('I14523) --> 'I14523
argument: t({ 'I14521 }, t(any_sexp) --> any_sexp & t('I14521) --> empty) | t({ 'I14522 & 'I14521 }, t(any_sexp) --> any_sexp & t('I14521) | t('I14522) --> any) -> any_sexpSEXP df_map(SEXP df, SEXP (*fn)(SEXP)) {
SEXP out = PROTECT(map(df, fn));
// Shallow ownership over `out` because `map()` generates a fresh
// list. We only care about "restoring" that bare list to the type of `df`,
// not the contents, so not recursive.
struct vec_restore_opts opts = {
.ownership = VCTRS_OWNERSHIP_shallow,
.recursively_proxied = false
};
out = vec_df_restore(out, df, &opts);
UNPROTECT(1);
return out;
}name: DF_PROXY
r_obj* df_proxy(r_obj* x, enum vctrs_proxy_kind kind) {
// Always clone to avoid modifying the original object, even if it is one
// we freshly created in C, because we often work with both the proxy and the
// original object within the same function (#1837)
x = KEEP(r_clone(x));
switch (kind) {
case VCTRS_PROXY_KIND_equal: DF_PROXY(vec_proxy_equal); break;
case VCTRS_PROXY_KIND_compare: DF_PROXY(vec_proxy_compare); break;
case VCTRS_PROXY_KIND_order: DF_PROXY(vec_proxy_order); break;
}
x = KEEP(df_flatten(x));
x = vec_proxy_unwrap(x);
FREE(2);
return x;
}function: t(list) --> *any_sexp
argument: t('I1488 & (p(chr) | vec[^int('I1498)]))r_obj* df_proxy_recurse(r_obj* x) {
r_obj* out = KEEP(r_clone(x));
r_ssize n = r_length(out);
r_obj* const * v_out = r_list_cbegin(out);
for (r_ssize i = 0; i < n; ++i) {
r_list_poke(out, i, vec_proxy_recurse(v_out[i]));
}
FREE(1);
return out;
}function: t(any_sexp, t(any_sexp) --> any_sexp) --> any_sexp argument: t(any_sexp & 'I23035, *t(any_sexp) --> any_sexp)
r_obj* df_ptype(r_obj* x, bool bare) {
r_obj* row_nms = KEEP(df_rownames(x));
r_obj* ptype = r_null;
if (bare) {
ptype = KEEP(bare_df_map(x, &col_ptype));
} else {
ptype = KEEP(df_map(x, &col_ptype));
}
if (r_typeof(row_nms) == R_TYPE_character) {
r_attrib_poke(ptype, r_syms.row_names, r_globals.empty_chr);
}
FREE(2);
return ptype;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym, (env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> c_bool argument: t(any_sexp, any_sexp)
r_obj* df_ptype2(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
r_obj* x_names = KEEP(r_names(x));
r_obj* y_names = KEEP(r_names(y));
r_obj* out = r_null;
if (obj_equal(x_names, y_names)) {
out = df_ptype2_loop(
x,
y,
x_names,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
} else {
out = df_ptype2_match(
x,
y,
x_names,
y_names,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
}
FREE(2);
return out;
}function: t(x1, (env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, *any) --> x1 where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(*x1 & 'I23526, list, *c_false) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* df_ptype2_loop(
r_obj* x,
r_obj* y,
r_obj* names,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
const r_ssize n_cols = r_length(names);
r_obj* out = KEEP(r_alloc_list(n_cols));
r_attrib_poke(out, r_syms.names, names);
r_ssize i = 0;
struct vctrs_arg* p_x_col_arg = new_subscript_arg_vec(p_x_arg, out, &i);
KEEP(p_x_col_arg->shelter);
struct vctrs_arg* p_y_col_arg = new_subscript_arg_vec(p_y_arg, out, &i);
KEEP(p_y_col_arg->shelter);
for (; i < n_cols; ++i) {
r_obj* x_col = r_list_get(x, i);
r_obj* y_col = r_list_get(y, i);
int _;
r_obj* type = vec_ptype2(
x_col,
y_col,
p_x_col_arg,
p_y_col_arg,
call,
s3_fallback,
&_
);
r_list_poke(out, i, type);
}
init_data_frame(out, 0);
FREE(3);
return out;
}function: t(^int) --> *c_int & t(int) --> *c_int_na argument: t(any_sexp)
r_obj* df_ptype2_match(
r_obj* x,
r_obj* y,
r_obj* x_names,
r_obj* y_names,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
r_obj* x_dups_pos = KEEP(vec_match(x_names, y_names));
r_obj* y_dups_pos = KEEP(vec_match(y_names, x_names));
int* x_dups_pos_data = r_int_begin(x_dups_pos);
int* y_dups_pos_data = r_int_begin(y_dups_pos);
r_ssize x_len = r_length(x_names);
r_ssize y_len = r_length(y_names);
// Count columns that are only in `y`
r_ssize rest_len = 0;
for (r_ssize i = 0; i < y_len; ++i) {
if (y_dups_pos_data[i] == r_globals.na_int) {
++rest_len;
}
}
r_ssize out_len = x_len + rest_len;
r_obj* out = KEEP(r_alloc_list(out_len));
r_obj* nms = KEEP(r_alloc_character(out_len));
r_attrib_poke(out, r_syms.names, nms);
r_ssize i = 0;
r_ssize y_col_arg_loc = 0;
struct vctrs_arg* p_x_col_arg = new_subscript_arg(p_x_arg, x_names, x_len, &i);
KEEP(p_x_col_arg->shelter);
struct vctrs_arg* p_y_col_arg = new_subscript_arg(p_y_arg, y_names, y_len, &y_col_arg_loc);
KEEP(p_y_col_arg->shelter);
// Fill in prototypes of all the columns that are in `x`, in order
for (; i < x_len; ++i) {
r_ssize dup = x_dups_pos_data[i];
r_obj* x_col = r_list_get(x, i);
r_obj* type;
if (dup == r_globals.na_int) {
type = vec_ptype_or_s3_fallback(
x_col,
p_x_col_arg,
vec_typeof(x_col),
call,
s3_fallback
);
} else {
// 1-based index
--dup;
y_col_arg_loc = dup;
r_obj* y_col = r_list_get(y, dup);
int _;
type = vec_ptype2(
x_col,
y_col,
p_x_col_arg,
p_y_col_arg,
call,
s3_fallback,
&_
);
}
r_list_poke(out, i, type);
r_chr_poke(nms, i, r_chr_get(x_names, i));
}
// Fill in prototypes of the columns that are only in `y`
for (r_ssize j = 0; i < out_len; ++j) {
r_ssize dup = y_dups_pos_data[j];
if (dup == r_globals.na_int) {
y_col_arg_loc = j;
r_obj* y_col = r_list_get(y, j);
r_obj* type = vec_ptype_or_s3_fallback(
y_col,
p_y_col_arg,
vec_typeof(y_col),
call,
s3_fallback
);
r_list_poke(out, i, type);
r_chr_poke(nms, i, r_chr_get(y_names, j));
++i;
}
}
init_data_frame(out, 0);
FREE(6);
return out;
}function: t({ 'I5865 }, c_int) --> 'I5865
argument: t('I5853 & (p(chr) | vec[^int('I5864)]), c_false)r_ssize df_raw_size_from_list(r_obj* x) {
if (r_length(x) >= 1) {
return vec_size(r_list_get(x, 0));
} else {
return 0;
}
}function: t(any_sexp, *t(any_sexp, any_sexp, *c_void) --> any_sexp, *c_void) --> any_sexp argument: t(any_sexp & 'I877, t(any_sexp, any_sexp & 'I881, *c_void) -> c_null | 'I881 & (c_null | null | p(chr) | sym | attr_any), c_null)
r_ssize df_rownames_size(r_obj* x) {
r_obj* row_names = r_attrib_map(x, df_rownames_size_cb, NULL);
if (row_names == NULL) {
return -1;
}
return rownames_size(row_names);
}function: ref('I888) --> 'I888
argument: any --> anyr_ssize df_size(r_obj* x) {
r_ssize n = df_rownames_size(x);
if (n < 0) {
r_stop_internal("Corrupt data frame: row.names are missing");
}
return n;
}function: t({ 'I7947 }, c_int) --> 'I7947
argument: t('I7921 & (p(chr) | vec[^int('I7928)]), c_false)r_obj* df_slice(r_obj* x, r_obj* subscript) {
r_ssize n = r_length(x);
r_ssize size = df_size(x);
r_obj* out = KEEP(r_alloc_list(n));
// FIXME: Should that be restored?
r_obj* nms = r_names(x);
r_attrib_poke(out, r_syms.names, nms);
for (r_ssize i = 0; i < n; ++i) {
r_obj* elt = r_list_get(x, i);
if (vec_size(elt) != size) {
r_stop_internal("Column `%s` (size %" R_PRI_SSIZE ") must match the data frame (size %" R_PRI_SSIZE ").",
r_chr_get_c_string(nms, i),
vec_size(elt),
size);
}
r_obj* sliced = vec_slice_unsafe(elt, subscript);
r_list_poke(out, i, sliced);
}
init_data_frame(out, vec_subscript_size(subscript));
r_obj* row_nms = KEEP(df_rownames(x));
if (r_typeof(row_nms) == R_TYPE_character) {
row_nms = slice_rownames(row_nms, subscript);
r_attrib_poke(out, r_syms.row_names, row_nms);
}
FREE(2);
return out;
}function: ref('I2363) --> 'I2363
argument: any --> anyuint32_t dict_key_size(SEXP x) {
const R_len_t x_size = vec_size(x);
if (x_size > R_LEN_T_MAX) {
// Ensure we catch the switch to supporting long vectors in `vec_size()`
r_stop_internal("Dictionary functions do not support long vectors.");
}
const double load_adjusted_size = x_size / 0.50;
if (load_adjusted_size > UINT32_MAX) {
r_stop_internal("Can't safely cast load adjusted size to a `uint32_t`.");
}
uint32_t size = (uint32_t)load_adjusted_size;
// Clamp to `INT32_MAX` to avoid overflow in `u32_safe_ceil2()`,
// at the cost of an increased maximum load factor for long input
size = size > INT32_MAX ? INT32_MAX : size;
size = u32_safe_ceil2(size);
size = (size < 16) ? 16 : size;
if (x_size > size) {
// Should never happen with `R_len_t` sizes.
// This is a defensive check that will be useful when we support long vectors.
r_stop_internal("Hash table size must be at least as large as input to avoid a load factor of >100%.");
}
// Rprintf("size: %u\n", size);
return size;
}function: ref('I23281) --> 'I23281
argument: any --> anyr_obj* dims_shape(r_obj* dimensions) {
if (r_length(dimensions) == 0) {
r_stop_internal("`dimensions` must have length.");
}
if (r_typeof(dimensions) != R_TYPE_integer) {
r_stop_internal("`dimensions` must be an integer vector.");
}
if (r_int_get(dimensions, 0) == 0) {
// Already a shape, no clone required
return dimensions;
}
dimensions = KEEP(r_clone_referenced(dimensions));
r_int_begin(dimensions)[0] = 0;
FREE(1);
return dimensions;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
bool duplicated_any(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
bool out = duplicated_any_loop(d, n);
UNPROTECT(nprot);
return out;
}function: t({ 'I2547 }, c_int) --> 'I2547
argument: t('I2535 & (p(chr) | vec[^int('I2541)]), c_false)static inline uint32_t expr_hash(r_obj* x) {
uint32_t hash = 0;
r_ssize n = Rf_xlength(x);
for (r_ssize i = 0; i < n; ++i) {
r_obj* elt = r_list_get(x, i);
hash = hash_combine(hash, obj_hash(elt));
}
return hash;
}function: t(list, 'I16106) --> list & t(p(chr), c_int & c_int_na('I16106)) --> v[^int('I16106)]("") & t(prim & 'I16107, c_int & c_int_na('I16106)) --> v[^int('I16106)]('I16107)
argument: t(p(int), any)static SEXP fct_as_factor_impl(SEXP x, SEXP x_levels, SEXP to_levels, bool* lossy, bool ordered) {
// Early exit if levels are identical
if (x_levels == to_levels) {
return x;
}
R_len_t x_levels_size = vec_size(x_levels);
R_len_t to_levels_size = vec_size(to_levels);
// Early exit if `to` has no levels. In this case it is being used as
// a template
if (to_levels_size == 0) {
return x;
}
// Always lossy if there are more levels in `x` than in `to`
if (x_levels_size > to_levels_size) {
*lossy = true;
return R_NilValue;
}
R_len_t x_size = vec_size(x);
const SEXP* p_x_levels = STRING_PTR_RO(x_levels);
const SEXP* p_to_levels = STRING_PTR_RO(to_levels);
bool is_contiguous_subset = true;
for (R_len_t i = 0; i < x_levels_size; ++i) {
if (p_x_levels[i] != p_to_levels[i]) {
is_contiguous_subset = false;
break;
}
}
// No recoding required if contiguous subset.
// Duplicate, strip non-factor attributes, and re-initialize with new levels.
// Using `r_clone_referenced()` avoids an immediate copy using ALTREP wrappers.
if (is_contiguous_subset) {
SEXP out = PROTECT(r_clone_referenced(x));
r_attrib_zap_all(out);
if (ordered) {
init_ordered(out, to_levels);
} else {
init_factor(out, to_levels);
}
UNPROTECT(1);
return out;
}
const int* p_x = INTEGER_RO(x);
SEXP out = PROTECT(Rf_allocVector(INTSXP, x_size));
int* p_out = INTEGER(out);
if (ordered) {
init_ordered(out, to_levels);
} else {
init_factor(out, to_levels);
}
SEXP recode = PROTECT(vec_match(x_levels, to_levels));
const int* p_recode = INTEGER_RO(recode);
// Detect if there are any levels in `x` that aren't in `to`
for (R_len_t i = 0; i < x_levels_size; ++i) {
if (p_recode[i] == NA_INTEGER) {
*lossy = true;
UNPROTECT(2);
return R_NilValue;
}
}
// Recode `x` int values into `to` level ordering
for (R_len_t i = 0; i < x_size; ++i) {
const int elt = p_x[i];
if (elt == NA_INTEGER) {
p_out[i] = NA_INTEGER;
continue;
}
p_out[i] = p_recode[elt - 1];
}
UNPROTECT(2);
return out;
}function: t(p(chr) & 'I27037) --> int0 with { levels: 'I27037 & p(chr), any } & t(v(chr & 'I27038) & 'I27037) --> int0 with { levels: 'I27037 & v(chr & 'I27038), any }
argument: t(any_sexp)SEXP fct_ptype2(
SEXP x,
SEXP y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg
) {
SEXP x_levels = PROTECT(Rf_getAttrib(x, R_LevelsSymbol));
SEXP y_levels = PROTECT(Rf_getAttrib(y, R_LevelsSymbol));
if (TYPEOF(x_levels) != STRSXP) {
stop_corrupt_factor_levels(x, p_x_arg);
}
if (TYPEOF(y_levels) != STRSXP) {
stop_corrupt_factor_levels(y, p_y_arg);
}
// Use `x_levels` if they are equal pointers, otherwise compute union
SEXP levels = (x_levels == y_levels) ?
x_levels :
levels_union(x_levels, y_levels);
PROTECT(levels);
SEXP out = new_empty_factor(levels);
UNPROTECT(3);
return out;
}function: t(s({ ptr: any_sexp }), any_sexp, any_sexp) --> any_sexp
argument: t(any, any_sexp & 'I36575, null)r_obj* ffi_altrep_new_lazy_character(r_obj* fn) {
r_obj* out = R_new_altrep(altrep_lazy_character_class, fn, r_null);
r_mark_shared(out);
return out;
}function: t(chr1 | chr[^(int \ 1)], null, any_sexp & 'I36570, any) --> null | any_sexp & 'I36570 argument: t(any_sexp & 'I36560, 'I36565, any_sexp & 'I36562, c_int_na)
r_obj* ffi_apply_name_spec(r_obj* name_spec, r_obj* outer, r_obj* inner, r_obj* n) {
return apply_name_spec(name_spec, r_chr_get(outer, 0), inner, r_int_get(n, 0));
}function: ref('I38687) --> 'I38687
argument: any --> anyr_obj* ffi_as_compact_condition(r_obj* x) {
if (r_typeof(x) != R_TYPE_logical) {
r_stop_internal("`x` must be a logical condition vector.");
}
const r_ssize size = r_length(x);
const int* v_x = r_lgl_cbegin(x);
r_obj* out = KEEP(new_compact_condition(size));
bool* v_out = compact_condition_begin(out);
for (r_ssize i = 0; i < size; ++i) {
const int elt = v_x[i];
if (elt == r_globals.na_int) {
r_stop_internal("Can't use `NA` when creating a `compact_condition`.");
}
v_out[i] = elt;
}
FREE(1);
return out;
}function: t(any_sexp, *{ shelter : any_sexp ; type : c(0..4) | c(99) ; name_repair_arg : { x : any_sexp ; env : any_sexp } ; fn : any_sexp ; quiet : c_bool ; call : { x : any_sexp ; env : any_sexp } }, { x : any_sexp ; env : any_sexp }) --> any_sexp
argument: t(any_sexp & 'I36266, *{ type : c(2) ; fn : null ; quiet : c_int }, { x : 'I36268 ; env : null })r_obj* ffi_as_df_row(r_obj* x, r_obj* quiet, r_obj* frame) {
struct name_repair_opts name_repair_opts = {
.type = NAME_REPAIR_unique,
.fn = r_null,
.quiet = r_lgl_get(quiet, 0)
};
struct r_lazy error_call = { .x = frame, .env = r_null };
return as_df_row(x, &name_repair_opts, error_call);
}function: t(any_sexp, c_null, { x : any_sexp ; env : any_sexp }) --> any
argument: t(any_sexp & 'I35036, *x1, { x : any_sexp & 'I35037 ; env : null }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_as_short_length(r_obj* n, r_obj* frame) {
struct r_lazy call = { .x = frame, .env = r_null };
struct r_lazy arg_lazy = { .x = syms.arg, .env = frame };
struct vctrs_arg arg = new_lazy_arg(&arg_lazy);
return r_len(vec_as_short_length(n, &arg, call));
}function: t(null, any_sexp, any_sexp, *{ call : { x : any_sexp ; env : any_sexp } ; value_arg : x1 ; x_arg : x1 ; ownership : c(0..2) ; assign_names : c_bool ; ignore_outer_names : c_bool ; slice_value : c_bool }) --> null & t(p(chr) | sym | attr_any, any_sexp, any_sexp, c_null) --> empty where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(any_sexp & 'I38568, any_sexp & 'I38569, any_sexp & 'I38570, *{ call : { x : 'I38572 ; env : null } ; value_arg : *x2 ; x_arg : *x1 ; ownership : c_false ; assign_names : c_false ; slice_value : c_bool }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void } and x2 = { shelter : any_sexp ; parent : *x2 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_assign(
r_obj* ffi_x,
r_obj* ffi_i,
r_obj* ffi_value,
r_obj* ffi_slice_value,
r_obj* ffi_frame
) {
struct r_lazy x_arg_lazy = { .x = syms.x_arg, .env = ffi_frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_lazy);
struct r_lazy value_arg_lazy = { .x = syms.value_arg, .env = ffi_frame };
struct vctrs_arg value_arg = new_lazy_arg(&value_arg_lazy);
struct r_lazy call = { .x = ffi_frame, .env = r_null };
const enum assignment_slice_value slice_value =
r_arg_as_bool(ffi_slice_value, "slice_value") ?
ASSIGNMENT_SLICE_VALUE_yes :
ASSIGNMENT_SLICE_VALUE_no;
// We don't expose this in the R API
const bool assign_names = false;
// Comes from the R side, so no known ownership
const enum vctrs_ownership ownership = VCTRS_OWNERSHIP_foreign;
const struct vec_assign_opts opts = {
.assign_names = assign_names,
.slice_value = slice_value,
.ownership = ownership,
.x_arg = &x_arg,
.value_arg = &value_arg,
.call = call
};
return vec_assign_opts(ffi_x, ffi_i, ffi_value, &opts);
}function: ref('I38678) --> 'I38678
argument: any --> anyr_obj* ffi_assign_compact_condition(
r_obj* x,
r_obj* index,
r_obj* value,
r_obj* ffi_slice_value
) {
struct r_lazy call = r_lazy_null;
const enum assignment_slice_value slice_value =
r_arg_as_bool(ffi_slice_value, "slice_value") ?
ASSIGNMENT_SLICE_VALUE_yes :
ASSIGNMENT_SLICE_VALUE_no;
if (!is_compact_condition(index)) {
r_stop_internal("`index` must be a `compact_condition`.");
}
const enum vctrs_index_style index_style = VCTRS_INDEX_STYLE_condition;
// Comes from the R side, so not owned, and not proxying recursively
const struct vec_proxy_assign_opts assign_opts = {
.x_arg = vec_args.x,
.value_arg = vec_args.value,
.call = call,
.slice_value = slice_value,
.index_style = index_style,
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
struct vec_restore_opts restore_opts = {
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
const r_ssize x_size = vec_size(x);
// Cast `value` and check that it can recycle
value = KEEP(vec_cast(value, x, vec_args.value, vec_args.x, call));
check_recyclable_against_index(
value,
index,
x_size,
assign_opts.slice_value,
assign_opts.index_style,
assign_opts.value_arg,
assign_opts.call
);
r_obj* proxy = KEEP(vec_proxy(x));
proxy = KEEP(vec_proxy_assign_opts(proxy, index, value, &assign_opts));
r_obj* out = vec_restore_opts(proxy, x, &restore_opts);
FREE(3);
return out;
}function: t(~c(..-1), ~c(..-1), c_true) --> int3 argument: t(c_int_na, c_int_na, c_int)
r_obj* ffi_assign_seq(
r_obj* x,
r_obj* value,
r_obj* ffi_start,
r_obj* ffi_size,
r_obj* ffi_increasing,
r_obj* ffi_slice_value
) {
r_ssize start = r_int_get(ffi_start, 0);
r_ssize size = r_int_get(ffi_size, 0);
bool increasing = r_lgl_get(ffi_increasing, 0);
struct r_lazy call = lazy_calls.vec_assign_seq;
const enum assignment_slice_value slice_value =
r_arg_as_bool(ffi_slice_value, "slice_value") ?
ASSIGNMENT_SLICE_VALUE_yes :
ASSIGNMENT_SLICE_VALUE_no;
r_obj* index = KEEP(compact_seq(start, size, increasing));
const enum vctrs_index_style index_style = VCTRS_INDEX_STYLE_location;
// Comes from the R side, so not owned, and not proxying recursively
const struct vec_proxy_assign_opts assign_opts = {
.x_arg = vec_args.x,
.value_arg = vec_args.value,
.call = call,
.slice_value = slice_value,
.index_style = index_style,
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
struct vec_restore_opts restore_opts = {
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
const r_ssize x_size = vec_size(x);
// Cast `value` and check that it can recycle
value = KEEP(vec_cast(value, x, vec_args.value, vec_args.x, call));
check_recyclable_against_index(
value,
index,
x_size,
assign_opts.slice_value,
assign_opts.index_style,
assign_opts.value_arg,
assign_opts.call
);
r_obj* proxy = KEEP(vec_proxy(x));
proxy = KEEP(vec_proxy_assign_opts(proxy, index, value, &assign_opts));
r_obj* out = vec_restore_opts(proxy, x, &restore_opts);
FREE(4);
return out;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, c_null, { x : any_sexp ; env : any_sexp }) --> ()
argument: t(any_sexp & 'I39216, *x1, { x : any_sexp ; env : any_sexp & 'I39217 }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_check_list(r_obj* x, r_obj* frame) {
struct r_lazy call = { .x = r_syms.call, .env = frame };
struct r_lazy arg_data = { .x = syms.arg, .env = frame };
struct vctrs_arg arg = new_lazy_arg(&arg_data);
obj_check_list(x, &arg, call);
return r_null;
}function: t(~c(..-1), ~c(..-1), c_true) --> int3 argument: t(any, any, c_int)
r_obj* ffi_compact_seq(r_obj* ffi_start, r_obj* ffi_size, r_obj* ffi_increasing) {
return compact_seq(
r_arg_as_ssize(ffi_start, "start"),
r_arg_as_ssize(ffi_size, "size"),
r_arg_as_bool(ffi_increasing, "increasing")
);
}function: t(any_sexp, c_null, { x : any_sexp ; env : any_sexp }) --> any
argument: t(any_sexp & 'I36820, *x1, { x : any_sexp ; env : any_sexp & 'I36823 }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_df_list(r_obj* x,
r_obj* size,
r_obj* unpack,
r_obj* name_repair,
r_obj* frame) {
struct r_lazy error_call = { .x = syms.dot_error_call, .env = frame };
struct name_repair_opts name_repair_opts = new_name_repair_opts(name_repair,
lazy_args.dot_name_repair,
false,
error_call);
KEEP(name_repair_opts.shelter);
r_ssize c_size = 0;
if (size == r_null) {
c_size = vec_size_common(x, 0, vec_args.empty, error_call);
} else {
c_size = vec_as_short_length(size, vec_args.dot_size, error_call);
}
const bool c_unpack = r_arg_as_bool(unpack, ".unpack");
r_obj* out = df_list(x, c_size, c_unpack, &name_repair_opts, error_call);
FREE(1);
return out;
}function: ref('I36944) --> 'I36944
argument: any --> anyr_obj* ffi_df_proxy(r_obj* x, r_obj* kind) {
if (!r_is_number(kind)) {
r_stop_internal("`kind` must be a single integer.");
}
enum vctrs_proxy_kind c_kind = r_int_get(kind, 0);
return df_proxy(x, c_kind);
}function: t(any_sexp, c_null, { x : any_sexp ; env : any_sexp }) --> any
argument: t(any_sexp & 'I38689, *x1, { x : 'I38690 ; env : null }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_init(r_obj* x, r_obj* ffi_n, r_obj* ffi_frame) {
struct r_lazy call = { .x = ffi_frame, .env = r_null };
r_ssize n = vec_as_short_length(ffi_n, vec_args.n, call);
r_obj* out = vec_init(x, n);
return out;
}function: t(any_sexp, any_sexp, c_bool, c_bool, c_bool) --> any_sexp argument: t(any_sexp & 'I35657, any_sexp & 'I35658, c_int, c_bool | c_void, c_false)
r_obj* ffi_interval_groups(r_obj* start,
r_obj* end,
r_obj* ffi_abutting,
r_obj* ffi_missing) {
const bool abutting = r_arg_as_bool(ffi_abutting, "abutting");
const enum vctrs_interval_missing missing = parse_missing(ffi_missing);
const bool locations = false;
r_obj* out = KEEP(vec_interval_group_info(start, end, abutting, missing, locations));
r_obj* loc_start = r_list_get(out, 0);
r_obj* loc_end = r_list_get(out, 1);
r_list_poke(out, 0, vec_slice_unsafe(start, loc_start));
r_list_poke(out, 1, vec_slice_unsafe(end, loc_end));
FREE(1);
return out;
}function: t(any_sexp, any_sexp, c_bool, c_bool, c_bool) --> any_sexp argument: t(any_sexp & 'I35670, any_sexp & 'I35671, c_int, c_bool | c_void, c_true)
r_obj* ffi_interval_locate_groups(r_obj* start,
r_obj* end,
r_obj* ffi_abutting,
r_obj* ffi_missing) {
const bool abutting = r_arg_as_bool(ffi_abutting, "abutting");
const enum vctrs_interval_missing missing = parse_missing(ffi_missing);
const bool locations = true;
r_obj* out = KEEP(vec_interval_group_info(start, end, abutting, missing, locations));
r_obj* key = r_list_get(out, 0);
r_obj* loc_start = r_list_get(key, 0);
r_obj* loc_end = r_list_get(key, 1);
r_list_poke(key, 0, vec_slice_unsafe(start, loc_start));
r_list_poke(key, 1, vec_slice_unsafe(end, loc_end));
FREE(1);
return out;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, c_null, { x : any_sexp ; env : any_sexp }) --> ()
argument: t(any_sexp & 'I39376, *x1, { x : 'I39379 ; env : null }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_list_all_recyclable(
r_obj* ffi_xs,
r_obj* ffi_size,
r_obj* ffi_allow_null,
r_obj* ffi_frame
) {
struct r_lazy error_call = {.x = ffi_frame, .env = r_null };
// This is an internal error
obj_check_list(ffi_xs, vec_args.x, error_call);
const r_ssize size = r_arg_as_ssize(ffi_size, "size");
const enum vctrs_allow_null allow_null = arg_as_allow_null(ffi_allow_null, "allow_null");
return r_lgl(list_all_recyclable(ffi_xs, size, allow_null, vec_args.x, error_call));
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, c_null, { x : any_sexp ; env : any_sexp }) --> ()
argument: t(any_sexp & 'I39325, *x1, { x : 'I39328 ; env : null }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_list_all_size(
r_obj* ffi_xs,
r_obj* ffi_size,
r_obj* ffi_allow_null,
r_obj* ffi_frame
) {
struct r_lazy error_call = {.x = ffi_frame, .env = r_null };
// This is an internal error
obj_check_list(ffi_xs, vec_args.x, error_call);
const r_ssize size = r_arg_as_ssize(ffi_size, "size");
const enum vctrs_allow_null allow_null = arg_as_allow_null(ffi_allow_null, "allow_null");
return r_lgl(list_all_size(ffi_xs, size, allow_null, vec_args.x, error_call));
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, c_null, { x : any_sexp ; env : any_sexp }) --> ()
argument: t(any_sexp & 'I39267, *x1, { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_list_all_vectors(r_obj* ffi_xs, r_obj* ffi_allow_null, r_obj* ffi_frame) {
obj_check_list(ffi_xs, vec_args.x, (struct r_lazy) { ffi_frame, r_null });
const enum vctrs_allow_null allow_null = arg_as_allow_null(ffi_allow_null, "allow_null");
return r_lgl(list_all_vectors(ffi_xs, allow_null));
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, c_null, { x : any_sexp ; env : any_sexp }) --> ()
argument: t(any_sexp & 'I39295, *x1, { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_list_check_all_vectors(r_obj* ffi_xs, r_obj* ffi_allow_null, r_obj* ffi_frame) {
// This is an internal error
obj_check_list(ffi_xs, vec_args.x, (struct r_lazy) {.x = ffi_frame, .env = r_null });
struct r_lazy call = { .x = r_syms.call, .env = ffi_frame };
struct r_lazy xs_arg_lazy = { .x = syms.arg, .env = ffi_frame };
struct vctrs_arg xs_arg = new_lazy_arg(&xs_arg_lazy);
const enum vctrs_allow_null allow_null = arg_as_allow_null(ffi_allow_null, "allow_null");
list_check_all_vectors(ffi_xs, allow_null, &xs_arg, call);
return r_null;
}function: t(chr) --> () argument: t(p(chr) | sym | attr_any)
r_obj* ffi_minimal_names(r_obj* x) {
r_obj* names = KEEP(vec_names(x));
if (names == r_null) {
names = r_alloc_character(vec_size(x));
} else {
names = ffi_as_minimal_names(names);
}
FREE(1);
return names;
}function: t(lang) --> any_sexp argument: t(any_sexp)
r_obj* ffi_new_data_frame(r_obj* args) {
args = r_node_cdr(args);
r_obj* x = r_node_car(args); args = r_node_cdr(args);
r_obj* n = r_node_car(args); args = r_node_cdr(args);
r_obj* cls = r_node_car(args); args = r_node_cdr(args);
r_obj* attrib = args;
if (r_typeof(x) != R_TYPE_list) {
r_abort_call(r_null, "`x` must be a list");
}
// Input comes from the R side, so we must always clone it. This is also
// important because we pull attributes from `x` later on, but clear the ones
// on `out` right now because we build it from scratch.
r_obj* out = KEEP(r_clone(x));
r_attrib_zap_all(out);
r_obj* names = NULL;
r_obj* row_names = NULL;
for (r_obj* node = attrib; node != r_null; node = r_node_cdr(node)) {
r_obj* tag = r_node_tag(node);
r_obj* value = r_node_car(node);
// We might add dynamic dots later on
if (tag == r_syms.class_) {
r_stop_internal("Can't supply `class` in `...`.");
}
if (tag == r_syms.names) {
names = value;
continue;
}
if (tag == r_syms.row_names) {
// We used to validate a user supplied `n` against a user supplied
// `row.names`, but that requires extracting out the `rownames_size()`,
// which can materialize ALTREP row name objects and is prohibitively
// expensive (tidyverse/dplyr#6596). So instead we say that user supplied
// `row.names` overrides both the implied size of `x` and a user supplied
// `n`, even if they are incompatible.
row_names = value;
continue;
}
r_attrib_poke(out, tag, value);
}
// `names` handling:
// - If `...` had `names`, use them.
// - If `x` is empty, use `character()` names (supports empty `list()` case).
// - Use `r_names(x)`.
//
// Note that this means `new_data_frame(list(1))` purposefully constructs a
// corrupt data frame with no names, which is questionable, but we have a test
// for this and I think we use it for testing other edge cases.
if (names == NULL) {
if (r_length(x) == 0) {
names = r_globals.empty_chr;
} else {
names = r_names(x);
}
}
r_attrib_poke_names(out, names);
// `row.names` handling:
// - If `...` had `row.names`, use them.
// - If `n` was provided, use it (overridden by `row.names` in `...`).
// - Use `df_raw_size_from_list(x)`.
//
// Note that this means `new_data_frame(new_data_frame(n = 10L))` will return
// a zero row data frame. `new_data_frame()` always treats `x` as a bare list,
// even if it might contain some extra info about the `row.names` in the zero
// column data frame case.
if (row_names == NULL) {
const r_ssize size = n != r_null ? df_size_from_n(n) : df_raw_size_from_list(x);
row_names = new_compact_rownames(size);
}
KEEP(row_names);
attrib_append_row_names(out, row_names);
FREE(1);
if (cls == r_null) {
cls = classes_data_frame;
} else {
cls = c_data_frame_class(cls);
}
r_attrib_poke_class(out, cls);
FREE(1);
return out;
}function: t(*c_void, *c_void, c(..-1) | c(1..)) | t(*c_void, *c_void, c_false) --> () argument: t(*c_int, *c_int_na, c_int)
r_obj* ffi_obj_hash(r_obj* x) {
uint32_t hash = 0;
hash = hash_combine(hash, obj_hash(x));
r_obj* out = KEEP(r_alloc_raw(sizeof(uint32_t)));
r_memcpy(r_raw_begin(out), &hash, sizeof(uint32_t));
FREE(1);
return out;
}function: ref('I37291) --> 'I37291
argument: any --> anyr_obj* ffi_outer_names(r_obj* names, r_obj* outer, r_obj* n) {
if (names != r_null && r_typeof(names) != R_TYPE_character) {
r_stop_internal("`names` must be `NULL` or a string.");
}
if (!r_is_number(n)) {
r_stop_internal("`n` must be a single integer.");
}
if (outer != r_null) {
outer = r_chr_get(outer, 0);
}
return outer_names(names, outer, r_int_get(n, 0));
}function: t(list, *c_string) --> list & t(prim & 'I36774, *c_string) --> v('I36774)
argument: t(c(19), *c_string)r_obj* ffi_proxy_info(r_obj* x) {
struct vctrs_proxy_info info = vec_proxy_info(x);
KEEP(info.inner);
r_obj* out = KEEP(Rf_mkNamed(R_TYPE_list, (const char*[]) { "type", "had_proxy_method", "proxy", "" }));
r_list_poke(out, 0, r_chr(vec_type_as_str(info.type)));
r_list_poke(out, 1, r_lgl(info.had_proxy_method));
r_list_poke(out, 2, info.inner);
FREE(2);
return out;
}function: ref('I37356) --> 'I37356
argument: any --> anyr_obj* ffi_s3_get_method(r_obj* generic, r_obj* cls, r_obj* table) {
if (!r_is_string(generic)) {
r_stop_internal("`generic` must be a string");
}
if (!r_is_string(cls)) {
r_stop_internal("`cls` must be a string");
}
return s3_get_method(r_chr_get_c_string(generic, 0),
r_chr_get_c_string(cls, 0),
table);
}argument: { x_arg : *x1 ; i_arg : *x2 } where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void } and x2 = { shelter : any_sexp ; parent : *x2 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* ffi_slice(r_obj* x,
r_obj* i,
r_obj* frame) {
struct vec_slice_opts opts = {
.x_arg = vec_args.x,
.i_arg = vec_args.i,
.call = {.x = r_syms.error_call, .env = frame}
};
return vec_slice_opts(x, i, &opts);
}function: t(any, ~c(..-1)) --> int2 argument: t(c_int_na, c_int_na)
r_obj* ffi_slice_rep(r_obj* x, r_obj* ffi_i, r_obj* ffi_n) {
r_ssize i = r_int_get(ffi_i, 0);
r_ssize n = r_int_get(ffi_n, 0);
r_obj* subscript = KEEP(compact_rep(i, n));
r_obj* out = vec_slice_unsafe(x, subscript);
FREE(1);
return out;
}function: t(~c(..-1), ~c(..-1), c_true) --> int3 argument: t(c_int_na, c_int_na, c_int)
r_obj* ffi_slice_seq(r_obj* x,
r_obj* ffi_start,
r_obj* ffi_size,
r_obj* ffi_increasing) {
r_ssize start = r_int_get(ffi_start, 0);
r_ssize size = r_int_get(ffi_size, 0);
bool increasing = r_lgl_get(ffi_increasing, 0);
r_obj* subscript = KEEP(compact_seq(start, size, increasing));
r_obj* out = vec_slice_unsafe(x, subscript);
FREE(1);
return out;
}function: t(list, *c_string) --> list & t(prim & 'I36760, *c_string) --> v('I36760)
argument: t(c(19), *c_string)r_obj* ffi_type_info(r_obj* x) {
r_obj* out = KEEP(Rf_mkNamed(R_TYPE_list, (const char*[]) { "type", "had_proxy_method", "" }));
const enum vctrs_type type = vec_typeof(x);
r_list_poke(out, 0, r_chr(vec_type_as_str(type)));
r_list_poke(out, 1, r_lgl(vec_proxy_method(x) != r_null));
FREE(1);
return out;
}function: t(any_sexp, c_bool) --> any_sexp argument: t(any_sexp & 'I36538, c_int)
r_obj* ffi_unique_names(r_obj* x, r_obj* quiet) {
return vec_unique_names(x, LOGICAL(quiet)[0]);
}function: t(~c(..-1), ~c(..-1), c_true) --> int3 argument: t(c_int_na, c_int_na, c_int)
r_obj* ffi_vec_chop_seq(r_obj* x, r_obj* starts, r_obj* sizes, r_obj* increasings) {
int* v_starts = r_int_begin(starts);
int* v_sizes = r_int_begin(sizes);
int* v_increasings = r_lgl_begin(increasings);
const r_ssize n = r_length(starts);
r_obj* indices = KEEP(r_alloc_list(n));
for (r_ssize i = 0; i < n; ++i) {
r_obj* index = compact_seq(v_starts[i], v_sizes[i], v_increasings[i]);
r_list_poke(indices, i, index);
}
r_obj* out = KEEP(vec_chop_unsafe(x, indices, r_null));
FREE(2);
return out;
}function: t(any_sexp, any_sexp, c_bool, any_sexp, *x1, *x1, { x : any_sexp ; env : any_sexp }) --> any_sexp where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(any_sexp & 'I39109, any_sexp & 'I39110, c_int, any_sexp & 'I39112, *x1, *x1, { x : 'I39113 ; env : null }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }SEXP ffi_vec_equal(
SEXP ffi_x,
SEXP ffi_y,
SEXP ffi_na_equal,
SEXP ffi_ptype,
SEXP ffi_frame
) {
struct r_lazy error_call = { .x = ffi_frame, .env = r_null };
const bool na_equal = r_arg_as_bool(ffi_na_equal, "na_equal");
return vec_equal(
ffi_x,
ffi_y,
na_equal,
ffi_ptype,
vec_args.x,
vec_args.y,
error_call
);
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> any argument: t(any_sexp)
r_obj* ffi_vec_hash(r_obj* x) {
x = KEEP(vec_proxy_equal(x));
const r_ssize size = vec_size(x);
r_obj* out = KEEP(r_alloc_raw(size * sizeof(uint32_t)));
uint32_t* v_out = (uint32_t*) r_raw_begin(out);
r_memset(v_out, 0, size * sizeof(uint32_t));
vec_hash_fill(x, size, true, v_out);
FREE(2);
return out;
}function: t(any_sexp, c_false, { x : any_sexp ; env : any_sexp }) --> int
argument: t(any_sexp & 'I38411, c_bool, { x : any_sexp & 'I38413 ; env : null })r_obj* ffi_vec_locate_run_bounds(r_obj* x, r_obj* ffi_start, r_obj* frame) {
struct r_lazy error_call = { .x = frame, .env = r_null };
const enum vctrs_run_bound which = as_run_bound(ffi_start, error_call);
return vec_locate_run_bounds(x, which, error_call);
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> any argument: t(any_sexp)
r_obj* ffi_vec_rep(r_obj* x, r_obj* ffi_times, r_obj* frame) {
struct r_lazy error_call = { .x = r_syms.error_call, .env = frame };
struct r_lazy x_arg_lazy = { .x = syms.x_arg, .env = frame };
struct vctrs_arg x_arg = new_lazy_arg(&x_arg_lazy);
struct r_lazy times_arg_lazy = { .x = syms.times_arg, .env = frame };
struct vctrs_arg times_arg = new_lazy_arg(×_arg_lazy);
ffi_times = KEEP(vec_cast(ffi_times,
r_globals.empty_int,
×_arg,
vec_args.empty,
error_call));
if (vec_size(ffi_times) != 1) {
stop_rep_times_size(error_call, ×_arg);
}
const int times = r_int_get(ffi_times, 0);
r_obj* out = vec_rep(x, times, error_call, &x_arg, ×_arg);
FREE(1);
return out;
}name: obj_hash
static inline uint32_t fn_hash(r_obj* x) {
uint32_t hash = 0;
hash = hash_combine(hash, obj_hash(r_fn_body(x)));
hash = hash_combine(hash, obj_hash(r_fn_env(x)));
hash = hash_combine(hash, obj_hash(r_fn_formals(x)));
return hash;
}function: t(c_true, c_true) --> c_true & t(c_false, c_false) | t(c_false, c_true) | t(c_true, c_false) --> c_false argument: t(c_int, c_bool)
static inline bool has_dim(SEXP x) {
return r_attrib_has_any(x) && r_dim(x) != R_NilValue;
}function: t(c_int_na, c_int) --> c_int argument: t(c_int_na & 'I2476, any)
static inline uint32_t hash_combine(uint32_t x, uint32_t y) {
return x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2));
}function: t(c_int_na, c_int) --> c_int argument: t(c_int, c_int_na)
int64_t int64_pack(double left, double right) {
const uint32_t left_u32 = (uint32_t) left;
const uint32_t right_u32 = (uint32_t) right;
const uint64_t out_u64 = ((uint64_t) left_u32) << 32 | right_u32;
const int64_t out = (int64_t) (out_u64 + INT64_MIN);
return out;
}name: ASSIGN
r_obj* int_assign(
r_obj* x,
r_obj* index,
r_obj* value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN(int, r_int_begin, INTEGER_RO);
}name: ASSIGN_SHAPED
static inline SEXP int_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_SHAPED(int, INTEGER, INTEGER_RO);
}function: ref('I21912) --> 'I21912
argument: any --> anyvoid int_check_consecutive(r_obj* subscript,
r_ssize n,
r_ssize n_extend,
const struct location_opts* opts) {
r_obj* extended = KEEP(r_alloc_integer(n_extend));
int* p_extended = r_int_begin(extended);
int i_extend = 0;
int new_n = n;
int* p_subscript = r_int_begin(subscript);
r_ssize n_subscript = Rf_length(subscript);
for (r_ssize i = 0; i < n_subscript; ++i) {
int elt = p_subscript[i];
// Missing value also covered here
if (elt <= n) {
continue;
}
// Special case: appending in ascending sequence at the end
// should not require any sorting
if (elt - 1 == new_n) {
++new_n;
--n_extend;
} else {
p_extended[i_extend++] = elt - 1;
}
}
if (n_extend != i_extend) {
r_stop_internal("int_check_consecutive",
"n_extend (%d) != i_extend (%d).",
n_extend,
i_extend);
}
if (i_extend == 0) {
FREE(1);
return;
}
// Only the first i_extend entries of the array are populated,
// the rest is never touched.
qsort(p_extended, i_extend, sizeof(int), &qsort_int_compare_scalar);
for (r_ssize i = 0; i < i_extend; ++i) {
int elt = p_extended[i];
if (elt != new_n + i) {
stop_location_oob_non_consecutive(subscript, n, opts);
}
}
FREE(1);
}name: COL_DETECT_MISSING
r_ssize int_col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
COL_DETECT_MISSING(int, r_int_cbegin, int_is_missing);
}name: VEC_COL_DETECT_RUN_BOUNDS_BOOL
void int_col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_COL_DETECT_RUN_BOUNDS_BOOL(int, r_int_cbegin, int_equal_na_equal);
}name: UINT32_MAX
void int_compute_range(
const int* p_x,
r_ssize size,
int* p_x_min,
uint32_t* p_range
) {
uint32_t range = UINT32_MAX;
int x_min = NA_INTEGER;
int x_max = NA_INTEGER;
r_ssize i = 0;
// Find first non-NA value
while (i < size) {
const int elt = p_x[i];
if (elt == NA_INTEGER) {
++i;
continue;
}
x_min = elt;
x_max = elt;
range = 0;
// Bump to next `i` since we know this one's value
++i;
break;
}
// All NAs - Return max range to signal to use radix sort
if (x_min == NA_INTEGER) {
*p_x_min = x_min;
*p_range = range;
return;
}
// Now that we have initial values, iterate through the rest
// to compute the final min/max.
for (r_ssize j = i; j < size; ++j) {
const int elt = p_x[j];
if (elt == NA_INTEGER) {
continue;
}
if (elt > x_max) {
x_max = elt;
} else if (elt < x_min) {
x_min = elt;
}
}
/*
* - Max possible range is from
* `c(.Machine$integer.max, -.Machine$integer.max)` which is exactly the
* max of a `uint32_t`.
* - We need to go up to `intmax_t` to avoid intermediate overflow.
* - `+ 1` to get an inclusive range on both ends.
*/
range = (uint32_t) r__intmax_add(r__intmax_subtract(x_max, x_min), 1);
*p_x_min = x_min;
*p_range = range;
}name: VEC_DETECT_COMPLETE
void int_detect_complete(SEXP x, R_len_t size, int* p_out) {
VEC_DETECT_COMPLETE(int, INTEGER_RO, int_is_missing);
}name: DETECT_MISSING
r_obj* int_detect_missing(r_obj* x) {
DETECT_MISSING(int, r_int_cbegin, int_is_missing);
}name: int
void int_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_DETECT_RUN_BOUNDS_BOOL(int, r_int_cbegin, int_equal_na_equal);
}name: EQUAL
SEXP int_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
EQUAL(int, INTEGER_RO, int_equal_na_equal, int_equal_na_propagate);
}name: UINT8_MAX
uint8_t int_extract_uint32_byte(uint32_t x, uint8_t shift) {
return (x >> shift) & UINT8_MAX;
}function: t(c_int & c_int_na('I21760)) --> int[^int('I21760)]
argument: tuple1r_obj* int_filter(r_obj* subscript, r_ssize n_filter, int value) {
const r_ssize size = r_length(subscript);
const int* v_subscript = r_int_cbegin(subscript);
r_obj* out = KEEP(r_alloc_integer(size - n_filter));
int* v_out = r_int_begin(out);
r_obj* names = r_names(subscript);
const bool has_names = names != r_null;
r_obj* const* v_names = NULL;
r_obj* out_names = r_null;
if (has_names) {
v_names = r_chr_cbegin(names);
out_names = r_alloc_character(size - n_filter);
r_attrib_poke_names(out, out_names);
}
r_ssize j = 0;
for (r_ssize i = 0; i < size; ++i) {
const int elt = v_subscript[i];
if (elt != value) {
v_out[j] = elt;
if (has_names) {
r_chr_poke(out_names, j, v_names[i]);
}
++j;
}
}
FREE(1);
return out;
}function: t(c_int & c_int_na('I21932)) --> int[^int('I21932)]
argument: tuple1r_obj* int_filter_oob(r_obj* subscript, r_ssize n, r_ssize n_oob) {
const r_ssize n_subscript = r_length(subscript);
const r_ssize n_out = n_subscript - n_oob;
const int* v_subscript = r_int_cbegin(subscript);
r_obj* out = KEEP(r_alloc_integer(n_out));
int* v_out = r_int_begin(out);
r_obj* names = r_names(subscript);
const bool has_names = names != r_null;
r_obj* const* v_names = NULL;
r_obj* out_names = r_null;
if (has_names) {
v_names = r_chr_cbegin(names);
out_names = r_alloc_character(n_out);
r_attrib_poke_names(out, out_names);
}
r_ssize j = 0;
for (r_ssize i = 0; i < n_subscript; ++i) {
const int elt = v_subscript[i];
if (abs(elt) <= n || elt == r_globals.na_int) {
v_out[j] = elt;
if (has_names) {
r_chr_poke(out_names, j, v_names[i]);
}
++j;
}
}
FREE(1);
return out;
}name: FIRST_MISSING
r_ssize int_first_missing(r_obj* x) {
FIRST_MISSING(int, r_int_cbegin, int_is_missing);
}name: HASH
static inline uint32_t int_hash(r_obj* x) {
HASH(int, r_int_cbegin, int_hash_scalar);
}name: HASH_FILL
static inline void int_hash_fill_na_equal(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL(int, r_int_cbegin, int_hash_scalar);
}name: HASH_FILL_NA_PROPAGATE
static inline void int_hash_fill_na_propagate(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL_NA_PROPAGATE(int, r_int_cbegin, int_hash_scalar, int_is_missing);
}name: UINT8_MAX_SIZE
void int_order_radix_recurse(
const r_ssize size,
const uint8_t pass,
uint32_t* p_x,
int* p_o,
uint32_t* p_x_aux,
int* p_o_aux,
uint8_t* p_bytes,
r_ssize* p_counts,
bool* p_skips,
struct group_infos* p_group_infos
) {
// Exit as fast as possible if we are below the insertion order boundary
if (size <= ORDER_INSERTION_BOUNDARY) {
int_order_insertion(size, p_x, p_o, p_group_infos);
return;
}
// Skip passes where our up front check told us that all bytes were the same
uint8_t next_pass = pass + 1;
r_ssize* p_counts_next_pass = p_counts + UINT8_MAX_SIZE;
while (next_pass < INT_MAX_RADIX_PASS && p_skips[next_pass]) {
++next_pass;
p_counts_next_pass += UINT8_MAX_SIZE;
}
const uint8_t radix = PASS_TO_RADIX(pass, INT_MAX_RADIX_PASS);
const uint8_t shift = radix * 8;
uint8_t byte = 0;
// Histogram for this pass
for (r_ssize i = 0; i < size; ++i) {
const uint32_t x_elt = p_x[i];
byte = int_extract_uint32_byte(x_elt, shift);
p_bytes[i] = byte;
++p_counts[byte];
}
// Fast check to see if all bytes were the same.
// If so, skip this `pass` since we learned nothing.
// No need to accumulate counts and iterate over chunks,
// we know all others are zero.
if (p_counts[byte] == size) {
// Reset count for other group chunks
p_counts[byte] = 0;
if (next_pass == INT_MAX_RADIX_PASS) {
// If we are already at the last pass, we are done
groups_size_maybe_push(size, p_group_infos);
} else {
// Otherwise, recurse on next byte using the same `size` since
// the group size hasn't changed
int_order_radix_recurse(
size,
next_pass,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts_next_pass,
p_skips,
p_group_infos
);
}
return;
}
r_ssize cumulative = 0;
// Accumulate counts, skip zeros
for (uint16_t i = 0; i < UINT8_MAX_SIZE; ++i) {
r_ssize count = p_counts[i];
if (count == 0) {
continue;
}
// Replace with `cumulative` first, then bump `cumulative`.
// `p_counts` now represents starting locations for each radix group.
p_counts[i] = cumulative;
cumulative += count;
}
// Place into auxiliary arrays in the correct order, then copy back over
for (r_ssize i = 0; i < size; ++i) {
const uint8_t byte = p_bytes[i];
const r_ssize loc = p_counts[byte]++;
p_o_aux[loc] = p_o[i];
p_x_aux[loc] = p_x[i];
}
// Copy back over
r_memcpy(p_o, p_o_aux, size * sizeof(*p_o_aux));
r_memcpy(p_x, p_x_aux, size * sizeof(*p_x_aux));
r_ssize last_cumulative_count = 0;
// Recurse on subgroups as required
for (uint16_t i = 0; last_cumulative_count < size && i < UINT8_MAX_SIZE; ++i) {
const r_ssize cumulative_count = p_counts[i];
if (!cumulative_count) {
continue;
}
// Set to zero to clear for subsequent groups
p_counts[i] = 0;
// Diff the accumulated counts to get the radix group size
const r_ssize group_size = cumulative_count - last_cumulative_count;
last_cumulative_count = cumulative_count;
if (group_size == 1) {
groups_size_maybe_push(1, p_group_infos);
++p_x;
++p_o;
continue;
}
// Can get here in the case of ties, like c(1L, 1L), which have a
// `group_size` of 2 in the last radix, but there is nothing left to
// compare so we are done.
if (next_pass == INT_MAX_RADIX_PASS) {
groups_size_maybe_push(group_size, p_group_infos);
p_x += group_size;
p_o += group_size;
continue;
}
// Order next byte of this subgroup
int_order_radix_recurse(
group_size,
next_pass,
p_x,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_counts_next_pass,
p_skips,
p_group_infos
);
p_x += group_size;
p_o += group_size;
}
}name: RESIZE
SEXP int_resize(SEXP x, r_ssize x_size, r_ssize size) {
RESIZE(INTEGER_RO, INTEGER, int, INTSXP);
}name: SLICE
r_obj* int_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE(R_TYPE_integer, int, r_int_begin, r_int_cbegin, r_globals.na_int);
}name: SLICE_SHAPED
static SEXP int_slice_shaped(SEXP x, SEXP index, struct strides_info* p_info) {
SLICE_SHAPED(INTSXP, int, INTEGER, INTEGER_RO, NA_INTEGER);
}name: strtol
bool is_dotdotint(const char* name) {
int n = strlen(name);
if (n < 3) {
return false;
}
if (name[0] != '.' || name[1] != '.') {
return false;
}
if (name[2] == '.') {
name += 3;
} else {
name += 2;
}
return (bool) strtol(name, NULL, 10);
}function: t(list<>, any_sexp, any_sexp, *{ shelter : any_sexp ; type : c(0..4) | c(99) ; name_repair_arg : { x : any_sexp ; env : any_sexp } ; fn : any_sexp ; quiet : c_bool ; call : { x : any_sexp ; env : any_sexp } }, c_null, { x : any_sexp ; env : any_sexp }) --> empty
argument: t({ null | 'I26949 | 'I26948 }, any_sexp, null, *{ type : c_false ; fn : null }, *x1, { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }static SEXP levels_union(SEXP x, SEXP y) {
SEXP args = PROTECT(Rf_allocVector(VECSXP, 2));
SET_VECTOR_ELT(args, 0, x);
SET_VECTOR_ELT(args, 1, y);
const struct name_repair_opts name_repair_opts = {
.type = NAME_REPAIR_none,
.fn = R_NilValue
};
// Combine with known ptype
// No name repair because this is just combining factor levels
SEXP xy = PROTECT(vec_c(
args,
r_globals.empty_chr,
R_NilValue,
&name_repair_opts,
vec_args.empty,
r_lazy_null
));
SEXP out = vec_unique(xy);
UNPROTECT(2);
return out;
}name: ASSIGN
r_obj* lgl_assign(
r_obj* x,
r_obj* index,
r_obj* value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN(int, LOGICAL, LOGICAL_RO);
}name: ASSIGN_SHAPED
static inline SEXP lgl_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_SHAPED(int, LOGICAL, LOGICAL_RO);
}name: COL_DETECT_MISSING
r_ssize lgl_col_detect_missing(r_obj* x,
r_ssize* v_loc,
r_ssize loc_size) {
COL_DETECT_MISSING(int, r_lgl_cbegin, lgl_is_missing);
}name: VEC_COL_DETECT_RUN_BOUNDS_BOOL
void lgl_col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_COL_DETECT_RUN_BOUNDS_BOOL(int, r_lgl_cbegin, lgl_equal_na_equal);
}name: VEC_DETECT_COMPLETE
void lgl_detect_complete(SEXP x, R_len_t size, int* p_out) {
VEC_DETECT_COMPLETE(int, LOGICAL_RO, lgl_is_missing);
}name: DETECT_MISSING
r_obj* lgl_detect_missing(r_obj* x) {
DETECT_MISSING(int, r_lgl_cbegin, lgl_is_missing);
}name: int
void lgl_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_DETECT_RUN_BOUNDS_BOOL(int, r_lgl_cbegin, lgl_equal_na_equal);
}name: EQUAL
SEXP lgl_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
EQUAL(int, LOGICAL_RO, lgl_equal_na_equal, lgl_equal_na_propagate);
}name: FIRST_MISSING
r_ssize lgl_first_missing(r_obj* x) {
FIRST_MISSING(int, r_lgl_cbegin, lgl_is_missing);
}name: HASH
static inline uint32_t lgl_hash(r_obj* x) {
HASH(int, r_lgl_cbegin, lgl_hash_scalar);
}name: HASH_FILL
static inline void lgl_hash_fill_na_equal(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL(int, r_lgl_cbegin, lgl_hash_scalar);
}name: HASH_FILL_NA_PROPAGATE
static inline void lgl_hash_fill_na_propagate(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL_NA_PROPAGATE(int, r_lgl_cbegin, lgl_hash_scalar, lgl_is_missing);
}name: SLICE
r_obj* lgl_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE(R_TYPE_logical, int, r_lgl_begin, r_lgl_cbegin, r_globals.na_lgl);
}name: SLICE_SHAPED
static SEXP lgl_slice_shaped(SEXP x, SEXP index, struct strides_info* p_info) {
SLICE_SHAPED(LGLSXP, int, LOGICAL, LOGICAL_RO, NA_LOGICAL);
}function: t(list) --> *any_sexp
argument: t('I25188 & (p(chr) | vec[^int('I25198)]))bool list_all_have_class(r_obj* xs, r_obj* class) {
r_ssize size = r_length(xs);
r_obj* const* v_xs = r_list_cbegin(xs);
for (r_ssize i = 0; i < size; ++i) {
r_obj* x = v_xs[i];
if (x == r_null) {
// Allow `NULL`s
continue;
}
if (!obj_has_class(x, class)) {
return false;
}
}
return true;
}function: t(list) --> *any_sexp
argument: t('I39353 & (p(chr) | vec[^int('I39368)]))bool list_all_recyclable(
r_obj* xs,
r_ssize size,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
if (r_typeof(xs) != R_TYPE_list) {
r_stop_unexpected_type(r_typeof(xs));
}
r_ssize i = 0;
const r_ssize xs_size = r_length(xs);
r_obj* xs_names = KEEP(r_names(xs));
r_obj* const* v_xs = r_list_cbegin(xs);
struct vctrs_arg* p_x_arg = new_subscript_arg(p_xs_arg, xs_names, xs_size, &i);
KEEP(p_x_arg->shelter);
bool out = true;
for (; i < xs_size; ++i) {
r_obj* x = v_xs[i];
if (!vec_is_recyclable(x, size, allow_null, p_x_arg, call)) {
out = false;
break;
}
}
FREE(2);
return out;
}function: t(list) --> *any_sexp
argument: t('I39302 & (p(chr) | vec[^int('I39317)]))bool list_all_size(
r_obj* xs,
r_ssize size,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
if (r_typeof(xs) != R_TYPE_list) {
r_stop_unexpected_type(r_typeof(xs));
}
r_ssize i = 0;
const r_ssize xs_size = r_length(xs);
r_obj* xs_names = KEEP(r_names(xs));
r_obj* const* v_xs = r_list_cbegin(xs);
struct vctrs_arg* p_x_arg = new_subscript_arg(p_xs_arg, xs_names, xs_size, &i);
KEEP(p_x_arg->shelter);
bool out = true;
for (; i < xs_size; ++i) {
r_obj* x = v_xs[i];
if (!vec_is_size(x, size, allow_null, p_x_arg, call)) {
out = false;
break;
}
}
FREE(2);
return out;
}function: t(list) --> *any_sexp
argument: t('I39247 & (p(chr) | vec[^int('I39264)]))bool list_all_vectors(r_obj* xs, enum vctrs_allow_null allow_null) {
if (r_typeof(xs) != R_TYPE_list) {
r_stop_unexpected_type(r_typeof(xs));
}
const r_ssize size = r_length(xs);
r_obj* const* v_xs = r_list_cbegin(xs);
for (r_ssize i = 0; i < size; ++i) {
r_obj* x = v_xs[i];
if (!obj_is_vector(x, allow_null)) {
return false;
}
}
return true;
}function: t(list) --> *any_sexp
argument: t('I23994 & (p(chr) | vec[^int('I24017)]))r_obj* list_as_locations(r_obj* indices, r_ssize n, r_obj* names, bool allow_compact) {
if (r_typeof(indices) != R_TYPE_list) {
r_abort_lazy_call(r_lazy_null, "`indices` must be a list of index values, or `NULL`.");
}
indices = KEEP(r_clone_referenced(indices));
const r_ssize size = r_length(indices);
r_obj* const* v_indices = r_list_cbegin(indices);
// Restrict index values to positive integer locations
// Also, notably, the `index` vector can't change size, i.e. `0` and `NA` aren't dropped.
const struct location_opts opts = {
.subscript_opts = {
.logical = SUBSCRIPT_TYPE_ACTION_ERROR,
.numeric = SUBSCRIPT_TYPE_ACTION_CAST,
.character = SUBSCRIPT_TYPE_ACTION_ERROR
},
.missing = SUBSCRIPT_MISSING_PROPAGATE,
.loc_negative = LOC_NEGATIVE_ERROR,
.loc_oob = LOC_OOB_ERROR,
.loc_zero = LOC_ZERO_ERROR
};
for (r_ssize i = 0; i < size; ++i) {
r_obj* index = v_indices[i];
if (is_compact_seq(index)) {
if (allow_compact) {
// Allow `compact_seq` to pass through untouched,
// assume caller can handle them natively
continue;
} else {
// We don't want them to slip through when not handled natively
r_stop_internal("`compact_seq` are not allowed.");
}
}
index = vec_as_location_opts(index, n, names, &opts);
r_list_poke(indices, i, index);
}
FREE(1);
return indices;
}name: ASSIGN_BARRIER_SHAPED
static SEXP list_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
const enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_BARRIER_SHAPED(SEXP, VECTOR_PTR_RO, SET_VECTOR_ELT);
}function: t(list) --> *any_sexp
argument: t('I31389 & (p(chr) | vec[^int('I31402)]))void list_check_all_condition_indices(
r_obj* xs,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
if (r_typeof(xs) != R_TYPE_list) {
r_stop_unexpected_type(r_typeof(xs));
}
r_ssize i = 0;
const r_ssize xs_size = r_length(xs);
r_obj* xs_names = KEEP(r_names(xs));
r_obj* const* v_xs = r_list_cbegin(xs);
struct vctrs_arg* p_x_arg = new_subscript_arg(p_xs_arg, xs_names, xs_size, &i);
KEEP(p_x_arg->shelter);
for (; i < xs_size; ++i) {
check_condition_index(v_xs[i], p_x_arg, call);
}
FREE(2);
}function: t(list) --> *any_sexp
argument: t('I31425 & (p(chr) | vec[^int('I31440)]))void list_check_all_size(
r_obj* xs,
r_ssize size,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
if (r_typeof(xs) != R_TYPE_list) {
r_stop_unexpected_type(r_typeof(xs));
}
r_ssize i = 0;
const r_ssize xs_size = r_length(xs);
r_obj* xs_names = KEEP(r_names(xs));
r_obj* const* v_xs = r_list_cbegin(xs);
struct vctrs_arg* p_x_arg = new_subscript_arg(p_xs_arg, xs_names, xs_size, &i);
KEEP(p_x_arg->shelter);
for (; i < xs_size; ++i) {
vec_check_size(v_xs[i], size, allow_null, p_x_arg, call);
}
FREE(2);
}function: t(list) --> *any_sexp
argument: t('I39274 & (p(chr) | vec<> & vec[^int('I39292)]))void list_check_all_vectors(
r_obj* xs,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
r_ssize i = 0;
struct vctrs_arg* x_arg = new_subscript_arg_vec(p_xs_arg, xs, &i);
KEEP(x_arg->shelter);
const r_ssize xs_size = r_length(xs);
r_obj* const* v_xs = r_list_cbegin(xs);
for (; i < xs_size; ++i) {
r_obj* x = v_xs[i];
obj_check_vector(x, allow_null, x_arg, call);
}
FREE(1);
}function: t(any_sexp, lgl[^(int \ 0)]<> | vec0<>, c_false, c_bool, x1, { x : any_sexp ; env : any_sexp }) --> any where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(any_sexp & 'I25140, null, c_true, c_false, *x1 & 'I25152, 'I25155 & { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* list_combine_common_class_fallback(
r_obj* xs,
bool has_indices,
r_obj* indices,
enum vctrs_index_style indices_style,
r_ssize size,
bool has_default,
r_obj* default_,
enum list_combine_multiple multiple,
enum assignment_slice_value slice_xs,
r_obj* ptype,
r_obj* name_spec,
const struct name_repair_opts* p_name_repair_opts,
struct vctrs_arg* p_xs_arg,
struct vctrs_arg* p_indices_arg,
struct vctrs_arg* p_default_arg,
struct r_lazy error_call
) {
r_obj* cls = KEEP(r_attrib_get(ptype, syms_fallback_class));
bool implements_c = class_implements_base_c(cls);
FREE(1);
if (implements_c) {
return base_list_combine_fallback(
xs,
has_indices,
indices,
indices_style,
size,
has_default,
default_,
multiple,
slice_xs,
name_spec,
p_xs_arg,
p_default_arg,
error_call
);
} else {
// Throw out the `vctrs:::common_class_fallback` ptype,
// it's served its purpose by getting us here
ptype = r_null;
const enum s3_fallback s3_fallback = S3_FALLBACK_false;
// Should cause a common type error, unless another fallback
// kicks in (for instance, homogeneous class with homogeneous
// attributes)
vec_ptype_common(
xs,
ptype,
PTYPE_FINALISE_DEFAULT,
s3_fallback,
p_xs_arg,
error_call
);
// We will have already checked `unmatched` before the fallback
// is invoked, so no need to check it again
enum list_combine_unmatched unmatched = LIST_COMBINE_UNMATCHED_default;
// Suboptimal: Call `list_combine_impl()` again to
// combine vector with homogeneous class fallback
return list_combine_impl(
xs,
has_indices,
indices,
indices_style,
size,
has_default,
default_,
unmatched,
multiple,
slice_xs,
ptype,
name_spec,
p_name_repair_opts,
p_xs_arg,
p_indices_arg,
p_default_arg,
error_call,
s3_fallback
);
}
}function: t(list) --> *any_sexp
argument: t('I24567 & (p(chr) | vec[^int('I24577)]))r_obj* list_condition_to_location_indices(r_obj* indices) {
// We probably don't own these, the user provides them.
indices = KEEP(r_clone_referenced(indices));
const r_ssize indices_size = r_length(indices);
r_obj* const* v_indices = r_list_cbegin(indices);
// Because we want `c(FALSE, NA, TRUE)` to become `c(NA, TRUE)`
// for assignment and size checking purposes
const bool na_propagate = true;
for (r_ssize i = 0; i < indices_size; ++i) {
r_obj* index = v_indices[i];
r_list_poke(indices, i, r_lgl_which(index, na_propagate));
}
FREE(1);
return indices;
}name: VEC_DETECT_COMPLETE
void list_detect_complete(SEXP x, R_len_t size, int* p_out) {
VEC_DETECT_COMPLETE(SEXP, VECTOR_PTR_RO, list_is_missing);
}name: EQUAL
SEXP list_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
EQUAL(SEXP, VECTOR_PTR_RO, list_equal_na_equal, list_equal_na_propagate);
}name: list_hash_scalar
static inline uint32_t list_hash(r_obj* x) {
HASH(r_obj*, r_list_cbegin, list_hash_scalar);
}function: t(list) --> *any_sexp
argument: t('I24553 & (p(chr) | vec[^int('I24564)]))r_obj* list_location_to_location_indices(r_obj* indices) {
// Only clone if at least one index is compact, which is rare
bool has_compact = false;
const r_ssize indices_size = r_length(indices);
r_obj* const* v_indices = r_list_cbegin(indices);
for (r_ssize i = 0; i < indices_size; ++i) {
r_obj* index = v_indices[i];
if (is_compact_seq(index)) {
has_compact = true;
break;
}
}
if (!has_compact) {
// Nothing to do, we are already in expanded location form
return indices;
}
// We probably don't own these, the user provides them.
indices = KEEP(r_clone_referenced(indices));
v_indices = r_list_cbegin(indices);
for (r_ssize i = 0; i < indices_size; ++i) {
r_obj* index = v_indices[i];
if (is_compact_seq(index)) {
r_list_poke(indices, i, vec_subscript_materialize(index));
}
}
FREE(1);
return indices;
}function: t(list) --> *any_sexp
argument: t('I26743 & (p(chr) | vec[^int('I26749)]))r_obj* list_pluck(r_obj* xs, r_ssize i) {
r_ssize n = r_length(xs);
r_obj* const * v_xs = r_list_cbegin(xs);
r_obj* out = KEEP(r_new_list(n));
for (r_ssize j = 0; j < n; ++j) {
r_obj* x = v_xs[j];
if (x != r_null) {
r_list_poke(out, j, r_list_get(x, i));
}
}
FREE(1);
return out;
}function: t(c_int & c_int_na('I30934)) --> int[^int('I30934)]
argument: tuple1r_obj* list_sizes(
r_obj* xs,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
obj_check_list(xs, p_xs_arg, call);
r_ssize size = vec_size(xs);
r_obj* const * v_xs = r_list_cbegin(xs);
r_obj* out = KEEP(r_alloc_integer(size));
int* v_out = r_int_begin(out);
r_obj* names = vec_names(xs);
r_attrib_poke_names(out, names);
r_ssize i = 0;
struct vctrs_arg* p_x_arg = new_subscript_arg_vec(p_xs_arg, xs, &i);
KEEP(p_x_arg->shelter);
for (; i < size; ++i) {
r_obj* x = v_xs[i];
v_out[i] = vec_size_params(x, p_x_arg, call);
}
FREE(2);
return out;
}name: SLICE_BARRIER
r_obj* list_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE_BARRIER(R_TYPE_list, r_list_cbegin, r_list_poke, r_null);
}name: SLICE_BARRIER_SHAPED
static SEXP list_slice_shaped(SEXP x, SEXP index, struct strides_info* p_info) {
SLICE_BARRIER_SHAPED(VECSXP, SEXP, VECTOR_PTR_RO, SET_VECTOR_ELT, R_NilValue);
}function: t(list) --> *any_sexp
argument: t('I26730 & (p(chr) | vec[^int('I26740)]))bool needs_df_list_combine_common_class_fallback(r_obj* x) {
r_ssize n_cols = r_length(x);
r_obj* const * v_x = r_list_cbegin(x);
for (r_ssize i = 0; i < n_cols; ++i) {
r_obj* col = v_x[i];
if (vec_is_common_class_fallback(col)) {
return true;
}
if (is_data_frame(col) && needs_df_list_combine_common_class_fallback(col)) {
return true;
}
}
return false;
}function: t(dbl & 'I27149, chr) | t(dbl & 'I27149, null) | t(dbl & 'I27149, p(chr)) | t(dbl & 'I27149, (env | externalptr | lang | list | v(clx | dbl | int | lgl | raw) | arrow) | sym) | t('I27149 & ((env | externalptr | lang | list | v(chr | clx | int | lgl | raw) | arrow) | null | p(chr) | sym), chr) | t('I27149 & ((env | externalptr | lang | list | v(chr | clx | int | lgl | raw) | arrow) | null | p(chr) | sym), null) | t('I27149 & ((env | externalptr | lang | list | v(chr | clx | int | lgl | raw) | arrow) | null | p(chr) | sym), p(chr)) | t('I27149 & ((env | externalptr | lang | list | v(chr | clx | int | lgl | raw) | arrow) | null | p(chr) | sym), (env | externalptr | lang | list | v(clx | dbl | int | lgl | raw) | arrow) | sym) --> any_sexp & 'I27149
argument: t(any_sexp, any_sexp & 'I27144)static SEXP new_empty_datetime(SEXP tzone) {
return new_datetime(r_globals.empty_dbl, tzone);
}function: t(lang, c_string) --> any
argument: t((v(chr & 'I30837) & vec[^int('I30835)]) & 'I30783, c(".name_repair"))struct name_repair_opts new_name_repair_opts(r_obj* name_repair,
struct r_lazy name_repair_arg,
bool quiet,
struct r_lazy call) {
struct name_repair_opts opts = {
.shelter = r_null,
.type = 0,
.fn = r_null,
.name_repair_arg = name_repair_arg,
.quiet = quiet,
.call = call
};
switch (r_typeof(name_repair)) {
case R_TYPE_character: {
if (!r_length(name_repair)) {
stop_name_repair(&opts);
}
r_obj* c = r_chr_get(name_repair, 0);
if (c == strings_none) {
opts.type = NAME_REPAIR_none;
} else if (c == strings_minimal) {
opts.type = NAME_REPAIR_minimal;
} else if (c == strings_unique) {
opts.type = NAME_REPAIR_unique;
} else if (c == strings_universal) {
opts.type = NAME_REPAIR_universal;
} else if (c == strings_check_unique) {
opts.type = NAME_REPAIR_check_unique;
} else if (c == strings_unique_quiet) {
opts.type = NAME_REPAIR_unique;
opts.quiet = true;
} else if (c == strings_universal_quiet) {
opts.type = NAME_REPAIR_universal;
opts.quiet = true;
} else {
struct repair_error_info info = new_repair_error_info(&opts);
KEEP(info.shelter);
r_abort_call(info.input_error_call,
"%s can't be \"%s\". See `?vctrs::vec_as_names`.",
r_format_error_arg(info.input_error_repair_arg),
r_str_c_string(c));
}
return opts;
}
case R_TYPE_call:
opts.fn = r_as_function(name_repair, ".name_repair");
opts.shelter = opts.fn;
opts.type = NAME_REPAIR_custom;
return opts;
case R_TYPE_closure:
opts.fn = name_repair;
opts.type = NAME_REPAIR_custom;
return opts;
default:
stop_name_repair(&opts);
}
r_stop_unreachable();
}function: t(^int) --> *c_int & t(int) --> *c_int_na argument: t(any_sexp)
static inline struct strides_info new_strides_info(SEXP x, SEXP index) {
SEXP dim = PROTECT(vec_dim(x));
const int* p_dim = INTEGER_RO(dim);
R_len_t dim_n = Rf_length(dim);
R_len_t shape_n = dim_n - 1;
R_len_t index_n = vec_subscript_size(index);
SEXP strides = PROTECT(vec_strides(p_dim, shape_n));
const int* p_strides = INTEGER_RO(strides);
const int* p_index = INTEGER_RO(index);
// If using a compact rep/seq, the `steps` won't be used, but we still
// need to put something in the struct
SEXP steps;
if (is_compact_rep(index) || is_compact_seq(index)) {
steps = r_globals.empty_int;
} else {
steps = vec_steps(p_index, index_n);
}
PROTECT(steps);
const int* p_steps = INTEGER_RO(steps);
// Initialize `shape_index` to the first element
SEXP shape_index = PROTECT(Rf_allocVector(INTSXP, shape_n));
int* p_shape_index = INTEGER(shape_index);
for (int i = 0; i < shape_n; ++i) {
p_shape_index[i] = 0;
}
R_len_t shape_elem_n = vec_shape_elem_n(p_dim, dim_n);
struct strides_info info = {
.dim = dim,
.p_dim = p_dim,
.strides = strides,
.p_strides = p_strides,
.index = index,
.p_index = p_index,
.steps = steps,
.p_steps = p_steps,
.shape_index = shape_index,
.p_shape_index = p_shape_index,
.dim_n = dim_n,
.shape_n = shape_n,
.index_n = index_n,
.shape_elem_n = shape_elem_n
};
UNPROTECT(4);
return info;
}function: t(raw) --> *c_int argument: tuple1
struct vctrs_arg* new_subscript_arg(struct vctrs_arg* parent,
r_obj* names,
r_ssize n,
r_ssize* p_i) {
r_obj* shelter = KEEP(r_alloc_list(2));
r_list_poke(shelter, 0, r_alloc_raw(sizeof(struct subscript_arg_data)));
r_list_poke(shelter, 1, names);
struct subscript_arg_data* p_data = r_raw_begin(r_list_get(shelter, 0));
p_data->self = (struct vctrs_arg) {
.shelter = shelter,
.parent = parent,
.fill = &subscript_arg_fill,
.data = p_data
};
p_data->names = names;
p_data->n = n;
p_data->p_i = p_i;
FREE(1);
return (struct vctrs_arg*) p_data;
}name: obj_hash
static inline uint32_t node_hash(r_obj* x) {
uint32_t hash = 0;
hash = hash_combine(hash, obj_hash(r_node_tag(x)));
hash = hash_combine(hash, obj_hash(r_node_car(x)));
hash = hash_combine(hash, obj_hash(r_node_cdr(x)));
return hash;
}function: t(*('I3256 \ c_string)) --> *('I3256 \ c_string) & t(c_int) --> c_int & t(c_int_na) --> c_int_na & t(c_string) --> c_string & t(c_double) --> c_double
argument: tuple1static r_obj* obj_attrib_count_cb(r_obj* _tag, r_obj* _value, void* data) {
struct attrib_count_data* p_data = (struct attrib_count_data*) data;
p_data->y_size++;
// Continue
return NULL;
}name: obj_encode_utf8
static r_obj* obj_attrib_encode_utf8_cb(r_obj* tag, r_obj* old, void* data) {
struct cb_data* p_data = (struct cb_data*) data;
r_obj* new = obj_encode_utf8(old);
if (old == new) {
return NULL;
}
KEEP(new);
if (!(*p_data->p_owned)) {
// Shallow clones `out` and its attributes
*p_data->p_out = r_clone(*p_data->p_out);
KEEP_AT(*p_data->p_out, p_data->shelter);
*p_data->p_owned = true;
}
r_attrib_poke(*p_data->p_out, tag, new);
FREE(1);
return NULL;
}function: t(any_sexp, *t(any_sexp, any_sexp, *c_void) --> any_sexp, *c_void) --> any_sexp
argument: t(any_sexp & 'I3258, t(any_sexp, any_sexp, *c_void) --> any_sexp, *{ y : 'I3259 ; x_size : c_false })static inline bool obj_attrib_equal(r_obj* x, r_obj* y) {
const bool x_has_attrib = r_attrib_has_any(x);
const bool y_has_attrib = r_attrib_has_any(y);
if (!x_has_attrib && !y_has_attrib) {
// Neither have attributes
return true;
}
if (x_has_attrib != y_has_attrib) {
// One or the other has attributes, but not both
return false;
}
// Ok, now we know both have attributes, compare them
struct attrib_equal_data equal_data = {
.y = y,
.x_size = 0
};
r_obj* result = r_attrib_map(x, obj_attrib_equal_cb, &equal_data);
// We got the signal that an attribute was different
if (result == r_null) {
return false;
}
// All attributes in `x` equal attributes in `y`.
// Lastly, ensure `y` doesn't have more attributes than `x`.
struct attrib_count_data count_data = {
.y_size = 0
};
r_attrib_map(y, obj_attrib_count_cb, &count_data);
return equal_data.x_size == count_data.y_size;
}function: t(*('I3246 \ c_string)) --> *('I3246 \ c_string) & t(c_int) --> c_int & t(c_int_na) --> c_int_na & t(c_string) --> c_string & t(c_double) --> c_double
argument: tuple1static r_obj* obj_attrib_equal_cb(r_obj* tag, r_obj* value, void* data) {
struct attrib_equal_data* p_data = (struct attrib_equal_data*) data;
p_data->x_size++;
r_obj* y_value = KEEP(r_attrib_get(p_data->y, tag));
// Return `r_null` when different to signal that we are done
SEXP out = obj_equal_utf8(value, y_value) ? NULL : r_null;
FREE(1);
return out;
}function: t(p(chr) | vec, p(chr) | vec, c(0..9) | c(17..18) | c(20..23) | c(30..31) | c(25) | c(99)) --> any
argument: t('I3552 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym), 'I3553 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym), c(13..16) | c(10) | c(19) | c(24))bool obj_equal_utf8(r_obj* x, r_obj* y) {
const enum r_type type = r_typeof(x);
// Types must be the same
if (type != r_typeof(y)) {
return false;
}
// Every type has a chance for an "equal pointer" optimization
if (x == y) {
return true;
}
switch (type) {
// Pure pointer comparison. If it didn't early exit in the pointer
// comparison above, then they must not be equal.
case R_TYPE_null:
case R_TYPE_symbol:
case R_TYPE_special:
case R_TYPE_builtin:
case R_TYPE_string:
case R_TYPE_environment:
case R_TYPE_pointer:
return false;
// Vectors
case R_TYPE_logical:
case R_TYPE_integer:
case R_TYPE_double:
case R_TYPE_character:
case R_TYPE_raw:
case R_TYPE_complex:
case R_TYPE_list:
return obj_vec_equal(x, y, type);
// Expression vectors
case R_TYPE_expression:
return obj_expr_equal(x, y);
// Node like
case R_TYPE_dots:
case R_TYPE_call:
case R_TYPE_pairlist:
case R_TYPE_bytecode:
return obj_node_equal(x, y);
// Functions
case R_TYPE_closure:
return obj_fn_equal(x, y);
default:
stop_unimplemented_type("obj_equal_utf8", type);
}
}function: t({ 'I3473 }, c_int) --> 'I3473
argument: t('I3445 & (p(chr) | vec[^int('I3456)]), c_false)static inline bool obj_expr_equal(r_obj* x, r_obj* y) {
const r_ssize n = r_length(x);
// Length check
if (n != r_length(y)) {
return false;
}
// Attribute check
if (!obj_attrib_equal(x, y)) {
return false;
}
// Data check
for (r_ssize i = 0; i < n; ++i) {
r_obj* x_elt = r_list_get(x, i);
r_obj* y_elt = r_list_get(y, i);
if (!obj_equal_utf8(x_elt, y_elt)) {
return false;
}
}
return true;
}name: obj_equal_utf8
static inline bool obj_fn_equal(r_obj* x, r_obj* y) {
// Attribute check
if (!obj_attrib_equal(x, y)) {
return false;
}
// Function body check
if (!obj_equal_utf8(r_fn_body(x), r_fn_body(y))) {
return false;
}
// Function environment check
if (!obj_equal_utf8(r_fn_env(x), r_fn_env(y))) {
return false;
}
// Function formals check
if (!obj_equal_utf8(r_fn_formals(x), r_fn_formals(y))) {
return false;
}
return true;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym, (env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> c_bool argument: t(any_sexp, any_sexp & 'I25174)
bool obj_has_class(r_obj* x, r_obj* class) {
r_obj* x_class = KEEP(r_class(x));
bool out = obj_equal(x_class, class);
FREE(1);
return out;
}name: obj_equal_utf8
static inline bool obj_node_equal(r_obj* x, r_obj* y) {
// Attribute check
if (!obj_attrib_equal(x, y)) {
return false;
}
// Tag check
if (!obj_equal_utf8(r_node_tag(x), r_node_tag(y))) {
return false;
}
// Value check
if (!obj_equal_utf8(r_node_car(x), r_node_car(y))) {
return false;
}
// Check rest
if (!obj_equal_utf8(r_node_cdr(x), r_node_cdr(y))) {
return false;
}
return true;
}name: P_EQUAL_NA_EQUAL
static inline int p_chr_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_EQUAL_NA_EQUAL(SEXP, chr_equal_na_equal);
}name: P_COMPARE_NA_EQUAL
int p_cpl_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(Rcomplex, cpl_compare_na_equal);
}name: P_EQUAL_NA_EQUAL
static inline int p_cpl_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_EQUAL_NA_EQUAL(Rcomplex, cpl_equal_na_equal);
}name: P_IS_MISSING
bool p_cpl_is_missing(const void* p_x, r_ssize i) {
P_IS_MISSING(r_complex, cpl_is_missing);
}name: P_COMPARE_NA_EQUAL
int p_dbl_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(double, dbl_compare_na_equal);
}name: P_EQUAL_NA_EQUAL
static inline int p_dbl_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_EQUAL_NA_EQUAL(double, dbl_equal_na_equal);
}name: P_IS_MISSING
bool p_dbl_is_missing(const void* p_x, r_ssize i) {
P_IS_MISSING(double, dbl_is_missing);
}function: ref('I35482) --> 'I35482
argument: any --> anyint p_df_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
struct poly_df_data* p_x_data = (struct poly_df_data*) p_x;
struct poly_df_data* p_y_data = (struct poly_df_data*) p_y;
r_ssize n_col = p_x_data->n_col;
if (n_col != p_y_data->n_col) {
r_stop_internal("`x` and `y` must have the same number of columns.");
}
enum vctrs_type* v_col_type = p_x_data->v_col_type;
const void** v_x_col_ptr = p_x_data->v_col_ptr;
const void** v_y_col_ptr = p_y_data->v_col_ptr;
// df-cols should already be flattened
for (r_ssize col = 0; col < n_col; ++col) {
const int cmp = p_col_compare_na_equal(
v_x_col_ptr[col], i,
v_y_col_ptr[col], j,
v_col_type[col]
);
if (cmp != 0) {
return cmp;
}
}
return 0;
}function: ref('I3786) --> 'I3786
argument: any --> anyint p_df_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
struct poly_df_data* p_x_data = (struct poly_df_data*) p_x;
struct poly_df_data* p_y_data = (struct poly_df_data*) p_y;
r_ssize n_col = p_x_data->n_col;
if (n_col != p_y_data->n_col) {
r_stop_internal("`x` and `y` must have the same number of columns.");
}
enum vctrs_type* v_col_type = p_x_data->v_col_type;
const void** v_x_col_ptr = p_x_data->v_col_ptr;
const void** v_y_col_ptr = p_y_data->v_col_ptr;
// df-cols should already be flattened
for (r_ssize col = 0; col < n_col; ++col) {
if (!p_col_equal_na_equal(v_x_col_ptr[col], i, v_y_col_ptr[col], j, v_col_type[col])) {
return false;
}
}
return true;
}function: t(*any \ c_null) --> c_false & t(c(..-1) | c(1..)) --> c_false & t(c_false) --> c_true & t(c_null) --> c_true & t(c_string) --> c_false argument: t(c_bool | c_null | c_void)
bool p_df_is_missing(const void* p_x, r_ssize i) {
struct poly_df_data* p_x_data = (struct poly_df_data*) p_x;
enum vctrs_type* v_col_type = p_x_data->v_col_type;
const void** v_col_ptr = p_x_data->v_col_ptr;
r_ssize n_col = p_x_data->n_col;
// df-cols should already be flattened
for (r_ssize col = 0; col < n_col; ++col) {
if (!p_col_is_missing(v_col_ptr[col], i, v_col_type[col])) {
return false;
}
}
return true;
}name: P_COMPARE_NA_EQUAL
int p_int_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(int, int_compare_na_equal);
}name: P_EQUAL_NA_EQUAL
static inline int p_int_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_EQUAL_NA_EQUAL(int, int_equal_na_equal);
}name: P_IS_MISSING
bool p_int_is_missing(const void* p_x, r_ssize i) {
P_IS_MISSING(int, int_is_missing);
}name: P_COMPARE_NA_EQUAL
int p_lgl_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(int, lgl_compare_na_equal);
}name: P_EQUAL_NA_EQUAL
static inline int p_lgl_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_EQUAL_NA_EQUAL(int, lgl_equal_na_equal);
}name: P_IS_MISSING
bool p_lgl_is_missing(const void* p_x, r_ssize i) {
P_IS_MISSING(int, lgl_is_missing);
}name: P_EQUAL_NA_EQUAL
static inline int p_list_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_EQUAL_NA_EQUAL(SEXP, list_equal_na_equal);
}function: ref('I3093) --> 'I3093
argument: any --> anyinline int p_nil_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
r_stop_internal("Can't compare NULL for equality.");
}function: ref('I15166) --> 'I15166
argument: any --> anybool p_nil_is_missing(const void* p_x, r_ssize i) {
r_stop_internal("Can't check NULL for missingness.");
}name: P_COMPARE_NA_EQUAL
int p_raw_compare_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_COMPARE_NA_EQUAL(Rbyte, raw_compare_na_equal);
}name: P_EQUAL_NA_EQUAL
static inline int p_raw_equal_na_equal(const void* p_x, r_ssize i, const void* p_y, r_ssize j) {
P_EQUAL_NA_EQUAL(Rbyte, raw_equal_na_equal);
}function: ref('I30652) --> 'I30652
argument: any --> anyenum vctrs_expand_vary parse_vary(r_obj* vary) {
if (!r_is_string(vary)) {
r_stop_internal("`vary` must be a string.");
}
const char* c_vary = r_chr_get_c_string(vary, 0);
if (!strcmp(c_vary, "slowest")) return VCTRS_EXPAND_VARY_slowest;
if (!strcmp(c_vary, "fastest")) return VCTRS_EXPAND_VARY_fastest;
r_stop_internal(
"`vary` must be either \"slowest\" or \"fastest\"."
);
}function: ref('I31288) --> 'I31288
argument: any --> anyenum vec_parallel_missing parse_vec_parallel_missing(r_obj* missing, struct r_lazy error_call) {
if (!r_is_scalar_logical(missing)) {
r_abort_lazy_call(error_call, "`.missing` must be `NA`, `FALSE`, or `TRUE`.");
}
const int c_missing = r_lgl_get(missing, 0);
if (c_missing == r_globals.na_lgl) {
return VEC_PARALLEL_MISSING_na;
} else if (c_missing == 0) {
return VEC_PARALLEL_MISSING_false;
} else if (c_missing == 1) {
return VEC_PARALLEL_MISSING_true;
} else {
r_stop_internal("Unexpected `missing` value, %i.", c_missing);
}
}function: t(chr, chr) --> c_bool argument: t(any_sexp, any_sexp)
SEXP posixlt_as_posixlt(SEXP x, SEXP to) {
SEXP x_tzone = PROTECT(tzone_get(x));
SEXP to_tzone = PROTECT(tzone_get(to));
if (tzone_equal(x_tzone, to_tzone)) {
UNPROTECT(2);
return x;
}
SEXP out = x;
// `as.POSIXlt.default()` doesn't respect `tz` so we have to do:
// POSIXlt<x-tzone> -> POSIXct<x-tzone> -> POSIXct<to-tzone> -> POSIXlt<to-tzone>
out = PROTECT(posixlt_as_posixct_impl(out, x_tzone));
out = PROTECT(posixct_as_posixct_impl(out, to_tzone));
out = PROTECT(posixct_as_posixlt_impl(out, to_tzone));
UNPROTECT(5);
return out;
}function: t(dbl) --> *c_double argument: t(any_sexp)
static SEXP posixt_as_date(SEXP ct, SEXP lt, bool* lossy) {
ct = PROTECT(datetime_validate(ct));
const double* p_ct = REAL(ct);
SEXP out = PROTECT(r_as_date(lt));
SEXP roundtrip = PROTECT(date_as_posixct(out, ct));
const double* p_roundtrip = REAL(roundtrip);
const R_len_t size = Rf_length(out);
for (R_len_t i = 0; i < size; ++i) {
const double ct_elt = p_ct[i];
// `NaN` and `NA` always convert without issue
if (isnan(ct_elt)) {
continue;
}
const double roundtrip_elt = p_roundtrip[i];
if (ct_elt != roundtrip_elt) {
*lossy = true;
UNPROTECT(3);
return R_NilValue;
}
}
UNPROTECT(3);
return out;
}name: vec_ptype2
r_obj* ptype2_common(r_obj* current,
r_obj* next,
struct counters* counters,
void* p_data) {
int left = -1;
struct ptype_common_reduce_opts* p_reduce_opts = (struct ptype_common_reduce_opts*) p_data;
current = vec_ptype2(
current,
next,
counters->curr_arg,
counters->next_arg,
p_reduce_opts->call,
p_reduce_opts->s3_fallback,
&left
);
// Update current if RHS is the common type. Otherwise the previous
// counter stays in effect.
if (!left) {
counters_shift(counters);
}
return current;
}function: t(list, c_int, any_sexp) --> () argument: t(any_sexp, any, any_sexp & 'I24758)
r_obj* push_default(
r_obj* xs,
r_obj* default_
) {
const r_ssize xs_size = vec_size(xs);
r_obj* xs_names = KEEP(r_names(xs));
xs = KEEP(r_list_resize(xs, xs_size + 1));
r_list_poke(xs, xs_size, default_);
if (xs_names != r_null) {
xs_names = r_chr_resize(xs_names, xs_size + 1);
r_attrib_poke_names(xs, xs_names);
r_chr_poke(xs_names, xs_size, r_strs.empty);
}
FREE(2);
return xs;
}function: t(list, c_int, any_sexp) --> () argument: t(any_sexp, any, any_sexp & 'I24778)
r_obj* push_default_index(
r_obj* indices,
r_obj* default_index
) {
const r_ssize indices_size = vec_size(indices);
r_obj* indices_names = KEEP(r_names(indices));
indices = KEEP(r_list_resize(indices, indices_size + 1));
r_list_poke(indices, indices_size, default_index);
if (indices_names != r_null) {
indices_names = r_chr_resize(indices_names, indices_size + 1);
r_attrib_poke_names(indices, indices_names);
r_chr_poke(indices_names, indices_size, r_strs.empty);
}
FREE(2);
return indices;
}name: INTMAX_MAX
intmax_t r__intmax_add(intmax_t x, intmax_t y) {
if ((y > 0 && x > (INTMAX_MAX - y)) ||
(y < 0 && x < (INTMAX_MIN - y))) {
r_stop_internal("Values too large to be added.");
}
return x + y;
}name: INTMAX_MIN
intmax_t r__intmax_subtract(intmax_t x, intmax_t y) {
if ((y > 0 && x < (INTMAX_MIN + y)) ||
(y < 0 && x > (INTMAX_MAX + y))) {
r_stop_internal("Subtraction resulted in overflow or underflow.");
}
return x - y;
}name: INTERP
void r_abort(const char* fmt, ...) {
char buf[BUFSIZE];
INTERP(buf, fmt, ...);
r_obj* message = KEEP(r_chr(buf));
// Evaluate in a mask but forward error call to the current frame
r_obj* frame = KEEP(r_peek_frame());
r_obj* mask = KEEP(r_alloc_environment(2, frame));
r_env_bind(mask, r_syms.error_call_flag, frame);
struct r_pair args[] = {
{ r_syms.message, message }
};
r_exec_n(r_null, r_syms.abort, args, R_ARR_SIZEOF(args), mask);
while (1); // No return
}name: INTERP
void r_abort_call(r_obj* call, const char* fmt, ...) {
char buf[BUFSIZE];
INTERP(buf, fmt, ...);
r_obj* message = KEEP(r_chr(buf));
struct r_pair args[] = {
{ r_syms.message, message },
{ r_syms.call, call }
};
r_obj* frame = KEEP(r_peek_frame());
r_exec_mask_n(r_null, r_syms.abort, args, R_ARR_SIZEOF(args), frame);
r_stop_unreachable();
}name: __VA_ARGS__
function: t(*c_void, c_int_na, c_false) | t(*c_void, c_int_na, c_int_na \ c_false) --> ()
argument: t(c_string, c_false, (c_int & c_int_na('I34186)) & 'I34183)r_obj* r_alloc_raw0(r_ssize n) {
r_obj* out = r_alloc_raw(n);
unsigned char* p_out = (unsigned char*) r_raw_begin(out);
r_memset(p_out, 0, n);
return out;
}function: t(list, 'I12047) --> list & t(prim & 'I12048, c_int & c_int_na('I12047)) --> v[^int('I12047)]('I12048)
argument: t((c(0..10) | c(13..25) | c(30..31) | c(99)) & 'I12043, 'I12044)r_obj* r_alloc_vector(enum r_type type, r_ssize n) {
#if R_VERSION >= R_Version(4, 6, 0)
return R_allocResizableVector(type, n);
#else
return Rf_allocVector(type, n);
#endif
}function: t(^int, c_int_na) --> c_int & t(int, c_int_na) --> c_int_na
argument: t((dbl & vec[^int('I31334)] & vec[^int('I31355)]) & 'I31322, c_false)r_ssize r_arg_as_ssize(r_obj* n, const char* arg) {
switch (r_typeof(n)) {
case R_TYPE_double: {
if (r_length(n) != 1) {
goto invalid;
}
double out = r_dbl_get(n, 0);
if (out > R_SSIZE_MAX) {
r_abort("`%s` is too large a number.", arg);
}
if (out != (int_least64_t) out) {
r_abort("`%s` must be a whole number, not a decimal number.", arg);
}
return (r_ssize) floor(out);
}
case R_TYPE_integer: {
if (r_length(n) != 1) {
goto invalid;
}
return (r_ssize) r_int_get(n, 0);
}
invalid:
default:
r_abort("`%s` must be a scalar integer or double.", arg);
}
}function: t(any_sexp) --> any_sexp argument: t(any_sexp & 'I35185, c_false, c_false)
static inline SEXP r_as_not_s4(SEXP x) {
// - Return value must be used, unlike `UNSET_S4_OBJECT()`
// - `Rf_asS4()` calls `shallow_duplicate(x)` if `MAYBE_SHARED(x)`
// - `flag = 0` goes through `UNSET_S4_OBJECT()`
// - `complete` is for S4 objects that wrap a "complete" S3 object by placing
// it in the `.Data` slot. If you set `complete = 1`, it will unwrap and
// return that, which we don't want. If `complete = 0`, no additional
// behavior will happen beyond the `UNSET_S4_OBJECT()` call.
const Rboolean flag = 0;
const int complete = 0;
return Rf_asS4(x, flag, complete);
}function: t(any_sexp, *t(any_sexp, any_sexp, *c_void) --> any_sexp, *c_void) --> any_sexp
argument: t(any_sexp & 'I375, *(t(any_sexp, any_sexp & 'I386, *c_void) -> c_null | 'I386 & (c_null | null | p(chr) | sym | attr_any)), *('I376 \ c_string))r_obj* r_attrib_get(r_obj* x, r_obj* tag) {
r_obj* out = r_attrib_map(x, &r_attrib_get_cb, &tag);
return out ? out : r_null;
}function: t(env, sym) --> any_sexp argument: t(any_sexp, sym)
r_obj* r_base_ns_get(const char* name) {
return r_env_get(r_envs.base, r_sym(name));
}function: t(any_sexp, lang | null) --> lang argument: t(any_sexp & 'I645, any_sexp)
SEXP r_call_n(SEXP fn, SEXP* tags, SEXP* cars) {
return Rf_lcons(fn, _r_pairlist(tags, cars));
}function: ref('I36493) --> 'I36493
argument: any --> anySEXP r_chr_iota(R_len_t n, char* buf, int len, const char* prefix) {
int prefix_len = strlen(prefix);
if (len - 1 < prefix_len) {
r_stop_internal("Prefix is larger than iota buffer.");
}
r_memcpy(buf, prefix, prefix_len);
len -= prefix_len;
char* beg = buf + prefix_len;
SEXP out = PROTECT(Rf_allocVector(STRSXP, n));
for (R_len_t i = 0; i < n; ++i) {
int written = snprintf(beg, len, "%d", i + 1);
if (written >= len) {
UNPROTECT(1);
return R_NilValue;
}
SET_STRING_ELT(out, i, Rf_mkChar(buf));
}
UNPROTECT(1);
return out;
}function: t(*c_void, *c_void, c(..-1) | c(1..)) | t(*c_void, *c_void, c_false) --> () argument: t(c_string, c_string & 'I37190, c_int)
r_obj* r_chr_paste_prefix(r_obj* names, const char* prefix, const char* sep) {
int n_prot = 0;
names = KEEP_N(r_clone(names), &n_prot);
r_ssize n = r_length(names);
int outer_len = strlen(prefix);
int names_len = r_chr_max_len(names);
int sep_len = strlen(sep);
int total_len = outer_len + names_len + sep_len + 1;
char* buf = vctrs_paste_buffer;
if (total_len > VCTRS_PASTE_BUFFER_MAX_SIZE) {
r_obj* buf_box = KEEP_N(
r_alloc_raw(total_len * sizeof(char)),
&n_prot
);
buf = (char*) RAW(buf_box);
}
buf[total_len - 1] = '\0';
char* bufp = buf;
r_memcpy(bufp, prefix, outer_len); bufp += outer_len;
for (int i = 0; i < sep_len; ++i) {
*bufp++ = sep[i];
}
r_obj* const* p_names = r_chr_cbegin(names);
for (r_ssize i = 0; i < n; ++i) {
const char* inner = r_str_c_string(p_names[i]);
int inner_n = strlen(inner);
r_memcpy(bufp, inner, inner_n);
bufp[inner_n] = '\0';
r_chr_poke(names, i, r_str(buf));
}
FREE(n_prot);
return names;
}name: RESIZE_BARRIER
r_obj* r_chr_resize(r_obj* x, r_ssize new_size) {
RESIZE_BARRIER(R_TYPE_character, r_chr_cbegin, r_chr_poke);
}name: RESIZE
r_obj* r_cpl_resize(r_obj* x, r_ssize new_size) {
RESIZE(R_TYPE_complex, r_complex, r_cpl_cbegin, r_cpl_begin);
}name: RESIZE
r_obj* r_dbl_resize(r_obj* x, r_ssize new_size) {
RESIZE(R_TYPE_double, double, r_dbl_cbegin, r_dbl_begin);
}function: any argument: t(any_sexp & 'I48, any_sexp & 'I49)
bool r_env_has(r_obj* env, r_obj* sym) {
#if RLANG_USE_R_EXISTS
bool r__env_has(r_obj*, r_obj*);
return r__env_has(env, sym);
#else
return R_existsVarInFrame(env, sym);
#endif
}function: t(env, sym, any_sexp) --> () argument: t(env, any_sexp, any_sexp & 'I20549)
r_obj* r_eval_with_x(r_obj* call, r_obj* x, r_obj* parent) {
r_obj* env = KEEP(r_alloc_environment(1, parent));
r_env_bind(env, r_syms.x, x);
r_obj* out = r_eval(call, env);
FREE(1);
return out;
}function: t(env, sym, any_sexp) --> () argument: t(env, any_sexp, any_sexp & 'I23885)
r_obj* r_eval_with_xyz(r_obj* call, r_obj* x, r_obj* y, r_obj* z, r_obj* parent) {
r_obj* env = KEEP(r_alloc_environment(3, parent));
r_env_bind(env, r_syms.x, x);
r_env_bind(env, r_syms.y, y);
r_env_bind(env, r_syms.z, z);
r_obj* out = r_eval(call, env);
FREE(1);
return out;
}function: t(lang) --> any_sexp argument: t(p(chr) | sym | attr_any | 'I204 \ null)
r_obj* r_exec_mask_n_call_poke(r_obj* fn_sym,
r_obj* fn,
const struct r_pair* args,
int n,
r_obj* env) {
if (fn_sym != r_null) {
r_env_bind(env, fn_sym, fn);
fn = fn_sym;
}
r_obj* list = KEEP(r_new_pairlist(args, n, NULL));
r_obj* node = list;
while (node != r_null) {
r_obj* car = r_node_car(node);
r_obj* tag = r_node_tag(node);
if (tag == r_null) {
// If symbol is not supplied, protect symbolic arguments from
// evaluation. If supplied this is not needed because of the
// masking.
r_node_poke_car(node, r_expr_protect(car));
} else {
// If symbol is supplied, assign the value in the environment and
// use the symbol instead of the value in the list of arguments
r_env_bind(env, tag, car);
r_node_poke_car(node, tag);
}
node = r_node_cdr(node);
}
r_obj* call = r_new_call(fn, list);
FREE(1);
return call;
}function: t(c_false, c_false) --> c_false & t(c_false, c_true) | t(c_true, c_false) | t(c_true, c_true) --> c_true argument: t(c_string, c_string)
r_obj* r_init_library(r_obj* ns) {
if (!R_IsNamespaceEnv(ns)) {
Rf_errorcall(r_null,
"Can't initialise rlang library.\n"
"x `ns` must be a namespace environment.");
}
// Local precious lists are disabled by default because rchk
// requires the base precious list and we don't want to
// double-preserve. Still enable it on CI to get that part of the
// code tested.
_r_use_local_precious_list =
getenv("RLIB_USE_LOCAL_PRECIOUS_LIST") ||
getenv("CI");
// Need to be first
r_init_library_vendor(); // Needed for xxh used in `r_preserve()`
r_init_library_globals_syms();
r_init_library_obj(ns);
r_init_library_globals(ns);
shared_x_env = r_parse_eval("new.env(hash = FALSE, parent = baseenv(), size = 1L)", r_envs.base);
r_preserve(shared_x_env);
shared_xy_env = r_parse_eval("new.env(hash = FALSE, parent = baseenv(), size = 1L)", r_envs.base);
r_preserve(shared_xy_env);
shared_xyz_env = r_parse_eval("new.env(hash = FALSE, parent = baseenv(), size = 1L)", r_envs.base);
r_preserve(shared_xyz_env);
r_init_library_sym();
r_init_library_eval();
r_init_library_env();
r_init_rlang_ns_env();
r_init_library_arg();
r_init_library_call();
r_init_library_cnd();
r_init_library_dyn_array();
r_init_library_fn();
r_init_library_quo();
r_init_library_session();
r_init_library_stack();
// Return a SEXP so the init function can be called from R
return r_null;
}function: t(*c_string, c_int & c_int_na('I34373)) --> chr[^int('I34373)]
argument: t(*c("tbl_df"), any)void r_init_library_globals(r_obj* ns) {
r_preserve_global(r_classes.data_frame = r_chr("data.frame"));
const char* v_tibble_class[] = { "tbl_df", "tbl", "data.frame" };
r_preserve_global(r_globals.empty_lgl = r_alloc_logical(0));
r_preserve_global(r_globals.empty_int = r_alloc_integer(0));
r_preserve_global(r_globals.empty_dbl = r_alloc_double(0));
r_preserve_global(r_globals.empty_cpl = r_alloc_complex(0));
r_preserve_global(r_globals.empty_raw = r_alloc_raw(0));
r_preserve_global(r_globals.empty_chr = r_alloc_character(0));
r_preserve_global(r_globals.empty_list = r_alloc_list(0));
r_globals.na_lgl = NA_LOGICAL;
r_globals.na_int = NA_INTEGER;
r_globals.na_dbl = NA_REAL;
r_globals.na_cpl = (r_complex) { .r = NA_REAL, .i = NA_REAL };
r_globals.na_str = NA_STRING;
r_preserve_global(r_chrs.empty_string = r_chr(""));
r_preserve_global(r_chrs.full = r_chr("full"));
r_classes.tibble = r_chr_n(v_tibble_class, R_ARR_SIZEOF(v_tibble_class));
r_preserve_global(r_classes.tibble);
r_strs.dots = r_sym_string(r_syms.dots);
r_strs.condition = r_sym_string(r_syms.condition);
r_strs.empty = r_chr_get(r_chrs.empty_string, 0);
r_strs.error = r_sym_string(r_syms.error);
r_strs.interrupt = r_sym_string(r_syms.interrupt);
r_strs.na = r_globals.na_str;
r_strs.message = r_sym_string(r_syms.message);
r_strs.warning = r_sym_string(r_syms.warning);
r_preserve_global(r_false = r_lgl(0));
r_preserve_global(r_true = r_lgl(1));
r_envs.empty = R_EmptyEnv;
r_envs.base = R_BaseEnv;
r_envs.global = R_GlobalEnv;
r_envs.ns = ns;
}name: R_TripleColonSymbol
void r_init_library_globals_syms(void) {
r_syms.abort = r_sym("abort");
r_syms.arg = r_sym("arg");
r_syms.brace = R_BraceSymbol;
r_syms.brackets = R_BracketSymbol;
r_syms.brackets2 = R_Bracket2Symbol;
r_syms.call = r_sym("call");
r_syms.class_ = R_ClassSymbol;
r_syms.colon2 = R_DoubleColonSymbol;
r_syms.colon3 = R_TripleColonSymbol;
r_syms.condition = r_sym("condition");
r_syms.dots = R_DotsSymbol;
r_syms.error = r_sym("error");
r_syms.error_arg = r_sym("error_arg");
r_syms.error_call = r_sym("error_call");
r_syms.error_call_flag = r_sym(".__error_call__.");
r_syms.expr = r_sym("expr");
r_syms.interrupt = r_sym("interrupt");
r_syms.missing = R_MissingArg;
r_syms.message = r_sym("message");
r_syms.names = R_NamesSymbol;
r_syms.options = r_sym("options");
r_syms.dim = R_DimSymbol;
r_syms.dim_names = R_DimNamesSymbol;
r_syms.row_names = R_RowNamesSymbol;
r_syms.stack_overflow_error = r_sym("stackOverflowError");
r_syms.warning = r_sym("warning");
r_syms.dot_environment = r_sym(".Environment");
r_syms.dot_fn = r_sym(".fn");
r_syms.dot_x = r_sym(".x");
r_syms.dot_y = r_sym(".y");
r_syms.function = r_sym("function");
r_syms.srcfile = r_sym("srcfile");
r_syms.srcref = r_sym("srcref");
r_syms.tilde = r_sym("~");
r_syms.w = r_sym("w");
r_syms.wholeSrcref = r_sym("wholeSrcref");
r_syms.x = r_sym("x");
r_syms.y = r_sym("y");
r_syms.z = r_sym("z");
}name: RESIZE
r_obj* r_int_resize(r_obj* x, r_ssize new_size) {
RESIZE(R_TYPE_integer, int, r_int_cbegin, r_int_begin);
}function: t(c_true, c_true) --> c_true & t(c_false, c_false) | t(c_false, c_true) | t(c_true, c_false) --> c_false argument: t(c_bool, c_int)
bool r_is_true(r_obj* x) {
return r_is_bool(x) && r_lgl_get(x, 0);
}function: t(*any \ c_null) --> c_false & t(c(..-1) | c(1..)) --> c_false & t(c_false) --> c_true & t(c_null) --> c_true & t(c_string) --> c_false argument: t(any_sexp & 'I902)
r_obj* r_lazy_eval(struct r_lazy lazy) {
if (!lazy.env) {
// Unitialised lazy variable
return r_null;
} else if (lazy.env == r_null) {
// Forced lazy variable
return lazy.x;
} else {
return r_eval(lazy.x, lazy.env);
}
}function: t('I5018 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym)) --> lang | 'I5018 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym)
argument: t(any_sexp)r_obj* r_lazy_eval_protect(struct r_lazy lazy) {
r_obj* out = KEEP(r_lazy_eval(lazy));
out = r_expr_protect(out);
FREE(1);
return out;
}function: t(*any \ c_null) --> c_false & t(c(..-1) | c(1..)) --> c_false & t(c_false) --> c_true & t(c_null) --> c_true & t(c_string) --> c_false argument: t(any_sexp & 'I38474)
bool r_lazy_is_null(struct r_lazy call) {
return !call.x && !call.env;
}function: t(c_int & c_int_na('I31302)) --> v1(^int('I31302)) & t(c_int_na \ c_int) --> v1(int \ ^int)
argument: t('I31292 & c_double)r_obj* r_len(r_ssize x) {
if (x > INT_MAX) {
return r_dbl(x);
} else {
return r_int(x);
}
}name: RESIZE
r_obj* r_lgl_resize(r_obj* x, r_ssize new_size) {
RESIZE(R_TYPE_logical, int, r_lgl_cbegin, r_lgl_begin);
}function: ref('I20708) --> 'I20708
argument: any --> anyr_obj* r_lgl_which(r_obj* x, bool na_propagate) {
const enum r_type type = r_typeof(x);
if (type != R_TYPE_logical) {
r_stop_unexpected_type(type);
}
const r_ssize n = r_length(x);
const int* v_x = r_lgl_cbegin(x);
const r_ssize out_n = r_lgl_sum(x, na_propagate);
if (out_n > INT_MAX) {
r_stop_internal("Can't fit result in an integer vector.");
}
r_obj* out = KEEP(r_alloc_integer(out_n));
int* v_out = r_int_begin(out);
r_obj* names = r_names(x);
const bool has_names = (names != r_null);
if (na_propagate) {
if (has_names) {
// Mark `NA` locations with negative location for extracting names later
for (r_ssize i = 0, j = 0; i < n && j < out_n; ++i) {
const int x_elt = v_x[i];
const bool missing = x_elt == r_globals.na_lgl;
const int elt = missing * (-i - 1) + !missing * x_elt * (i + 1);
v_out[j] = elt;
j += (bool) elt;
}
} else {
for (r_ssize i = 0, j = 0; i < n && j < out_n; ++i) {
const int x_elt = v_x[i];
const bool missing = x_elt == r_globals.na_lgl;
const int elt = missing * r_globals.na_int + !missing * x_elt * (i + 1);
v_out[j] = elt;
j += (bool) elt;
}
}
} else {
for (r_ssize i = 0, j = 0; i < n && j < out_n; ++i) {
const int x_elt = v_x[i];
v_out[j] = i + 1;
j += (x_elt == 1);
}
}
if (has_names) {
r_obj* const* v_names = r_chr_cbegin(names);
r_obj* out_names = r_alloc_character(out_n);
r_attrib_poke_names(out, out_names);
if (na_propagate) {
// `v_out` contains negative locations which tells you the location of the
// name to extract while also serving as a signal of where `NA`s should go
// in the finalized output
for (r_ssize i = 0; i < out_n; ++i) {
const int loc = v_out[i];
const int abs_loc = abs(loc);
const bool same = (loc == abs_loc);
v_out[i] = same * loc + !same * r_globals.na_int;
r_chr_poke(out_names, i, v_names[abs_loc - 1]);
}
} else {
// `v_out` doesn't contain `NA`, so we can use the locations directly
for (r_ssize i = 0; i < out_n; ++i) {
const int loc = v_out[i] - 1;
r_chr_poke(out_names, i, v_names[loc]);
}
}
}
FREE(1);
return out;
}name: RESIZE_BARRIER
r_obj* r_list_resize(r_obj* x, r_ssize new_size) {
RESIZE_BARRIER(R_TYPE_list, r_list_cbegin, r_list_poke);
}function: t(raw) --> *c_int argument: t(any_sexp)
struct r_dict* r_new_dict(r_ssize size) {
if (size <= 0) {
r_abort("`size` of dictionary must be positive.");
}
size = size_round_power_2(size);
r_obj* shelter = KEEP(r_alloc_list(2));
r_obj* dict_raw = r_alloc_raw0(sizeof(struct r_dict));
r_list_poke(shelter, 0, dict_raw);
struct r_dict* p_dict = r_raw_begin(dict_raw);
p_dict->shelter = shelter;
p_dict->buckets = r_alloc_list(size);
r_list_poke(shelter, 1, p_dict->buckets);
p_dict->p_buckets = r_list_cbegin(p_dict->buckets);
p_dict->n_buckets = size;
r_attrib_poke(shelter, r_syms.class_, r_chr("rlang_dict"));
FREE(1);
return p_dict;
}function: t(c_true, c_true) --> c_true & t(c_false, c_false) | t(c_false, c_true) | t(c_true, c_false) --> c_false argument: t(c_int_na & 'I123, *any_sexp & 'I124)
r_obj* r_new_pairlist(const struct r_pair* args,
int n,
r_obj** tail) {
r_obj* shelter = KEEP(r_new_node(R_NilValue, R_NilValue));
r_obj* node = shelter;
for (int i = 0; i < n; ++i) {
struct r_pair arg = args[i];
r_obj* tag = arg.x;
r_obj* car = arg.y;
r_obj* cdr = r_new_node(car, r_null);
r_node_poke_tag(cdr, tag);
r_node_poke_cdr(node, cdr);
node = cdr;
}
if (n && tail) {
*tail = node;
}
FREE(1);
return r_node_cdr(shelter);
}name: FILL
void r_p_int_fill(int* p_x, int value, R_len_t n) {
FILL();
}name: FILL
void r_p_lgl_fill(int* p_x, int value, R_len_t n) {
FILL();
}function: t(any_sexp) --> c_void argument: t(())
function: t(any_sexp) --> c_void argument: t(())
name: RESIZE
r_obj* r_raw_resize(r_obj* x, r_ssize new_size) {
RESIZE(R_TYPE_raw, unsigned char, r_raw_cbegin, r_raw_begin);
}function: ref('I25373) --> 'I25373
argument: any --> anySEXP r_seq(R_len_t from, R_len_t to) {
R_len_t n = to - from;
if (n < 0) {
r_stop_internal("Negative length.");
}
SEXP seq = PROTECT(Rf_allocVector(INTSXP, n));
r_int_fill_seq(seq, from, n);
UNPROTECT(1);
return seq;
}function: ref('I37060) --> 'I37060
argument: any --> anyr_ssize r_ssize_add(r_ssize x, r_ssize y) {
intmax_t out = r__intmax_add(x, y);
if (out > R_SSIZE_MAX) {
r_stop_internal("Result too large for an `r_ssize`.");
}
return (r_ssize) out;
}function: ref('I30945) --> 'I30945
argument: any --> anyint r_ssize_as_integer(r_ssize x) {
if (x > INT_MAX || x < INT_MIN) {
r_stop_internal("Result can't be represented as `int`.");
}
return (int) x;
}name: __VA_ARGS__
function: ref('I20613) --> 'I20613
argument: any --> anyfunction: ref('I2071) --> 'I2071
argument: any --> anyfunction: ref('I57) --> 'I57
argument: any --> anyfunction: t(p(^chr('I5849))) --> c_string('I5849) & t(na_string) --> c("NA")
argument: t(sym)const char* r_type_as_c_string(enum r_type type) {
return CHAR(Rf_type2str(type));
}function: t(c(0..9) | c(17..18) | c(20..23) | c(30..31) | c(25) | c(99), any_sexp) --> any & t(c(14), dbl) --> *c_double & t(c(15), clx) --> *any & t(c(16), chr) --> *p(chr) & t(c(19), list) --> *any_sexp & t(c(24), raw) --> *c_void & t(c(10), lgl) | t(c(13), int) --> *c_int_na argument: t(c(0..10) | c(13..25) | c(30..31) | c(99), 'I2202 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym))
const void* r_vec_cbegin(r_obj* x) {
return r_vec_cbegin0(r_typeof(x), x);
}name: ASSIGN
r_obj* raw_assign(
r_obj* x,
r_obj* index,
r_obj* value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN(Rbyte, RAW, RAW_RO);
}name: ASSIGN_SHAPED
static inline SEXP raw_assign_shaped(
SEXP proxy,
SEXP index,
SEXP value,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
ASSIGN_SHAPED(Rbyte, RAW, RAW_RO);
}name: VEC_COL_DETECT_RUN_BOUNDS_BOOL
void raw_col_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_COL_DETECT_RUN_BOUNDS_BOOL(Rbyte, r_raw_cbegin, raw_equal_na_equal);
}function: ref('I35282) --> 'I35282
argument: any --> anyint raw_compare_na_equal(Rbyte x, Rbyte y) {
r_stop_internal("Can't compare raw types.");
}name: Rbyte
void raw_detect_run_bounds_bool(r_obj* x, r_ssize size, enum vctrs_run_bound which, bool* v_out) {
VEC_DETECT_RUN_BOUNDS_BOOL(Rbyte, r_raw_cbegin, raw_equal_na_equal);
}name: EQUAL
SEXP raw_equal(SEXP x, SEXP y, R_len_t size, bool x_recycles, bool y_recycles, bool na_equal) {
EQUAL(Rbyte, RAW_RO, raw_equal_na_equal, raw_equal_na_propagate);
}name: HASH
static inline uint32_t raw_hash(r_obj* x) {
HASH(Rbyte, r_raw_cbegin, raw_hash_scalar);
}name: HASH_FILL
static inline void raw_hash_fill_na_equal(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL(Rbyte, r_raw_cbegin, raw_hash_scalar);
}name: HASH_FILL_NA_PROPAGATE
static inline void raw_hash_fill_na_propagate(r_obj* x, r_ssize size, uint32_t* v_out) {
HASH_FILL_NA_PROPAGATE(Rbyte, r_raw_cbegin, raw_hash_scalar, raw_is_missing);
}name: SLICE
r_obj* raw_slice(r_obj* x, r_obj* subscript, enum vctrs_materialize materialize) {
SLICE(R_TYPE_raw, char, (char*) r_raw_begin, (char*) r_raw_cbegin, 0);
}name: SLICE_SHAPED
static SEXP raw_slice_shaped(SEXP x, SEXP index, struct strides_info* p_info) {
SLICE_SHAPED(RAWSXP, Rbyte, RAW, RAW_RO, 0);
}function: t(list) --> *any_sexp
argument: t('I4990 & (p(chr) | vec[^int('I4998)]))r_obj* reduce(
r_obj* current,
struct vctrs_arg* p_current_arg,
struct vctrs_arg* p_parent_arg,
r_obj* rest,
r_obj* (*impl)(r_obj* current, r_obj* next, struct counters* counters, void* data),
void* data
) {
const r_ssize n = r_length(rest);
r_obj* names = KEEP(r_names(rest));
r_obj* const* v_rest = r_list_cbegin(rest);
struct counters* counters = new_counters(
names,
p_current_arg,
p_parent_arg
);
KEEP(counters->shelter);
r_keep_loc current_pi;
KEEP_HERE(current, ¤t_pi);
for (r_ssize i = 0; i < n; ++i) {
r_obj* next = v_rest[i];
current = impl(current, next, counters, data);
KEEP_AT(current, current_pi);
counters_increment(counters);
}
FREE(3);
return current;
}name: vec_slice
static SEXP remove_na_levels(SEXP levels) {
R_len_t size = vec_size(levels);
const SEXP* p_levels = STRING_PTR_RO(levels);
// There might only ever be 1 `NA` level.
// Remove it if it exists.
for (R_len_t i = 0; i < size; ++i) {
if (p_levels[i] == NA_STRING) {
int na_loc = (i + 1) * -1;
SEXP na_loc_obj = PROTECT(r_int(na_loc));
SEXP out = vec_slice(levels, na_loc_obj);
UNPROTECT(1);
return out;
}
}
return levels;
}function: ref('I856) --> 'I856
argument: any --> anyenum rownames_type rownames_type(r_obj* x) {
switch (r_typeof(x)) {
case R_TYPE_character:
return ROWNAMES_TYPE_identifiers;
case R_TYPE_integer:
if (r_length(x) == 2 && r_int_begin(x)[0] == r_globals.na_int) {
return ROWNAMES_TYPE_automatic_compact;
} else {
return ROWNAMES_TYPE_automatic;
}
default:
r_stop_internal("Unexpected type `%s`.", Rf_type2char(r_typeof(x)));
}
}function: t(p(^chr('I19986))) --> c_string('I19986) & t(na_string) --> c("NA")
argument: t(any_sexp)SEXP s3_find_method2(const char* generic,
SEXP x,
SEXP table,
SEXP* method_sym_out) {
SEXP cls = PROTECT(s3_get_class0(x));
SEXP method_sym = s3_paste_method_sym(generic, CHAR(cls));
SEXP method = s3_sym_get_method(method_sym, table);
if (method == R_NilValue) {
*method_sym_out = R_NilValue;
} else {
*method_sym_out = method_sym;
}
UNPROTECT(1);
return method;
}function: t(p(^chr('I19970))) --> c_string('I19970) & t(na_string) --> c("NA")
argument: t(any_sexp)SEXP s3_find_method_xy(const char* generic,
SEXP x,
SEXP y,
SEXP table,
SEXP* method_sym_out) {
SEXP x_class = PROTECT(s3_get_class0(x));
SEXP y_class = PROTECT(s3_get_class0(y));
SEXP method_sym = R_NilValue;
method_sym = s3_paste_method_sym(generic, CHAR(x_class));
method_sym = s3_paste_method_sym(CHAR(PRINTNAME(method_sym)), CHAR(y_class));
SEXP method = s3_sym_get_method(method_sym, table);
if (method == R_NilValue) {
*method_sym_out = R_NilValue;
} else {
*method_sym_out = method_sym;
}
UNPROTECT(2);
return method;
}function: ref('I1400) --> 'I1400
argument: any --> anySEXP s3_get_class(SEXP x) {
SEXP cls = R_NilValue;
if (r_is_object(x)) {
cls = Rf_getAttrib(x, R_ClassSymbol);
}
// This handles unclassed objects as well as gremlins objects where
// `x` passes `r_is_object()`, but the class is NULL
if (cls == R_NilValue) {
cls = s3_bare_class(x);
}
if (!Rf_length(cls)) {
r_stop_internal("Class must have length.");
}
return cls;
}function: t(v(chr & 'I19948), c_int) --> prim & 'I19948 argument: t(any_sexp, c_false)
SEXP s3_get_class0(SEXP x) {
SEXP cls = PROTECT(s3_get_class(x));
SEXP out = STRING_ELT(cls, 0);
UNPROTECT(1);
return out;
}function: ref('I47) --> 'I47
argument: any --> anySEXP s3_paste_method_sym(const char* generic, const char* cls) {
int gen_len = strlen(generic);
int cls_len = strlen(cls);
int dot_len = 1;
if (gen_len + cls_len + dot_len >= sizeof(s3_buf)) {
r_stop_internal("Generic or class name is too long.");
}
char* buf = s3_buf;
r_memcpy(buf, generic, gen_len); buf += gen_len;
*buf = '.'; ++buf;
r_memcpy(buf, cls, cls_len); buf += cls_len;
*buf = '\0';
return Rf_install(s3_buf);
}function: ref('I23094) --> 'I23094
argument: any --> anyr_obj* s3_ptype(r_obj* x,
struct vctrs_arg* x_arg,
struct r_lazy call) {
switch (class_type(x)) {
case VCTRS_CLASS_bare_tibble:
return df_ptype(x, true);
case VCTRS_CLASS_data_frame:
return df_ptype(x, false);
case VCTRS_CLASS_bare_data_frame:
r_stop_internal("Bare data frames should be handled by `vec_ptype()`.");
case VCTRS_CLASS_none:
r_stop_internal("Non-S3 classes should be handled by `vec_ptype()`.");
default:
break;
}
r_obj* method = KEEP(vec_ptype_method(x));
r_obj* out;
if (method == r_null) {
obj_check_vector(x, VCTRS_ALLOW_NULL_no, x_arg, call);
out = vec_slice(x, r_null);
} else {
out = vec_ptype_invoke(x, method);
}
FREE(1);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> c_bool argument: t(any_sexp)
SEXP s3_sym_get_method(SEXP sym, SEXP table) {
// `r_env_get()` errors on missing bindings,
// so we have to check with `r_env_has()`
if (r_env_has(R_GlobalEnv, sym)) {
SEXP method = r_env_get(R_GlobalEnv, sym);
if (r_is_function(method)) {
return method;
}
}
if (r_env_has(table, sym)) {
SEXP method = r_env_get(table, sym);
if (r_is_function(method)) {
return method;
}
}
return R_NilValue;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> c_bool argument: t(any_sexp)
static SEXP s4_get_method(const char* cls, SEXP table) {
SEXP sym = Rf_install(cls);
// `r_env_get()` errors on missing bindings,
// so we have to check with `r_env_has()`
if (r_env_has(table, sym)) {
SEXP method = r_env_get(table, sym);
if (r_is_function(method)) {
return method;
}
}
return R_NilValue;
}function: t('I23978 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym)) --> lang | 'I23978 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym)
argument: t(any_sexp)void stop_assert_size(r_ssize actual,
r_ssize required,
struct vctrs_arg* arg,
struct r_lazy call) {
r_obj* ffi_call = KEEP(r_lazy_eval(call));
ffi_call = KEEP(r_expr_protect(ffi_call));
r_obj* syms[5] = {
syms_actual,
syms_required,
r_syms.arg,
r_syms.call,
NULL
};
r_obj* args[5] = {
KEEP(r_int(actual)),
KEEP(r_int(required)),
KEEP(vctrs_arg(arg)),
ffi_call,
NULL
};
r_obj* stop_call = KEEP(r_call_n(syms_stop_assert_size, syms, args));
r_eval(stop_call, vctrs_ns_env);
never_reached("stop_assert_size");
}function: t(any_sexp, *any_sexp, *any_sexp) --> any_sexp argument: t(sym, *(c_null | sym), *(c_null | null | p(chr) | sym | attr_any))
void stop_incompatible_shape(SEXP x, SEXP y,
R_len_t x_size, R_len_t y_size, int axis,
struct vctrs_arg* p_x_arg, struct vctrs_arg* p_y_arg) {
SEXP syms[8] = {
r_sym("x"),
r_sym("y"),
r_sym("x_size"),
r_sym("y_size"),
r_sym("axis"),
r_sym("x_arg"),
r_sym("y_arg"),
NULL
};
SEXP args[8] = {
PROTECT(r_protect(x)),
PROTECT(r_protect(y)),
PROTECT(r_int(x_size)),
PROTECT(r_int(y_size)),
PROTECT(r_int(axis)),
PROTECT(vctrs_arg(p_x_arg)),
PROTECT(vctrs_arg(p_y_arg)),
NULL
};
SEXP call = PROTECT(r_call_n(r_sym("stop_incompatible_shape"), syms, args));
Rf_eval(call, vctrs_ns_env);
never_reached("stop_incompatible_shape");
}function: t(any_sexp) --> any_sexp argument: t(())
void stop_name_spec_in_fallback(r_obj* xs, struct r_lazy error_call) {
r_obj* common_class = KEEP(r_class(list_first_non_null(xs, NULL)));
const char* class_str = r_chr_get_c_string(common_class, 0);
r_abort_lazy_call(
error_call,
"Can't use a name specification with non-vctrs types.\n"
"vctrs methods must be implemented for class `%s`.\n"
"See <https://vctrs.r-lib.org/articles/s3-vector.html>.",
class_str
);
}function: t('I1003 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym)) --> lang | 'I1003 & ((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym)
argument: t(any_sexp)void stop_scalar_type(r_obj* x,
struct vctrs_arg* arg,
struct r_lazy call) {
r_obj* ffi_call = KEEP(r_lazy_eval(call));
ffi_call = KEEP(r_expr_protect(ffi_call));
r_obj* stop_call = KEEP(r_call4(r_sym("stop_scalar_type"),
KEEP(r_protect(x)),
KEEP(vctrs_arg(arg)),
ffi_call));
r_eval(stop_call, vctrs_ns_env);
r_stop_unreachable();
}function: ref('I3551) --> 'I3551
argument: any --> anyvoid stop_unimplemented_type(const char* fn, SEXPTYPE type) {
r_stop_internal("Unimplemented type `%s`.", Rf_type2char(type));
}function: ref('I1113) --> 'I1113
argument: any --> anyvoid stop_unimplemented_vctrs_type(const char* fn, enum vctrs_type type) {
r_stop_internal("Unsupported vctrs type `%s`.", vec_type_as_str(type));
}function: t(v(chr & 'I16421), c_int) --> prim & 'I16421 argument: t(p(chr) | sym | attr_any, c_false)
static SEXP tzone_get(SEXP x) {
SEXP tzone = PROTECT(Rf_getAttrib(x, syms_tzone));
if (tzone == R_NilValue) {
UNPROTECT(1);
return chrs_empty;
}
R_len_t size = Rf_length(tzone);
if (size == 1) {
UNPROTECT(1);
return tzone;
}
if (size == 0) {
Rf_errorcall(R_NilValue, "Corrupt datetime with 0-length `tzone` attribute");
}
// If there are multiple, only take the first
SEXP out = PROTECT(Rf_allocVector(STRSXP, 1));
SET_STRING_ELT(out, 0, STRING_ELT(tzone, 0));
UNPROTECT(2);
return out;
}function: ref('I2349) --> 'I2349
argument: any --> anyuint32_t u32_safe_ceil2(uint32_t x) {
// Return 2^0 when `x` is 0
x += (x == 0);
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
if (x == 0) {
// INT32_MAX+2 <= x <= UINT32_MAX (i.e. 2^31+1 <= x <= 2^32-1) would attempt
// to ceiling to 2^32, which is 1 greater than `UINT32_MAX`, resulting in
// overflow wraparound to 0.
r_stop_internal("`x` results in an `uint32_t` overflow.");
}
return x;
}function: t(c_int_na, c_int) --> c_int argument: t(any, c(13))
static inline uint32_t uint32_hash(uint32_t x) {
x ^= x >> 16;
x *= 0x85ebca6b;
x ^= x >> 13;
x *= 0xc2b2ae35;
x ^= x >> 16;
return x;
}name: UINT64_C
static inline uint32_t uint64_hash(uint64_t x) {
x ^= x >> 33;
x *= UINT64_C(0xff51afd7ed558ccd);
x ^= x >> 33;
x *= UINT64_C(0xc4ceb9fe1a85ec53);
x ^= x >> 33;
return x;
}function: t(chr, c_bool) --> any_sexp argument: t(any_sexp & 'I36547, c_int)
r_obj* vctrs_as_unique_names(r_obj* names, r_obj* quiet) {
r_obj* out = KEEP(vec_as_unique_names(names, r_lgl_get(quiet, 0)));
FREE(1);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
SEXP vctrs_count(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
SEXP count = PROTECT_N(Rf_allocVector(INTSXP, d->size), &nprot);
int* p_count = INTEGER(count);
// Load dictionary and accumulate `p_count`
vctrs_count_loop(d, n, p_count);
// Create output
SEXP out_loc = PROTECT_N(Rf_allocVector(INTSXP, d->used), &nprot);
int* p_out_loc = INTEGER(out_loc);
// Reuse `count` storage, which will be narrowed
SEXP out_count = count;
int* p_out_count = p_count;
int i = 0;
for (uint32_t hash = 0; hash < d->size; ++hash) {
if (d->key[hash] == DICT_EMPTY) {
continue;
}
p_out_loc[i] = d->key[hash] + 1;
p_out_count[i] = p_count[hash];
i++;
}
out_count = PROTECT_N(r_int_resize(out_count, d->used), &nprot);
SEXP out = PROTECT_N(Rf_allocVector(VECSXP, 2), &nprot);
SET_VECTOR_ELT(out, 0, out_loc);
SET_VECTOR_ELT(out, 1, out_count);
SEXP names = PROTECT_N(Rf_allocVector(STRSXP, 2), &nprot);
SET_STRING_ELT(names, 0, Rf_mkChar("loc"));
SET_STRING_ELT(names, 1, Rf_mkChar("count"));
Rf_setAttrib(out, R_NamesSymbol, names);
init_data_frame(out, d->used);
UNPROTECT(nprot);
return out;
}function: t(c_int & c_int_na('I37008)) --> v1(^int('I37008)) & t(c_int_na \ c_int) --> v1(int \ ^int)
argument: tuple1SEXP vctrs_df_size(SEXP x) {
return r_int(df_raw_size(x));
}function: t(any_sexp, any_sexp, *any_sexp, *any_sexp) --> any_sexp argument: t(any_sexp & 'I726, any_sexp & 'I727, *(c_null | 'I728 \ c_string), *(c_null | 'I729 \ c_string))
SEXP vctrs_dispatch1(SEXP fn_sym, SEXP fn,
SEXP x_sym, SEXP x) {
SEXP syms[2] = { x_sym, NULL };
SEXP args[2] = { x, NULL };
return vctrs_dispatch_n(fn_sym, fn, syms, args);
}function: t(any_sexp, any_sexp, *any_sexp, *any_sexp) --> any_sexp argument: t(any_sexp & 'I5535, any_sexp & 'I5536, *(c_null | 'I5537 \ c_string), *(c_null | 'I5538 \ c_string))
SEXP vctrs_dispatch2(SEXP fn_sym, SEXP fn,
SEXP x_sym, SEXP x,
SEXP y_sym, SEXP y) {
SEXP syms[3] = { x_sym, y_sym, NULL };
SEXP args[3] = { x, y, NULL };
return vctrs_dispatch_n(fn_sym, fn, syms, args);
}function: t(any_sexp, any_sexp, *any_sexp, *any_sexp) --> any_sexp argument: t(any_sexp & 'I6755, any_sexp & 'I6756, *(c_null | 'I6757 \ c_string), *(c_null | 'I6758 \ c_string))
SEXP vctrs_dispatch3(SEXP fn_sym, SEXP fn,
SEXP x_sym, SEXP x,
SEXP y_sym, SEXP y,
SEXP z_sym, SEXP z) {
SEXP syms[4] = { x_sym, y_sym, z_sym, NULL };
SEXP args[4] = { x, y, z, NULL };
return vctrs_dispatch_n(fn_sym, fn, syms, args);
}function: t(any_sexp, any_sexp, *any_sexp, *any_sexp) --> any_sexp argument: t(any_sexp & 'I19996, any_sexp & 'I19997, *(c_null | 'I19998 \ c_string), *(c_null | 'I19999 \ c_string))
r_obj* vctrs_dispatch5(r_obj* fn_sym, r_obj* fn,
r_obj* x1_sym, r_obj* x1,
r_obj* x2_sym, r_obj* x2,
r_obj* x3_sym, r_obj* x3,
r_obj* x4_sym, r_obj* x4,
r_obj* x5_sym, r_obj* x5) {
r_obj* syms[6] = { x1_sym, x2_sym, x3_sym, x4_sym, x5_sym, NULL };
r_obj* args[6] = { x1, x2, x3, x4, x5, NULL };
return vctrs_dispatch_n(fn_sym, fn, syms, args);
}function: t(any_sexp, any_sexp, *any_sexp, *any_sexp) --> any_sexp argument: t(any_sexp & 'I16752, any_sexp & 'I16753, *(c_null | 'I16754 \ c_string), *(c_null | 'I16755 \ c_string))
SEXP vctrs_dispatch6(SEXP fn_sym, SEXP fn,
SEXP x1_sym, SEXP x1,
SEXP x2_sym, SEXP x2,
SEXP x3_sym, SEXP x3,
SEXP x4_sym, SEXP x4,
SEXP x5_sym, SEXP x5,
SEXP x6_sym, SEXP x6) {
SEXP syms[7] = { x1_sym, x2_sym, x3_sym, x4_sym, x5_sym, x6_sym, NULL };
SEXP args[7] = { x1, x2, x3, x4, x5, x6, NULL };
return vctrs_dispatch_n(fn_sym, fn, syms, args);
}function: t(null, any_sexp, *any_sexp, c_null, env) | t(null, any_sexp, *sym, *any_sexp, env) | t(sym, any_sexp, *any_sexp, c_null, env) | t(sym, any_sexp, *sym, *any_sexp, env) --> any argument: t(any_sexp & 'I715, any_sexp & 'I716, *any_sexp & 'I717, *any_sexp & 'I718, any)
SEXP vctrs_dispatch_n(SEXP fn_sym, SEXP fn, SEXP* syms, SEXP* args) {
SEXP mask = PROTECT(r_peek_frame());
SEXP out = vctrs_eval_mask_n_impl(fn_sym, fn, syms, args, mask);
UNPROTECT(1);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
SEXP vctrs_duplicated(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
SEXP out = PROTECT_N(Rf_allocVector(LGLSXP, n), &nprot);
int* p_out = LOGICAL(out);
r_memset(p_out, 0, n * sizeof(int));
uint32_t* p_hashes = (uint32_t*) R_alloc(n, sizeof(uint32_t));
vctrs_duplicated_loop(d, n, p_hashes, p_out);
UNPROTECT(nprot);
return out;
}function: t(any_sexp, *any_sexp, *any_sexp) --> any argument: t(any_sexp & 'I20360, *(c_null | 'I20361 \ c_string), *(c_null | 'I20362 \ c_string))
SEXP vctrs_eval_mask1(SEXP fn,
SEXP x_sym, SEXP x) {
SEXP syms[2] = { x_sym, NULL };
SEXP args[2] = { x, NULL };
return vctrs_eval_mask_n(fn, syms, args);
}function: t(any_sexp, *any_sexp, *any_sexp) --> any argument: t(any_sexp & 'I20566, *(c_null | 'I20567 \ c_string), *(c_null | 'I20568 \ c_string))
SEXP vctrs_eval_mask2(SEXP fn,
SEXP x_sym, SEXP x,
SEXP y_sym, SEXP y) {
SEXP syms[3] = { x_sym, y_sym, NULL };
SEXP args[3] = { x, y, NULL };
return vctrs_eval_mask_n(fn, syms, args);
}function: t(any_sexp, *any_sexp, *any_sexp) --> any argument: t(any_sexp & 'I20944, *(c_null | 'I20945 \ c_string), *(c_null | 'I20946 \ c_string))
SEXP vctrs_eval_mask4(SEXP fn,
SEXP x1_sym, SEXP x1,
SEXP x2_sym, SEXP x2,
SEXP x3_sym, SEXP x3,
SEXP x4_sym, SEXP x4) {
SEXP syms[5] = { x1_sym, x2_sym, x3_sym, x4_sym, NULL };
SEXP args[5] = { x1, x2, x3, x4, NULL };
return vctrs_eval_mask_n(fn, syms, args);
}function: t(any_sexp, *any_sexp, *any_sexp) --> any argument: t(any_sexp & 'I20135, *(c_null | 'I20136 \ c_string), *(c_null | 'I20137 \ c_string))
SEXP vctrs_eval_mask5(SEXP fn,
SEXP x1_sym, SEXP x1,
SEXP x2_sym, SEXP x2,
SEXP x3_sym, SEXP x3,
SEXP x4_sym, SEXP x4,
SEXP x5_sym, SEXP x5) {
SEXP syms[6] = { x1_sym, x2_sym, x3_sym, x4_sym, x5_sym, NULL };
SEXP args[6] = { x1, x2, x3, x4, x5, NULL };
return vctrs_eval_mask_n(fn, syms, args);
}function: t(any_sexp, *any_sexp, *any_sexp) --> any argument: t(any_sexp & 'I21108, *(c_null | 'I21109 \ c_string), *(c_null | 'I21110 \ c_string))
SEXP vctrs_eval_mask6(SEXP fn,
SEXP x1_sym, SEXP x1,
SEXP x2_sym, SEXP x2,
SEXP x3_sym, SEXP x3,
SEXP x4_sym, SEXP x4,
SEXP x5_sym, SEXP x5,
SEXP x6_sym, SEXP x6) {
SEXP syms[7] = { x1_sym, x2_sym, x3_sym, x4_sym, x5_sym, x6_sym, NULL };
SEXP args[7] = { x1, x2, x3, x4, x5, x6, NULL };
return vctrs_eval_mask_n(fn, syms, args);
}function: t(any_sexp, *any_sexp, *any_sexp) --> any argument: t(any_sexp & 'I16187, *(c_null | 'I16188 \ c_string), *(c_null | 'I16189 \ c_string))
SEXP vctrs_eval_mask7(SEXP fn,
SEXP x1_sym, SEXP x1,
SEXP x2_sym, SEXP x2,
SEXP x3_sym, SEXP x3,
SEXP x4_sym, SEXP x4,
SEXP x5_sym, SEXP x5,
SEXP x6_sym, SEXP x6,
SEXP x7_sym, SEXP x7) {
SEXP syms[8] = { x1_sym, x2_sym, x3_sym, x4_sym, x5_sym, x6_sym, x7_sym, NULL };
SEXP args[8] = { x1, x2, x3, x4, x5, x6, x7, NULL };
return vctrs_eval_mask_n(fn, syms, args);
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
SEXP vctrs_group_id(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
SEXP out = PROTECT_N(Rf_allocVector(INTSXP, n), &nprot);
int* p_out = INTEGER(out);
vctrs_group_id_loop(d, n, p_out);
SEXP n_groups = PROTECT_N(Rf_ScalarInteger(d->used), &nprot);
Rf_setAttrib(out, syms_n, n_groups);
UNPROTECT(nprot);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
SEXP vctrs_group_rle(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
SEXP g = PROTECT_N(Rf_allocVector(INTSXP, n), &nprot);
int* p_g = INTEGER(g);
SEXP l = PROTECT_N(Rf_allocVector(INTSXP, n), &nprot);
int* p_l = INTEGER(l);
if (n == 0) {
SEXP out = PROTECT_N(new_group_rle(g, l, 0), &nprot);
UNPROTECT(nprot);
return out;
}
const R_len_t size = vctrs_group_rle_loop(d, n, p_g, p_l);
g = PROTECT_N(Rf_lengthgets(g, size), &nprot);
l = PROTECT_N(Rf_lengthgets(l, size), &nprot);
SEXP out = new_group_rle(g, l, d->used);
UNPROTECT(nprot);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
SEXP vctrs_id(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
SEXP out = PROTECT_N(Rf_allocVector(INTSXP, n), &nprot);
int* p_out = INTEGER(out);
vctrs_id_loop(d, n, p_out);
UNPROTECT(nprot);
return out;
}function: t(any_sexp, any_sexp, c_bool, x1, x1, { x : any_sexp ; env : any_sexp }) --> empty where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(any_sexp & 'I34098, any_sexp & 'I34099, c_int, *x2, *x1, { x : 'I34101 ; env : null }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void } and x2 = { shelter : any_sexp ; parent : *x2 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }SEXP vctrs_in(SEXP needles, SEXP haystack, SEXP na_equal_, SEXP frame) {
struct r_lazy needles_arg_ = { .x = syms.needles_arg, .env = frame };
struct vctrs_arg needles_arg = new_lazy_arg(&needles_arg_);
struct r_lazy haystack_arg_ = { .x = syms.haystack_arg, .env = frame };
struct vctrs_arg haystack_arg = new_lazy_arg(&haystack_arg_);
struct r_lazy call = { .x = frame, .env = r_null };
return vec_in(
needles,
haystack,
r_bool_as_int(na_equal_),
&needles_arg,
&haystack_arg,
call
);
}function: ref('I35139) --> 'I35139
argument: any --> anyr_obj* vctrs_integer64_proxy(r_obj* x) {
if (r_typeof(x) != R_TYPE_double) {
r_stop_internal("`x` must be a double.");
}
if (r_attrib_get(x, R_DimSymbol) != r_null) {
r_stop_internal("`x` should not have a `dim` attribute.");
}
r_ssize size = r_length(x);
// Casting `const double*` to `const long long*` is UB, but we are mimicking
// what bit64 is doing, so if this ever breaks it means that bit64 is broken.
const long long* v_x = (const long long*) r_dbl_cbegin(x);
r_obj* nms = KEEP(r_chr_n(
v_integer64_proxy_df_names_c_strings,
INTEGER64_PROXY_DF_SIZE
));
r_obj* out = KEEP(r_alloc_df_list(
size,
nms,
v_integer64_proxy_df_types,
INTEGER64_PROXY_DF_SIZE
));
r_init_data_frame(out, size);
r_obj* left = r_list_get(out, INTEGER64_PROXY_DF_LOCS_left);
r_obj* right = r_list_get(out, INTEGER64_PROXY_DF_LOCS_right);
double* v_left = r_dbl_begin(left);
double* v_right = r_dbl_begin(right);
for (r_ssize i = 0; i < size; ++i) {
const long long elt = v_x[i];
if (elt == r_na_llong) {
v_left[i] = r_globals.na_dbl;
v_right[i] = r_globals.na_dbl;
continue;
}
const int64_t elt_i64 = (int64_t) elt;
int64_unpack(elt_i64, i, v_left, v_right);
}
FREE(2);
return out;
}function: ref('I35158) --> 'I35158
argument: any --> anyr_obj* vctrs_integer64_restore(r_obj* x) {
if (!is_data_frame(x)) {
r_stop_internal("`x` must be a data frame.");
}
if (r_length(x) != 2) {
r_stop_internal("`x` must have two columns.");
}
r_obj* left = r_list_get(x, INTEGER64_PROXY_DF_LOCS_left);
r_obj* right = r_list_get(x, INTEGER64_PROXY_DF_LOCS_right);
const double* v_left = r_dbl_cbegin(left);
const double* v_right = r_dbl_cbegin(right);
r_ssize size = r_length(left);
r_obj* out = KEEP(r_alloc_double(size));
// See above comment about UB in this cast
long long* v_out = (long long*) r_dbl_begin(out);
r_attrib_poke_class(out, r_chr("integer64"));
for (r_ssize i = 0; i < size; ++i) {
const double left = v_left[i];
const double right = v_right[i];
if (isnan(left)) {
v_out[i] = r_na_llong;
continue;
}
v_out[i] = (long long) int64_pack(left, right);
}
FREE(1);
return out;
}function: t({ 'I32528 }, c_int) --> 'I32528
argument: t(any_sexp & 'I32522, c_int_na)SEXP vctrs_list_get(SEXP x, SEXP index) {
int idx = find_offset(x, index);
return VECTOR_ELT(x, idx);
}function: t({ 'I39616 }, c_int, 'I39615) --> { 'I39616 | 'I39615 } & t(expr, c_int, lang | sym) --> expr
argument: t('I39602, c_int_na, any_sexp & 'I39604)SEXP vctrs_list_set(SEXP x, SEXP index, SEXP value) {
int idx = find_offset(x, index);
SEXP out = PROTECT(Rf_shallow_duplicate(x));
SET_VECTOR_ELT(out, idx, value);
UNPROTECT(1);
return out;
}function: t(any_sexp, any_sexp, c_bool, *x1, *x1, { x : any_sexp ; env : any_sexp }) --> any_sexp where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(any_sexp & 'I33494, any_sexp & 'I33495, c_int, *x2, *x1, { x : any_sexp & 'I33497 ; env : null }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void } and x2 = { shelter : any_sexp ; parent : *x2 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }SEXP vctrs_match(SEXP needles, SEXP haystack, SEXP na_equal,
SEXP frame) {
struct r_lazy call = { .x = frame, .env = r_null };
struct r_lazy needles_arg_ = { .x = syms.needles_arg, .env = frame };
struct vctrs_arg needles_arg = new_lazy_arg(&needles_arg_);
struct r_lazy haystack_arg_ = { .x = syms.haystack_arg, .env = frame };
struct vctrs_arg haystack_arg = new_lazy_arg(&haystack_arg_);
return vec_match_params(needles,
haystack,
r_bool_as_int(na_equal),
&needles_arg,
&haystack_arg,
call);
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
SEXP vctrs_n_distinct(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
vctrs_n_distinct_loop(d, n);
UNPROTECT(nprot);
return Rf_ScalarInteger(d->used);
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
SEXP vctrs_unique_loc(SEXP x) {
int nprot = 0;
R_len_t n = vec_size(x);
x = PROTECT_N(vec_proxy_equal(x), &nprot);
x = PROTECT_N(obj_encode_utf8(x), &nprot);
struct dictionary* d = new_dictionary(x);
PROTECT_DICT(d, &nprot);
struct growable g = new_growable(INTSXP, 256);
PROTECT_GROWABLE(&g, &nprot);
vctrs_unique_loc_loop(d, &g, n);
SEXP out = growable_values(&g);
UNPROTECT(nprot);
return out;
}function: t(vec[^int('I36606)]) --> c_int & c_int_na('I36606) & t(p(chr) | vec[^int('I36606)]) --> c_int
argument: t(any_sexp)r_obj* vec_as_chop_sizes(r_obj* sizes, r_ssize size) {
sizes = KEEP(vec_cast(
sizes,
r_globals.empty_int,
vec_args.sizes,
vec_args.empty,
r_lazy_null
));
const r_ssize n_sizes = r_length(sizes);
const int* v_sizes = r_int_cbegin(sizes);
r_ssize total = 0;
for (r_ssize i = 0; i < n_sizes; ++i) {
const int elt = v_sizes[i];
if (elt == r_globals.na_int) {
r_abort_lazy_call(r_lazy_null, "`sizes` can't contain missing values.");
} else if (elt < 0) {
r_abort_lazy_call(r_lazy_null, "`sizes` can't contain negative sizes.");
} else if (elt > size) {
r_abort_lazy_call(r_lazy_null, "`sizes` can't contain sizes larger than %i.", size);
}
total += elt;
}
if (total != size) {
r_abort_lazy_call(r_lazy_null, "`sizes` must sum to size %i, not size %i.", size, total);
}
FREE(1);
return sizes;
}function: t(env, sym, any_sexp) --> () argument: t(env, sym, ())
r_obj* vec_as_custom_names(r_obj* names, const struct name_repair_opts* opts) {
names = KEEP(ffi_as_minimal_names(names));
// Don't use vctrs dispatch utils because we match argument positionally
r_obj* call = KEEP(r_call2(syms_repair, syms_names));
r_obj* mask = KEEP(r_alloc_empty_environment(R_GlobalEnv));
r_env_bind(mask, syms_repair, opts->fn);
r_env_bind(mask, syms_names, names);
r_obj* out = KEEP(r_eval(call, mask));
vec_validate_minimal_names(out, r_length(names), opts->call);
FREE(4);
return out;
}function: t(p(chr) | vec, c_int_na | c_double) --> () argument: t(list, c_int)
r_obj* vec_as_df_col(r_obj* x, r_obj* outer) {
r_obj* out = KEEP(r_alloc_list(1));
r_list_poke(out, 0, x);
if (outer != strings_empty) {
r_obj* names = KEEP(r_str_as_character(outer));
r_attrib_poke_names(out, names);
FREE(1);
}
init_data_frame(out, r_length(x));
FREE(1);
return out;
}argument: { }r_obj* vec_as_location_ctxt(r_obj* subscript,
r_ssize n,
r_obj* names,
struct vctrs_arg* arg,
struct r_lazy call) {
struct location_opts opts = {
.subscript_opts = {
.subscript_arg = arg,
.call = call
}
};
return vec_as_location_opts(subscript,
n,
names,
&opts);
}function: t(*{ x : any_sexp ; call : { x : any_sexp ; env : any_sexp } ; p_x_arg : x1 ; s3_fallback : c_bool ; to : any_sexp ; p_to_arg : x1 }, *any) --> null where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(*{ x : 'I34928 ; call : 'I34930 ; p_x_arg : 'I34929 ; to : any_sexp }, *c_null)r_ssize vec_as_ssize(r_obj* n,
struct vctrs_arg* p_arg,
struct r_lazy call) {
if (r_is_object(n)) {
struct cast_opts cast_opts = {
.x = n,
.to = r_globals.empty_dbl,
.p_x_arg = p_arg,
.call = call
};
ERR err = NULL;
n = vec_cast_e(&cast_opts, &err);
if (err) {
goto invalid;
}
}
KEEP(n);
switch (r_typeof(n)) {
case R_TYPE_double: {
if (r_length(n) != 1) {
goto invalid;
}
double out = r_dbl_get(n, 0);
if (out == r_globals.na_int) {
goto invalid;
}
if (out != floor(out)) {
r_abort_lazy_call(call,
"%s must be a whole number, not a fractional number.",
vec_arg_format(p_arg));
}
if (out > R_SSIZE_MAX) {
r_abort_lazy_call(call,
"%s is too large a number.",
vec_arg_format(p_arg));
}
FREE(1);
return (r_ssize) out;
}
case R_TYPE_integer: {
if (r_length(n) != 1) {
goto invalid;
}
int out = r_int_get(n, 0);
if (out == r_globals.na_int) {
goto invalid;
}
FREE(1);
return (r_ssize) out;
}
invalid:
default:
r_abort_lazy_call(call,
"%s must be a single number, not %s.",
vec_arg_format(p_arg),
r_obj_type_friendly_length(n));
}
}function: ref('I7286) --> 'I7286
argument: any --> anyr_obj* vec_bare_df_restore(r_obj* x,
r_obj* to,
const struct vec_restore_opts* p_opts) {
if (r_typeof(x) != R_TYPE_list) {
r_stop_internal("Attempt to restore data frame from a %s.",
r_type_as_c_string(r_typeof(x)));
}
int n_prot = 0;
if (!is_data_frame(to)) {
to = KEEP_N(vec_proxy(to), &n_prot);
if (!is_data_frame(to)) {
r_stop_internal("Expected restoration target to have a df proxy.");
}
}
if (p_opts->recursively_proxied) {
r_ssize n_cols = r_length(x);
if (n_cols != r_length(to)) {
r_stop_internal("Shape of `x` doesn't match `to` in recursive df restoration.");
};
r_obj* const * v_x = r_list_cbegin(x);
r_obj* const * v_to = r_list_cbegin(to);
// During restoration, if we have deep ownership over `x` we can
// propagate that ownership to the columns, otherwise we have no
// known ownership over the columns
enum vctrs_ownership col_ownership;
switch (p_opts->ownership) {
case VCTRS_OWNERSHIP_foreign: col_ownership = VCTRS_OWNERSHIP_foreign; break;
case VCTRS_OWNERSHIP_shallow: col_ownership = VCTRS_OWNERSHIP_foreign; break;
case VCTRS_OWNERSHIP_deep: col_ownership = VCTRS_OWNERSHIP_deep; break;
default: r_stop_unreachable();
}
const struct vec_restore_opts col_opts = {
.ownership = col_ownership,
.recursively_proxied = p_opts->recursively_proxied
};
for (r_ssize i = 0; i < n_cols; ++i) {
r_obj* x_restored = vec_restore_opts(v_x[i], v_to[i], &col_opts);
r_list_poke(x, i, x_restored);
}
}
x = KEEP(vec_restore_default(x, to, p_opts->ownership));
if (r_attrib_get(x, r_syms.names) == r_null) {
r_obj* names = KEEP(r_alloc_character(r_length(x)));
r_attrib_poke(x, r_syms.names, names);
FREE(1);
}
r_obj* rownames = KEEP(df_rownames(x));
if (rownames == r_null) {
r_ssize size = df_raw_size(x);
init_compact_rownames(x, size);
} else if (rownames_type(rownames) == ROWNAMES_TYPE_identifiers) {
rownames = KEEP(vec_as_names(rownames, p_unique_repair_silent_opts));
x = vec_proxy_set_names(x, rownames, p_opts->ownership);
FREE(1);
}
FREE(2);
FREE(n_prot);
return x;
}function: t(*{ x : any_sexp ; call : { x : any_sexp ; env : any_sexp } ; p_x_arg : *x1 ; s3_fallback : c_bool ; to : any_sexp ; p_to_arg : *x1 }) --> any_sexp where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(*{ x : 'I20476 ; call : 'I20480 ; p_x_arg : 'I20478 ; to : 'I20477 ; p_to_arg : 'I20479 })r_obj* vec_cast(r_obj* x,
r_obj* to,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_to_arg,
struct r_lazy call) {
struct cast_opts opts = {
.x = x,
.to = to,
.p_x_arg = p_x_arg,
.p_to_arg = p_to_arg,
.call = call
};
return vec_cast_opts(&opts);
}function: t(any_sexp, any_sexp, c_null) --> empty
argument: t(any_sexp & 'I38746, any_sexp & 'I38747, *{ call : 'I38750 ; s3_fallback : 'I38748 ; p_arg : 'I38749 })r_obj* vec_cast_common_params(r_obj* xs,
r_obj* to,
enum s3_fallback s3_fallback,
struct vctrs_arg* p_arg,
struct r_lazy call) {
struct cast_common_opts opts = {
.p_arg = p_arg,
.call = call,
.s3_fallback = s3_fallback
};
return vec_cast_common_opts(xs, to, &opts);
}function: t(sym) --> c_string argument: t(null)
r_obj* vec_cast_dispatch_s3(const struct cast_opts* opts) {
r_obj* x = opts->x;
r_obj* to = opts->to;
r_obj* method_sym = r_null;
r_obj* method = s3_find_method_xy("vec_cast", to, x, vctrs_method_table, &method_sym);
// Compatibility with legacy double dispatch mechanism
if (method == r_null) {
r_obj* to_method_sym = r_null;
r_obj* to_method = KEEP(s3_find_method2("vec_cast",
to,
vctrs_method_table,
&to_method_sym));
if (to_method != r_null) {
// Only `to_method`s contained within a package will
// have an S3 methods table to look in
r_obj* to_table = s3_get_table(r_fn_env(to_method));
if (to_table != r_null) {
const char* to_method_str = r_sym_c_string(to_method_sym);
method = s3_find_method2(
to_method_str,
x,
to_table,
&method_sym
);
}
}
FREE(1);
}
KEEP(method);
if (method == r_null) {
r_obj* out = vec_cast_default_full(x,
to,
opts->p_x_arg,
opts->p_to_arg,
opts->call,
opts->s3_fallback,
true);
FREE(1);
return out;
}
r_obj* r_x_arg = KEEP(vctrs_arg(opts->p_x_arg));
r_obj* r_to_arg = KEEP(vctrs_arg(opts->p_to_arg));
r_obj* out = vec_invoke_coerce_method(method_sym, method,
syms_x, x,
syms_to, to,
syms_x_arg, r_x_arg,
syms_to_arg, r_to_arg,
opts->call,
opts->s3_fallback);
FREE(3);
return out;
}name: vec_cast_opts
r_obj* vec_cast_params(r_obj* x,
r_obj* to,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_to_arg,
struct r_lazy call,
enum s3_fallback s3_fallback) {
const struct cast_opts opts = {
.x = x,
.to = to,
.p_x_arg = p_x_arg,
.p_to_arg = p_to_arg,
.call = call,
.s3_fallback = s3_fallback
};
return vec_cast_opts(&opts);
}function: t(c_int_na, c_int_na, c_null, { x : any_sexp ; env : any_sexp }) --> empty
argument: t(any, 'I24636, *x1 & 'I24638, 'I24639 & { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_ssize vec_check_recyclable(
r_obj* x,
r_ssize size,
enum vctrs_allow_null allow_null,
struct vctrs_arg* p_x_arg,
struct r_lazy call
) {
const r_ssize x_size = vec_size_params(x, p_x_arg, call);
if (x_size == size || x_size == 1) {
return x_size;
}
// It is up to the caller to be prepared to handle this!
if (allow_null_as_bool(allow_null) && x == r_null) {
return 0;
}
stop_recycle_incompatible_size(x_size, size, p_x_arg, call);
}function: t(lgl, c_false) | t(lgl, c_true) --> c_int argument: t(raw & 'I25273, c_bool & 'I25274)
r_ssize vec_condition_subscript_sum(r_obj* x, bool na_true) {
if (is_compact_condition(x)) {
return compact_condition_sum(x);
} else {
return r_lgl_sum(x, na_true);
}
}function: t(v(dbl & 'I5770) & 'I5769) --> v(dbl & 'I5770) & 'I5769 & t(v(int & 'I5770) & 'I5769) --> p(dbl) argument: t(any_sexp)
SEXP vec_date_restore(SEXP x, SEXP to, const enum vctrs_ownership ownership) {
SEXP out = PROTECT(vec_restore_default(x, to, ownership));
out = date_validate(out);
UNPROTECT(1);
return out;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> c_false argument: t(any_sexp)
int vec_decreasing_expansion(SEXP x) {
// Bare vectors
if (!r_is_object(x) && !has_dim(x)) {
return 1;
}
// Compute number of cols in df-cols,
// and do proxy-compare on the cols as needed
if (is_data_frame(x)) {
return df_decreasing_expansion(x);
}
int expansion;
// Otherwise we have an S3 column that could have a data frame
// ordering proxy containing multiple columns, so we need to check for that
SEXP proxy = PROTECT(vec_proxy_order(x));
// If the `proxy` is a data frame, the expansion factor is the
// number of columns. Otherwise it is 1.
if (is_data_frame(proxy)) {
expansion = Rf_length(proxy);
} else {
expansion = 1;
}
UNPROTECT(1);
return expansion;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> any argument: t(any_sexp)
SEXP vec_detect_complete(SEXP x) {
SEXP proxy = PROTECT(vec_proxy_equal(x));
R_len_t size = vec_size(proxy);
SEXP out = PROTECT(r_new_logical(size));
int* p_out = LOGICAL(out);
// Initialize assuming fully complete
for (R_len_t i = 0; i < size; ++i) {
p_out[i] = 1;
}
vec_detect_complete_switch(proxy, size, p_out);
UNPROTECT(2);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any argument: t(any_sexp)
r_obj* vec_detect_missing(r_obj* x) {
r_obj* proxy = KEEP(vec_proxy_equal(x));
r_obj* out = proxy_detect_missing(proxy);
FREE(1);
return out;
}function: t(c_int & c_int_na('I38445)) --> lgl[^int('I38445)]
argument: tuple1r_obj* vec_detect_run_bounds(r_obj* x, enum vctrs_run_bound which, struct r_lazy error_call) {
struct r_vector_bool* p_where = vec_detect_run_bounds_bool(x, which, error_call);
KEEP(p_where->shelter);
const bool* v_where = r_vector_bool_cbegin(p_where);
const r_ssize size = r_vector_bool_length(p_where);
r_obj* out = KEEP(r_alloc_logical(size));
int* v_out = r_lgl_begin(out);
for (r_ssize i = 0; i < size; ++i) {
v_out[i] = v_where[i];
}
FREE(2);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
struct r_vector_bool* vec_detect_run_bounds_bool(r_obj* x,
enum vctrs_run_bound which,
struct r_lazy error_call) {
obj_check_vector(x, VCTRS_ALLOW_NULL_no, vec_args.x, error_call);
r_obj* proxy = KEEP(vec_proxy_equal(x));
proxy = KEEP(obj_encode_utf8(proxy));
const r_ssize size = vec_size(proxy);
struct r_vector_bool* p_out = r_new_vector_bool(size);
KEEP(p_out->shelter);
bool* v_out = r_vector_bool_begin(p_out);
const enum vctrs_type type = vec_proxy_typeof(proxy);
switch (type) {
case VCTRS_TYPE_logical: lgl_detect_run_bounds_bool(proxy, size, which, v_out); break;
case VCTRS_TYPE_integer: int_detect_run_bounds_bool(proxy, size, which, v_out); break;
case VCTRS_TYPE_double: dbl_detect_run_bounds_bool(proxy, size, which, v_out); break;
case VCTRS_TYPE_complex: cpl_detect_run_bounds_bool(proxy, size, which, v_out); break;
case VCTRS_TYPE_character: chr_detect_run_bounds_bool(proxy, size, which, v_out); break;
case VCTRS_TYPE_raw: raw_detect_run_bounds_bool(proxy, size, which, v_out); break;
case VCTRS_TYPE_list: list_detect_run_bounds_bool(proxy, size, which, v_out); break;
case VCTRS_TYPE_dataframe: df_detect_run_bounds_bool(proxy, size, which, v_out); break;
default: stop_unimplemented_vctrs_type("vec_detect_run_bounds_bool", type);
}
FREE(3);
return p_out;
}function: t(v(chr & 'I39108), c_int) --> 'I39108 argument: t(any_sexp, c_false)
SEXP vec_equal(
SEXP x,
SEXP y,
bool na_equal,
SEXP ptype,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy error_call
) {
SEXP args = PROTECT(r_alloc_list(2));
r_list_poke(args, 0, x);
r_list_poke(args, 1, y);
SEXP names = r_alloc_character(2);
r_attrib_poke_names(args, names);
SEXP x_name = PROTECT(vctrs_arg(p_x_arg));
SEXP y_name = PROTECT(vctrs_arg(p_y_arg));
r_chr_poke(names, 0, r_chr_get(x_name, 0));
r_chr_poke(names, 1, r_chr_get(y_name, 0));
args = PROTECT(vec_cast_common(args, ptype, vec_args.empty, error_call));
const R_len_t size = vec_size_common(args, -1, vec_args.empty, error_call);
x = r_list_get(args, 0);
y = r_list_get(args, 1);
const bool x_recycles = vec_size(x) == 1;
const bool y_recycles = vec_size(y) == 1;
SEXP x_proxy = PROTECT(vec_proxy_equal(x));
SEXP y_proxy = PROTECT(vec_proxy_equal(y));
x_proxy = PROTECT(obj_encode_utf8(x_proxy));
y_proxy = PROTECT(obj_encode_utf8(y_proxy));
enum vctrs_type type = vec_proxy_typeof(x_proxy);
SEXP out;
switch (type) {
case VCTRS_TYPE_logical: out = lgl_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_integer: out = int_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_double: out = dbl_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_complex: out = cpl_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_character: out = chr_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_raw: out = raw_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_list: out = list_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_dataframe: out = df_equal(x_proxy, y_proxy, size, x_recycles, y_recycles, na_equal); break;
case VCTRS_TYPE_scalar: r_abort_lazy_call(error_call, "Can't compare scalars with `vec_equal()`.");
default: stop_unimplemented_vctrs_type("vec_equal", type);
}
UNPROTECT(8);
return out;
}name: EQUAL_COL
void vec_equal_col_na_equal(
SEXP x,
SEXP y,
bool x_recycles,
bool y_recycles,
int* p_out,
struct df_short_circuit_info* p_info
) {
switch (vec_proxy_typeof(x)) {
case VCTRS_TYPE_logical: EQUAL_COL(int, LOGICAL_RO, lgl_equal_na_equal); break;
case VCTRS_TYPE_integer: EQUAL_COL(int, INTEGER_RO, int_equal_na_equal); break;
case VCTRS_TYPE_double: EQUAL_COL(double, REAL_RO, dbl_equal_na_equal); break;
case VCTRS_TYPE_complex: EQUAL_COL(Rcomplex, COMPLEX_RO, cpl_equal_na_equal); break;
case VCTRS_TYPE_character: EQUAL_COL(SEXP, STRING_PTR_RO, chr_equal_na_equal); break;
case VCTRS_TYPE_raw: EQUAL_COL(Rbyte, RAW_RO, raw_equal_na_equal); break;
case VCTRS_TYPE_list: EQUAL_COL(SEXP, VECTOR_PTR_RO, list_equal_na_equal); break;
case VCTRS_TYPE_dataframe: r_stop_internal("Data frame columns should be flattened already.");
case VCTRS_TYPE_scalar: Rf_errorcall(R_NilValue, "Can't compare scalars with `vec_equal()`.");
default: stop_unimplemented_vctrs_type("vec_equal", vec_proxy_typeof(x));
}
}name: EQUAL_COL
void vec_equal_col_na_propagate(
SEXP x,
SEXP y,
bool x_recycles,
bool y_recycles,
int* p_out,
struct df_short_circuit_info* p_info
) {
switch (vec_proxy_typeof(x)) {
case VCTRS_TYPE_logical: EQUAL_COL(int, LOGICAL_RO, lgl_equal_na_propagate); break;
case VCTRS_TYPE_integer: EQUAL_COL(int, INTEGER_RO, int_equal_na_propagate); break;
case VCTRS_TYPE_double: EQUAL_COL(double, REAL_RO, dbl_equal_na_propagate); break;
case VCTRS_TYPE_complex: EQUAL_COL(Rcomplex, COMPLEX_RO, cpl_equal_na_propagate); break;
case VCTRS_TYPE_character: EQUAL_COL(SEXP, STRING_PTR_RO, chr_equal_na_propagate); break;
case VCTRS_TYPE_raw: EQUAL_COL(Rbyte, RAW_RO, raw_equal_na_propagate); break;
case VCTRS_TYPE_list: EQUAL_COL(SEXP, VECTOR_PTR_RO, list_equal_na_propagate); break;
case VCTRS_TYPE_dataframe: r_stop_internal("Data frame columns should be flattened already.");
case VCTRS_TYPE_scalar: Rf_errorcall(R_NilValue, "Can't compare scalars with `vec_equal()`.");
default: stop_unimplemented_vctrs_type("vec_equal", vec_proxy_typeof(x));
}
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, c_null, { x : any_sexp ; env : any_sexp }) --> ()
argument: t(any_sexp & 'I31135, *x1, 'I31138 & { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* vec_expand_grid(r_obj* xs,
enum vctrs_expand_vary vary,
const struct name_repair_opts* p_name_repair_opts,
struct r_lazy error_call) {
obj_check_list(xs, vec_args.empty, error_call);
if (vec_any_missing(xs)) {
// Drop `NULL`s before any other checks
r_obj* complete = KEEP(vec_detect_complete(xs));
xs = vec_slice(xs, complete);
FREE(1);
}
KEEP(xs);
const r_ssize n = r_length(xs);
r_obj* out = KEEP(r_alloc_list(n));
r_obj* names = KEEP(vec_names2(xs));
if (!r_is_minimal_names(names)) {
r_abort_lazy_call(error_call, "All inputs must be named.");
}
names = vec_as_names(names, p_name_repair_opts);
r_attrib_poke_names(out, names);
r_obj* sizes = KEEP(list_sizes(xs, vec_args.empty, error_call));
const int* v_sizes = r_int_cbegin(sizes);
r_obj* cumulative = KEEP(r_alloc_raw(n * sizeof(r_ssize)));
r_ssize* v_cumulative = r_raw_begin(cumulative);
r_ssize size = 1;
for (r_ssize i = 0; i < n; ++i) {
size = r_ssize_mult(size, v_sizes[i]);
v_cumulative[i] = size;
}
// TODO: Support long vectors here
if (size > R_LEN_T_MAX) {
r_abort_lazy_call(
error_call,
"Long vectors are not yet supported. "
"Expansion results in an allocation larger than 2^31-1 elements. "
"Attempted allocation size was %.0lf.",
(double) size
);
}
r_obj* const* v_xs = r_list_cbegin(xs);
r_obj* ffi_times_each = KEEP(r_alloc_integer(1));
int* p_ffi_times_each = r_int_begin(ffi_times_each);
for (r_ssize i = 0; i < n; ++i) {
r_obj* x = v_xs[i];
r_ssize times_each = 0;
r_ssize times = 0;
if (size != 0) {
switch (vary) {
case VCTRS_EXPAND_VARY_slowest: {
times_each = size / v_cumulative[i];
times = v_cumulative[i] / v_sizes[i];
break;
};
case VCTRS_EXPAND_VARY_fastest: {
times_each = v_cumulative[i] / v_sizes[i];
times = size / v_cumulative[i];
break;
}
}
}
*p_ffi_times_each = r_ssize_as_integer(times_each);
x = KEEP(vec_rep_each(x, ffi_times_each, error_call, vec_args.x, vec_args.empty));
x = vec_rep(x, r_ssize_as_integer(times), error_call, vec_args.x, vec_args.empty);
r_list_poke(out, i, x);
FREE(1);
}
init_data_frame(out, size);
FREE(6);
return out;
}function: t(lgl) --> *c_int argument: t(any_sexp)
SEXP vec_fill_missing(SEXP x, bool down, bool leading, int max_fill) {
r_ssize size = vec_size(x);
SEXP na = PROTECT(vec_detect_missing(x));
const int* p_na = LOGICAL_RO(na);
SEXP loc = PROTECT(r_new_integer(size));
int* p_loc = INTEGER(loc);
const bool has_max_fill = max_fill != INFINITE_FILL;
if (down) {
if (has_max_fill) {
vec_fill_missing_down_with_max_fill(p_na, size, leading, max_fill, p_loc);
} else {
vec_fill_missing_down(p_na, size, leading, p_loc);
}
} else {
if (has_max_fill) {
vec_fill_missing_up_with_max_fill(p_na, size, leading, max_fill, p_loc);
} else {
vec_fill_missing_up(p_na, size, leading, p_loc);
}
}
SEXP out = vec_slice_unsafe(x, loc);
UNPROTECT(2);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any argument: t(any_sexp)
r_ssize vec_first_missing(r_obj* x) {
r_obj* proxy = KEEP(vec_proxy_equal(x));
r_ssize out = proxy_first_missing(proxy);
FREE(1);
return out;
}name: vec_hash_fill
void vec_hash_fill(r_obj* x, r_ssize size, bool na_equal, uint32_t* v_out) {
if (has_dim(x)) {
// The conversion to data frame is only a stopgap, in the long
// term, we'll hash arrays natively
x = KEEP(r_as_data_frame(x));
vec_hash_fill(x, size, na_equal, v_out);
FREE(1);
return;
}
if (na_equal) {
switch (vec_proxy_typeof(x)) {
case VCTRS_TYPE_logical: lgl_hash_fill_na_equal(x, size, v_out); return;
case VCTRS_TYPE_integer: int_hash_fill_na_equal(x, size, v_out); return;
case VCTRS_TYPE_double: dbl_hash_fill_na_equal(x, size, v_out); return;
case VCTRS_TYPE_complex: cpl_hash_fill_na_equal(x, size, v_out); return;
case VCTRS_TYPE_character: chr_hash_fill_na_equal(x, size, v_out); return;
case VCTRS_TYPE_raw: raw_hash_fill_na_equal(x, size, v_out); return;
case VCTRS_TYPE_list: list_hash_fill_na_equal(x, size, v_out); return;
case VCTRS_TYPE_dataframe: df_hash_fill(x, size, na_equal, v_out); return;
default: break;
}
} else {
switch (vec_proxy_typeof(x)) {
case VCTRS_TYPE_logical: lgl_hash_fill_na_propagate(x, size, v_out); return;
case VCTRS_TYPE_integer: int_hash_fill_na_propagate(x, size, v_out); return;
case VCTRS_TYPE_double: dbl_hash_fill_na_propagate(x, size, v_out); return;
case VCTRS_TYPE_complex: cpl_hash_fill_na_propagate(x, size, v_out); return;
case VCTRS_TYPE_character: chr_hash_fill_na_propagate(x, size, v_out); return;
case VCTRS_TYPE_raw: raw_hash_fill_na_propagate(x, size, v_out); return;
case VCTRS_TYPE_list: list_hash_fill_na_propagate(x, size, v_out); return;
case VCTRS_TYPE_dataframe: df_hash_fill(x, size, na_equal, v_out); return;
default: break;
}
}
stop_unimplemented_vctrs_type("vec_hash_fill", vec_proxy_typeof(x));
}function: t(c_int & c_int_na('I38178)) --> int[^int('I38178)]
argument: tuple1r_obj* vec_identify_runs(r_obj* x, struct r_lazy error_call) {
struct r_vector_bool* p_starts = vec_detect_run_bounds_bool(x, VCTRS_RUN_BOUND_start, error_call);
KEEP(p_starts->shelter);
const bool* v_starts = r_vector_bool_cbegin(p_starts);
const r_ssize size = r_vector_bool_length(p_starts);
r_obj* out = KEEP(r_alloc_integer(size));
int* v_out = r_int_begin(out);
int n = 0;
for (r_ssize i = 0; i < size; ++i) {
n += v_starts[i];
v_out[i] = n;
}
r_obj* ffi_n = r_int(n);
r_attrib_poke(out, syms_n, ffi_n);
FREE(2);
return out;
}name: args_start
r_obj* vec_interval_complement(r_obj* start,
r_obj* end,
r_obj* lower,
r_obj* upper) {
int n_prot = 0;
int _;
r_obj* ptype = vec_ptype2(
start,
end,
args_start,
args_end,
r_lazy_null,
S3_FALLBACK_false,
&_
);
KEEP_N(ptype, &n_prot);
ptype = KEEP_N(vec_ptype_finalise(ptype), &n_prot);
start = vec_cast_params(
start,
ptype,
args_start,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(start, &n_prot);
end = vec_cast_params(
end,
ptype,
args_end,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(end, &n_prot);
r_obj* start_proxy = KEEP_N(vec_proxy_compare(start), &n_prot);
start_proxy = KEEP_N(obj_encode_utf8(start_proxy), &n_prot);
r_obj* end_proxy = KEEP_N(vec_proxy_compare(end), &n_prot);
end_proxy = KEEP_N(obj_encode_utf8(end_proxy), &n_prot);
const enum vctrs_type type_proxy = vec_proxy_typeof(start_proxy);
struct poly_vec* p_poly_start = new_poly_vec(start_proxy, type_proxy);
KEEP_N(p_poly_start->shelter, &n_prot);
const void* p_start = p_poly_start->p_vec;
struct poly_vec* p_poly_end = new_poly_vec(end_proxy, type_proxy);
KEEP_N(p_poly_end->shelter, &n_prot);
const void* p_end = p_poly_end->p_vec;
poly_binary_int_fn* const fn_compare = poly_p_compare_na_equal(type_proxy);
bool use_lower = (lower != r_null);
bool use_upper = (upper != r_null);
bool append_lower = false;
bool append_upper = false;
const void* p_lower = NULL;
if (use_lower) {
if (vec_size(lower) != 1) {
r_abort("`lower` must be size 1.");
}
lower = vec_cast_params(
lower,
ptype,
args_lower,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(lower, &n_prot);
r_obj* lower_proxy = KEEP_N(vec_proxy_compare(lower), &n_prot);
lower_proxy = KEEP_N(obj_encode_utf8(lower_proxy), &n_prot);
r_obj* lower_complete = KEEP_N(vec_detect_complete(lower_proxy), &n_prot);
if (!r_lgl_get(lower_complete, 0)) {
r_abort("`lower` can't contain missing values.");
}
struct poly_vec* p_poly_lower = new_poly_vec(lower_proxy, type_proxy);
KEEP_N(p_poly_lower->shelter, &n_prot);
p_lower = p_poly_lower->p_vec;
}
const void* p_upper = NULL;
if (use_upper) {
if (vec_size(upper) != 1) {
r_abort("`upper` must be size 1.");
}
upper = vec_cast_params(
upper,
ptype,
args_upper,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(upper, &n_prot);
r_obj* upper_proxy = KEEP_N(vec_proxy_compare(upper), &n_prot);
upper_proxy = KEEP_N(obj_encode_utf8(upper_proxy), &n_prot);
r_obj* upper_complete = KEEP_N(vec_detect_complete(upper_proxy), &n_prot);
if (!r_lgl_get(upper_complete, 0)) {
r_abort("`upper` can't contain missing values.");
}
struct poly_vec* p_poly_upper = new_poly_vec(upper_proxy, type_proxy);
KEEP_N(p_poly_upper->shelter, &n_prot);
p_upper = p_poly_upper->p_vec;
}
if (use_lower && use_upper && fn_compare(p_lower, 0, p_upper, 0) >= 0) {
// Handle the special case of `lower >= upper` up front.
// This could also be an error, but we try to be a little flexible.
// These can't follow the standard code path because it assumes
// `lower < upper`, like the rest of the intervals.
// - `lower > upper` is an invalid interval.
// - `lower = upper` will always result in an empty complement.
r_obj* out = KEEP_N(r_new_list(2), &n_prot);
r_list_poke(out, 0, vec_slice_unsafe(start, r_globals.empty_int));
r_list_poke(out, 1, vec_slice_unsafe(end, r_globals.empty_int));
r_obj* out_names = r_new_character(2);
r_attrib_poke_names(out, out_names);
r_chr_poke(out_names, 0, r_str("start"));
r_chr_poke(out_names, 1, r_str("end"));
r_init_data_frame(out, 0);
FREE(n_prot);
return out;
}
// Merge to sort, remove all missings, and merge all abutting intervals
const bool abutting = true;
const bool locations = false;
r_obj* minimal = KEEP_N(vec_interval_group_info(
start,
end,
abutting,
VCTRS_INTERVAL_MISSING_drop,
locations
), &n_prot);
const int* v_loc_minimal_start = r_int_cbegin(r_list_get(minimal, 0));
const int* v_loc_minimal_end = r_int_cbegin(r_list_get(minimal, 1));
r_ssize size = vec_size(minimal);
// Because we have the minimal interval information (i.e. no intervals overlap
// or abut!), we know that the complement takes exactly `size - 1` space if
// `lower` and `upper` aren't used.
//
// If `lower` is used, it can at most add one more interval, and
// requires one more `loc_end` location. No `loc_start` location is needed
// because we just append `lower` to the front if needed.
//
// If `upper` is used, it can at most add one more interval, and
// requires one more `loc_start` location. No `loc_end` location is needed
// because we just append `upper` to the end if needed.
const r_ssize max_size_start = r_ssize_max(size - 1 + use_upper, 0);
const r_ssize max_size_end = r_ssize_max(size - 1 + use_lower, 0);
r_obj* loc_start = KEEP_N(r_alloc_integer(max_size_start), &n_prot);
int* v_loc_start = r_int_begin(loc_start);
r_ssize i_start = 0;
r_obj* loc_end = KEEP_N(r_alloc_integer(max_size_end), &n_prot);
int* v_loc_end = r_int_begin(loc_end);
r_ssize i_end = 0;
r_ssize i = 0;
r_ssize loc_lower_is_after_start_of = -1;
r_ssize loc_lower_is_before_end_of = 0;
if (use_lower) {
// Shift `i` forward to the first interval completely past `lower`.
// Track information about where `lower` is in relation to the intervals.
for (; i < size; ++i) {
const r_ssize loc_start = v_loc_minimal_start[i] - 1;
const r_ssize loc_end = v_loc_minimal_end[i] - 1;
if (fn_compare(p_lower, 0, p_end, loc_end) == 1) {
++loc_lower_is_before_end_of;
++loc_lower_is_after_start_of;
} else if (fn_compare(p_lower, 0, p_start, loc_start) >= 0) {
++loc_lower_is_after_start_of;
} else {
break;
}
}
}
r_ssize loc_upper_is_after_start_of = size - 1;
r_ssize loc_upper_is_before_end_of = size;
if (use_upper) {
// Shift `size` backwards to the first interval that is completely before `upper`.
// Track information about where `upper` is in relation to the intervals.
for (; size - 1 >= 0; --size) {
const r_ssize loc_start = v_loc_minimal_start[size - 1] - 1;
const r_ssize loc_end = v_loc_minimal_end[size - 1] - 1;
if (fn_compare(p_upper, 0, p_start, loc_start) == -1) {
--loc_upper_is_before_end_of;
--loc_upper_is_after_start_of;
} else if (fn_compare(p_upper, 0, p_end, loc_end) <= 0) {
--loc_upper_is_before_end_of;
} else {
break;
}
}
}
const bool has_intervals_between = i < size;
if (use_lower && has_intervals_between) {
r_ssize loc_gap_start = -1;
if (loc_lower_is_before_end_of == loc_lower_is_after_start_of) {
// `lower` is in the middle of an interval, use the end of that interval
loc_gap_start = v_loc_minimal_end[loc_lower_is_before_end_of] - 1;
} else {
// `lower` is not within an interval, use `lower`
append_lower = true;
}
// The next start location is the end of the interval that `loc_gap_start`
// lines up with. We know this start location exists because of
// `has_intervals_between`.
const r_ssize loc_gap_end = v_loc_minimal_start[loc_lower_is_after_start_of + 1] - 1;
if (!append_lower) {
v_loc_start[i_start] = loc_gap_start + 1;
++i_start;
}
v_loc_end[i_end] = loc_gap_end + 1;
++i_end;
}
r_ssize loc_previous_end = -1;
if (i < size) {
// Set information about first usable interval
loc_previous_end = v_loc_minimal_end[i] - 1;
++i;
}
for (; i < size; ++i) {
const r_ssize loc_elt_start = v_loc_minimal_start[i] - 1;
const r_ssize loc_elt_end = v_loc_minimal_end[i] - 1;
const r_ssize loc_gap_start = loc_previous_end;
const r_ssize loc_gap_end = loc_elt_start;
v_loc_start[i_start] = loc_gap_start + 1;
++i_start;
v_loc_end[i_end] = loc_gap_end + 1;
++i_end;
loc_previous_end = loc_elt_end;
}
if (use_upper && has_intervals_between) {
// The previous end location is the start of the interval that `loc_gap_end`
// lines up with. We know this end location exists because of
// `has_intervals_between`.
const r_ssize loc_gap_start = v_loc_minimal_end[loc_upper_is_before_end_of - 1] - 1;
r_ssize loc_gap_end = -1;
if (loc_upper_is_before_end_of == loc_upper_is_after_start_of) {
// `upper` is in the middle of an interval, use the start of that interval
loc_gap_end = v_loc_minimal_start[loc_upper_is_before_end_of] - 1;
} else {
// `upper` is not within an interval, use `upper`
append_upper = true;
}
v_loc_start[i_start] = loc_gap_start + 1;
++i_start;
if (!append_upper) {
v_loc_end[i_end] = loc_gap_end + 1;
++i_end;
}
}
if (use_lower && use_upper && !has_intervals_between) {
/*
* This branch handles the case when `lower` and `upper` have no full
* intervals between them. They can be in any of these states. In
* particular, if they are in the same interval together, then there is
* no complement.
*
* | [ ) <lower> <upper> [ ) | append_lower = append_upper = true. complement: <lower> -> <upper>
* | [ <lower> ) <upper> [ ) | append_upper = true. complement: ) -> <upper>
* | [ ) <lower> [ <upper> ) | append_lower = true. complement: <lower> -> [
* | [ <lower> ) [ <upper> ) | both in separate intervals. complement: ) -> [
* | [ <lower> <upper> ) [ ) | both in same interval! complement: none
* | [ ) [ <lower> <upper> ) | both in same interval! complement: none
*/
bool lower_in_interval = false;
bool upper_in_interval = false;
r_ssize loc_gap_start = -1;
if (loc_lower_is_before_end_of == loc_lower_is_after_start_of) {
lower_in_interval = true;
loc_gap_start = v_loc_minimal_end[loc_lower_is_before_end_of] - 1;
} else {
append_lower = true;
}
r_ssize loc_gap_end = -1;
if (loc_upper_is_before_end_of == loc_upper_is_after_start_of) {
upper_in_interval = true;
loc_gap_end = v_loc_minimal_start[loc_upper_is_before_end_of] - 1;
} else {
append_upper = true;
}
const bool lower_and_upper_in_same_interval =
lower_in_interval &&
upper_in_interval &&
(loc_lower_is_before_end_of == loc_upper_is_before_end_of);
if (!append_lower && !lower_and_upper_in_same_interval) {
v_loc_start[i_start] = loc_gap_start + 1;
++i_start;
}
if (!append_upper && !lower_and_upper_in_same_interval) {
v_loc_end[i_end] = loc_gap_end + 1;
++i_end;
}
}
// This should essentially be free.
// It will only ever shrink `loc_start` and `loc_end`.
loc_start = KEEP_N(r_int_resize(loc_start, i_start), &n_prot);
loc_end = KEEP_N(r_int_resize(loc_end, i_end), &n_prot);
// Slice `end` to get new starts and `start` to get new ends!
r_obj* out_start = KEEP_N(vec_slice_unsafe(end, loc_start), &n_prot);
r_obj* out_end = KEEP_N(vec_slice_unsafe(start, loc_end), &n_prot);
if (append_lower || append_upper) {
r_obj* args = KEEP_N(r_new_list(2), &n_prot);
const struct name_repair_opts name_repair_opts = {
.type = NAME_REPAIR_none,
.fn = R_NilValue
};
if (append_lower) {
// Push `lower` to the start of the new starts
r_list_poke(args, 0, lower);
r_list_poke(args, 1, out_start);
out_start = KEEP_N(vec_c(
args,
ptype,
R_NilValue,
&name_repair_opts,
vec_args.empty,
r_lazy_null
), &n_prot);
}
if (append_upper) {
// Push `upper` to the end of the new ends
r_list_poke(args, 0, out_end);
r_list_poke(args, 1, upper);
out_end = KEEP_N(vec_c(
args,
ptype,
R_NilValue,
&name_repair_opts,
vec_args.empty,
r_lazy_null
), &n_prot);
}
}
r_obj* out = KEEP_N(r_new_list(2), &n_prot);
r_list_poke(out, 0, out_start);
r_list_poke(out, 1, out_end);
r_obj* out_names = r_new_character(2);
r_attrib_poke_names(out, out_names);
r_chr_poke(out_names, 0, r_str("start"));
r_chr_poke(out_names, 1, r_str("end"));
r_init_data_frame(out, vec_size(out_start));
FREE(n_prot);
return out;
}name: args_start
r_obj* vec_interval_group_info(r_obj* start,
r_obj* end,
bool abutting,
enum vctrs_interval_missing missing,
bool locations) {
int n_prot = 0;
int _;
r_obj* ptype = vec_ptype2(
start,
end,
args_start,
args_end,
r_lazy_null,
S3_FALLBACK_false,
&_
);
KEEP_N(ptype, &n_prot);
ptype = KEEP_N(vec_ptype_finalise(ptype), &n_prot);
start = vec_cast_params(
start,
ptype,
args_start,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(start, &n_prot);
end = vec_cast_params(
end,
ptype,
args_end,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(end, &n_prot);
r_obj* start_proxy = KEEP_N(vec_proxy_compare(start), &n_prot);
start_proxy = KEEP_N(obj_encode_utf8(start_proxy), &n_prot);
r_obj* end_proxy = KEEP_N(vec_proxy_compare(end), &n_prot);
end_proxy = KEEP_N(obj_encode_utf8(end_proxy), &n_prot);
const enum vctrs_type type_proxy = vec_proxy_typeof(start_proxy);
struct poly_vec* p_poly_start = new_poly_vec(start_proxy, type_proxy);
KEEP_N(p_poly_start->shelter, &n_prot);
const void* p_start = p_poly_start->p_vec;
struct poly_vec* p_poly_end = new_poly_vec(end_proxy, type_proxy);
KEEP_N(p_poly_end->shelter, &n_prot);
const void* p_end = p_poly_end->p_vec;
poly_binary_int_fn* const fn_compare = poly_p_compare_na_equal(type_proxy);
poly_unary_bool_fn* const fn_is_missing = poly_p_is_missing(type_proxy);
const r_ssize size = vec_size(start_proxy);
if (size != vec_size(end_proxy)) {
r_abort("`start` and `end` must have the same size.");
}
// Order is computed as ascending order, placing missing intervals up front
// as the "smallest" values. We document that we assume that if `start` is
// missing, then `end` is missing too.
r_obj* order = interval_order(
start_proxy,
end_proxy,
chrs_asc,
chrs_smallest,
size
);
KEEP_N(order, &n_prot);
const int* v_order = r_int_cbegin(order);
// Assume the intervals can be merged into half their original size.
// Apply a minimum size to avoid a size of zero.
const r_ssize initial_size = r_ssize_max(size / 2, 1);
struct r_dyn_array* p_loc_start = r_new_dyn_vector(R_TYPE_integer, initial_size);
KEEP_N(p_loc_start->shelter, &n_prot);
struct r_dyn_array* p_loc_end = r_new_dyn_vector(R_TYPE_integer, initial_size);
KEEP_N(p_loc_end->shelter, &n_prot);
struct r_dyn_array* p_loc = NULL;
if (locations) {
p_loc = r_new_dyn_vector(R_TYPE_list, initial_size);
KEEP_N(p_loc->shelter, &n_prot);
}
r_ssize i = 0;
r_ssize loc_order_missing_start = 0;
r_ssize loc_order_missing_end = -1;
// Move `i` past any missing intervals (they are at the front),
// recording last missing interval location for later. Only need to check
// missingness of `start`, because we document that we assume that `end`
// is missing if `start` is missing.
for (; i < size; ++i) {
const r_ssize loc = v_order[i] - 1;
if (!fn_is_missing(p_start, loc)) {
break;
}
loc_order_missing_end = i;
}
r_ssize loc_order_start = 0;
r_ssize loc_order_end = -1;
r_ssize loc_group_start = 0;
r_ssize loc_group_end = -1;
if (i < size) {
// Set information about first usable interval
const r_ssize loc = v_order[i] - 1;
loc_order_start = i;
loc_order_end = i;
loc_group_start = loc;
loc_group_end = loc;
++i;
}
const int merge_limit = abutting ? -1 : 0;
for (; i < size; ++i) {
const r_ssize loc = v_order[i] - 1;
// If `abutting`, this says: if group end < new start, finish out the group
// If `!abutting`, this says: if group end <= new start, finish out the group
if (fn_compare(p_end, loc_group_end, p_start, loc) <= merge_limit) {
r_dyn_int_push_back(p_loc_start, loc_group_start + 1);
r_dyn_int_push_back(p_loc_end, loc_group_end + 1);
if (locations) {
const r_ssize loc_size = loc_order_end - loc_order_start + 1;
r_obj* loc = r_new_integer(loc_size);
r_dyn_list_push_back(p_loc, loc);
int* v_loc = r_int_begin(loc);
const int* v_order_start = v_order + loc_order_start;
r_memcpy(v_loc, v_order_start, loc_size * sizeof(*v_loc));
}
loc_order_start = loc_order_end + 1;
loc_group_start = loc;
loc_group_end = loc;
} else if (fn_compare(p_end, loc_group_end, p_end, loc) == -1) {
loc_group_end = loc;
}
loc_order_end = i;
}
if (loc_order_end >= loc_order_start) {
// Log last interval
r_dyn_int_push_back(p_loc_start, loc_group_start + 1);
r_dyn_int_push_back(p_loc_end, loc_group_end + 1);
if (locations) {
const r_ssize loc_size = loc_order_end - loc_order_start + 1;
r_obj* loc = r_new_integer(loc_size);
r_dyn_list_push_back(p_loc, loc);
int* v_loc = r_int_begin(loc);
const int* v_order_start = v_order + loc_order_start;
r_memcpy(v_loc, v_order_start, loc_size * sizeof(*v_loc));
}
}
if (missing == VCTRS_INTERVAL_MISSING_group &&
loc_order_missing_end >= loc_order_missing_start) {
// Log missing interval at the end
const r_ssize loc_group_missing_start = v_order[loc_order_missing_start] - 1;
const r_ssize loc_group_missing_end = v_order[loc_order_missing_end] - 1;
r_dyn_int_push_back(p_loc_start, loc_group_missing_start + 1);
r_dyn_int_push_back(p_loc_end, loc_group_missing_end + 1);
if (locations) {
const r_ssize loc_size = loc_order_missing_end - loc_order_missing_start + 1;
r_obj* loc = r_new_integer(loc_size);
r_dyn_list_push_back(p_loc, loc);
int* v_loc = r_int_begin(loc);
const int* v_order_start = v_order + loc_order_missing_start;
r_memcpy(v_loc, v_order_start, loc_size * sizeof(*v_loc));
}
}
r_obj* key = KEEP_N(r_new_list(2), &n_prot);
r_list_poke(key, 0, r_dyn_unwrap(p_loc_start));
r_list_poke(key, 1, r_dyn_unwrap(p_loc_end));
r_obj* key_names = r_new_character(2);
r_attrib_poke_names(key, key_names);
r_chr_poke(key_names, 0, r_str("start"));
r_chr_poke(key_names, 1, r_str("end"));
r_init_data_frame(key, p_loc_start->count);
r_obj* out = r_null;
r_keep_loc out_shelter;
KEEP_HERE(out, &out_shelter);
++n_prot;
if (locations) {
out = r_new_list(2);
KEEP_AT(out, out_shelter);
r_list_poke(out, 0, key);
r_list_poke(out, 1, r_dyn_unwrap(p_loc));
r_obj* out_names = r_new_character(2);
r_attrib_poke_names(out, out_names);
r_chr_poke(out_names, 0, r_str("key"));
r_chr_poke(out_names, 1, r_str("loc"));
r_init_data_frame(out, p_loc_start->count);
} else {
out = key;
}
FREE(n_prot);
return out;
}name: args_start
r_obj* vec_interval_locate_containers(r_obj* start, r_obj* end) {
int n_prot = 0;
int _;
r_obj* ptype = vec_ptype2(
start,
end,
args_start,
args_end,
r_lazy_null,
S3_FALLBACK_false,
&_
);
KEEP_N(ptype, &n_prot);
ptype = KEEP_N(vec_ptype_finalise(ptype), &n_prot);
start = vec_cast_params(
start,
ptype,
args_start,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(start, &n_prot);
end = vec_cast_params(
end,
ptype,
args_end,
vec_args.empty,
r_lazy_null,
S3_FALLBACK_false
);
KEEP_N(end, &n_prot);
r_obj* start_proxy = KEEP_N(vec_proxy_compare(start), &n_prot);
start_proxy = KEEP_N(obj_encode_utf8(start_proxy), &n_prot);
r_obj* end_proxy = KEEP_N(vec_proxy_compare(end), &n_prot);
end_proxy = KEEP_N(obj_encode_utf8(end_proxy), &n_prot);
const enum vctrs_type type_proxy = vec_proxy_typeof(start_proxy);
struct poly_vec* p_poly_start = new_poly_vec(start_proxy, type_proxy);
KEEP_N(p_poly_start->shelter, &n_prot);
const void* p_start = p_poly_start->p_vec;
struct poly_vec* p_poly_end = new_poly_vec(end_proxy, type_proxy);
KEEP_N(p_poly_end->shelter, &n_prot);
const void* p_end = p_poly_end->p_vec;
poly_binary_int_fn* const fn_compare = poly_p_compare_na_equal(type_proxy);
poly_unary_bool_fn* const fn_is_missing = poly_p_is_missing(type_proxy);
const r_ssize size = vec_size(start_proxy);
if (size != vec_size(end_proxy)) {
r_abort("`start` and `end` must have the same size.");
}
// Order is computed with the first column in ascending order, and the
// second column in descending order. This makes it easy to find the
// containers, as any time we detect something that isn't contained in the
// current container, it must be a new container. Missing intervals are up
// front for easy detection. We document that we assume that if `start` is
// missing, then `end` is missing too.
r_obj* direction = KEEP_N(r_new_character(2), &n_prot);
r_chr_poke(direction, 0, r_str("asc"));
r_chr_poke(direction, 1, r_str("desc"));
r_obj* na_value = KEEP_N(r_new_character(2), &n_prot);
r_chr_poke(na_value, 0, r_str("smallest"));
r_chr_poke(na_value, 1, r_str("largest"));
r_obj* order = interval_order(
start_proxy,
end_proxy,
direction,
na_value,
size
);
KEEP_N(order, &n_prot);
const int* v_order = r_int_cbegin(order);
// Assume that half the intervals are containers.
// This is probably a little high.
// Apply a minimum size to avoid a size of zero.
const r_ssize initial_size = r_ssize_max(size / 2, 1);
struct r_dyn_array* p_loc = r_new_dyn_vector(R_TYPE_integer, initial_size);
KEEP_N(p_loc->shelter, &n_prot);
r_ssize i = 0;
bool any_missing = false;
// Move `i` past any missing intervals (they are at the front),
// recording if there are any missing intervals for later. Only need to check
// missingness of `start`, because we document that we assume that `end`
// is missing if `start` is missing.
for (; i < size; ++i) {
const r_ssize loc = v_order[i] - 1;
if (!fn_is_missing(p_start, loc)) {
break;
}
any_missing = true;
}
r_ssize loc_container = -1;
if (i < size) {
// Set information about first usable container
const r_ssize loc = v_order[i] - 1;
loc_container = loc;
r_dyn_int_push_back(p_loc, loc_container + 1);
++i;
}
for (; i < size; ++i) {
const r_ssize loc = v_order[i] - 1;
if ((fn_compare(p_start, loc_container, p_start, loc) != 1) &&
(fn_compare(p_end, loc_container, p_end, loc) != -1)) {
// Still in current container
continue;
}
// New container
loc_container = loc;
r_dyn_int_push_back(p_loc, loc_container + 1);
}
if (any_missing) {
// Push missing container as the last container.
// We know missings are at the front, so just use the first order value
// as the location. This matches ascending ordering with missing values
// at the end, and breaking ties with the first missing location we saw.
r_dyn_int_push_back(p_loc, v_order[0]);
}
r_obj* out = r_dyn_unwrap(p_loc);
FREE(n_prot);
return out;
}name: vec_ptype2
void vec_is_coercible_cb(void* data_) {
struct is_coercible_data* data = (struct is_coercible_data*) data_;
int _;
data->out = vec_ptype2(
data->x,
data->y,
data->p_x_arg,
data->p_y_arg,
data->call,
data->s3_fallback,
&_
);
}name: c_strs_vctrs_common_class_fallback
bool vec_is_common_class_fallback(r_obj* ptype) {
return r_inherits(ptype, c_strs_vctrs_common_class_fallback);
}function: t(any_sexp, *t(any_sexp, any_sexp, *c_void) --> any_sexp, *c_void) --> any_sexp argument: t(any_sexp & 'I5614, t(any_sexp, any_sexp, *c_void) -> c_null | null, c_null)
bool vec_is_restored(r_obj* x, r_obj* to) {
// Don't restore if there is an actual `[` method that ignored
// attributes. Some methods like [.ts intentionally strip the class
// and attributes. FIXME: This branch is now probably sufficient.
if (s3_find_method("[", to, base_method_table) != r_null) {
return true;
}
if (!r_attrib_has_any(x)) {
return false;
}
// Class is restored if it contains any other attributes than names.
// We might want to add support for data frames later on.
return r_attrib_map(x, vec_is_restored_cb, NULL) != NULL;
}name: vec_ptype2
SEXP vec_match_params(SEXP needles,
SEXP haystack,
bool na_equal,
struct vctrs_arg* needles_arg,
struct vctrs_arg* haystack_arg,
struct r_lazy call) {
int nprot = 0;
int _;
SEXP type = vec_ptype2(
needles,
haystack,
needles_arg,
haystack_arg,
call,
S3_FALLBACK_false,
&_
);
PROTECT_N(type, &nprot);
type = PROTECT_N(vec_ptype_finalise(type), &nprot);
needles = vec_cast_params(
needles,
type,
needles_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
PROTECT_N(needles, &nprot);
haystack = vec_cast_params(
haystack,
type,
haystack_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
PROTECT_N(haystack, &nprot);
needles = PROTECT_N(vec_proxy_equal(needles), &nprot);
needles = PROTECT_N(obj_encode_utf8(needles), &nprot);
haystack = PROTECT_N(vec_proxy_equal(haystack), &nprot);
haystack = PROTECT_N(obj_encode_utf8(haystack), &nprot);
R_len_t n_haystack = vec_size(haystack);
R_len_t n_needle = vec_size(needles);
struct dictionary* d = new_dictionary_params(haystack, false, na_equal);
PROTECT_DICT(d, &nprot);
// Load dictionary with haystack
load_with_haystack(d, n_haystack);
struct dictionary* d_needles = new_dictionary_params(needles, true, na_equal);
PROTECT_DICT(d_needles, &nprot);
// Locate needles
SEXP out = PROTECT_N(Rf_allocVector(INTSXP, n_needle), &nprot);
int* p_out = INTEGER(out);
if (na_equal) {
vec_match_loop(p_out, d, d_needles, n_needle);
} else {
vec_match_loop_propagate(p_out, d, d_needles, n_needle);
}
UNPROTECT(nprot);
return out;
}function: t(c_int & c_int_na('I30883)) --> chr[^int('I30883)]
argument: tuple1r_obj* vec_names2(r_obj* x) {
r_obj* names = vec_names(x);
if (names == r_null) {
return r_alloc_character(vec_size(x));
} else {
return names;
}
}function: t(vec[^int('I13033)]) --> c_int & c_int_na('I13033) & t(p(chr) | vec[^int('I13033)]) --> c_int
argument: t(any_sexp)r_obj* vec_names_impl(r_obj* x, bool proxy) {
bool has_class = r_is_object(x);
if (has_class && r_inherits(x, "data.frame")) {
// Only return row names if they are character. Data frames with
// automatic row names are treated as unnamed.
r_obj* rn = df_rownames(x);
if (rownames_type(rn) == ROWNAMES_TYPE_identifiers) {
return rn;
} else {
return r_null;
}
}
if (vec_bare_dim(x) == r_null) {
if (!proxy && has_class) {
return vctrs_dispatch1(syms_names, fns_names, syms_x, x);
} else {
return r_names(x);
}
}
r_obj* dimnames = KEEP(r_attrib_get(x, r_syms.dim_names));
if (dimnames == r_null || r_length(dimnames) < 1) {
FREE(1);
return r_null;
}
r_obj* out = r_list_get(dimnames, 0);
FREE(1);
return out;
}function: t({ 'I12025 }, c_int) --> 'I12025
argument: t(any_sexp, c_false)SEXP vec_order(
SEXP x,
SEXP direction,
SEXP na_value,
bool nan_distinct,
SEXP chr_proxy_collate
) {
const bool group_sizes = false;
SEXP info = vec_order_info_impl(x, direction, na_value, nan_distinct, chr_proxy_collate, group_sizes);
return r_list_get(info, 0);
}function: ref('I8230) --> 'I8230
argument: any --> anySEXP vec_order_compute_na_last(
SEXP na_largest,
SEXP decreasing
) {
const r_ssize size = r_length(na_largest);
if (size != r_length(decreasing)) {
r_stop_internal(
"`na_largest` and `decreasing` should already match in size."
);
}
SEXP na_last = PROTECT(r_new_logical(size));
int* p_na_last = LOGICAL(na_last);
const int* p_na_largest = LOGICAL_RO(na_largest);
const int* p_decreasing = LOGICAL_RO(decreasing);
for (r_ssize i = 0; i < size; ++i) {
p_na_last[i] = p_decreasing[i] ? !p_na_largest[i] : p_na_largest[i];
}
UNPROTECT(1);
return na_last;
}function: t(any_sexp & 'I12015, c(..-1), x1, { x : any_sexp ; env : any_sexp }) --> any_sexp & 'I12015 where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(list, any, *x1, { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }SEXP vec_order_info_impl(
SEXP x,
SEXP direction,
SEXP na_value,
bool nan_distinct,
SEXP chr_proxy_collate,
bool group_sizes
) {
// TODO call
struct r_lazy call = r_lazy_null;
int n_prot = 0;
SEXP decreasing = PROTECT_N(parse_direction(direction), &n_prot);
SEXP na_largest = PROTECT_N(parse_na_value(na_value), &n_prot);
// Call on `x` before potentially flattening cols with `vec_proxy_order()`
SEXP args = PROTECT_N(vec_order_expand_args(x, decreasing, na_largest), &n_prot);
R_len_t arg_size = vec_size_common(args, 0, vec_args.empty, call);
args = PROTECT_N(vec_recycle_common(args, arg_size, vec_args.empty, call), &n_prot);
decreasing = VECTOR_ELT(args, 0);
na_largest = VECTOR_ELT(args, 1);
SEXP na_last = PROTECT_N(vec_order_compute_na_last(na_largest, decreasing), &n_prot);
SEXP proxy = PROTECT_N(vec_proxy_order(x), &n_prot);
proxy = PROTECT_N(obj_encode_utf8(proxy), &n_prot);
proxy = PROTECT_N(proxy_apply_chr_proxy_collate(proxy, chr_proxy_collate), &n_prot);
r_ssize size = vec_size(proxy);
const enum vctrs_type type = vec_proxy_typeof(proxy);
// Compute the maximum size required for auxiliary working memory
const size_t n_bytes_lazy_raw = vec_compute_n_bytes_lazy_raw(proxy, type);
// Auxiliary vectors to hold intermediate results while ordering.
// If `x` is a data frame we allocate enough room for the largest column type.
struct lazy_raw* p_lazy_x_chunk = new_lazy_raw(size, n_bytes_lazy_raw);
PROTECT_LAZY_VEC(p_lazy_x_chunk, &n_prot);
struct lazy_raw* p_lazy_x_aux = new_lazy_raw(size, n_bytes_lazy_raw);
PROTECT_LAZY_VEC(p_lazy_x_aux, &n_prot);
struct lazy_raw* p_lazy_o_aux = new_lazy_raw(size, sizeof(int));
PROTECT_LAZY_VEC(p_lazy_o_aux, &n_prot);
struct lazy_raw* p_lazy_bytes = new_lazy_raw(size, sizeof(uint8_t));
PROTECT_LAZY_VEC(p_lazy_bytes, &n_prot);
// Compute the maximum size of the `counts` vector needed during radix
// ordering. 4 * 256 for integers, 8 * 256 for doubles, not used for characters
// since the number of iterations depends on string length.
size_t n_bytes_lazy_counts = vec_compute_n_bytes_lazy_counts(proxy, type);
r_ssize size_lazy_counts = UINT8_MAX_SIZE * n_bytes_lazy_counts;
struct lazy_raw* p_lazy_counts = new_lazy_raw(size_lazy_counts, sizeof(r_ssize));
PROTECT_LAZY_VEC(p_lazy_counts, &n_prot);
// Determine if group tracking can be turned off.
// We turn if off if ordering non-data frame input as long as
// locations haven't been requested by the user.
// It is more efficient to ignore it when possible.
bool force_groups = group_sizes;
bool ignore_groups = force_groups ? false : (is_data_frame(proxy) ? false : true);
// Construct the two sets of group info needed for tracking groups.
// We switch between them after each data frame column is processed.
struct group_info* p_group_info0 = new_group_info();
PROTECT_GROUP_INFO(p_group_info0, &n_prot);
struct group_info* p_group_info1 = new_group_info();
PROTECT_GROUP_INFO(p_group_info1, &n_prot);
struct group_infos* p_group_infos = new_group_infos(
p_group_info0,
p_group_info1,
size,
force_groups,
ignore_groups
);
PROTECT_GROUP_INFOS(p_group_infos, &n_prot);
struct order* p_order = new_order(size);
PROTECT_ORDER(p_order, &n_prot);
vec_order_switch(
proxy,
decreasing,
na_last,
nan_distinct,
size,
type,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
SEXP out = PROTECT_N(r_alloc_list(3), &n_prot);
r_list_poke(out, 0, p_order->data);
if (group_sizes) {
struct group_info* p_group_info = groups_current(p_group_infos);
SEXP sizes = p_group_info->data;
sizes = r_int_resize(sizes, p_group_info->n_groups);
r_list_poke(out, 1, sizes);
r_list_poke(out, 2, r_int((int) p_group_info->max_group_size));
}
UNPROTECT(n_prot);
return out;
}function: t(list) --> *any_sexp
argument: t((vec<> & vec0 & vec[^int('I31819)]) & 'I31791)r_obj* vec_parallel(
r_obj* xs,
enum vec_parallel_missing missing,
r_ssize size,
struct vctrs_arg* p_xs_arg,
struct r_lazy error_call,
enum vec_parallel_variant parallel
) {
// Input must be a list
obj_check_list(xs, p_xs_arg, error_call);
// Every element of that list must be a bare logical vector
list_check_all_condition_indices(xs, p_xs_arg, error_call);
// Every element of that list must be the same size
size = compute_size(size, xs);
list_check_all_size(xs, size, VCTRS_ALLOW_NULL_no, p_xs_arg, error_call);
r_obj* out = KEEP(r_alloc_logical(size));
int* v_out = r_lgl_begin(out);
const r_ssize xs_size = r_length(xs);
r_obj* const* v_xs = r_list_cbegin(xs);
if (xs_size == 0) {
// Zero input case is special, fill with values that match `any()` and `all()`
switch (parallel) {
case VEC_PARALLEL_VARIANT_all: r_p_lgl_fill(v_out, 1, size); break;
case VEC_PARALLEL_VARIANT_any: r_p_lgl_fill(v_out, 0, size); break;
default: r_stop_unreachable();
}
} else {
// Initialize output with first input
r_obj* x = v_xs[0];
const int* v_x = r_lgl_begin(x);
vec_parallel_init(v_x, missing, size, v_out);
// Combine with remaining inputs
for (r_ssize i = 1; i < xs_size; ++i) {
r_obj* x = v_xs[i];
const int* v_x = r_lgl_begin(x);
switch (parallel) {
case VEC_PARALLEL_VARIANT_all: vec_pall_fill(v_x, missing, size, v_out); break;
case VEC_PARALLEL_VARIANT_any: vec_pany_fill(v_x, missing, size, v_out); break;
default: r_stop_unreachable();
}
}
}
FREE(1);
return out;
}function: t(c_int & c_int_na('I26688)) --> chr[^int('I26688)]
argument: tuple1r_obj* vec_proxy_assign_names(
r_obj* proxy,
r_obj* index,
r_obj* value_proxy,
enum vctrs_ownership ownership,
enum assignment_slice_value slice_value,
enum vctrs_index_style index_style
) {
// Both of these inputs are assumed to be proxied already
r_obj* proxy_nms = KEEP(vec_proxy_names(proxy));
r_obj* value_nms = KEEP(vec_proxy_names(value_proxy));
if (proxy_nms == r_null && value_nms == r_null) {
// No names at all to worry about
FREE(2);
return proxy;
}
if (value_nms == r_null) {
// If there are `proxy_nms` but no `value_nms`, we need clear any names at
// this `index`. This also clears when we freshly create `proxy_nms` which
// is a no-op, but that's okay, it keeps the logic simple.
value_nms = r_chrs.empty_string;
}
if (proxy_nms == r_null) {
proxy_nms = KEEP(r_alloc_character(vec_size(proxy)));
} else {
proxy_nms = KEEP(vec_clone_referenced(proxy_nms, ownership));
}
proxy_nms = KEEP(chr_assign(
proxy_nms,
index,
value_nms,
ownership,
slice_value,
index_style
));
proxy = KEEP(vec_clone_referenced(proxy, ownership));
proxy = vec_proxy_set_names(proxy, proxy_nms, ownership);
FREE(5);
return proxy;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> c(0..10) | c(13..25) | c(30..31) | c(99) argument: t(any_sexp | 'I26691)
r_obj* vec_proxy_assign_opts(r_obj* proxy,
r_obj* index,
r_obj* value,
const struct vec_proxy_assign_opts* p_opts) {
int n_protect = 0;
// Ignore vectors marked as fallback because the caller will apply a fallback
// method instead. We can't lift this check out of `vec_proxy_assign_opts()`
// and just apply at the call sites because we recurse through here with data
// frames and individual columns might need the fallback even if the whole
// data frame itself doesn't need it.
if (vec_is_common_class_fallback(proxy)) {
return proxy;
}
// We only allow `ignore_outer_names` on the "outer" call to
// `vec_proxy_assign_opts()`. After it has been used once, it is set to
// `false` for any recursive calls back into this function.
struct vec_proxy_assign_opts opts_copy = *p_opts;
const bool ignore_outer_names = opts_copy.ignore_outer_names;
opts_copy.ignore_outer_names = false;
struct vctrs_proxy_info value_info = vec_proxy_info(value);
KEEP_N(value_info.inner, &n_protect);
if (r_typeof(proxy) != r_typeof(value_info.inner)) {
r_stop_internal("`proxy` of type `%s` incompatible with `value` proxy of type `%s`.",
r_type_as_c_string(r_typeof(proxy)),
r_type_as_c_string(r_typeof(value_info.inner)));
}
// If a fallback is required, the `proxy` is identical to the output container
// because no proxy method was called
r_obj* out = r_null;
if (vec_requires_fallback(value, value_info)) {
index = KEEP_N(vec_subscript_materialize(index), &n_protect);
out = KEEP_N(vec_assign_fallback(proxy, index, value, opts_copy.slice_value, opts_copy.index_style), &n_protect);
} else if (has_dim(proxy)) {
out = KEEP_N(vec_assign_shaped(proxy, index, value_info.inner, opts_copy.ownership, opts_copy.slice_value, opts_copy.index_style), &n_protect);
} else {
out = KEEP_N(vec_assign_switch(proxy, index, value_info.inner, &opts_copy), &n_protect);
}
if (!ignore_outer_names && p_opts->assign_names) {
out = vec_proxy_assign_names(out, index, value_info.inner, opts_copy.ownership, opts_copy.slice_value, opts_copy.index_style);
}
FREE(n_protect);
return out;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> c_false argument: t(any_sexp)
r_obj* vec_proxy_compare(r_obj* x) {
r_obj* out = KEEP(vec_proxy_compare_impl(x));
if (is_data_frame(out)) {
// Automatically proxy df-proxies recursively.
// Also flattens and unwraps them (#1537, #1664).
out = df_proxy(out, VCTRS_PROXY_KIND_compare);
}
FREE(1);
return out;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> c_false argument: t(any_sexp)
r_obj* vec_proxy_equal(r_obj* x) {
r_obj* out = KEEP(vec_proxy_equal_impl(x));
if (is_data_frame(out)) {
// Automatically proxy df-proxies recursively.
// Also flattens and unwraps them (#1537, #1664).
out = df_proxy(out, VCTRS_PROXY_KIND_equal);
}
FREE(1);
return out;
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> c_false argument: t(any_sexp)
r_obj* vec_proxy_order(r_obj* x) {
r_obj* out = KEEP(vec_proxy_order_impl(x));
if (is_data_frame(out)) {
// Automatically proxy df-proxies recursively.
// Also flattens and unwraps them (#1537, #1664).
out = df_proxy(out, VCTRS_PROXY_KIND_order);
}
FREE(1);
return out;
}name: vec_proxy_2
r_obj* vec_proxy_recurse(r_obj* x) {
return vec_proxy_2(x, true);
}function: t(sym) --> c_string argument: t(null)
r_obj* vec_ptype2_dispatch_s3(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback
) {
x = KEEP(vec_ptype(x, p_x_arg, call));
y = KEEP(vec_ptype(y, p_y_arg, call));
r_obj* method_sym = r_null;
r_obj* method = s3_find_method_xy("vec_ptype2", x, y, vctrs_method_table, &method_sym);
// Compatibility with legacy double dispatch mechanism
if (method == r_null) {
r_obj* x_method_sym = r_null;
r_obj* x_method = KEEP(s3_find_method2(
"vec_ptype2",
x,
vctrs_method_table,
&x_method_sym
));
if (x_method != r_null) {
// Only `x_method`s contained within a package will
// have an S3 methods table to look in
r_obj* x_table = s3_get_table(r_fn_env(x_method));
if (x_table != r_null) {
const char* x_method_str = r_sym_c_string(x_method_sym);
method = s3_find_method2(
x_method_str,
y,
x_table,
&method_sym
);
}
}
FREE(1);
}
KEEP(method);
if (method == r_null) {
r_obj* out = vec_ptype2_default_full(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback,
true
);
FREE(3);
return out;
}
r_obj* ffi_x_arg = KEEP(vctrs_arg(p_x_arg));
r_obj* ffi_y_arg = KEEP(vctrs_arg(p_y_arg));
r_obj* out = vec_invoke_coerce_method(
method_sym,
method,
syms_x,
x,
syms_y,
y,
syms_x_arg,
ffi_x_arg,
syms_y_arg,
ffi_y_arg,
call,
s3_fallback
);
FREE(5);
return out;
}function: t(null & 'I24249) --> null & 'I24249 & t('I24249 & ((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | p(chr) | sym)) --> 'I24249 & ((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | p(chr) | sym)
argument: t(any_sexp)r_obj* vec_ptype_final(r_obj* x, struct vctrs_arg* x_arg, struct r_lazy call) {
r_obj* out = KEEP(vec_ptype(x, x_arg, call));
out = vec_ptype_finalise(out);
FREE(1);
return out;
}function: t(vec[^int('I835)]) --> c_int & c_int_na('I835) & t(p(chr) | vec[^int('I835)]) --> c_int
argument: t(any_sexp)r_ssize vec_raw_size(r_obj* x) {
r_obj* dimensions = r_dim(x);
if (dimensions == r_null || r_length(dimensions) == 0) {
return r_length(x);
}
if (r_typeof(dimensions) != R_TYPE_integer) {
r_stop_internal("Corrupt vector, `dim` attribute is not an integer vector.");
}
return r_int_get(dimensions, 0);
}function: t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym) --> any argument: t(any_sexp)
r_obj* vec_rep_each(r_obj* x,
r_obj* times,
struct r_lazy error_call,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_times_arg) {
times = KEEP(vec_cast(times,
r_globals.empty_int,
p_times_arg,
vec_args.empty,
error_call));
const r_ssize times_size = vec_size(times);
r_obj* out;
if (times_size == 1) {
const int times_ = r_int_get(times, 0);
if (times_ == 1) {
out = x;
} else if (times_ == 0) {
out = vec_slice_unsafe(x, r_globals.empty_int);
} else {
out = vec_rep_each_uniform(x, times_, error_call, p_times_arg);
}
} else {
out = vec_rep_each_impl(x, times, times_size, error_call, p_times_arg);
}
FREE(1);
return out;
}function: t(c_int_na, c_int_na, c_null, { x : any_sexp ; env : any_sexp }) --> empty
argument: t('I31026, any, *x1 & 'I31028, 'I31027 & { x : any_sexp ; env : any_sexp }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }static r_obj* vec_rep_each_impl(r_obj* x,
r_obj* times,
const r_ssize times_size,
struct r_lazy error_call,
struct vctrs_arg* p_times_arg) {
const r_ssize x_size = vec_size(x);
if (x_size != times_size) {
stop_recycle_incompatible_size(times_size,
x_size,
p_times_arg,
error_call);
}
const int* v_times = r_int_cbegin(times);
r_ssize size = 0;
for (r_ssize i = 0; i < times_size; ++i) {
const int elt_times = v_times[i];
check_rep_each_times(elt_times, i + 1, error_call, p_times_arg);
const r_ssize elt_times_ = (r_ssize) elt_times;
if (plus_would_overflow(size, elt_times_)) {
stop_rep_size_oob(error_call);
}
size += elt_times_;
}
r_obj* subscript = KEEP(r_alloc_integer(size));
int* v_subscript = r_int_begin(subscript);
r_ssize k = 0;
for (r_ssize i = 1; i <= x_size; ++i) {
const r_ssize elt_times = (r_ssize) v_times[i - 1];
for (r_ssize j = 0; j < elt_times; ++j, ++k) {
v_subscript[k] = i;
}
}
r_obj* out = vec_slice_unsafe(x, subscript);
FREE(1);
return out;
}function: t(any_sexp, *t(any_sexp, any_sexp, *c_void) --> any_sexp, *c_void) --> any_sexp
argument: t('I5703, t(any_sexp, any_sexp, *c_void) -> c_null, *{ names : null ; dim : null ; dim_names : null ; row_names : null })r_obj* vec_restore_default(r_obj* x, r_obj* to, enum vctrs_ownership ownership) {
if (x == to) {
// Rare but useful pointer comparison
return x;
}
if (!r_attrib_has_any(x) && !r_attrib_has_any(to)) {
// No one has attributes (nothing to clear, nothing to add).
// Don't need to worry about OBJECT/S4 bit, you'd always have at least one attribute.
return x;
}
// Note: Could this be `R_tryWrap()` one day? For backwards compatibility with
// R < 4.6, maybe we would have our own ALTREP wrapper class implementation?
// https://github.com/wch/r-source/commit/84293ec070c219b9ad2df44ae84d3f0f58d5ce7c
x = KEEP(vec_clone_referenced(x, ownership));
// In one pass, collect attributes we want to retain from `x`
struct vec_restore_collect_data data = {
.names = r_null,
.dim = r_null,
.dim_names = r_null,
.row_names = r_null
};
r_attrib_map(x, vec_restore_collect_cb, &data);
r_obj* names = KEEP(data.names);
r_obj* dim = KEEP(data.dim);
r_obj* dim_names = KEEP(data.dim_names);
r_obj* row_names = KEEP(data.row_names);
if (dim == r_null) {
// This is a vector, clear any `dim` or `dim_names`
dim_names = r_null;
} else {
// This is an array, clear any `names` or `row_names`
names = r_null;
row_names = r_null;
}
// We don't actually retain row names if `to` isn't a data frame
if (row_names != r_null && !is_data_frame(to)) {
row_names = r_null;
}
// Copy over all attributes from `to`
//
// Uses `SHALLOW_DUPLICATE_ATTRIB()`. Notably:
// - Shallow clones attribute pairlist from `to`
// - `SET_ATTRIB()` for efficiency and avoids
// `Rf_getAttrib()`/`Rf_setAttrib()` funny business
// - `SET_OBJECT()`
// - `SET_S4_OBJECT()` / `UNSET_S4_OBJECT()`
r_attrib_clone_from(x, to);
// Retain specific attributes from `x`
//
// We must set all 4! If `to` had `names` but `x` does not, then `names` will
// be `r_null` and will clear the `names` brought over by
// `r_attrib_clone_from()`.
r_attrib_poke(x, r_syms.names, names);
r_attrib_poke(x, r_syms.dim, dim);
r_attrib_poke(x, r_syms.dim_names, dim_names);
r_attrib_poke(x, r_syms.row_names, row_names);
FREE(5);
return x;
}function: t(~c(..-1), ~c(..-1), c_true) --> int3 argument: t(any, ~c_false, c_false)
r_obj* vec_reverse(r_obj* x) {
const r_ssize size = vec_size(x);
const r_ssize start = (size == 0) ? 0 : size - 1;
const bool increasing = false;
r_obj* index = KEEP(compact_seq(start, size, increasing));
r_obj* out = vec_slice_unsafe(x, index);
FREE(1);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
r_obj* vec_set_difference(r_obj* x,
r_obj* y,
r_obj* ptype,
struct vctrs_arg* x_arg,
struct vctrs_arg* y_arg,
struct r_lazy call) {
int n_prot = 0;
if (ptype == r_null) {
int _;
ptype = vec_ptype2(
x,
y,
x_arg,
y_arg,
call,
S3_FALLBACK_false,
&_
);
KEEP_N(ptype, &n_prot);
ptype = vec_ptype_finalise(ptype);
KEEP_N(ptype, &n_prot);
}
x = vec_cast_params(
x,
ptype,
x_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(x, &n_prot);
y = vec_cast_params(
y,
ptype,
y_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(y, &n_prot);
r_obj* x_proxy = KEEP_N(vec_proxy_equal(x), &n_prot);
x_proxy = KEEP_N(obj_encode_utf8(x_proxy), &n_prot);
r_obj* y_proxy = KEEP_N(vec_proxy_equal(y), &n_prot);
y_proxy = KEEP_N(obj_encode_utf8(y_proxy), &n_prot);
const r_ssize x_size = vec_size(x_proxy);
const r_ssize y_size = vec_size(y_proxy);
struct dictionary* x_dict = new_dictionary(x_proxy);
PROTECT_DICT(x_dict, &n_prot);
struct dictionary* y_dict = new_dictionary_partial(y_proxy);
PROTECT_DICT(y_dict, &n_prot);
r_obj* marked_shelter = KEEP_N(r_alloc_raw(x_size * sizeof(bool)), &n_prot);
bool* v_marked = (bool*) r_raw_begin(marked_shelter);
vec_set_difference_loop(x_dict, y_dict, x_size, y_size, v_marked);
r_ssize n_marked = 0;
for (r_ssize i = 0; i < x_size; ++i) {
n_marked += v_marked[i];
}
r_obj* loc = KEEP_N(r_alloc_integer(n_marked), &n_prot);
int* v_loc = r_int_begin(loc);
r_ssize j = 0;
for (r_ssize i = 0; i < x_size; ++i) {
if (v_marked[i]) {
v_loc[j] = i + 1;
++j;
}
}
r_obj* out = vec_slice_unsafe(x, loc);
FREE(n_prot);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
r_obj* vec_set_intersect(r_obj* x,
r_obj* y,
r_obj* ptype,
struct vctrs_arg* x_arg,
struct vctrs_arg* y_arg,
struct r_lazy call) {
int n_prot = 0;
if (ptype == r_null) {
int _;
ptype = vec_ptype2(
x,
y,
x_arg,
y_arg,
call,
S3_FALLBACK_false,
&_
);
KEEP_N(ptype, &n_prot);
ptype = vec_ptype_finalise(ptype);
KEEP_N(ptype, &n_prot);
}
x = vec_cast_params(
x,
ptype,
x_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(x, &n_prot);
y = vec_cast_params(
y,
ptype,
y_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(y, &n_prot);
r_obj* x_proxy = KEEP_N(vec_proxy_equal(x), &n_prot);
x_proxy = KEEP_N(obj_encode_utf8(x_proxy), &n_prot);
r_obj* y_proxy = KEEP_N(vec_proxy_equal(y), &n_prot);
y_proxy = KEEP_N(obj_encode_utf8(y_proxy), &n_prot);
const r_ssize x_size = vec_size(x_proxy);
const r_ssize y_size = vec_size(y_proxy);
struct dictionary* x_dict = new_dictionary(x_proxy);
PROTECT_DICT(x_dict, &n_prot);
struct dictionary* y_dict = new_dictionary_partial(y_proxy);
PROTECT_DICT(y_dict, &n_prot);
r_obj* marked_shelter = KEEP_N(r_alloc_raw(x_size * sizeof(bool)), &n_prot);
bool* v_marked = (bool*) r_raw_begin(marked_shelter);
r_memset(v_marked, 0, x_size * sizeof(bool));
vec_set_intersect_loop(x_dict, y_dict, x_size, y_size, v_marked);
r_ssize n_marked = 0;
for (r_ssize i = 0; i < x_size; ++i) {
n_marked += v_marked[i];
}
r_obj* loc = KEEP_N(r_alloc_integer(n_marked), &n_prot);
int* v_loc = r_int_begin(loc);
r_ssize j = 0;
for (r_ssize i = 0; i < x_size; ++i) {
if (v_marked[i]) {
v_loc[j] = i + 1;
++j;
}
}
r_obj* out = vec_slice_unsafe(x, loc);
FREE(n_prot);
return out;
}function: t(<...>, any_sexp, c_false, c(0..2)) --> any_sexp
argument: t('I7229 & ((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym), null & 'I7230, c_bool & 'I7231, c(0..2) & 'I7232)r_obj* vec_set_names_impl(r_obj* x, r_obj* names, bool proxy, const enum vctrs_ownership ownership) {
check_names(x, names);
if (is_data_frame(x)) {
return vec_set_df_rownames(x, names, proxy, ownership);
}
if (has_dim(x)) {
return vec_set_rownames(x, names, proxy, ownership);
}
if (!proxy && r_is_object(x)) {
return set_names_dispatch(x, names);
}
// Early exit if no new names and no existing names
if (names == r_null && r_attrib_get(x, r_syms.names) == r_null) {
return x;
}
switch (ownership) {
case VCTRS_OWNERSHIP_foreign: {
// We likely need to clone, but to do this we will use `names<-`
// which can perform a cheaper ALTREP shallow duplication
x = KEEP(set_names_dispatch(x, names));
break;
}
case VCTRS_OWNERSHIP_shallow:
case VCTRS_OWNERSHIP_deep: {
// This ends up skipping the cloning altogether
x = KEEP(vec_clone_referenced(x, ownership));
r_attrib_poke(x, r_syms.names, names);
break;
}
default: r_stop_unreachable();
}
FREE(1);
return x;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
r_obj* vec_set_symmetric_difference(r_obj* x,
r_obj* y,
r_obj* ptype,
struct vctrs_arg* x_arg,
struct vctrs_arg* y_arg,
struct r_lazy call) {
int n_prot = 0;
if (ptype == r_null) {
int _;
ptype = vec_ptype2(
x,
y,
x_arg,
y_arg,
call,
S3_FALLBACK_false,
&_
);
KEEP_N(ptype, &n_prot);
ptype = vec_ptype_finalise(ptype);
KEEP_N(ptype, &n_prot);
}
x = vec_cast_params(
x,
ptype,
x_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(x, &n_prot);
y = vec_cast_params(
y,
ptype,
y_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(y, &n_prot);
r_obj* x_proxy = KEEP_N(vec_proxy_equal(x), &n_prot);
x_proxy = KEEP_N(obj_encode_utf8(x_proxy), &n_prot);
r_obj* y_proxy = KEEP_N(vec_proxy_equal(y), &n_prot);
y_proxy = KEEP_N(obj_encode_utf8(y_proxy), &n_prot);
const r_ssize x_size = vec_size(x_proxy);
const r_ssize y_size = vec_size(y_proxy);
struct dictionary* x_dict = new_dictionary(x_proxy);
PROTECT_DICT(x_dict, &n_prot);
struct dictionary* y_dict = new_dictionary(y_proxy);
PROTECT_DICT(y_dict, &n_prot);
r_obj* x_marked_shelter = KEEP_N(r_alloc_raw(x_size * sizeof(bool)), &n_prot);
bool* v_x_marked = (bool*) r_raw_begin(x_marked_shelter);
r_obj* y_marked_shelter = KEEP_N(r_alloc_raw(y_size * sizeof(bool)), &n_prot);
bool* v_y_marked = (bool*) r_raw_begin(y_marked_shelter);
const struct r_ssize_pair n_marked = vec_set_symmetric_difference_loop(
x_dict,
y_dict,
x_size,
y_size,
v_x_marked,
v_y_marked
);
const r_ssize n_x_marked = n_marked.x;
const r_ssize n_y_marked = n_marked.y;
r_obj* loc = KEEP_N(r_alloc_integer(n_x_marked), &n_prot);
int* v_loc = r_int_begin(loc);
r_ssize j = 0;
for (r_ssize i = 0; i < x_size; ++i) {
if (v_x_marked[i]) {
v_loc[j] = i + 1;
++j;
}
}
// Slice out `x`, then reuse `loc` for slicing `y`
x = KEEP_N(vec_slice_unsafe(x, loc), &n_prot);
loc = KEEP_N(r_int_resize(loc, n_y_marked), &n_prot);
v_loc = r_int_begin(loc);
j = 0;
for (r_ssize i = 0; i < y_size; ++i) {
if (v_y_marked[i]) {
v_loc[j] = i + 1;
++j;
}
}
y = KEEP_N(vec_slice_unsafe(y, loc), &n_prot);
const struct name_repair_opts name_repair_opts = {
.type = NAME_REPAIR_none,
.fn = r_null
};
r_obj* args = KEEP_N(r_alloc_list(2), &n_prot);
r_list_poke(args, 0, x);
r_list_poke(args, 1, y);
r_obj* out = vec_c(
args,
ptype,
r_null,
&name_repair_opts,
vec_args.empty,
r_lazy_null
);
FREE(n_prot);
return out;
}function: t((env | externalptr | lang | list | vec | arrow) | null | p(chr) | sym) --> any_sexp argument: t(any_sexp)
r_obj* vec_set_union(r_obj* x,
r_obj* y,
r_obj* ptype,
struct vctrs_arg* x_arg,
struct vctrs_arg* y_arg,
struct r_lazy call) {
int n_prot = 0;
if (ptype == r_null) {
int _;
ptype = vec_ptype2(
x,
y,
x_arg,
y_arg,
call,
S3_FALLBACK_false,
&_
);
KEEP_N(ptype, &n_prot);
ptype = vec_ptype_finalise(ptype);
KEEP_N(ptype, &n_prot);
}
x = vec_cast_params(
x,
ptype,
x_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(x, &n_prot);
y = vec_cast_params(
y,
ptype,
y_arg,
vec_args.empty,
call,
S3_FALLBACK_false
);
KEEP_N(y, &n_prot);
r_obj* x_proxy = KEEP_N(vec_proxy_equal(x), &n_prot);
x_proxy = KEEP_N(obj_encode_utf8(x_proxy), &n_prot);
r_obj* y_proxy = KEEP_N(vec_proxy_equal(y), &n_prot);
y_proxy = KEEP_N(obj_encode_utf8(y_proxy), &n_prot);
const r_ssize x_size = vec_size(x_proxy);
const r_ssize y_size = vec_size(y_proxy);
struct dictionary* x_dict = new_dictionary(x_proxy);
PROTECT_DICT(x_dict, &n_prot);
struct dictionary* y_dict = new_dictionary(y_proxy);
PROTECT_DICT(y_dict, &n_prot);
r_obj* marked_shelter = KEEP_N(r_alloc_raw(x_size * sizeof(bool)), &n_prot);
bool* v_marked = (bool*) r_raw_begin(marked_shelter);
const r_ssize n_x_marked = vec_set_union_x_loop(
x_dict,
x_size,
v_marked
);
r_obj* loc = KEEP_N(r_alloc_integer(n_x_marked), &n_prot);
int* v_loc = r_int_begin(loc);
r_ssize j = 0;
for (r_ssize i = 0; i < x_size; ++i) {
if (v_marked[i]) {
v_loc[j] = i + 1;
++j;
}
}
// Go ahead and slice out `x`
x = KEEP_N(vec_slice_unsafe(x, loc), &n_prot);
// Resize `v_marked` for use with `y`
marked_shelter = KEEP_N(r_raw_resize(marked_shelter, y_size * sizeof(bool)), &n_prot);
v_marked = (bool*) r_raw_begin(marked_shelter);
const r_ssize n_y_marked = vec_set_union_y_loop(
x_dict,
y_dict,
x_size,
y_size,
v_marked
);
loc = KEEP_N(r_int_resize(loc, n_y_marked), &n_prot);
v_loc = r_int_begin(loc);
j = 0;
for (r_ssize i = 0; i < y_size; ++i) {
if (v_marked[i]) {
v_loc[j] = i + 1;
++j;
}
}
y = KEEP_N(vec_slice_unsafe(y, loc), &n_prot);
const struct name_repair_opts name_repair_opts = {
.type = NAME_REPAIR_none,
.fn = r_null
};
r_obj* args = KEEP_N(r_alloc_list(2), &n_prot);
r_list_poke(args, 0, x);
r_list_poke(args, 1, y);
r_obj* out = vec_c(
args,
ptype,
r_null,
&name_repair_opts,
vec_args.empty,
r_lazy_null
);
FREE(n_prot);
return out;
}function: t(int[^(int \ 0)], int[^(int \ 0)], any_sexp, any_sexp, x1, x1) --> empty where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(p(chr) | sym | attr_any, p(chr) | sym | attr_any, any_sexp & 'I23456, any_sexp & 'I23457, *x1 & 'I23458, *x1 & 'I23459) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_obj* vec_shape2(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg
) {
r_obj* x_dimensions = r_dim(x);
if (x_dimensions == r_null) {
r_obj* y_dimensions = r_dim(y);
if (y_dimensions == r_null) {
return r_null;
} else {
KEEP(y_dimensions);
r_obj* out = dims_shape(y_dimensions);
FREE(1);
return out;
}
} else {
KEEP(x_dimensions);
r_obj* y_dimensions = r_dim(y);
if (y_dimensions == r_null) {
r_obj* out = dims_shape(x_dimensions);
FREE(1);
return out;
} else {
KEEP(y_dimensions);
r_obj* out = dims_shape2(x_dimensions, y_dimensions, x, y, p_x_arg, p_y_arg);
FREE(2);
return out;
}
}
}function: t(any_sexp, *x1, *x1, any_sexp, t(any_sexp, any_sexp, *{ shelter : any_sexp ; names : any_sexp ; curr_arg : *x1 ; next_arg : *x1 ; curr : any ; next : any ; curr_counter : x1 ; next_counter : x1 ; curr_counter_arg_data : { i : *any ; names : *any_sexp ; p_parent : *x1 } ; next_counter_arg_data : { i : *any ; names : *any_sexp ; p_parent : *x1 } ; p_data : *c_void }, *c_void) --> any_sexp, *c_void) --> any_sexp where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(null, *x2, *x3 & 'I5241, any_sexp & 'I5239, *(t(any_sexp, any_sexp, *{ shelter : any_sexp ; names : any_sexp ; curr_arg : *x1 ; next_arg : *x1 ; curr : any ; next : any ; curr_counter : x1 ; next_counter : x1 ; curr_counter_arg_data : { i : *any ; names : *any_sexp ; p_parent : *x1 } ; next_counter_arg_data : { i : *any ; names : *any_sexp ; p_parent : *x1 } ; p_data : *c_void }, *c_void) -> empty), *{ call : 'I5242 ; current_size : c(-1) }) where x1 = { shelter : any_sexp ; parent : *x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void } and x2 = { shelter : any_sexp ; parent : *x2 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void } and x3 = { shelter : any_sexp ; parent : *x3 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }r_ssize vec_size_common(
r_obj* xs,
r_ssize absent,
struct vctrs_arg* p_xs_arg,
struct r_lazy call
) {
struct size_common_reduce_opts reduce_opts = {
.current_size = -1,
.call = call
};
// Interested in `reduce_opts.current_size`,
// not in the returned `r_obj*` from `reduce()`
reduce(
r_null,
vec_args.empty,
p_xs_arg,
xs,
&size2_common,
&reduce_opts
);
r_ssize out = reduce_opts.current_size;
if (out == -1) {
out = absent;
}
return out;
}function: t(any_sexp, any_sexp, c_null) --> empty & t((env<> | externalptr<> | lang<> | list<> | vec<> | arrow<>) | null | p(chr) | sym, any_sexp, *{ call : { x : any_sexp ; env : any_sexp } ; x_arg : x1 ; i_arg : x1 }) --> any_sexp where x1 = *{ shelter : any_sexp ; parent : x1 ; fill : t(*c_void, c_string, any) --> any ; data : *c_void }
argument: t(any_sexp & 'I23014, any_sexp & 'I23015, *(*c_false))r_obj* vec_slice(r_obj* x, r_obj* i) {
const struct vec_slice_opts opts = { 0 };
return vec_slice_opts(x, i, &opts);
}name: PROTECT_STRIDES_INFO
SEXP vec_slice_shaped(enum vctrs_type type, SEXP x, SEXP index) {
int n_protect = 0;
struct strides_info info = new_strides_info(x, index);
PROTECT_STRIDES_INFO(&info, &n_protect);
SEXP out = vec_slice_shaped_base(type, x, index, &info);
UNPROTECT(n_protect);
return out;
}function: t({ 'I8089 }, c_int) --> 'I8089
argument: t(p(chr) | sym | attr_any, c_false)r_obj* vec_slice_unsafe(r_obj* x, r_obj* subscript) {
int nprot = 0;
struct vctrs_proxy_info info = vec_proxy_info(x);
KEEP_N(info.inner, &nprot);
// Fallback to `[` if the class doesn't implement a proxy. This is
// to be maximally compatible with existing classes.
if (vec_requires_fallback(x, info)) {
if (info.type == VCTRS_TYPE_scalar) {
obj_check_vector(x, VCTRS_ALLOW_NULL_no, NULL, r_lazy_null);
}
subscript = KEEP_N(vec_subscript_materialize(subscript), &nprot);
r_obj* out;
if (has_dim(x)) {
out = KEEP_N(vec_slice_fallback(x, subscript), &nprot);
} else {
out = KEEP_N(vec_slice_dispatch(x, subscript), &nprot);
}
// Take over attribute restoration only if there is no `[` method
if (!vec_is_restored(out, x)) {
// Sliced `out` comes from R, so is foreign. Technically not proxied at all,
// so "restoring" is a bit of a hack, but we only restore if it looks like the
// `[` result is missing attributes.
struct vec_restore_opts restore_opts = {
.ownership = VCTRS_OWNERSHIP_foreign,
.recursively_proxied = false
};
out = vec_restore_opts(out, x, &restore_opts);
}
FREE(nprot);
return out;
}
switch (info.type) {
case VCTRS_TYPE_null:
r_stop_internal("Unexpected `NULL`.");
case VCTRS_TYPE_logical:
case VCTRS_TYPE_integer:
case VCTRS_TYPE_double:
case VCTRS_TYPE_complex:
case VCTRS_TYPE_character:
case VCTRS_TYPE_raw:
case VCTRS_TYPE_list: {
r_obj* out;
if (has_dim(x)) {
out = KEEP_N(vec_slice_shaped(info.type, info.inner, subscript), &nprot);
r_obj* names = KEEP_N(r_attrib_get(x, r_syms.dim_names), &nprot);
if (names != r_null) {
names = KEEP_N(r_clone(names), &nprot);
r_obj* row_names = r_list_get(names, 0);
row_names = KEEP_N(slice_names(row_names, subscript), &nprot);
r_list_poke(names, 0, row_names);
r_attrib_poke(out, r_syms.dim_names, names);
}
} else {
out = KEEP_N(vec_slice_base(info.type, info.inner, subscript, VCTRS_MATERIALIZE_false), &nprot);
r_obj* names = KEEP_N(r_names(x), &nprot);
names = KEEP_N(slice_names(names, subscript), &nprot);
r_attrib_poke_names(out, names);
}
// Sliced `out` is a fresh object from `vec_slice_base()` or
// `vec_slice_shaped()` that we control (and we even modify names directly
// above). For atomics, shallow and deep ownership are the same. We mark as
// shallow just for consistency with the data frame path.
struct vec_restore_opts restore_opts = {
.ownership = VCTRS_OWNERSHIP_shallow,
.recursively_proxied = false
};
out = vec_restore_opts(out, x, &restore_opts);
FREE(nprot);
return out;
}
case VCTRS_TYPE_dataframe: {
r_obj* out = KEEP_N(df_slice(info.inner, subscript), &nprot);
// Sliced `out` is a fresh list container from `df_slice()`, but we don't
// necessarily own the sliced columns (an individual column could have gone
// through the fallback path) so we set shallow ownership. This is fine, we
// don't restore recursively here, so only the list container will need to
// be modified during restoration.
struct vec_restore_opts restore_opts = {
.ownership = VCTRS_OWNERSHIP_shallow,
.recursively_proxied = false
};
out = vec_restore_opts(out, x, &restore_opts);
FREE(nprot);
return out;
}
default:
stop_unimplemented_vctrs_type("vec_slice_impl", info.type);
}
}function: t(raw) --> lgl argument: t(^int & 'I5505)
SEXP vec_subscript_materialize(SEXP x) {
if (is_compact_rep(x)) {
return compact_rep_materialize(x);
} else if (is_compact_seq(x)) {
return compact_seq_materialize(x);
} else if (is_compact_condition(x)) {
return compact_condition_materialize(x);
} else {
return x;
}
}function: t(chr, any, c_bool) --> any_sexp & t(null, any, c_bool) --> empty argument: t(any_sexp, any, c_bool & 'I36528)
r_obj* vec_unique_names(r_obj* x, bool quiet) {
r_obj* names = KEEP(vec_names(x));
r_obj* out = vec_unique_names_impl(names, vec_size(x), quiet);
FREE(1);
return out;
}function: t(p(chr) | vec, c_int_na | c_double) --> () argument: t(list, c_int)
r_obj* vec_unrep(r_obj* x, struct r_lazy error_call) {
r_obj* times = KEEP(vec_run_sizes(x, error_call));
const int* v_times = r_int_cbegin(times);
const r_ssize size = r_length(times);
r_obj* loc = KEEP(r_alloc_integer(size));
int* v_loc = r_int_begin(loc);
r_ssize current = 1;
for (r_ssize i = 0; i < size; ++i) {
v_loc[i] = current;
current += v_times[i];
}
r_obj* out = KEEP(r_new_list(2));
r_list_poke(out, 0, vec_slice_unsafe(x, loc));
r_list_poke(out, 1, times);
r_obj* names = r_new_character(2);
r_attrib_poke_names(out, names);
r_chr_poke(names, 0, strings_key);
r_chr_poke(names, 1, strings_times);
init_data_frame(out, size);
FREE(3);
return out;
}r_obj* chop(r_obj* x,
struct vctrs_proxy_info info,
struct vctrs_chop_indices* p_indices) {
r_obj* proxy = info.inner;
r_obj* names = KEEP(r_names(proxy));
const enum vctrs_type type = info.type;
const r_ssize out_size = indices_out_size(p_indices, proxy);
r_obj* out = KEEP(r_alloc_list(out_size));
// Treat `elt` as owned after slicing (we also poke its names directly).
// `vec_proxy_info()` doesn't recursively proxy.
const struct vec_restore_opts elt_restore_opts = {
.ownership = VCTRS_OWNERSHIP_shallow,
.recursively_proxied = false
};
for (r_ssize i = 0; i < out_size; ++i) {
r_obj* index = indices_next(p_indices);
// Always materialize ALTREP vectors when chopping to avoid inefficiently
// creating a large amount of small ALTREP objects that are used downstream.
// This is a heuristic and we should also be on the lookout for cases where
// we chop to create a small amount of large ALTREP objects that are
// quickly discarded (#1450).
r_obj* elt = KEEP(vec_slice_base(
type,
proxy,
index,
VCTRS_MATERIALIZE_true
));
if (names != r_null) {
r_obj* elt_names = slice_names(names, index);
r_attrib_poke_names(elt, elt_names);
}
elt = vec_restore_opts(elt, x, &elt_restore_opts);
r_list_poke(out, i, elt);
FREE(1);
}
FREE(2);
return out;
}void chr_order(
SEXP x,
bool decreasing,
bool na_last,
r_ssize size,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct group_infos* p_group_infos
) {
const SEXP* p_x = STRING_PTR_RO(x);
const enum vctrs_sortedness sortedness = chr_sortedness(
p_x,
size,
decreasing,
na_last,
p_group_infos
);
// Handle sorted cases and set ordering to initialized
if (sortedness != VCTRS_SORTEDNESS_unsorted) {
int* p_o = p_order->p_data;
ord_resolve_sortedness(sortedness, size, p_o);
p_order->initialized = true;
return;
}
int* p_o = init_order(p_order);
const char** p_x_chunk = (const char**) init_lazy_raw(p_lazy_x_chunk);
// Extract out `CHAR()` string pointers and `Rf_length()` string sizes,
// skipping missings along the way, but returning the count of them and
// the max string size
const struct r_ssize_int_pair pair = chr_extract_without_missings(
size,
p_x,
p_x_chunk
);
const r_ssize n_missing = pair.x;
const int max_string_size = pair.y;
if (n_missing != 0) {
// If there are missings, handle them by pushing their ordering to the front
// (or back, depending on `na_last`) of `p_o`
int* p_o_aux = init_lazy_raw(p_lazy_o_aux);
chr_handle_missings(
size,
n_missing,
na_last,
p_x,
p_o,
p_o_aux
);
size -= n_missing;
p_o = na_last ? p_o : (p_o + n_missing);
}
if (!na_last && n_missing != 0) {
// Push `na_last` group before sorting
groups_size_maybe_push(n_missing, p_group_infos);
}
if (size <= ORDER_INSERTION_BOUNDARY) {
chr_order_insertion(
size,
decreasing,
p_x_chunk,
p_o,
p_group_infos
);
} else {
const char** p_x_aux = (const char**) init_lazy_raw(p_lazy_x_aux);
int* p_o_aux = (int*) init_lazy_raw(p_lazy_o_aux);
uint8_t* p_bytes = (uint8_t*) init_lazy_raw(p_lazy_bytes);
chr_order_radix(
size,
decreasing,
max_string_size,
p_x_chunk,
p_o,
p_x_aux,
p_o_aux,
p_bytes,
p_group_infos
);
}
if (na_last && n_missing != 0) {
// Push `na_last` group after sorting
groups_size_maybe_push(n_missing, p_group_infos);
}
}enum vctrs_sortedness chr_sortedness(const SEXP* p_x,
r_ssize size,
bool decreasing,
bool na_last,
struct group_infos* p_group_infos) {
if (size == 0) {
return VCTRS_SORTEDNESS_sorted;
}
if (size == 1) {
groups_size_maybe_push(1, p_group_infos);
return VCTRS_SORTEDNESS_sorted;
}
const int direction = decreasing ? -1 : 1;
const int na_order = na_last ? 1 : -1;
SEXP previous = p_x[0];
const char* previous_string = CHAR(previous);
r_ssize count = 0;
// Check for strictly opposite of expected order
// (ties are not allowed so we can reverse the vector stably)
for (r_ssize i = 1; i < size; ++i, ++count) {
SEXP current = p_x[i];
const char* current_string = CHAR(current);
int cmp = str_cmp_maybe_na(
current,
previous,
current_string,
previous_string,
direction,
na_order
);
if (cmp >= 0) {
break;
}
previous = current;
previous_string = current_string;
}
// Was in strictly opposite of expected order.
if (count == size - 1) {
// Each group is size 1 since this is strict ordering
for (r_ssize j = 0; j < size; ++j) {
groups_size_maybe_push(1, p_group_infos);
}
return VCTRS_SORTEDNESS_reversed;
}
// Was partially in expected order. Need to sort.
if (count != 0) {
return VCTRS_SORTEDNESS_unsorted;
}
// Retain the original `n_groups` to be able to reset the group sizes if
// it turns out we don't have expected ordering
struct group_info* p_group_info = groups_current(p_group_infos);
r_ssize original_n_groups = p_group_info->n_groups;
r_ssize group_size = 1;
// Check for expected ordering - allowing ties since we don't have to
// reverse the ordering.
for (r_ssize i = 1; i < size; ++i) {
SEXP current = p_x[i];
const char* current_string = CHAR(current);
int cmp = str_cmp_maybe_na(
current,
previous,
current_string,
previous_string,
direction,
na_order
);
// Not expected ordering
if (cmp < 0) {
p_group_info->n_groups = original_n_groups;
return VCTRS_SORTEDNESS_unsorted;
}
previous = current;
previous_string = current_string;
// Continue group run
if (cmp == 0) {
++group_size;
continue;
}
// Expected ordering
groups_size_maybe_push(group_size, p_group_infos);
group_size = 1;
}
// Push final group run
groups_size_maybe_push(group_size, p_group_infos);
// Expected ordering
return VCTRS_SORTEDNESS_sorted;
}void counters_shift(struct counters* p_counters) {
// Swap the counters data
SWAP(struct vctrs_arg, p_counters->curr_counter, p_counters->next_counter);
SWAP(r_ssize*, p_counters->curr_counter_arg_data.i, p_counters->next_counter_arg_data.i);
// Update the handles to `vctrs_arg`
p_counters->curr_arg = (struct vctrs_arg*) &p_counters->curr_counter;
p_counters->next_arg = (struct vctrs_arg*) &p_counters->next_counter;
// Update the current index
p_counters->curr = p_counters->next;
}enum vctrs_sortedness dbl_sortedness(const double* p_x,
r_ssize size,
bool decreasing,
bool na_last,
bool nan_distinct,
struct group_infos* p_group_infos) {
if (size == 0) {
return VCTRS_SORTEDNESS_sorted;
}
if (size == 1) {
groups_size_maybe_push(1, p_group_infos);
return VCTRS_SORTEDNESS_sorted;
}
const int direction = decreasing ? -1 : 1;
const int na_order = na_last ? 1 : -1;
const int na_nan_order = nan_distinct ? na_order : 0;
double previous = p_x[0];
enum vctrs_dbl previous_type = dbl_classify(previous);
r_ssize count = 0;
// Check for strictly opposite of expected order
// (ties are not allowed so we can reverse the vector stably)
for (r_ssize i = 1; i < size; ++i, ++count) {
double current = p_x[i];
enum vctrs_dbl current_type = dbl_classify(current);
int cmp = dbl_cmp(
current,
previous,
current_type,
previous_type,
direction,
na_order,
na_nan_order
);
if (cmp >= 0) {
break;
}
previous = current;
previous_type = current_type;
}
// Was in strictly opposite of expected order.
if (count == size - 1) {
// Each group is size 1 since this is strict ordering
for (r_ssize j = 0; j < size; ++j) {
groups_size_maybe_push(1, p_group_infos);
}
return VCTRS_SORTEDNESS_reversed;
}
// Was partially in expected order. Need to sort.
if (count != 0) {
return VCTRS_SORTEDNESS_unsorted;
}
// Retain the original `n_groups` to be able to reset the group sizes if
// it turns out we don't have expected ordering
struct group_info* p_group_info = groups_current(p_group_infos);
r_ssize original_n_groups = p_group_info->n_groups;
r_ssize group_size = 1;
// Check for expected ordering - allowing ties since we don't have to
// reverse the ordering.
for (r_ssize i = 1; i < size; ++i) {
double current = p_x[i];
enum vctrs_dbl current_type = dbl_classify(current);
int cmp = dbl_cmp(
current,
previous,
current_type,
previous_type,
direction,
na_order,
na_nan_order
);
// Not expected ordering
if (cmp < 0) {
p_group_info->n_groups = original_n_groups;
return VCTRS_SORTEDNESS_unsorted;
}
previous = current;
previous_type = current_type;
// Continue group run
if (cmp == 0) {
++group_size;
continue;
}
// Expected ordering
groups_size_maybe_push(group_size, p_group_infos);
group_size = 1;
}
// Push final group run
groups_size_maybe_push(group_size, p_group_infos);
// Expected ordering
return VCTRS_SORTEDNESS_sorted;
}void df_order(
SEXP x,
SEXP decreasing,
SEXP na_last,
bool nan_distinct,
r_ssize size,
struct order* p_order,
struct lazy_raw* p_lazy_x_chunk,
struct lazy_raw* p_lazy_x_aux,
struct lazy_raw* p_lazy_o_aux,
struct lazy_raw* p_lazy_bytes,
struct lazy_raw* p_lazy_counts,
struct group_infos* p_group_infos
) {
r_ssize n_cols = r_length(x);
bool recycle_decreasing;
r_ssize n_decreasing = r_length(decreasing);
int* p_decreasing = LOGICAL(decreasing);
if (n_decreasing == 1) {
recycle_decreasing = true;
} else if (n_decreasing == n_cols) {
recycle_decreasing = false;
} else {
Rf_errorcall(
R_NilValue,
"Internal error: `vec_order_expand_args()` should expand "
"`decreasing` to have length 1 or length equal "
"to the number of columns of `x` after calling `vec_proxy_order()`."
);
}
bool recycle_na_last;
r_ssize n_na_last = r_length(na_last);
int* p_na_last = LOGICAL(na_last);
if (n_na_last == 1) {
recycle_na_last = true;
} else if (n_na_last == n_cols) {
recycle_na_last = false;
} else {
Rf_errorcall(
R_NilValue,
"Internal error: `vec_order_expand_args()` should expand "
"`na_last` to have length 1 or length equal "
"to the number of columns of `x` after calling `vec_proxy_order()`."
);
}
// Special case no columns
if (n_cols == 0) {
init_order(p_order);
if (size != 0) {
groups_size_maybe_push(size, p_group_infos);
}
return;
}
SEXP col = VECTOR_ELT(x, 0);
bool col_decreasing = p_decreasing[0];
bool col_na_last = p_na_last[0];
enum vctrs_type type = vec_proxy_typeof(col);
// Apply on one column to fill `p_group_infos`.
// First column is immutable and we must copy into `x_chunk`.
vec_order_base_switch(
col,
col_decreasing,
col_na_last,
nan_distinct,
size,
type,
p_order,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
// For complex, we have to rerun the column a second time on the
// imaginary part. This is done by decrementing `i` after processing
// the real part so the column is rerun.
bool complex_first_pass = true;
// Iterate over remaining columns by group chunk
for (r_ssize i = 1; i < n_cols; ++i) {
// Get the number of group chunks from previous column group info
struct group_info* p_group_info_pre = groups_current(p_group_infos);
r_ssize n_groups = p_group_info_pre->n_groups;
// If there were no ties, we are completely done
if (n_groups == size) {
break;
}
if (!recycle_decreasing) {
col_decreasing = p_decreasing[i];
}
if (!recycle_na_last) {
col_na_last = p_na_last[i];
}
// Reset pointer between columns since we increment it as
// we iterate through the groups, but need it to start from the beginning
// on the next column. `p_o` is initialized now that we have already
// processed at least one column.
int* p_o_col = p_order->p_data;
col = VECTOR_ELT(x, i);
type = vec_proxy_typeof(col);
// Turn off group tracking if:
// - We are on the last column
// - The user didn't request group information
// - That column isn't the first pass of a complex column
if (i == n_cols - 1 && !p_group_infos->force_groups && !complex_first_pass) {
p_group_infos->ignore_groups = true;
}
// Swap to other group info to prepare for this column
groups_swap(p_group_infos);
// Iterate over this column's group chunks
for (r_ssize group = 0; group < n_groups; ++group) {
r_ssize group_size = p_group_info_pre->p_data[group];
// Fast handling of simplest case
if (group_size == 1) {
++p_o_col;
groups_size_maybe_push(1, p_group_infos);
continue;
}
// Extract current chunk and place into `x_chunk` in sequential order
switch (type) {
case VCTRS_TYPE_integer: DF_ORDER_EXTRACT_CHUNK(INTEGER_RO, int); break;
case VCTRS_TYPE_logical: DF_ORDER_EXTRACT_CHUNK(LOGICAL_RO, int); break;
case VCTRS_TYPE_double: DF_ORDER_EXTRACT_CHUNK(REAL_RO, double); break;
case VCTRS_TYPE_character: DF_ORDER_EXTRACT_CHUNK(STRING_PTR_RO, SEXP); break;
case VCTRS_TYPE_complex: DF_ORDER_EXTRACT_CHUNK_CPL(); break;
default: Rf_errorcall(R_NilValue, "Unknown data frame column type in `vec_order()`.");
}
vec_order_chunk_switch(
col_decreasing,
col_na_last,
nan_distinct,
group_size,
type,
p_o_col,
p_lazy_x_chunk,
p_lazy_x_aux,
p_lazy_o_aux,
p_lazy_bytes,
p_lazy_counts,
p_group_infos
);
p_o_col += group_size;
}
if (type == VCTRS_TYPE_complex) {
if (complex_first_pass) {
// Transition from first pass to second pass
complex_first_pass = false;
// Decrement `i` so we reuse this column
--i;
} else {
// Reset flag for future complex columns
complex_first_pass = true;
}
}
}
}int find_offset(SEXP x, SEXP index) {
if (Rf_length(index) != 1) {
Rf_errorcall(R_NilValue, "Invalid index: must have length 1");
}
int n = Rf_length(x);
if (TYPEOF(index) == INTSXP) {
int val = INTEGER(index)[0];
if (val == NA_INTEGER)
Rf_errorcall(R_NilValue, "Invalid index: NA_integer_");
val--;
if (val < 0 || val >= n)
Rf_errorcall(R_NilValue, "Invalid index: out of bounds");
return val;
} else if (TYPEOF(index) == REALSXP) {
double val = REAL(index)[0];
if (R_IsNA(val))
Rf_errorcall(R_NilValue, "Invalid index: NA_real_");
val--;
if (val < 0 || val >= n)
Rf_errorcall(R_NilValue, "Invalid index: out of bounds");
if (val > R_LEN_T_MAX) {
Rf_errorcall(R_NilValue, "Invalid index: too large");
}
return (int) val;
} else if (TYPEOF(index) == STRSXP) {
SEXP names = PROTECT(Rf_getAttrib(x, R_NamesSymbol));
if (names == R_NilValue)
Rf_errorcall(R_NilValue, "Corrupt x: no names");
SEXP val_0 = STRING_ELT(index, 0);
if (val_0 == NA_STRING)
Rf_errorcall(R_NilValue, "Invalid index: NA_character_");
const char* val_0_chr = Rf_translateCharUTF8(val_0);
if (val_0_chr[0] == '\0')
Rf_errorcall(R_NilValue, "Invalid index: empty string");
for (int j = 0; j < Rf_length(names); ++j) {
SEXP name_j = STRING_ELT(names, j);
if (name_j == NA_STRING)
Rf_errorcall(R_NilValue, "Corrupt x: element %i is unnamed", j + 1);
if (equal_string(val_0, &val_0_chr, name_j)) {
UNPROTECT(1);
return j;
}
}
Rf_errorcall(R_NilValue, "Invalid index: field name '%s' not found", val_0_chr);
} else {
Rf_errorcall(R_NilValue, "Invalid index: must be a character or numeric vector");
}
}void group_realloc(r_ssize size, struct group_info* p_group_info) {
// Reallocate
p_group_info->data = int_resize(
p_group_info->data,
p_group_info->data_size,
size
);
// Reprotect
REPROTECT(p_group_info->data, p_group_info->data_pi);
// Update pointer
p_group_info->p_data = INTEGER(p_group_info->data);
// Update size
p_group_info->data_size = size;
}r_obj* indices_next(struct vctrs_chop_indices* p_indices) {
const r_ssize loc = p_indices->loc;
++(p_indices->loc);
if (p_indices->has_indices) {
return p_indices->v_indices[loc];
} else if (p_indices->has_sizes) {
const r_ssize start = p_indices->p_index[0] + p_indices->p_index[1];
const r_ssize size = p_indices->v_sizes[loc];
const bool increasing = true;
init_compact_seq(p_indices->p_index, start, size, increasing);
return p_indices->index;
} else {
*p_indices->p_index = loc + 1;
return p_indices->index;
}
}r_obj* int_as_location(r_obj* subscript,
r_ssize n,
const struct location_opts* opts) {
const int* data = r_int_cbegin(subscript);
r_ssize loc_n = r_length(subscript);
// Zeros need to be filtered out from the subscript vector.
// `int_invert_location()` filters them out for negative indices, but
// positive indices need to go through and `int_filter_zero()`.
r_ssize n_zero = 0;
r_ssize n_oob = 0;
r_ssize n_missing = 0;
for (r_ssize i = 0; i < loc_n; ++i, ++data) {
int elt = *data;
if (elt == r_globals.na_int) {
switch (opts->missing) {
case SUBSCRIPT_MISSING_PROPAGATE: break;
case SUBSCRIPT_MISSING_REMOVE: ++n_missing; break;
case SUBSCRIPT_MISSING_ERROR: stop_subscript_missing(subscript, opts);
}
} else if (elt == 0) {
switch (opts->loc_zero) {
case LOC_ZERO_REMOVE: ++n_zero; break;
case LOC_ZERO_ERROR: stop_location_zero(subscript, opts);
case LOC_ZERO_IGNORE: break;
}
} else if (elt < 0) {
switch (opts->loc_negative) {
case LOC_NEGATIVE_INVERT: return int_invert_location(subscript, n, opts);
case LOC_NEGATIVE_ERROR: stop_location_negative(subscript, opts);
case LOC_NEGATIVE_IGNORE: {
if (abs(elt) > n) {
switch (opts->loc_oob) {
case LOC_OOB_ERROR: stop_subscript_oob_location(subscript, n, opts);
case LOC_OOB_EXTEND: stop_subscript_negative_oob_location(subscript, n, opts);
case LOC_OOB_REMOVE: ++n_oob; break;
}
}
break;
}
}
} else if (elt > n) {
switch (opts->loc_oob) {
case LOC_OOB_ERROR: stop_subscript_oob_location(subscript, n, opts);
case LOC_OOB_EXTEND: ++n_oob; break;
case LOC_OOB_REMOVE: ++n_oob; break;
}
}
}
r_keep_loc subscript_shelter;
KEEP_HERE(subscript, &subscript_shelter);
if (n_missing > 0) {
subscript = int_filter_missing(subscript, n_missing);
KEEP_AT(subscript, subscript_shelter);
}
if (n_zero > 0) {
subscript = int_filter_zero(subscript, n_zero);
KEEP_AT(subscript, subscript_shelter);
}
if (n_oob > 0) {
switch (opts->loc_oob) {
case LOC_OOB_ERROR: {
r_stop_internal("An error should have been thrown on the first OOB value.");
}
case LOC_OOB_EXTEND: {
int_check_consecutive(subscript, n, n_oob, opts);
break;
}
case LOC_OOB_REMOVE: {
subscript = int_filter_oob(subscript, n, n_oob);
KEEP_AT(subscript, subscript_shelter);
break;
}
}
}
FREE(1);
return subscript;
}r_obj* int_invert_location(r_obj* subscript,
r_ssize n,
const struct location_opts* opts) {
const int* data = r_int_cbegin(subscript);
r_ssize loc_n = r_length(subscript);
r_obj* sel = KEEP(r_alloc_logical(n));
r_lgl_fill(sel, 1, n);
int* sel_data = r_lgl_begin(sel);
for (r_ssize i = 0; i < loc_n; ++i, ++data) {
int j = *data;
if (j == r_globals.na_int) {
// Following base R by erroring on `missing = "propagate"`, e.g. `1[c(NA, -1)]`.
// Doesn't make sense to invert an `NA`, so we can't meaningfully propagate.
switch (opts->missing) {
case SUBSCRIPT_MISSING_PROPAGATE: stop_location_negative_missing(subscript, opts);
case SUBSCRIPT_MISSING_REMOVE: continue;
case SUBSCRIPT_MISSING_ERROR: stop_location_negative_missing(subscript, opts);
}
}
if (j >= 0) {
if (j == 0) {
switch (opts->loc_zero) {
case LOC_ZERO_REMOVE: continue;
case LOC_ZERO_IGNORE: continue;
case LOC_ZERO_ERROR: stop_location_zero(subscript, opts);
}
} else {
stop_location_negative_positive(subscript, opts);
}
}
j = -j;
if (j > n) {
switch (opts->loc_oob) {
case LOC_OOB_REMOVE: {
continue;
}
case LOC_OOB_EXTEND:
case LOC_OOB_ERROR: {
// Setting `oob` to `"error"` and `"extend"` result in errors here,
// because extending with a negative subscript is nonsensical
stop_subscript_negative_oob_location(subscript, n, opts);
}
}
}
sel_data[j - 1] = 0;
}
r_obj* out = lgl_as_location(sel, n, opts);
FREE(1);
return out;
}void int_order_counting(
const int* p_x,
r_ssize size,
int x_min,
uint32_t range,
bool initialized,
bool decreasing,
bool na_last,
int* p_o,
int* p_o_aux,
struct group_infos* p_group_infos
) {
// - Only allocate this once (counts are reset to 0 at end)
// - Allocating as static allows us to allocate an array this large
// - `+ 1` to ensure there is room for the extra `NA` bucket
static r_ssize p_counts[INT_ORDER_COUNTING_RANGE_BOUNDARY + 1] = { 0 };
// `NA` values get counted in the last used bucket
uint32_t na_bucket = range;
r_ssize na_count = 0;
// Sanity check
if (range > INT_ORDER_COUNTING_RANGE_BOUNDARY) {
Rf_errorcall(R_NilValue, "Internal error: `range > INT_ORDER_COUNTING_RANGE_BOUNDARY`.");
}
// Histogram pass
for (r_ssize i = 0; i < size; ++i) {
const int elt = p_x[i];
if (elt == NA_INTEGER) {
++na_count;
} else {
const uint32_t bucket = elt - x_min;
++p_counts[bucket];
}
}
// Add `NA` counts once at the end
p_counts[na_bucket] = na_count;
r_ssize cumulative = 0;
// Handle decreasing/increasing by altering the order in which
// counts are accumulated
const int direction = decreasing ? -1 : 1;
r_ssize j = decreasing ? range - 1 : 0;
// `na_last = false` pushes NA counts to the front
if (!na_last && na_count != 0) {
p_counts[na_bucket] = cumulative;
cumulative += na_count;
groups_size_maybe_push(na_count, p_group_infos);
}
// Accumulate counts, skip zeros
for (uint32_t i = 0; i < range; ++i) {
r_ssize count = p_counts[j];
if (count == 0) {
j += direction;
continue;
}
// Insert current cumulative value, then increment
p_counts[j] = cumulative;
cumulative += count;
// At this point we will handle this group completely
groups_size_maybe_push(count, p_group_infos);
j += direction;
}
// `na_last = true` pushes NA counts to the back
if (na_last && na_count != 0) {
p_counts[na_bucket] = cumulative;
groups_size_maybe_push(na_count, p_group_infos);
}
// If order is not initialized, we are on the first column / atomic vector
// and can place the order directly into the result. Much faster than
// initializing, placing in `p_o_aux`, and copying back over.
if (initialized) {
for (r_ssize i = 0; i < size; ++i) {
const int elt = p_x[i];
uint32_t bucket = (elt == NA_INTEGER) ? na_bucket : elt - x_min;
const r_ssize loc = p_counts[bucket]++;
p_o_aux[loc] = p_o[i];
}
r_memcpy(p_o, p_o_aux, size * sizeof(*p_o_aux));
} else {
for (r_ssize i = 0; i < size; ++i) {
const int elt = p_x[i];
uint32_t bucket = (elt == NA_INTEGER) ? na_bucket : elt - x_min;
const r_ssize loc = p_counts[bucket]++;
p_o[loc] = i + 1;
}
}
// Reset counts for next column.
// Only reset what we might have touched.
// `+ 1` to reset the NA bucket too.
r_memset(p_counts, 0, (range + 1) * sizeof(r_ssize));
}enum vctrs_sortedness int_sortedness(const int* p_x,
r_ssize size,
bool decreasing,
bool na_last,
struct group_infos* p_group_infos) {
if (size == 0) {
return VCTRS_SORTEDNESS_sorted;
}
if (size == 1) {
groups_size_maybe_push(1, p_group_infos);
return VCTRS_SORTEDNESS_sorted;
}
const int direction = decreasing ? -1 : 1;
const int na_order = na_last ? 1 : -1;
int previous = p_x[0];
r_ssize count = 0;
// Check for strictly opposite of expected order
// (ties are not allowed so we can reverse the vector stably)
for (r_ssize i = 1; i < size; ++i, ++count) {
int current = p_x[i];
int cmp = int_cmp(
current,
previous,
direction,
na_order
);
if (cmp >= 0) {
break;
}
previous = current;
}
// Was in strictly opposite of expected order.
if (count == size - 1) {
// Each group is size 1 since this is strict ordering
for (r_ssize j = 0; j < size; ++j) {
groups_size_maybe_push(1, p_group_infos);
}
return VCTRS_SORTEDNESS_reversed;
}
// Was partially in expected order. Need to sort.
if (count != 0) {
return VCTRS_SORTEDNESS_unsorted;
}
// Retain the original `n_groups` to be able to reset the group sizes if
// it turns out we don't have expected ordering
struct group_info* p_group_info = groups_current(p_group_infos);
r_ssize original_n_groups = p_group_info->n_groups;
r_ssize group_size = 1;
// Check for expected ordering - allowing ties since we don't have to
// reverse the ordering.
for (r_ssize i = 1; i < size; ++i) {
int current = p_x[i];
int cmp = int_cmp(
current,
previous,
direction,
na_order
);
// Not expected ordering
if (cmp < 0) {
p_group_info->n_groups = original_n_groups;
return VCTRS_SORTEDNESS_unsorted;
}
previous = current;
// Continue group run
if (cmp == 0) {
++group_size;
continue;
}
// Expected ordering
groups_size_maybe_push(group_size, p_group_infos);
group_size = 1;
}
// Push final group run
groups_size_maybe_push(group_size, p_group_infos);
// Expected ordering
return VCTRS_SORTEDNESS_sorted;
}SEXP ord_as_ordered(const struct cast_opts* p_opts) {
SEXP x_levels = PROTECT(Rf_getAttrib(p_opts->x, R_LevelsSymbol));
SEXP to_levels = PROTECT(Rf_getAttrib(p_opts->to, R_LevelsSymbol));
SEXP out;
if (ord_ptype2_validate(
x_levels,
to_levels,
p_opts->x,
p_opts->to,
p_opts->p_x_arg,
p_opts->p_to_arg
)) {
out = p_opts->x;
} else {
out = vec_cast_default(
p_opts->x,
p_opts->to,
p_opts->p_x_arg,
p_opts->p_to_arg,
p_opts->call,
p_opts->s3_fallback
);
}
UNPROTECT(2);
return out;
}void r_dyn_resize(struct r_dyn_array* p_arr,
r_ssize capacity) {
enum r_type type = p_arr->type;
r_ssize capacity_multiplier = p_arr->type == R_TYPE_raw ?
r_ssize_mult(p_arr->elt_byte_size, capacity) :
capacity;
r_obj* data = r_vec_resize0(type,
r_list_get(p_arr->shelter, 1),
capacity_multiplier);
r_list_poke(p_arr->shelter, 1, data);
p_arr->count = r_ssize_min(p_arr->count, capacity);
p_arr->capacity = capacity;
p_arr->data = data;
switch (type) {
case R_TYPE_character:
case R_TYPE_list:
break;
default:
p_arr->v_data = r_vec_begin0(type, data);
break;
}
p_arr->v_data_const = r_vec_cbegin0(type, data);
}const char* vctrs_type2_as_str(enum vctrs_type2 type) {
switch (type) {
case VCTRS_TYPE2_null_null: return "VCTRS_TYPE2_null_null";
case VCTRS_TYPE2_null_logical: return "VCTRS_TYPE2_null_logical";
case VCTRS_TYPE2_null_integer: return "VCTRS_TYPE2_null_integer";
case VCTRS_TYPE2_null_double: return "VCTRS_TYPE2_null_double";
case VCTRS_TYPE2_null_complex: return "VCTRS_TYPE2_null_complex";
case VCTRS_TYPE2_null_character: return "VCTRS_TYPE2_null_character";
case VCTRS_TYPE2_null_raw: return "VCTRS_TYPE2_null_raw";
case VCTRS_TYPE2_null_list: return "VCTRS_TYPE2_null_list";
case VCTRS_TYPE2_null_dataframe: return "VCTRS_TYPE2_null_dataframe";
case VCTRS_TYPE2_null_s3: return "VCTRS_TYPE2_null_s3";
case VCTRS_TYPE2_null_unspecified: return "VCTRS_TYPE2_null_unspecified";
case VCTRS_TYPE2_null_scalar: return "VCTRS_TYPE2_null_scalar";
case VCTRS_TYPE2_unspecified_logical: return "VCTRS_TYPE2_unspecified_logical";
case VCTRS_TYPE2_unspecified_integer: return "VCTRS_TYPE2_unspecified_integer";
case VCTRS_TYPE2_unspecified_double: return "VCTRS_TYPE2_unspecified_double";
case VCTRS_TYPE2_unspecified_complex: return "VCTRS_TYPE2_unspecified_complex";
case VCTRS_TYPE2_unspecified_character: return "VCTRS_TYPE2_unspecified_character";
case VCTRS_TYPE2_unspecified_raw: return "VCTRS_TYPE2_unspecified_raw";
case VCTRS_TYPE2_unspecified_list: return "VCTRS_TYPE2_unspecified_list";
case VCTRS_TYPE2_unspecified_dataframe: return "VCTRS_TYPE2_unspecified_dataframe";
case VCTRS_TYPE2_unspecified_s3: return "VCTRS_TYPE2_unspecified_s3";
case VCTRS_TYPE2_unspecified_unspecified: return "VCTRS_TYPE2_unspecified_unspecified";
case VCTRS_TYPE2_unspecified_scalar: return "VCTRS_TYPE2_unspecified_scalar";
case VCTRS_TYPE2_logical_logical: return "VCTRS_TYPE2_logical_logical";
case VCTRS_TYPE2_logical_integer: return "VCTRS_TYPE2_logical_integer";
case VCTRS_TYPE2_logical_double: return "VCTRS_TYPE2_logical_double";
case VCTRS_TYPE2_logical_complex: return "VCTRS_TYPE2_logical_complex";
case VCTRS_TYPE2_logical_character: return "VCTRS_TYPE2_logical_character";
case VCTRS_TYPE2_logical_raw: return "VCTRS_TYPE2_logical_raw";
case VCTRS_TYPE2_logical_list: return "VCTRS_TYPE2_logical_list";
case VCTRS_TYPE2_logical_dataframe: return "VCTRS_TYPE2_logical_dataframe";
case VCTRS_TYPE2_logical_s3: return "VCTRS_TYPE2_logical_s3";
case VCTRS_TYPE2_logical_scalar: return "VCTRS_TYPE2_logical_scalar";
case VCTRS_TYPE2_integer_integer: return "VCTRS_TYPE2_integer_integer";
case VCTRS_TYPE2_integer_double: return "VCTRS_TYPE2_integer_double";
case VCTRS_TYPE2_integer_complex: return "VCTRS_TYPE2_integer_complex";
case VCTRS_TYPE2_integer_character: return "VCTRS_TYPE2_integer_character";
case VCTRS_TYPE2_integer_raw: return "VCTRS_TYPE2_integer_raw";
case VCTRS_TYPE2_integer_list: return "VCTRS_TYPE2_integer_list";
case VCTRS_TYPE2_integer_dataframe: return "VCTRS_TYPE2_integer_dataframe";
case VCTRS_TYPE2_integer_s3: return "VCTRS_TYPE2_integer_s3";
case VCTRS_TYPE2_integer_scalar: return "VCTRS_TYPE2_integer_scalar";
case VCTRS_TYPE2_double_double: return "VCTRS_TYPE2_double_double";
case VCTRS_TYPE2_double_complex: return "VCTRS_TYPE2_double_complex";
case VCTRS_TYPE2_double_character: return "VCTRS_TYPE2_double_character";
case VCTRS_TYPE2_double_raw: return "VCTRS_TYPE2_double_raw";
case VCTRS_TYPE2_double_list: return "VCTRS_TYPE2_double_list";
case VCTRS_TYPE2_double_dataframe: return "VCTRS_TYPE2_double_dataframe";
case VCTRS_TYPE2_double_s3: return "VCTRS_TYPE2_double_s3";
case VCTRS_TYPE2_double_scalar: return "VCTRS_TYPE2_double_scalar";
case VCTRS_TYPE2_complex_complex: return "VCTRS_TYPE2_complex_complex";
case VCTRS_TYPE2_complex_character: return "VCTRS_TYPE2_complex_character";
case VCTRS_TYPE2_complex_raw: return "VCTRS_TYPE2_complex_raw";
case VCTRS_TYPE2_complex_list: return "VCTRS_TYPE2_complex_list";
case VCTRS_TYPE2_complex_dataframe: return "VCTRS_TYPE2_complex_dataframe";
case VCTRS_TYPE2_complex_s3: return "VCTRS_TYPE2_complex_s3";
case VCTRS_TYPE2_complex_scalar: return "VCTRS_TYPE2_complex_scalar";
case VCTRS_TYPE2_character_character: return "VCTRS_TYPE2_character_character";
case VCTRS_TYPE2_character_raw: return "VCTRS_TYPE2_character_raw";
case VCTRS_TYPE2_character_list: return "VCTRS_TYPE2_character_list";
case VCTRS_TYPE2_character_dataframe: return "VCTRS_TYPE2_character_dataframe";
case VCTRS_TYPE2_character_s3: return "VCTRS_TYPE2_character_s3";
case VCTRS_TYPE2_character_scalar: return "VCTRS_TYPE2_character_scalar";
case VCTRS_TYPE2_raw_raw: return "VCTRS_TYPE2_raw_raw";
case VCTRS_TYPE2_raw_list: return "VCTRS_TYPE2_raw_list";
case VCTRS_TYPE2_raw_dataframe: return "VCTRS_TYPE2_raw_dataframe";
case VCTRS_TYPE2_raw_s3: return "VCTRS_TYPE2_raw_s3";
case VCTRS_TYPE2_raw_scalar: return "VCTRS_TYPE2_raw_scalar";
case VCTRS_TYPE2_list_list: return "VCTRS_TYPE2_list_list";
case VCTRS_TYPE2_list_dataframe: return "VCTRS_TYPE2_list_dataframe";
case VCTRS_TYPE2_list_s3: return "VCTRS_TYPE2_list_s3";
case VCTRS_TYPE2_list_scalar: return "VCTRS_TYPE2_list_scalar";
case VCTRS_TYPE2_dataframe_dataframe: return "VCTRS_TYPE2_dataframe_dataframe";
case VCTRS_TYPE2_dataframe_s3: return "VCTRS_TYPE2_dataframe_s3";
case VCTRS_TYPE2_dataframe_scalar: return "VCTRS_TYPE2_dataframe_scalar";
case VCTRS_TYPE2_S3_s3: return "VCTRS_TYPE2_S3_s3";
case VCTRS_TYPE2_S3_scalar: return "VCTRS_TYPE2_S3_scalar";
case VCTRS_TYPE2_scalar_scalar: return "VCTRS_TYPE2_scalar_scalar";
}
r_stop_unreachable();
}const char* vctrs_type2_s3_as_str(enum vctrs_type2_s3 type) {
switch (type) {
case VCTRS_TYPE2_S3_null_bare_factor: return "VCTRS_TYPE2_S3_null_bare_factor";
case VCTRS_TYPE2_S3_null_bare_ordered: return "VCTRS_TYPE2_S3_null_bare_ordered";
case VCTRS_TYPE2_S3_null_bare_date: return "VCTRS_TYPE2_S3_null_bare_date";
case VCTRS_TYPE2_S3_null_bare_posixct: return "VCTRS_TYPE2_S3_null_bare_posixct";
case VCTRS_TYPE2_S3_null_bare_posixlt: return "VCTRS_TYPE2_S3_null_bare_posixlt";
case VCTRS_TYPE2_S3_null_bare_tibble: return "VCTRS_TYPE2_S3_null_bare_tibble";
case VCTRS_TYPE2_S3_null_unknown: return "VCTRS_TYPE2_S3_null_unknown";
case VCTRS_TYPE2_S3_unspecified_bare_factor: return "VCTRS_TYPE2_S3_unspecified_bare_factor";
case VCTRS_TYPE2_S3_unspecified_bare_ordered: return "VCTRS_TYPE2_S3_unspecified_bare_ordered";
case VCTRS_TYPE2_S3_unspecified_bare_date: return "VCTRS_TYPE2_S3_unspecified_bare_date";
case VCTRS_TYPE2_S3_unspecified_bare_posixct: return "VCTRS_TYPE2_S3_unspecified_bare_posixct";
case VCTRS_TYPE2_S3_unspecified_bare_posixlt: return "VCTRS_TYPE2_S3_unspecified_bare_posixlt";
case VCTRS_TYPE2_S3_unspecified_bare_tibble: return "VCTRS_TYPE2_S3_unspecified_bare_tibble";
case VCTRS_TYPE2_S3_unspecified_unknown: return "VCTRS_TYPE2_S3_unspecified_unknown";
case VCTRS_TYPE2_S3_logical_bare_factor: return "VCTRS_TYPE2_S3_logical_bare_factor";
case VCTRS_TYPE2_S3_logical_bare_ordered: return "VCTRS_TYPE2_S3_logical_bare_ordered";
case VCTRS_TYPE2_S3_logical_bare_date: return "VCTRS_TYPE2_S3_logical_bare_date";
case VCTRS_TYPE2_S3_logical_bare_posixct: return "VCTRS_TYPE2_S3_logical_bare_posixct";
case VCTRS_TYPE2_S3_logical_bare_posixlt: return "VCTRS_TYPE2_S3_logical_bare_posixlt";
case VCTRS_TYPE2_S3_logical_bare_tibble: return "VCTRS_TYPE2_S3_logical_bare_tibble";
case VCTRS_TYPE2_S3_logical_unknown: return "VCTRS_TYPE2_S3_logical_unknown";
case VCTRS_TYPE2_S3_integer_bare_factor: return "VCTRS_TYPE2_S3_integer_bare_factor";
case VCTRS_TYPE2_S3_integer_bare_ordered: return "VCTRS_TYPE2_S3_integer_bare_ordered";
case VCTRS_TYPE2_S3_integer_bare_date: return "VCTRS_TYPE2_S3_integer_bare_date";
case VCTRS_TYPE2_S3_integer_bare_posixct: return "VCTRS_TYPE2_S3_integer_bare_posixct";
case VCTRS_TYPE2_S3_integer_bare_posixlt: return "VCTRS_TYPE2_S3_integer_bare_posixlt";
case VCTRS_TYPE2_S3_integer_bare_tibble: return "VCTRS_TYPE2_S3_integer_bare_tibble";
case VCTRS_TYPE2_S3_integer_unknown: return "VCTRS_TYPE2_S3_integer_unknown";
case VCTRS_TYPE2_S3_double_bare_factor: return "VCTRS_TYPE2_S3_double_bare_factor";
case VCTRS_TYPE2_S3_double_bare_ordered: return "VCTRS_TYPE2_S3_double_bare_ordered";
case VCTRS_TYPE2_S3_double_bare_date: return "VCTRS_TYPE2_S3_double_bare_date";
case VCTRS_TYPE2_S3_double_bare_posixct: return "VCTRS_TYPE2_S3_double_bare_posixct";
case VCTRS_TYPE2_S3_double_bare_posixlt: return "VCTRS_TYPE2_S3_double_bare_posixlt";
case VCTRS_TYPE2_S3_double_bare_tibble: return "VCTRS_TYPE2_S3_double_bare_tibble";
case VCTRS_TYPE2_S3_double_unknown: return "VCTRS_TYPE2_S3_double_unknown";
case VCTRS_TYPE2_S3_complex_bare_factor: return "VCTRS_TYPE2_S3_complex_bare_factor";
case VCTRS_TYPE2_S3_complex_bare_ordered: return "VCTRS_TYPE2_S3_complex_bare_ordered";
case VCTRS_TYPE2_S3_complex_bare_date: return "VCTRS_TYPE2_S3_complex_bare_date";
case VCTRS_TYPE2_S3_complex_bare_posixct: return "VCTRS_TYPE2_S3_complex_bare_posixct";
case VCTRS_TYPE2_S3_complex_bare_posixlt: return "VCTRS_TYPE2_S3_complex_bare_posixlt";
case VCTRS_TYPE2_S3_complex_bare_tibble: return "VCTRS_TYPE2_S3_complex_bare_tibble";
case VCTRS_TYPE2_S3_complex_unknown: return "VCTRS_TYPE2_S3_complex_unknown";
case VCTRS_TYPE2_S3_character_bare_factor: return "VCTRS_TYPE2_S3_character_bare_factor";
case VCTRS_TYPE2_S3_character_bare_ordered: return "VCTRS_TYPE2_S3_character_bare_ordered";
case VCTRS_TYPE2_S3_character_bare_date: return "VCTRS_TYPE2_S3_character_bare_date";
case VCTRS_TYPE2_S3_character_bare_posixct: return "VCTRS_TYPE2_S3_character_bare_posixct";
case VCTRS_TYPE2_S3_character_bare_posixlt: return "VCTRS_TYPE2_S3_character_bare_posixlt";
case VCTRS_TYPE2_S3_character_bare_tibble: return "VCTRS_TYPE2_S3_character_bare_tibble";
case VCTRS_TYPE2_S3_character_unknown: return "VCTRS_TYPE2_S3_character_unknown";
case VCTRS_TYPE2_S3_raw_bare_factor: return "VCTRS_TYPE2_S3_raw_bare_factor";
case VCTRS_TYPE2_S3_raw_bare_ordered: return "VCTRS_TYPE2_S3_raw_bare_ordered";
case VCTRS_TYPE2_S3_raw_bare_date: return "VCTRS_TYPE2_S3_raw_bare_date";
case VCTRS_TYPE2_S3_raw_bare_posixct: return "VCTRS_TYPE2_S3_raw_bare_posixct";
case VCTRS_TYPE2_S3_raw_bare_posixlt: return "VCTRS_TYPE2_S3_raw_bare_posixlt";
case VCTRS_TYPE2_S3_raw_bare_tibble: return "VCTRS_TYPE2_S3_raw_bare_tibble";
case VCTRS_TYPE2_S3_raw_unknown: return "VCTRS_TYPE2_S3_raw_unknown";
case VCTRS_TYPE2_S3_list_bare_factor: return "VCTRS_TYPE2_S3_list_bare_factor";
case VCTRS_TYPE2_S3_list_bare_ordered: return "VCTRS_TYPE2_S3_list_bare_ordered";
case VCTRS_TYPE2_S3_list_bare_date: return "VCTRS_TYPE2_S3_list_bare_date";
case VCTRS_TYPE2_S3_list_bare_posixct: return "VCTRS_TYPE2_S3_list_bare_posixct";
case VCTRS_TYPE2_S3_list_bare_posixlt: return "VCTRS_TYPE2_S3_list_bare_posixlt";
case VCTRS_TYPE2_S3_list_bare_tibble: return "VCTRS_TYPE2_S3_list_bare_tibble";
case VCTRS_TYPE2_S3_list_unknown: return "VCTRS_TYPE2_S3_list_unknown";
case VCTRS_TYPE2_S3_dataframe_bare_factor: return "VCTRS_TYPE2_S3_dataframe_bare_factor";
case VCTRS_TYPE2_S3_dataframe_bare_ordered: return "VCTRS_TYPE2_S3_dataframe_bare_ordered";
case VCTRS_TYPE2_S3_dataframe_bare_date: return "VCTRS_TYPE2_S3_dataframe_bare_date";
case VCTRS_TYPE2_S3_dataframe_bare_posixct: return "VCTRS_TYPE2_S3_dataframe_bare_posixct";
case VCTRS_TYPE2_S3_dataframe_bare_posixlt: return "VCTRS_TYPE2_S3_dataframe_bare_posixlt";
case VCTRS_TYPE2_S3_dataframe_bare_tibble: return "VCTRS_TYPE2_S3_dataframe_bare_tibble";
case VCTRS_TYPE2_S3_dataframe_unknown: return "VCTRS_TYPE2_S3_dataframe_unknown";
case VCTRS_TYPE2_S3_scalar_bare_factor: return "VCTRS_TYPE2_S3_scalar_bare_factor";
case VCTRS_TYPE2_S3_scalar_bare_ordered: return "VCTRS_TYPE2_S3_scalar_bare_ordered";
case VCTRS_TYPE2_S3_scalar_bare_date: return "VCTRS_TYPE2_S3_scalar_bare_date";
case VCTRS_TYPE2_S3_scalar_bare_posixct: return "VCTRS_TYPE2_S3_scalar_bare_posixct";
case VCTRS_TYPE2_S3_scalar_bare_posixlt: return "VCTRS_TYPE2_S3_scalar_bare_posixlt";
case VCTRS_TYPE2_S3_scalar_bare_tibble: return "VCTRS_TYPE2_S3_scalar_bare_tibble";
case VCTRS_TYPE2_S3_scalar_unknown: return "VCTRS_TYPE2_S3_scalar_unknown";
case VCTRS_TYPE2_S3_bare_factor_bare_factor: return "VCTRS_TYPE2_S3_bare_factor_bare_factor";
case VCTRS_TYPE2_S3_bare_factor_bare_ordered: return "VCTRS_TYPE2_S3_bare_factor_bare_ordered";
case VCTRS_TYPE2_S3_bare_factor_bare_date: return "VCTRS_TYPE2_S3_bare_factor_bare_date";
case VCTRS_TYPE2_S3_bare_factor_bare_posixct: return "VCTRS_TYPE2_S3_bare_factor_bare_posixct";
case VCTRS_TYPE2_S3_bare_factor_bare_posixlt: return "VCTRS_TYPE2_S3_bare_factor_bare_posixlt";
case VCTRS_TYPE2_S3_bare_factor_bare_tibble: return "VCTRS_TYPE2_S3_bare_factor_bare_tibble";
case VCTRS_TYPE2_S3_bare_factor_unknown: return "VCTRS_TYPE2_S3_bare_factor_unknown";
case VCTRS_TYPE2_S3_bare_ordered_bare_ordered: return "VCTRS_TYPE2_S3_bare_ordered_bare_ordered";
case VCTRS_TYPE2_S3_bare_ordered_bare_date: return "VCTRS_TYPE2_S3_bare_ordered_bare_date";
case VCTRS_TYPE2_S3_bare_ordered_bare_posixct: return "VCTRS_TYPE2_S3_bare_ordered_bare_posixct";
case VCTRS_TYPE2_S3_bare_ordered_bare_posixlt: return "VCTRS_TYPE2_S3_bare_ordered_bare_posixlt";
case VCTRS_TYPE2_S3_bare_ordered_bare_tibble: return "VCTRS_TYPE2_S3_bare_ordered_bare_tibble";
case VCTRS_TYPE2_S3_bare_ordered_unknown: return "VCTRS_TYPE2_S3_bare_ordered_unknown";
case VCTRS_TYPE2_S3_bare_date_bare_date: return "VCTRS_TYPE2_S3_bare_date_bare_date";
case VCTRS_TYPE2_S3_bare_date_bare_posixct: return "VCTRS_TYPE2_S3_bare_date_bare_posixct";
case VCTRS_TYPE2_S3_bare_date_bare_posixlt: return "VCTRS_TYPE2_S3_bare_date_bare_posixlt";
case VCTRS_TYPE2_S3_bare_date_bare_tibble: return "VCTRS_TYPE2_S3_bare_date_bare_tibble";
case VCTRS_TYPE2_S3_bare_date_unknown: return "VCTRS_TYPE2_S3_bare_date_unknown";
case VCTRS_TYPE2_S3_bare_posixct_bare_posixct: return "VCTRS_TYPE2_S3_bare_posixct_bare_posixct";
case VCTRS_TYPE2_S3_bare_posixct_bare_posixlt: return "VCTRS_TYPE2_S3_bare_posixct_bare_posixlt";
case VCTRS_TYPE2_S3_bare_posixct_bare_tibble: return "VCTRS_TYPE2_S3_bare_posixct_bare_tibble";
case VCTRS_TYPE2_S3_bare_posixct_unknown: return "VCTRS_TYPE2_S3_bare_posixct_unknown";
case VCTRS_TYPE2_S3_bare_posixlt_bare_posixlt: return "VCTRS_TYPE2_S3_bare_posixlt_bare_posixlt";
case VCTRS_TYPE2_S3_bare_posixlt_bare_tibble: return "VCTRS_TYPE2_S3_bare_posixlt_bare_tibble";
case VCTRS_TYPE2_S3_bare_posixlt_unknown: return "VCTRS_TYPE2_S3_bare_posixlt_unknown";
case VCTRS_TYPE2_S3_bare_tibble_bare_tibble: return "VCTRS_TYPE2_S3_bare_tibble_bare_tibble";
case VCTRS_TYPE2_S3_bare_tibble_unknown: return "VCTRS_TYPE2_S3_bare_tibble_unknown";
case VCTRS_TYPE2_S3_unknown_unknown: return "VCTRS_TYPE2_S3_unknown_unknown";
}
r_stop_unreachable();
}r_obj* vec_assign_switch(
r_obj* proxy,
r_obj* index,
r_obj* value,
const struct vec_proxy_assign_opts* p_opts
) {
switch (vec_proxy_typeof(proxy)) {
case VCTRS_TYPE_logical: return lgl_assign(proxy, index, value, p_opts->ownership, p_opts->slice_value, p_opts->index_style);
case VCTRS_TYPE_integer: return int_assign(proxy, index, value, p_opts->ownership, p_opts->slice_value, p_opts->index_style);
case VCTRS_TYPE_double: return dbl_assign(proxy, index, value, p_opts->ownership, p_opts->slice_value, p_opts->index_style);
case VCTRS_TYPE_complex: return cpl_assign(proxy, index, value, p_opts->ownership, p_opts->slice_value, p_opts->index_style);
case VCTRS_TYPE_character: return chr_assign(proxy, index, value, p_opts->ownership, p_opts->slice_value, p_opts->index_style);
case VCTRS_TYPE_raw: return raw_assign(proxy, index, value, p_opts->ownership, p_opts->slice_value, p_opts->index_style);
case VCTRS_TYPE_list: return list_assign(proxy, index, value, p_opts->ownership, p_opts->slice_value, p_opts->index_style);
case VCTRS_TYPE_dataframe: return df_assign(proxy, index, value, p_opts);
case VCTRS_TYPE_scalar: stop_scalar_type(proxy, vec_args.empty, r_lazy_null);
default: stop_unimplemented_vctrs_type("vec_assign_switch", vec_typeof(proxy));
}
r_stop_unreachable();
}r_obj* vec_cast_opts(const struct cast_opts* opts) {
r_obj* x = opts->x;
r_obj* to = opts->to;
struct vctrs_arg* p_x_arg = opts->p_x_arg;
struct vctrs_arg* p_to_arg = opts->p_to_arg;
struct r_lazy call = opts->call;
if (x == r_null) {
// Allow both `vec_cast(NULL, <vector>)` and `vec_cast(NULL, NULL)`
obj_check_vector(to, VCTRS_ALLOW_NULL_yes, p_to_arg, call);
return x;
}
if (to == r_null) {
// Allow `vec_cast(<vector>, NULL)`
obj_check_vector(x, VCTRS_ALLOW_NULL_no, p_x_arg, call);
return x;
}
enum vctrs_type x_type = vec_typeof(x);
enum vctrs_type to_type = vec_typeof(to);
if (x_type == VCTRS_TYPE_unspecified) {
return vec_init(to, vec_size(x));
}
if (x_type == VCTRS_TYPE_scalar) {
stop_scalar_type(x, p_x_arg, call);
}
if (to_type == VCTRS_TYPE_scalar) {
stop_scalar_type(to, p_to_arg, call);
}
r_obj* out = r_null;
bool lossy = false;
if (to_type == VCTRS_TYPE_s3 || x_type == VCTRS_TYPE_s3) {
out = KEEP(vec_cast_dispatch_native(opts, x_type, to_type, &lossy));
} else {
out = KEEP(vec_cast_switch_native(opts, x_type, to_type, &lossy));
}
if (lossy || out == r_null) {
// This broadcasts dimensions too
FREE(1);
return vec_cast_dispatch_s3(opts);
}
if (has_dim(x) || has_dim(to)) {
r_obj* x_dim = KEEP(r_dim(x));
r_obj* x_dim_names = KEEP(r_dim_names(x));
r_obj* out_dim = KEEP(r_dim(out));
r_obj* out_dim_names = KEEP(r_dim_names(out));
// Ensure `out` has the shape of `x`.
// Native casting doesn't propagate shape.
if (!obj_equal(out_dim, x_dim) || !obj_equal(out_dim_names, x_dim_names)) {
out = KEEP(r_clone_referenced(out));
r_attrib_poke_dim(out, x_dim);
r_attrib_poke_dim_names(out, x_dim_names);
FREE(1);
}
KEEP(out);
// Broadcast `out` to the shape of `to`
out = vec_shape_broadcast(out, to, p_x_arg, p_to_arg, call);
FREE(5);
}
FREE(1);
return out;
}r_obj* vec_ptype2_impl(
r_obj* x,
r_obj* y,
struct vctrs_arg* p_x_arg,
struct vctrs_arg* p_y_arg,
struct r_lazy call,
enum s3_fallback s3_fallback,
int* left,
bool first_pass
) {
const enum vctrs_type x_type = vec_typeof(x);
const enum vctrs_type y_type = vec_typeof(y);
if (x_type == VCTRS_TYPE_null) {
// When `x` and `y` are `NULL`, keep using `x` name (1)
// When `x` is `NULL` but `y` isn't, switch to `y` name (0)
*left = y_type == VCTRS_TYPE_null;
return vec_ptype_or_s3_fallback(y, p_y_arg, x_type, call, s3_fallback);
}
if (y_type == VCTRS_TYPE_null) {
// When `x` and `y` are `NULL`, keep using `x` name (1)
// When `y` is `NULL` but `x` isn't, keep using `x` name (1)
*left = 1;
return vec_ptype_or_s3_fallback(x, p_x_arg, x_type, call, s3_fallback);
}
if (x_type == VCTRS_TYPE_unspecified) {
// When `x` and `y` are unspecified, keep using `x` name (1)
// When `x` is unspecified by `y` isn't, switch to `y` name (0)
*left = y_type == VCTRS_TYPE_unspecified;
return vec_ptype_or_s3_fallback(y, p_y_arg, y_type, call, s3_fallback);
}
if (y_type == VCTRS_TYPE_unspecified) {
// When `x` and `y` are unspecified, keep using `x` name (1)
// When `y` is unspecified but `x` isn't, keep using `x` name (1)
*left = 1;
return vec_ptype_or_s3_fallback(x, p_x_arg, x_type, call, s3_fallback);
}
if (x_type == VCTRS_TYPE_scalar) {
stop_scalar_type(x, p_x_arg, call);
}
if (y_type == VCTRS_TYPE_scalar) {
stop_scalar_type(y, p_y_arg, call);
}
if (x_type != VCTRS_TYPE_s3 && y_type != VCTRS_TYPE_s3) {
return vec_ptype2_switch_native(
x,
y,
x_type,
y_type,
p_x_arg,
p_y_arg,
call,
s3_fallback,
left
);
}
if (x_type == VCTRS_TYPE_s3 || y_type == VCTRS_TYPE_s3) {
r_obj* out = KEEP(vec_ptype2_dispatch_native(
x,
y,
x_type,
y_type,
p_x_arg,
p_y_arg,
call,
s3_fallback,
left
));
if (out != r_null) {
out = vec_shaped_ptype(out, x, y, p_x_arg, p_y_arg);
FREE(1);
return out;
}
FREE(1);
}
// Try native dispatch again with prototypes, in case the prototype
// is another type. FIXME: Use R-level callback instead.
if (first_pass) {
x = KEEP(vec_ptype(x, p_x_arg, call));
y = KEEP(vec_ptype(y, p_y_arg, call));
r_obj* out = vec_ptype2_impl(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback,
left,
false
);
FREE(2);
return out;
}
return vec_ptype2_dispatch_s3(
x,
y,
p_x_arg,
p_y_arg,
call,
s3_fallback
);
}r_ssize vec_set_union_x_loop(
struct dictionary* x_dict,
r_ssize x_size,
bool* v_marked
) {
switch (x_dict->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_SET_UNION_X_LOOP(nil_dict_hash_scalar);
case VCTRS_TYPE_logical: VEC_SET_UNION_X_LOOP(lgl_dict_hash_scalar);
case VCTRS_TYPE_integer: VEC_SET_UNION_X_LOOP(int_dict_hash_scalar);
case VCTRS_TYPE_double: VEC_SET_UNION_X_LOOP(dbl_dict_hash_scalar);
case VCTRS_TYPE_complex: VEC_SET_UNION_X_LOOP(cpl_dict_hash_scalar);
case VCTRS_TYPE_character: VEC_SET_UNION_X_LOOP(chr_dict_hash_scalar);
case VCTRS_TYPE_raw: VEC_SET_UNION_X_LOOP(raw_dict_hash_scalar);
case VCTRS_TYPE_list: VEC_SET_UNION_X_LOOP(list_dict_hash_scalar);
case VCTRS_TYPE_dataframe: VEC_SET_UNION_X_LOOP(df_dict_hash_scalar);
default: stop_unimplemented_vctrs_type("vec_set_union_x_loop", x_dict->p_poly_vec->type);
}
}r_ssize vec_set_union_y_loop(
struct dictionary* x_dict,
struct dictionary* y_dict,
r_ssize x_size,
r_ssize y_size,
bool* v_marked
) {
switch (x_dict->p_poly_vec->type) {
case VCTRS_TYPE_null: VEC_SET_UNION_Y_LOOP(nil_dict_hash_scalar, nil_dict_hash_with);
case VCTRS_TYPE_logical: VEC_SET_UNION_Y_LOOP(lgl_dict_hash_scalar, lgl_dict_hash_with);
case VCTRS_TYPE_integer: VEC_SET_UNION_Y_LOOP(int_dict_hash_scalar, int_dict_hash_with);
case VCTRS_TYPE_double: VEC_SET_UNION_Y_LOOP(dbl_dict_hash_scalar, dbl_dict_hash_with);
case VCTRS_TYPE_complex: VEC_SET_UNION_Y_LOOP(cpl_dict_hash_scalar, cpl_dict_hash_with);
case VCTRS_TYPE_character: VEC_SET_UNION_Y_LOOP(chr_dict_hash_scalar, chr_dict_hash_with);
case VCTRS_TYPE_raw: VEC_SET_UNION_Y_LOOP(raw_dict_hash_scalar, raw_dict_hash_with);
case VCTRS_TYPE_list: VEC_SET_UNION_Y_LOOP(list_dict_hash_scalar, list_dict_hash_with);
case VCTRS_TYPE_dataframe: VEC_SET_UNION_Y_LOOP(df_dict_hash_scalar, df_dict_hash_with);
default: stop_unimplemented_vctrs_type("vec_set_union_y_loop", x_dict->p_poly_vec->type);
}
}enum vctrs_type2 vec_typeof2_impl(enum vctrs_type type_x,
enum vctrs_type type_y,
int* left) {
switch (type_x) {
case VCTRS_TYPE_null: {
switch (type_y) {
case VCTRS_TYPE_null: *left = -1; return VCTRS_TYPE2_null_null;
case VCTRS_TYPE_unspecified: *left = 0; return VCTRS_TYPE2_null_unspecified;
case VCTRS_TYPE_logical: *left = 0; return VCTRS_TYPE2_null_logical;
case VCTRS_TYPE_integer: *left = 0; return VCTRS_TYPE2_null_integer;
case VCTRS_TYPE_double: *left = 0; return VCTRS_TYPE2_null_double;
case VCTRS_TYPE_complex: *left = 0; return VCTRS_TYPE2_null_complex;
case VCTRS_TYPE_character: *left = 0; return VCTRS_TYPE2_null_character;
case VCTRS_TYPE_raw: *left = 0; return VCTRS_TYPE2_null_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_null_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_null_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_null_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_null_scalar;
}
}
case VCTRS_TYPE_unspecified: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_unspecified;
case VCTRS_TYPE_unspecified: *left = -1; return VCTRS_TYPE2_unspecified_unspecified;
case VCTRS_TYPE_logical: *left = 0; return VCTRS_TYPE2_unspecified_logical;
case VCTRS_TYPE_integer: *left = 0; return VCTRS_TYPE2_unspecified_integer;
case VCTRS_TYPE_double: *left = 0; return VCTRS_TYPE2_unspecified_double;
case VCTRS_TYPE_complex: *left = 0; return VCTRS_TYPE2_unspecified_complex;
case VCTRS_TYPE_character: *left = 0; return VCTRS_TYPE2_unspecified_character;
case VCTRS_TYPE_raw: *left = 0; return VCTRS_TYPE2_unspecified_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_unspecified_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_unspecified_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_unspecified_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_unspecified_scalar;
}
}
case VCTRS_TYPE_logical: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_logical;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_logical;
case VCTRS_TYPE_logical: *left = -1; return VCTRS_TYPE2_logical_logical;
case VCTRS_TYPE_integer: *left = 0; return VCTRS_TYPE2_logical_integer;
case VCTRS_TYPE_double: *left = 0; return VCTRS_TYPE2_logical_double;
case VCTRS_TYPE_complex: *left = 0; return VCTRS_TYPE2_logical_complex;
case VCTRS_TYPE_character: *left = 0; return VCTRS_TYPE2_logical_character;
case VCTRS_TYPE_raw: *left = 0; return VCTRS_TYPE2_logical_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_logical_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_logical_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_logical_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_logical_scalar;
}
}
case VCTRS_TYPE_integer: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_integer;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_integer;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_integer;
case VCTRS_TYPE_integer: *left = -1; return VCTRS_TYPE2_integer_integer;
case VCTRS_TYPE_double: *left = 0; return VCTRS_TYPE2_integer_double;
case VCTRS_TYPE_complex: *left = 0; return VCTRS_TYPE2_integer_complex;
case VCTRS_TYPE_character: *left = 0; return VCTRS_TYPE2_integer_character;
case VCTRS_TYPE_raw: *left = 0; return VCTRS_TYPE2_integer_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_integer_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_integer_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_integer_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_integer_scalar;
}
}
case VCTRS_TYPE_double: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_double;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_double;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_double;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_double;
case VCTRS_TYPE_double: *left = -1; return VCTRS_TYPE2_double_double;
case VCTRS_TYPE_complex: *left = 0; return VCTRS_TYPE2_double_complex;
case VCTRS_TYPE_character: *left = 0; return VCTRS_TYPE2_double_character;
case VCTRS_TYPE_raw: *left = 0; return VCTRS_TYPE2_double_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_double_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_double_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_double_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_double_scalar;
}
}
case VCTRS_TYPE_complex: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_complex;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_complex;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_complex;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_complex;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_double_complex;
case VCTRS_TYPE_complex: *left = -1; return VCTRS_TYPE2_complex_complex;
case VCTRS_TYPE_character: *left = 0; return VCTRS_TYPE2_complex_character;
case VCTRS_TYPE_raw: *left = 0; return VCTRS_TYPE2_complex_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_complex_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_complex_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_complex_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_complex_scalar;
}
}
case VCTRS_TYPE_character: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_character;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_character;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_character;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_character;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_double_character;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_complex_character;
case VCTRS_TYPE_character: *left = -1; return VCTRS_TYPE2_character_character;
case VCTRS_TYPE_raw: *left = 0; return VCTRS_TYPE2_character_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_character_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_character_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_character_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_character_scalar;
}
}
case VCTRS_TYPE_raw: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_raw;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_raw;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_raw;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_raw;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_double_raw;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_complex_raw;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_character_raw;
case VCTRS_TYPE_raw: *left = -1; return VCTRS_TYPE2_raw_raw;
case VCTRS_TYPE_list: *left = 0; return VCTRS_TYPE2_raw_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_raw_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_raw_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_raw_scalar;
}
}
case VCTRS_TYPE_list: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_list;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_list;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_list;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_list;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_double_list;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_complex_list;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_character_list;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_raw_list;
case VCTRS_TYPE_list: *left = -1; return VCTRS_TYPE2_list_list;
case VCTRS_TYPE_dataframe: *left = 0; return VCTRS_TYPE2_list_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_list_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_list_scalar;
}
}
case VCTRS_TYPE_dataframe: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_dataframe;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_dataframe;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_dataframe;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_dataframe;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_double_dataframe;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_complex_dataframe;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_character_dataframe;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_raw_dataframe;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_list_dataframe;
case VCTRS_TYPE_dataframe: *left = -1; return VCTRS_TYPE2_dataframe_dataframe;
case VCTRS_TYPE_s3: *left = 0; return VCTRS_TYPE2_dataframe_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_dataframe_scalar;
}
}
case VCTRS_TYPE_s3: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_s3;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_s3;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_s3;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_s3;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_double_s3;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_complex_s3;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_character_s3;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_raw_s3;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_list_s3;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_dataframe_s3;
case VCTRS_TYPE_s3: *left = -1; return VCTRS_TYPE2_S3_s3;
case VCTRS_TYPE_scalar: *left = 0; return VCTRS_TYPE2_S3_scalar;
}
}
case VCTRS_TYPE_scalar: {
switch (type_y) {
case VCTRS_TYPE_null: *left = 1; return VCTRS_TYPE2_null_scalar;
case VCTRS_TYPE_unspecified: *left = 1; return VCTRS_TYPE2_unspecified_scalar;
case VCTRS_TYPE_logical: *left = 1; return VCTRS_TYPE2_logical_scalar;
case VCTRS_TYPE_integer: *left = 1; return VCTRS_TYPE2_integer_scalar;
case VCTRS_TYPE_double: *left = 1; return VCTRS_TYPE2_double_scalar;
case VCTRS_TYPE_complex: *left = 1; return VCTRS_TYPE2_complex_scalar;
case VCTRS_TYPE_character: *left = 1; return VCTRS_TYPE2_character_scalar;
case VCTRS_TYPE_raw: *left = 1; return VCTRS_TYPE2_raw_scalar;
case VCTRS_TYPE_list: *left = 1; return VCTRS_TYPE2_list_scalar;
case VCTRS_TYPE_dataframe: *left = 1; return VCTRS_TYPE2_dataframe_scalar;
case VCTRS_TYPE_s3: *left = 1; return VCTRS_TYPE2_S3_scalar;
case VCTRS_TYPE_scalar: *left = -1; return VCTRS_TYPE2_scalar_scalar;
}
}}
r_stop_unreachable();
}enum vctrs_type2_s3 vec_typeof2_s3_impl(r_obj* x,
r_obj* y,
enum vctrs_type type_x,
enum vctrs_type type_y,
int* left) {
switch (type_x) {
case VCTRS_TYPE_null: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_null_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_null_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_null_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_null_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_null_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_null_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_null_unknown;
}
}
case VCTRS_TYPE_unspecified: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_unspecified_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_unspecified_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_unspecified_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_unspecified_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_unspecified_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_unspecified_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_unspecified_unknown;
}
}
case VCTRS_TYPE_logical: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_logical_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_logical_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_logical_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_logical_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_logical_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_logical_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_logical_unknown;
}
}
case VCTRS_TYPE_integer: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_integer_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_integer_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_integer_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_integer_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_integer_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_integer_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_integer_unknown;
}
}
case VCTRS_TYPE_double: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_double_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_double_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_double_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_double_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_double_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_double_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_double_unknown;
}
}
case VCTRS_TYPE_complex: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_complex_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_complex_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_complex_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_complex_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_complex_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_complex_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_complex_unknown;
}
}
case VCTRS_TYPE_character: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_character_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_character_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_character_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_character_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_character_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_character_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_character_unknown;
}
}
case VCTRS_TYPE_raw: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_raw_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_raw_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_raw_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_raw_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_raw_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_raw_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_raw_unknown;
}
}
case VCTRS_TYPE_list: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_list_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_list_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_list_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_list_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_list_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_list_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_list_unknown;
}
}
case VCTRS_TYPE_dataframe: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_dataframe_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_dataframe_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_dataframe_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_dataframe_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_dataframe_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_dataframe_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_dataframe_unknown;
}
}
case VCTRS_TYPE_scalar: {
switch (class_type(y)) {
case VCTRS_CLASS_bare_factor: *left = 0; return VCTRS_TYPE2_S3_scalar_bare_factor;
case VCTRS_CLASS_bare_ordered: *left = 0; return VCTRS_TYPE2_S3_scalar_bare_ordered;
case VCTRS_CLASS_bare_date: *left = 0; return VCTRS_TYPE2_S3_scalar_bare_date;
case VCTRS_CLASS_bare_posixct: *left = 0; return VCTRS_TYPE2_S3_scalar_bare_posixct;
case VCTRS_CLASS_bare_posixlt: *left = 0; return VCTRS_TYPE2_S3_scalar_bare_posixlt;
case VCTRS_CLASS_bare_tibble: *left = 0; return VCTRS_TYPE2_S3_scalar_bare_tibble;
default: *left = 0; return VCTRS_TYPE2_S3_scalar_unknown;
}
}
case VCTRS_TYPE_s3: {
return vec_typeof2_s3_impl2(x, y, type_y, left);
}}
r_stop_unreachable();
}