#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];