```//
// Course: BU CAS CS 520
// Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
//

(* ****** ****** *)

dataview array_v (a:t@ype, int, addr) =
| {l:addr} array_v_nil (a, 0, l) of ()
array_v_cons (a, n+1, l) of (a @ l, array_v (a, n, l+sizeof a))
(*
// you may also define it this way:
array_v_cons (a, n+1, l) of (MUL (n, sizeof a, ofs), array_v (a, n, l), a @ l + ofs)
*)

fun{a:t@ype}
(pf: !array_v (a, n, l) | p: ptr l): a = let
prval array_v_cons (pf1, pf2) = pf // pf1: a @ l, pf2: ...
val x = !p
prval () = pf := array_v_cons {a} (pf1, pf2)
in
x
end // end of [getfst]

(*
fun{a:t@ype} // O(i)-time
getelt {n,i:nat | i < n} {l:addr}
(pf: !array_v (a, n, l) | p: ptr l, i: int i): a =
if i = 0 then getfst (pf | p)
else let
prval array_v_cons (pf1, pf2) = pf // pf1: a @ l, pf2: ...
val x = getelt {n-1,i-1} {l+sizeof a} (pf2 | p+sizeof<a>, i-1)
prval () = pf := array_v_cons {a} (pf1, pf2)
in
x
end // end of [if]
*)

extern
prfun split {a:t@ype}
{n,i:nat | i <= n}
pf_mul: MUL (i, sizeof a, ofs)
, pf_arr: array_v (a, n, l)
, i: size_t i
) : (
array_v (a, i, l), array_v (a, n-i, l+ofs)
)

extern
prfun unsplit {a:t@ype}
{i,ni:nat}
pf_mul: MUL (i, sizeof a, ofs)
, pf1_arr: array_v (a, i, l)
, pf2_arr: array_v (a, ni, l+ofs)
) : (
array_v (a, i+ni, l)
)

extern
prfun takeout {a:t@ype}
pf_mul: MUL (i, sizeof a, ofs)
, pf_arr: array_v (a, n, l)
) : (a @ l+ofs, a @ l+ofs -<lin> array_v (a, n, l))

(*
fun{a:t@ype} // O(1)-time
getelt {n,i:nat | i < n} {l:addr}
(pf: !array_v (a, n, l) | p: ptr l, i: size_t i): a = let
val (pf_mul | ofs) = mul2_size1_size1 (i, sizeof<a>)
prval (pf1, pf2) = split {a} (pf_mul, pf, i)
val x = getfst (pf2 | p + ofs)
prval () = pf := unsplit {a} (pf_mul, pf1, pf2)
in
x
end // end of [getelt]
*)

fun{a:t@ype} // O(1)-time
getelt {n,i:nat | i < n} {l:addr}
(pf: !array_v (a, n, l) | p: ptr l, i: size_t i): a = let
val (pf_mul | ofs) = mul2_size1_size1 (i, sizeof<a>)
prval (pf_at, fpf) = takeout {a} (pf_mul, pf)
val x = !(p+ofs)
prval () = pf := fpf (pf_at)
in
x
end // end of [getelt]

(* ****** ****** *)

(* end of [array.dats] *)
```