Task

Show how to concatenate two arrays in your language.



If this is as simple as array1 + array2, so be it.




(* 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