Skip to content

Instantly share code, notes, and snippets.

@crackcomm
Last active September 12, 2021 13:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crackcomm/9d5fbeaa8e038194cdbf0ba990d698e6 to your computer and use it in GitHub Desktop.
Save crackcomm/9d5fbeaa8e038194cdbf0ba990d698e6 to your computer and use it in GitHub Desktop.
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
;;
(library
(name bigarray_str)
(public_name bigarray_str)
(libraries core)
(foreign_stubs
(language c)
(names stubs)
(flags -std=c99 -pedantic)))
#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
}
@nojb
Copy link

nojb commented Sep 11, 2021

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.

@crackcomm
Copy link
Author

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