I believe this should is doable without much trouble from inside the runtime, but I don’t think all required functionality is accessible from outside the runtime (you would need to duplicate the caml_ba_update_proxy function).
CAMLprim value ba_cast_to_char(value vb)
#define b (Caml_ba_array_val(vb))
for (int i = 0; i < b->num_dims; i++)
dim[i] = b->dim[i] * caml_ba_element_size[b->flags & CAML_BA_KIND_MASK];
int flags = CAML_BA_CHAR | (b->flags & (CAML_BA_LAYOUT_MASK | CAML_BA_MANAGED_MASK));
res = caml_ba_alloc(flags, b->num_dims, b->data, dim);
/* Copy the finalization function from the original array (PR#8568) */
Custom_ops_val(res) = Custom_ops_val(vb);
/* Create or update proxy in case of managed bigarray */
/* Return result */
: ('a, 'b, 'c) Bigarray.Genarray.t
-> (char, int8_unsigned_elt, 'c) Bigarray.Genarray.t
let elems ba = Array.reduce_exn Int.( * ) (Bigarray.Genarray.dims ba)
let cast ba =
let ba = Bigarray.reshape ba [| elems ba |] in
c_cast ba |> array1_of_genarray
It again seems to work but I’m not sure if the code is correct, in particular should it replicate CAML_BA_MANAGED_MASK or should it be set to EXTERNAL and whether data should be passed to caml_ba_alloc or only to caml_ba_update_proxy?
I think there’s a problem in your code: you’re multiplying every dimension by the byte size of elements. Only one dimension should be multiplied. Consider a 2x2 array of 64-bit floats, with size 2x2x8 = 32 bytes. You’re turning it into a 16x16 array of bytes, with size 16x16x1 = 256 bytes.
More generally: can you write a specification for what you’re trying to achieve?
Yes, you are completely right. I was reshaping the array into a single dimension and I didn’t catch the mistake. Only the last dimension should be multiplied by the byte size.
The main use of this function is to cast multidimensional array into a bigstring type for hashing and sending it across the network. Hopefully that could be achieved without any C extensions. I think it’s pretty common operation.