Converting a (int, Bigarray.int8_unsigned_elt,...) to a (char, Bigarray.int8_unsigned_elt,...)

I have a need to convert a

(int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t

to a

(char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t

Is there an easy way of doing this without doing a full copy?

I don’t think so (and there are a couple of different possible semantics for such a function). You can easily write a C binding to do it, though.

Cheers,
Nicolas

1 Like

Ok, thanks - I was hoping for a magical solution! I’ll do a C binding - thanks again.

I believe Obj.magic does this without making a copy (disclaimer: I never touch it personally, since I don’t know what I’m doing).

let i = Bigarray.Array1.create Bigarray.Int8_unsigned Bigarray.C_layout 10;;
val i : (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t = <abstr>

Bigarray.Array1.set i 0 5;;
- : unit = ()

let c : (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t = Obj.magic i;;
val c : (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t = <abstr>

Bigarray.Array1.get c 0;;
- : char = '\005'

Bigarray.Array1.set c 0 '\002';;
- : unit = ()

Bigarray.Array1.get i 0;;
- : int = 2

I was missing this feature some time ago as well. I didn’t want to write
C bindings, and I looked into if using Obj.magic was possible. Looking
at the bigarray code it seemed to me to be safe in the version I looked at.

I ended up just copying the whole bigarray into a new one as the code
wasn’t too critical, and I didn’t want to worry about it breaking in the
future.

I did it to get a bigarray which was correctly aligned to a word but my previous me told me that it’s probably really unsafe:

I think that if you know exactly at which point you will do such operation and be sure that the bigarray is not shared by anyone, I think it’s fine.

I haven’t looked very closely, but mutating the bigarray value in-place may cause some issues with operations to the original bigarray value which depend on the underlying OCaml type (eg hashing, comparing, marshalling, etc). In any case, it is generally a bad idea to mutate values that OCaml considers immutable.

What I had in mind when I suggested writing a C binding is to allocate a new bigarray pointing to the same “data” part. This should be 100% safe. The only detail to be aware of is that if the “data” part is managed by OCaml, then one needs to increase its refcount to keep OCaml from deallocating it prematurely.

Cheers,
Nicolas

Maybe this is relevant? Casting bigarray between different kinds, using ctypes, possible problems?