static void as_array_chr()

in r/src/as_array.c [321:404]


static void as_array_chr(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);
  }

  // Only consider the default create for now
  if (schema_view.type != NANOARROW_TYPE_STRING) {
    call_as_nanoarrow_array(x_sexp, array, schema_xptr, "as_nanoarrow_array_from_c");
    return;
  }

  int64_t len = Rf_xlength(x_sexp);

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

  // Keep these buffers under the umbrella of the array so that we don't have
  // to worry about cleaning them up if STRING_ELT jumps
  struct ArrowBuffer* offset_buffer = ArrowArrayBuffer(array, 1);
  struct ArrowBuffer* data_buffer = ArrowArrayBuffer(array, 2);

  ArrowBufferReserve(offset_buffer, (len + 1) * sizeof(int32_t));

  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 = STRING_ELT(x_sexp, i);
    if (item == NA_STRING) {
      null_count++;
    } else {
      const void* vmax = vmaxget();
      const char* item_utf8 = Rf_translateCharUTF8(item);
      int64_t item_size = strlen(item_utf8);
      if ((item_size + cumulative_len) > INT_MAX) {
        Rf_error("Use na_large_string() to convert character() with total size > 2GB");
      }

      int result = ArrowBufferAppend(data_buffer, item_utf8, item_size);
      if (result != NANOARROW_OK) {
        Rf_error("ArrowBufferAppend() failed");
      }
      cumulative_len += item_size;

      vmaxset(vmax);
    }

    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 = STRING_ELT(x_sexp, i) != NA_STRING;
      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);
  }
}