in r/src/as_array.c [196:319]
static void as_array_dbl(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);
}
// Consider double -> na_double() and double -> na_int64()/na_int32()
// (mostly so that we can support date/time types with various units)
switch (schema_view.type) {
case NANOARROW_TYPE_DOUBLE:
case NANOARROW_TYPE_INT64:
case NANOARROW_TYPE_INT32:
break;
default:
call_as_nanoarrow_array(x_sexp, array, schema_xptr, "as_nanoarrow_array_from_c");
return;
}
double* x_data = REAL(x_sexp);
int64_t len = Rf_xlength(x_sexp);
result = ArrowArrayInitFromType(array, schema_view.type);
if (result != NANOARROW_OK) {
Rf_error("ArrowArrayInitFromType() failed");
}
if (schema_view.type == NANOARROW_TYPE_DOUBLE) {
// Just borrow the data buffer (zero-copy)
buffer_borrowed(ArrowArrayBuffer(array, 1), x_data, len * sizeof(double), x_sexp);
} else if (schema_view.type == NANOARROW_TYPE_INT64) {
// double -> int64_t
struct ArrowBuffer* buffer = ArrowArrayBuffer(array, 1);
result = ArrowBufferReserve(buffer, len * sizeof(int64_t));
if (result != NANOARROW_OK) {
Rf_error("ArrowBufferReserve() failed");
}
int64_t* buffer_data = (int64_t*)buffer->data;
for (int64_t i = 0; i < len; i++) {
// UBSAN warns for buffer_data[i] = nan
if (R_IsNA(x_data[i]) || R_IsNaN(x_data[i])) {
buffer_data[i] = 0;
} else {
buffer_data[i] = x_data[i];
}
}
buffer->size_bytes = len * sizeof(int64_t);
} else {
// double -> int32_t
struct ArrowBuffer* buffer = ArrowArrayBuffer(array, 1);
result = ArrowBufferReserve(buffer, len * sizeof(int32_t));
if (result != NANOARROW_OK) {
Rf_error("ArrowBufferReserve() failed");
}
int32_t* buffer_data = (int32_t*)buffer->data;
// It's easy to accidentally overflow here, so make sure to warn
int64_t n_overflow = 0;
for (int64_t i = 0; i < len; i++) {
// UBSAN warns for buffer_data[i] = nan
if (R_IsNA(x_data[i]) || R_IsNaN(x_data[i])) {
buffer_data[i] = 0;
} else if (x_data[i] > INT_MAX || x_data[i] < INT_MIN) {
n_overflow++;
buffer_data[i] = 0;
} else {
buffer_data[i] = x_data[i];
}
}
if (n_overflow > 0) {
Rf_warning("%ld value(s) overflowed in double -> na_int32() creation",
(long)n_overflow);
}
buffer->size_bytes = len * sizeof(int32_t);
}
// Set the array fields
array->length = len;
array->offset = 0;
int64_t null_count = 0;
// Look for the first null (will be the last index if there are none)
int64_t first_null = -1;
for (int64_t i = 0; i < len; i++) {
if (R_IsNA(x_data[i]) || R_IsNaN(x_data[i])) {
first_null = i;
break;
}
}
// If there are nulls, pack the validity buffer
if (first_null != -1) {
struct ArrowBitmap bitmap;
ArrowBitmapInit(&bitmap);
result = ArrowBitmapReserve(&bitmap, len);
if (result != NANOARROW_OK) {
Rf_error("ArrowBitmapReserve() failed");
}
ArrowBitmapAppendUnsafe(&bitmap, 1, first_null);
for (int64_t i = first_null; i < len; i++) {
uint8_t is_valid = !R_IsNA(x_data[i]) && !R_IsNaN(x_data[i]);
null_count += !is_valid;
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);
}
}