static void as_array_list()

in r/src/as_array.c [456:543]


static void as_array_list(SEXP x_sexp, struct ArrowArray* array, SEXP schema_xptr,
                          struct ArrowError* error) {
  struct ArrowSchema* schema = schema_from_xptr(schema_xptr);
  struct ArrowSchemaView schema_view;
  int result = ArrowSchemaViewInit(&schema_view, schema, error);
  if (result != NANOARROW_OK) {
    Rf_error("ArrowSchemaViewInit(): %s", error->message);
  }

  // We handle list(raw()) for now but fall back to arrow for vctrs::list_of()
  // Arbitrary nested list support is complicated without some concept of a
  // "builder", which we don't use.
  if (schema_view.type != NANOARROW_TYPE_BINARY) {
    call_as_nanoarrow_array(x_sexp, array, schema_xptr, "as_nanoarrow_array_from_c");
    return;
  }

  result = ArrowArrayInitFromType(array, schema_view.type);
  if (result != NANOARROW_OK) {
    Rf_error("ArrowArrayInitFromType() failed");
  }

  int64_t len = Rf_xlength(x_sexp);
  struct ArrowBuffer* offset_buffer = ArrowArrayBuffer(array, 1);
  struct ArrowBuffer* data_buffer = ArrowArrayBuffer(array, 2);

  result = ArrowBufferReserve(offset_buffer, (len + 1) * sizeof(int32_t));
  if (result != NANOARROW_OK) {
    Rf_error("ArrowBufferReserve() failed");
  }

  int64_t null_count = 0;
  int32_t cumulative_len = 0;
  ArrowBufferAppendUnsafe(offset_buffer, &cumulative_len, sizeof(int32_t));

  for (int64_t i = 0; i < len; i++) {
    SEXP item = VECTOR_ELT(x_sexp, i);
    if (item == R_NilValue) {
      ArrowBufferAppendUnsafe(offset_buffer, &cumulative_len, sizeof(int32_t));
      null_count++;
      continue;
    }

    if (Rf_isObject(item) || TYPEOF(item) != RAWSXP) {
      Rf_error("All list items must be raw() or NULL in conversion to na_binary()");
    }

    int64_t item_size = Rf_xlength(item);
    if ((item_size + cumulative_len) > INT_MAX) {
      Rf_error("Use na_large_binary() to convert list(raw()) with total size > 2GB");
    }

    result = ArrowBufferAppend(data_buffer, RAW(item), item_size);
    if (result != NANOARROW_OK) {
      Rf_error("ArrowBufferAppend() failed");
    }

    cumulative_len += item_size;
    ArrowBufferAppendUnsafe(offset_buffer, &cumulative_len, sizeof(int32_t));
  }

  // Set the array fields
  array->length = len;
  array->offset = 0;

  // If there are nulls, pack the validity buffer
  if (null_count > 0) {
    struct ArrowBitmap bitmap;
    ArrowBitmapInit(&bitmap);
    result = ArrowBitmapReserve(&bitmap, len);
    if (result != NANOARROW_OK) {
      Rf_error("ArrowBitmapReserve() failed");
    }

    for (int64_t i = 0; i < len; i++) {
      uint8_t is_valid = VECTOR_ELT(x_sexp, i) != R_NilValue;
      ArrowBitmapAppend(&bitmap, is_valid, 1);
    }

    ArrowArraySetValidityBitmap(array, &bitmap);
  }

  array->null_count = null_count;
  result = ArrowArrayFinishBuildingDefault(array, error);
  if (result != NANOARROW_OK) {
    Rf_error("ArrowArrayFinishBuildingDefault(): %s", error->message);
  }
}