| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| |
| arrow_installed <- function() { |
| opt <- Sys.getenv( |
| "R_NANOARROW_WITHOUT_ARROW", |
| getOption("nanoarrow.without_arrow", FALSE) |
| ) |
| |
| if (identical(tolower(opt), "true")) { |
| FALSE |
| } else { |
| requireNamespace("arrow", quietly = TRUE) |
| } |
| } |
| |
| assert_arrow_installed <- function(reason) { |
| if (!arrow_installed()) { |
| stop( |
| sprintf("Package 'arrow' required for %s", reason), |
| call. = FALSE |
| ) |
| } |
| } |
| |
| warn_lossy_conversion <- function(count, msg) { |
| cnd <- simpleWarning( |
| sprintf("%d value(s) %s", count, msg), |
| call = sys.call(-1) |
| ) |
| class(cnd) <- union("nanoarrow_warning_lossy_conversion", class(cnd)) |
| |
| warning(cnd) |
| } |
| |
| # Internally we use R_PreserveObject() and R_ReleaseObject() to manage R objects |
| # that must be kept alive for ArrowArray buffers to stay valid. This count |
| # should be zero after tests have run in a fresh session and both gc() and |
| # preserved_empty() have been run. If this isn't the case, compile with |
| # -DNANOARROW_DEBUG_PRESERVE and run preserved_empty() to get verbose output |
| # about which objects didn't get released (including an R traceback to where |
| # they were preserved). |
| preserved_count <- function() { |
| .Call(nanoarrow_c_preserved_count) |
| } |
| |
| # Most objects are both preserved and released on the R main thread; however |
| # when sending objects into the wild there is no guarantee that they will be |
| # deleted on the R main thread (even though they usually are). The R package |
| # handles this by keeping a list of objects that couldn't be released: calling |
| # this function will release them and return how many were released. |
| preserved_empty <- function() { |
| .Call(nanoarrow_c_preserved_empty) |
| } |
| |
| # To test the "release from another thread" mechanism, this preserves obj, |
| # releases it from another thread and returns. |
| preserve_and_release_on_other_thread <- function(obj) { |
| invisible(.Call(nanoarrow_c_preserve_and_release_on_other_thread, obj)) |
| } |
| |
| # This is used by bookkeeping infrastructure when debugging an imbalance in |
| # preserved/released SEXPs. |
| current_stack_trace_chr <- function() { |
| tb <- rlang::trace_back() |
| paste0(utils::capture.output(print(tb)), collapse = "\n") |
| } |
| |
| # Consolidate places we should call vctrs::vec_slice() |
| # if/when a vctrs dependency is added |
| vec_slice2 <- function(x, i) { |
| if (is.data.frame(x)) { |
| x[i, , drop = FALSE] |
| } else { |
| x[i] |
| } |
| } |
| |
| `%||%` <- function(rhs, lhs) { |
| if (is.null(rhs)) lhs else rhs |
| } |
| |
| new_data_frame <- function(x, nrow) { |
| structure(x, row.names = c(NA, nrow), class = "data.frame") |
| } |
| |
| vec_gen <- function(ptype, n = 1e3, prop_true = 0.5, prop_na = 0, |
| chr_len = function(n) ceiling(25 * stats::runif(n))) { |
| vec <- switch( |
| class(ptype)[1], |
| logical = stats::runif(n) < prop_true, |
| integer = as.integer(stats::runif(n, min = -1, max = 1) * .Machine$integer.max), |
| numeric = stats::runif(n), |
| character = strrep(rep_len(letters, n), chr_len(n)), |
| data.frame = new_data_frame( |
| lapply( |
| ptype, |
| vec_gen, |
| n = n, |
| prop_true = prop_true, |
| prop_na = prop_na, |
| chr_len = chr_len |
| ), |
| n |
| ), |
| stop(sprintf("Don't know how to generate vector for type %s", class(ptype)[1])) |
| ) |
| |
| if (!is.data.frame(vec) && prop_na > 0) { |
| is_na <- stats::runif(n) < prop_na |
| vec[is_na] <- ptype[NA_integer_] |
| } |
| |
| vec |
| } |
| |
| vec_shuffle <- function(x) { |
| if (is.data.frame(x)) { |
| i <- sample(seq_len(nrow(x)), replace = FALSE) |
| } else { |
| i <- sample(seq_along(x), replace = FALSE) |
| } |
| |
| vec_slice2(x, i) |
| } |