123 lines
4.5 KiB
Plaintext
123 lines
4.5 KiB
Plaintext
(* The Rosetta Code array concatenation task, in ATS2. *)
|
|
|
|
(* In a way, the task is misleading: in a language such as ATS, one
|
|
can always devise a very-easy-to-use array type, put the code for
|
|
that in a library, and overload operators. Thus we can have
|
|
"array1 + array2" as array concatenation in ATS, complete with
|
|
garbage collection when the result no longer is needed.
|
|
|
|
It depends on what libraries are in one's repertoire.
|
|
|
|
Nevertheless, it seems fair to demonstrate how to concatenate two
|
|
barebones arrays at the nitpicking lowest level, without anything
|
|
but the barest contents of the ATS2 prelude. It will make ATS
|
|
programming look difficult; but ATS programming *is* difficult,
|
|
when you are using it to overcome the programming safety
|
|
deficiencies of a language such as C, without losing the runtime
|
|
efficiency of C code.
|
|
|
|
What we want is the kind of routine that would be used *in the
|
|
implementation* of "array1 + array2". So let us begin ... *)
|
|
|
|
#include "share/atspre_staload.hats" (* Loads some needed template
|
|
code. *)
|
|
|
|
fn {t : t@ype}
|
|
|
|
(* The demonstration will be for arrays of a non-linear type t. Were
|
|
the arrays to contain a *linear* type (vt@ype), then either the old
|
|
arrays would have to be destroyed or a copy procedure would be
|
|
needed for the elements. *)
|
|
|
|
arrayconcat1 {m, n : nat}
|
|
{pa, pb, pc : addr}
|
|
(pfa : !(@[t][m]) @ pa,
|
|
pfb : !(@[t][n]) @ pb,
|
|
pfc : !(@[t?][m + n]) @ pc >> @[t][m + n] @ pc |
|
|
pa : ptr pa,
|
|
pb : ptr pb,
|
|
pc : ptr pc,
|
|
m : size_t m,
|
|
n : size_t n) : void =
|
|
|
|
(* The routine takes as arguments three low-level arrays, passed by
|
|
value, as pointers with associated views. The first array is of
|
|
length m, with elements of type t, and the array must have been
|
|
initialized; the second is a similar array of length n. The third
|
|
array is uninitialized (thus the "?" character) and must have
|
|
length m+n; its type will change to "initialized". *)
|
|
|
|
{
|
|
prval (pfleft, pfright) = array_v_split {t?} {pc} {m + n} {m} pfc
|
|
|
|
(* We have had to split the view of array c into a left part pfleft,
|
|
of length m, and a right part pfright of length n. Arrays a and b
|
|
will be copied into the respective parts of c. *)
|
|
|
|
val _ = array_copy<t> (!pc, !pa, m)
|
|
val _ = array_copy<t> (!(ptr_add<t> (pc, m)), !pb, n)
|
|
|
|
(* Copying an array *safely* is more complex than what we are doing
|
|
here, but above the task has been given to the "array_copy"
|
|
template in the prelude. The "!" signs appear because array_copy is
|
|
call-by-reference but we are passing it pointers. *)
|
|
|
|
(* pfleft and pfright now refer to *initialized* arrays: one of length
|
|
m, starting at address pc; the other of length n, starting at
|
|
address pc+(m*sizeof<t>). *)
|
|
|
|
prval _ = pfc := array_v_unsplit {t} {pc} {m, n} (pfleft, pfright)
|
|
|
|
(* Before we can exit, the view of array c has to be replaced. It is
|
|
replaced by "unsplitting" the (now initialized) left and right
|
|
parts of the array. *)
|
|
|
|
(* We are done. Everything should now work, and the result will be
|
|
safe from buffer overruns or underruns, and against accidental
|
|
misuse of uninitialized data. *)
|
|
|
|
}
|
|
|
|
(* arrayconcat2 is a pass-by-reference interface to arrayconcat1. *)
|
|
fn {t : t@ype}
|
|
arrayconcat2 {m, n : nat}
|
|
(a : &(@[t][m]),
|
|
b : &(@[t][n]),
|
|
c : &(@[t?][m + n]) >> @[t][m + n],
|
|
m : size_t m,
|
|
n : size_t n) : void =
|
|
arrayconcat1 (view@ a, view@ b, view@ c |
|
|
addr@ a, addr@ b, addr@ c, m, n)
|
|
|
|
(* Overloads to let you say "arrayconcat" for either routine above. *)
|
|
overload arrayconcat with arrayconcat1
|
|
overload arrayconcat with arrayconcat2
|
|
|
|
implement
|
|
main0 () =
|
|
|
|
(* A demonstration program. *)
|
|
|
|
let
|
|
(* Some arrays on the stack. Because they are on the stack, they
|
|
will not need explicit freeing. *)
|
|
var a = @[int][3] (1, 2, 3)
|
|
var b = @[int][4] (5, 6, 7, 8)
|
|
var c : @[int?][7]
|
|
|
|
in
|
|
|
|
(* Compute c as the concatenation of a and b. *)
|
|
arrayconcat<int> (a, b, c, i2sz 3, i2sz 4);
|
|
|
|
(* The following simply prints the result. *)
|
|
let
|
|
(* Copy c to a linear linked list, because the prelude provides
|
|
means to easily print such a list. *)
|
|
val lst = array2list (c, i2sz 7)
|
|
in
|
|
println! (lst); (* Print the list. *)
|
|
free lst (* The list is linear and must be freed. *)
|
|
end
|
|
end
|