Suppose your favorite C function does some operation with an array of
values.
node_t make_node_c (unsigned id, unsigned n, node neighbors[]);
In the ATS portion of your program, you may want to work with an easier to
use interface
like the following to make building nodes a little less tedious.
fun make_node (id: uint, neighbors: List0 (node)): node
Using functions in the ATS2 prelude, we can easily provide this
functionality.
Assume we’ve given the C function the following type in ATS. Suppose node
is just an abstract type.
abstype node = ptr
fun make_node_c {n:nat} (id: uint, n: uint n, neighbors:
&(@[node][n])): node = “mac#”
Now, let’s implement the version that takes a list instead.
implement make_node (id, neighbors) = let
val n = g1int2uint (length (neighbors))
//
val (pf , gc | p) = array_ptr_alloc<node> (u2sz (n))
val () = array_copy_from_list<node> (!p, neighbors)
//
val node = make_node_c (id, n, !p)
//
val () = array_ptr_free{node} (pf, gc | p)
in
node
end
Now, building nodes using the underlying C library should be much simpler
than before. If each node is
reference counted, you would have to make the node type linear to prevent
memory leaks. Suppose
we want the following function
absvtype node = ptr
fun make_node_vt (id: uint, neighbors: !List0_vt (node)): node
Which means that we make a new node, but preserve the linear list of nodes
(The ! operator specifies the list is not consumed).
Assuming our C function doesn’t affect the reference count of any nodes in
the array we give it, we could have the following
implementation:
implement make_node_vt (id, neighbors) = let
val n = g1int2uint (length (neighbors))
//
val (pf , gc | p) = array_ptr_alloc<node> (u2sz (n))
val () = array_copy_from_list_vt<node> (!p, neighbors)
//
val node = make_node_c (id, n, !p)
//
val nss = array_copy_to_list_vt<node> (!p, u2sz (n))
val () = array_ptr_free{node} (pf, gc | p)
(* Put the nodes "back" into neighbors *)
val () = neighbors := nss
in
node
end
Which may be simpler to work with than allocating, initializing,
uninitializing (freeing nodes in the arrays), and de-allocating arrays
whenever you
want to make a node.