```  #line 411 "/home/travis/build/felix-lang/felix/src/packages/arrays.fdoc"

Compile time fix length array.
open class Farray
{
typedef array[t,n] = t ^ n;

//ctor[T,N] array[T,N] (x:array[T,N]) => x;

Array copy.
fun copy[T,N] (var x:array[T,N]) => x;

Array of one element.
ctor[T] array[T,1] (x:T) => x :>> array[T,1];

Array as value.
instance[t,n] ArrayValue[array[t,n], t] {
fun len (x:array[t, n]): size => Typing::arrayindexcount[n];

//fun unsafe_get: array[t, n] * size -> t = "\$1.data[\$2]";
fun unsafe_get (var a: array[t, n], j: size): t => a . (j :>> n);
}

Pointer to array as value.
instance[t,n] ArrayValue[&array[t,n], &t] {
fun len (x:&array[t, n]): size => Typing::arrayindexcount[n];
/* won't work for compact linear types! */
fun unsafe_get: &array[t, n] * size  -> &t = "(&(\$1->data[\$2]))";
}

// this one should
proc unsafe_set[t,n] (a: &(t^n), i:size, v:t) { a . (i.int) <- v; }

proc set[t,n, I in ints] (a: &array[t,n], i:I,v:t) {
assert i.size < (*a).len;
unsafe_set (a,i.size,v);
}

// these cannot work for compact linear arrays
fun stl_begin[t,n]: &array[t,n] -> +t = "(?1*)(\$1->data)";
fun stl_end[t,n] ( x:&array[t,n] ) : +t => stl_begin x + x*.len;

Array map.
fun map[V,N,U] (_f:V->U) (x:array[V,N]):array[U,N] = {
var o : array[U,N];
val n = x.len;
if n > 0uz
for var i: size in 0uz upto n - 1uz
call set (&o,i, _f x.i)
;
return o;
}

// Note: for many loops below, note we're using unsigned values
// iterating from 0 to N-1. Subtraction N-1 fails for n == 0
// so we need a special test.

Join two arrays (functional).
fun join[T, N, M] (x:array[T, N]) (y:array[T, M]):array[T, N + M] = {
var o : array[T, N + M];

if x.len > 0uz
for var i in 0uz upto len(x) - 1uz
call set (&o, i,x.i)
;
i = x.len;
if y.len > 0uz
for var k in 0uz upto len(y) - 1uz
call set(&o,i + k, y.k)
;
return o;
}

Append value to end of an array (functional).
fun join[T, N] (x:array[T, N]) (y:T):array[T, N + 1] = {
var o : array[T, N + 1];

if x.len > 0uz
for var i in 0uz upto len(x) - 1uz
call set (&o, i,x.i)
;
set(&o,x.len, y);
return o;
}

Prepand value to start of an array (functional).
fun join[T, M] (x:T) (y:array[T, M]):array[T, 1 + M] = {
var o : array[T, 1 + M];

set (&o, 0, x);
if y.len > 0uz
for var k in 0uz upto len(y) - 1uz
call set(&o,1uz + k, y.k)
;
return o;
}

Join two arrays (functional).
// will probably clash with tuple joining functions if we implement them
fun + [T, N, M] (x:array[T, N], y:array[T, M]):array[T, N + M] => join x y;

Transpose and array.
Subsumes zip.
Example: transpose ( (1,2,3), (4,5,6) ) = ( (1,4), (2,4), (3,6) ).
fun transpose[T,N,M] (y:array[array[T,M],N]) : array[array[T,N],M] = {
var o : array[array[T,N],M];
var n = len y;
var m = len y.0;
for var i in 0uz upto n - 1uz
for var j in 0uz upto m - 1uz do
val pfirst : +array[T,N] = &o.stl_begin;
val psub: +array[T,N] = pfirst + j;
val pelt : +T = psub.stl_begin;
set(pelt,i, y.i.j);
done
return o;
}

Reverse elements of an array.
fun rev[T, N] (x:array[T, N]): array[T, N] = {
var o : array[T, N];
var n = len x;
if n > 0uz
for var i:size in 0uz upto n - 1uz
call set(&o,n - 1uz - i, x.i)
;
return o;
}

fun sort[T,N] (cmp: T * T -> bool) (var x:array[T,N]) : array[T,N] = {
Sort::stl_sort (Sort::stl_comparator cmp, stl_begin (&x), stl_end (&x));
return x;
}

fun sort[T,N] (var x:array[T,N]) : array[T,N] = {
Sort::stl_sort (stl_begin (&x), stl_end (&x));
return x;
}

Display: convert to string like (1,2,3).
instance[T,N with Show[T]] Str[array[T, N]] {
fun str (xs:array[T,N]) = {
var o = '(';
val n = xs.len;
if n  > 0uz do
o += repr xs.0;

for var i:size in 1uz upto n - 1uz
perform o += ', ' + repr xs.i
;
done
return o + ')';
}
}

Equality and Inequality.
instance[T,N with Eq[T]] Eq[array[T, N]] {
fun == (xs:array[T,N],ys:array[T,N]) = {
val n = xs.len;
// assert n == ys.len;
if n == 0uz do
return true;
else
for var i:size in 0uz upto n - 1uz
if not (xs.i == ys.i) return false;
done
return true;
}
}

Lexicographical total order based on
total order of elements.
instance[T,N with Tord[T]] Tord[array[T,N]] {
fun < (xs:array[T,N],ys:array[T,N]) = {
val n = xs.len;
if n == 0uz return false;
// assert n == ys.len;
var i:size;
ph1:for i in 0uz upto n - 1uz
if not (xs.i < ys.i) break ph1;
for i in i upto n - 1uz
if not (xs.i <= ys.i) return false;
return true;
}
}
}

open[T,N] Eq[array[T,N]];
open[T,N] Tord[array[T,N]];
open[T,N with Eq[T]] Set[array[T,N],T];

open[T,N] ArrayValue[array[T,N], T];
open[T,N] ArrayValue[&array[T,N], &T];

```