Last active
September 12, 2021 13:23
-
-
Save crackcomm/9d5fbeaa8e038194cdbf0ba990d698e6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open Core | |
open Bigarray | |
external c_cast | |
: ('a, 'b, 'c) Bigarray.Genarray.t | |
-> (char, int8_unsigned_elt, 'c) Bigarray.Genarray.t | |
= "ba_cast_to_char" | |
let elems ba = Array.reduce_exn ~f:Int.( * ) (Bigarray.Genarray.dims ba) | |
let cast ba = | |
let ba = Bigarray.reshape ba [| elems ba |] in | |
c_cast ba |> array1_of_genarray | |
;; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(library | |
(name bigarray_str) | |
(public_name bigarray_str) | |
(libraries core) | |
(foreign_stubs | |
(language c) | |
(names stubs) | |
(flags -std=c99 -pedantic))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define CAML_INTERNALS | |
#include <caml/custom.h> | |
#include <caml/fail.h> | |
#include <caml/memory.h> | |
#include <caml/bigarray.h> | |
// Source: https://github.com/ocaml/ocaml/blob/4.12/runtime/bigarray.c#L919-L941 | |
static void caml_ba_update_proxy(struct caml_ba_array *b1, | |
struct caml_ba_array *b2) | |
{ | |
struct caml_ba_proxy *proxy; | |
/* Nothing to do for un-managed arrays */ | |
if ((b1->flags & CAML_BA_MANAGED_MASK) == CAML_BA_EXTERNAL) | |
return; | |
if (b1->proxy != NULL) | |
{ | |
/* If b1 is already a proxy for a larger array, increment refcount of | |
proxy */ | |
b2->proxy = b1->proxy; | |
++b1->proxy->refcount; | |
} | |
else | |
{ | |
/* Otherwise, create proxy and attach it to both b1 and b2 */ | |
proxy = malloc(sizeof(struct caml_ba_proxy)); | |
if (proxy == NULL) | |
caml_raise_out_of_memory(); | |
proxy->refcount = 2; /* original array + sub array */ | |
proxy->data = b1->data; | |
proxy->size = | |
b1->flags & CAML_BA_MAPPED_FILE ? caml_ba_byte_size(b1) : 0; | |
b1->proxy = proxy; | |
b2->proxy = proxy; | |
} | |
} | |
CAMLprim value ba_cast_to_char(value vb) | |
{ | |
CAMLparam1(vb); | |
CAMLlocal1(res); | |
#define b (Caml_ba_array_val(vb)) | |
intnat dim[CAML_BA_MAX_NUM_DIMS]; | |
for (int i = 0; i < b->num_dims; i++) | |
{ | |
dim[i] = (i == b->num_dims - 1) ? b->dim[i] * caml_ba_element_size[b->flags & CAML_BA_KIND_MASK] : b->dim[i]; | |
} | |
int flags = (b->flags & ~CAML_BA_KIND_MASK) | CAML_BA_CHAR; | |
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 */ | |
caml_ba_update_proxy(b, Caml_ba_array_val(res)); | |
/* Return result */ | |
CAMLreturn(res); | |
#undef b | |
} |
That indeed looks much better, I will try that, thanks a lot again for all of your help.
As a mental model you can look at the caml_ba_slice
function that takes a "slice" of a bigarray without copying the data. What you are doing is not very different; and you will see there that the flags of the "source" array are copied as-is to the destination array.
I was using caml_ba_reshape
since it looks simpler, yet I didn't look close enough at what caml_ba_update_proxy
is doing. I will get some sleep and try to make the kind
an input, maybe it's possible to get that merged into ocaml trunk. It would be pretty awesome but I have no idea how the core team perceives adding new features to standard library.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yes you are right of course, but what I was thinking about is to reuse
b->flags
to a maximum (in particular the "managed"/"external" bit), and set just the "kind" bit:... but, again, some testing will be required to make sure that everything works well :)