Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# vctrs (development version)

* `vec_interleave()` gains new `.size` and `.error_call` arguments.

* `vec_interleave()` now reports the correct index in errors when `NULL`s are present.

* New `list_combine()` for combining a list of vectors together according to a set of `indices`. We now recommend using:

* `list_combine(x, indices = indices, size = size)` over `list_unchop(x, indices = indices)`
Expand Down
82 changes: 55 additions & 27 deletions R/slice-interleave.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@
#'
#' ## vctrs dependencies
#'
#' - [list_unchop()]
#' - [list_combine()]
#'
#' @inheritParams vec_c
#'
#' @param ... Vectors to interleave. These will be
#' [recycled][theory-faq-recycling] to a common size.
#' @param ... Vectors to interleave.
#'
#' @param .size The expected size of each vector. If not provided, computed
#' automatically by [vec_size_common()]. Each vector will be
#' [recycled][theory-faq-recycling] to this size.
#'
#' @param .ptype The expected type of each vector. If not provided, computed
#' automatically by [vec_ptype_common()]. Each vector will be
#' [cast][theory-faq-coercion] to this type.
#'
#' @export
#' @examples
Expand All @@ -35,8 +42,15 @@
#' y <- data_frame(x = 3:4, y = c("c", "d"))
#'
#' vec_interleave(x, y)
#'
#' # `.size` can be used to recycle size 1 elements before interleaving
#' vec_interleave(1, 2, .size = 3)
#'
#' # `.ptype` can be used to enforce a particular type
#' typeof(vec_interleave(1, 2, .ptype = integer()))
vec_interleave <- function(
...,
.size = NULL,
.ptype = NULL,
.name_spec = NULL,
.name_repair = c(
Expand All @@ -46,34 +60,48 @@ vec_interleave <- function(
"universal",
"unique_quiet",
"universal_quiet"
)
),
.error_call = current_env()
) {
args <- list2(...)

# `NULL`s must be dropped up front to generate appropriate indices
if (vec_any_missing(args)) {
missing <- vec_detect_missing(args)
args <- vec_slice(args, !missing)
}

n <- length(args)
size <- vec_size_common(!!!args)

indices <- vec_interleave_indices(n, size)

# TODO: Consider switching to `list_combine()`, add tests for empty `...`
# case, which would start returning `unspecified()` rather than `NULL`.
# This would be more correct and good for composibility, see
# https://github.com/r-lib/vctrs/issues/2055
list_unchop(
x = args,
indices = indices,
list_interleave(
x = list2(...),
size = .size,
ptype = .ptype,
name_spec = .name_spec,
name_repair = .name_repair
name_repair = .name_repair,
x_arg = "",
error_call = .error_call
)
}

vec_interleave_indices <- function(n, size) {
.Call(ffi_interleave_indices, n, size)
# It's sometimes more convenient to supply a list, plus you get access to
# `x_arg` for better error messages than you get from `vec_interleave(!!!x)`.
# We could consider exporting this alongside `vec_interleave()`.
list_interleave <- function(
x,
...,
size = NULL,
ptype = NULL,
name_spec = NULL,
name_repair = c(
"minimal",
"unique",
"check_unique",
"universal",
"unique_quiet",
"universal_quiet"
),
x_arg = caller_arg(x),
error_call = current_env()
) {
check_dots_empty0(...)
.Call(
ffi_list_interleave,
x,
size,
ptype,
name_spec,
name_repair,
environment()
)
}
31 changes: 22 additions & 9 deletions man/vec_interleave.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 10 additions & 1 deletion src/decl/slice-interleave-decl.h
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
static r_obj* vec_interleave_indices(r_ssize n, r_ssize size);
static
r_ssize list_interleave_x_size_used(r_obj* const* v_x, r_ssize x_size);

static
r_obj* list_interleave_indices(
r_obj* const* v_x,
r_ssize x_size,
r_ssize x_size_used,
r_ssize elt_size
);
1 change: 1 addition & 0 deletions src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ void vctrs_init_globals(r_obj* ns) {
INIT_ARG(indices);
INIT_ARG(sizes);
INIT_ARG(ptype);
INIT_ARG(size);

// Lazy args ---------------------------------------------------------
INIT_LAZY_ARG_2(dot_name_repair, ".name_repair");
Expand Down
1 change: 1 addition & 0 deletions src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ struct vec_args {
struct vctrs_arg* indices;
struct vctrs_arg* sizes;
struct vctrs_arg* ptype;
struct vctrs_arg* size;
};

struct lazy_args {
Expand Down
4 changes: 2 additions & 2 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ extern r_obj* vctrs_integer64_proxy(r_obj*);
extern r_obj* vctrs_integer64_restore(r_obj*);
extern r_obj* vctrs_list_drop_empty(r_obj*);
extern r_obj* vctrs_is_altrep(r_obj* x);
extern r_obj* ffi_interleave_indices(r_obj*, r_obj*);
extern r_obj* ffi_list_interleave(r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*);
extern r_obj* ffi_compute_nesting_container_info(r_obj*, r_obj*);
extern r_obj* ffi_locate_matches(r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*, r_obj*);
extern r_obj* ffi_interval_groups(r_obj*, r_obj*, r_obj*, r_obj*);
Expand Down Expand Up @@ -343,7 +343,7 @@ static const R_CallMethodDef CallEntries[] = {
{"vctrs_integer64_restore", (DL_FUNC) &vctrs_integer64_restore, 1},
{"vctrs_list_drop_empty", (DL_FUNC) &vctrs_list_drop_empty, 1},
{"vctrs_is_altrep", (DL_FUNC) &vctrs_is_altrep, 1},
{"ffi_interleave_indices", (DL_FUNC) &ffi_interleave_indices, 2},
{"ffi_list_interleave", (DL_FUNC) &ffi_list_interleave, 6},
{"ffi_compute_nesting_container_info", (DL_FUNC) &ffi_compute_nesting_container_info, 2},
{"ffi_locate_matches", (DL_FUNC) &ffi_locate_matches, 14},
{"ffi_interval_groups", (DL_FUNC) &ffi_interval_groups, 4},
Expand Down
Loading
Loading