Given a viewtype VT and integer I, the special static term @[VT][I] is a viewtype for an array of elements of the type VT (and thus the size of @[VT][I] is I times the size of VT). If VT happens to be a type (instead of viewtype), then @[VT][I] is also a type. If a linear proof of the view (@[VT][I]) @ L is available, then we say that a linear array of size I is stored at the location L in which each element is of the type VT. A view of the form @[VT][I] @ L is often referred to as an array view.
The interfaces for various functions on linear arrays can be found in the file prelude/SATS/array.sats. In particular, we have the following functions for manipulating array views:
viewdef array_v (a:viewt@ype, n:int, l: addr) = @[a][n] @ l
praxi array_v_nil :
{a:viewt@ype} {l:addr} () -<prf> array_v (a, 0, l)
praxi array_v_unnil :
{a:viewt@ype} {l:addr} array_v (a, 0, l) -<prf> void
praxi array_v_cons : {a:viewt@ype} {n:nat} {l:addr}
(a @ l, array_v (a, n, l+sizeof a)) -<prf> array_v (a, n+1, l)
praxi array_v_uncons : {a:viewt@ype} {n:int | n > 0} {l:addr}
array_v (a, n, l) -<prf> (a @ l, array_v (a, n-1, l+sizeof a))
fun{a:viewt@ype}
array_ptr_alloc {n:nat} (asz: int n):<>
[l:addr | l <> null] (free_gc_v (a, n, l), array_v (a?, n, l) | ptr l)
The view constructor free_gc_v is abstract, and a proof of the view
free_gc_v (a, n, l) can be thought of as a certificate that must be
provided when the allocated array is to be freed. The array view
array_v (a?, n, l) is for an uninitialized array of size
n in which each element should be of the type a if
initialized.
fn{a:t@ype}
array_ptr_initialize_list {n:nat}
(A: &(@[a?][n]) >> @[a][n], xs: list (a, n))
:<> void = loop (view@ A | &A, xs) where {
fun loop {n: nat} {l:addr} .<n>. ( // [loop] is tail-recursive!
pf_arr: !array_v (a?, n, l) >> array_v (a, n, l) | p_arr: ptr l, xs: list (a, n)
) :<> void = case+ xs of
| list_cons (x, xs) => let
prval (pf1_at, pf2_arr) = array_v_uncons {a?} (pf_arr)
val () = !p_arr := x
val () = loop (pf2_arr | p_arr + sizeof<a>, xs)
in
pf_arr := array_v_cons {a} (pf1_at, pf2_arr)
end // end of [list_cons]
| list_nil () => let
prval () = array_v_unnil {a?} (pf_arr) in pf_arr := array_v_nil {a} ()
end // end of [list_nil]
// end of [loop]
} // end of [array_ptr_initialize_list]
Note that the first argument of the function
array_ptr_initialize_list is passed as a reference
(call-by-reference). We use the expression view@ A for some
particular left-value in which a proof of the view associated with the
variable A is stored, and the expression &A for the address
of the variable A.
fn{a:t@ype} array_ptr_swap
{n:nat} {i,j:nat | i < n; j < n}
(A: &(@[a][n]), i: int i, j: int j):<> void = begin
let val tmp = A.[i] in A.[i] := A.[j]; A.[j] := tmp end
end // endof [array_ptr_swap]
The following two function templates are also available:
fun{a:t@ype} array_ptr_get_elt_at
{n:nat} (A: &(@[a][n]), i: natLt n):<> a
fun{a:t@ype} array_ptr_set_elt_at
{n:nat} (A: &(@[a][n]), i: natLt n, x:a):<> void
overload [] with array_ptr_get_elt_at
overload [] with array_ptr_set_elt_at
Because of the overloading of [] with both
array_ptr_get_elt_at and array_ptr_set_elt_at, the function
array_ptr_swap can also be implemented as follows:
fn{a:t@ype} array_ptr_swap
{n:nat} {i,j:nat | i < n; j < n}
(A: &(@[a][n]), i: int i, j: int j):<> void = begin
let val tmp = A[i] in A[i] := A[j]; A[j] := tmp end
end // endof [array_ptr_swap]
The use of [i] for .[i] possibly makes the code look more conventional.
For accessing an array of linear elements, the following function template array_ptr_takeout can be used:
fun{a:viewt@ype}
array_ptr_takeout {n,i:nat | i < n} {l0:addr} (
pf: array_v (a, n, l0) | base: ptr l0, offset: int i
) :<> [l:addr] (
a @ l
, a @ l -<lin,prf> array_v (a, n, l0)
| ptr l
)
// end of [array_ptr_takeout]
fun array_ptr_free {a:viewt@ype} {n:int} {l:addr}
(pf_gc: free_gc_v (a, n, l), pf_arr: array_v (a?, n, l) | _: ptr l):<> void
Note that in order to free an array of I elements allocated at an
address L, a proof of the view free_gc_v (VT, I, L) must be
provided, where the viewtype VT is employed for specifying the size
of each element in the array.
The code used for illustration is available here.