Package: src/packages/dynamic_metatyping.fdoc

Dynamic Meta-typing

key file
typedesc.flx share/lib/std/felix/dyntype/typedesc.flx

First Class Type Descriptor.

//[typedesc.flx]
include "std/felix/rtti";

class DynamicMetaTyping
{
  open Rtti;

  interface typedesc_t
  {
    name: 1 -> string;
    len: 1 -> size; // all the objects
    object_size: 1 -> size; // one object
    object_alignment: 1 -> size;
    dflt_init : address -> 0;
    destroy : address -> 0;
    copy_init : address * address -> 0;
    move_init : address * address -> 0; // leaves src dflt init
    copy_assign : address * address -> 0;
    move_assign : address * address -> 0; // leaves source dflt init
  }

  object CxxType (fcops: Rtti::fcops_t, tname:string, tlen: size)
    implements typedesc_t
  =
  {
    method fun name () => tname;

    method fun len() => tlen;

    method fun object_size() => Rtti::object_size fcops;
    method fun object_alignment() => Rtti::object_alignment fcops;

    method proc dflt_init (dst:address)
      => Rtti::dflt_init (fcops, dst);

    method proc destroy(dst:address)
      => Rtti::destroy(fcops, dst);

    method proc copy_init (dst:address, src:address)
      => Rtti::copy_init (fcops, dst, src);

    method proc move_init (dst:address, src:address)
      => Rtti::move_init (fcops, dst, src);

    method proc copy_assign (dst:address, src:address) {
      println$ "Felix CxxType.copy_assign "+dst.str+ " <- " + src.str;
      Rtti::copy_assign (fcops, dst, src);
    }

    method proc move_assign(dst:address, src:address)
      => Rtti::move_assign (fcops, dst, src);
  }

  ctor typedesc_t (ptd: gc_shape_t) =>
    let fcops = ptd.get_fcops in
    let name = ptd.cname.string in
    let esize = ptd.bytes_per_element * ptd.number_of_elements in
    CxxType (fcops, name, esize)
  ;


  typedef binproc_t = address * address -> 0; // P2
  typedef unproc_t = address -> 0; // P1
  typedef get_size_t = 1 -> size; // FZ

  // NOTE: currently NOT GC aware!

  body FelixValueType_poly[P2,A2,P1,FZ] = """
    class FelixValueType : public virtual ValueType
    {
      ?4 object_size_ptr;
      ?4 object_size_ptr;
      ?3 dflt_init_ptr;
      ?3 destroy_ptr;
      ?1 copy_init_ptr;
      ?1 move_init_ptr;
      ?1 copy_assign_ptr;
      ?1 move_assign_ptr;

      size_t object_size() { return sizeof(?1); }
      size_t object_alignment() { return alignof(?1); }

      void dflt_init_impl (void *dst) {
        ::flx::rtl::executil::run (dflt_init_ptr->call(0,dst));
      }

      void destroy_impl (void *dst) {
        ::flx::rtl::executil::run (destroy_ptr->call(0,dst));
      }

      void copy_init_impl (void *dst, void *src) {
        ::flx::rtl::executil::run (copy_init_ptr->call(0,?2(dst,src)));
      }

      void move_init_impl (void *dst, void *src) {
        ::flx::rtl::executil::run (move_init_ptr->call(0,?2(dst,src)));
      }

      void copy_assign_impl (void *dst, void *src) {
        fprintf(stderr, "C++FelixValueType.copy_assign %p<-%p\\n",dst,src);
        ::flx::rtl::executil::run (copy_assign_ptr->call(0,?2(dst,src)));
      }

      void move_assign_impl (void *dst, void *src) {
        ::flx::rtl::executil::run (move_assign_ptr->call(0,?2(dst,src)));
      }

    public:
      FelixValueType (?3 di, ?3 de, ?1 ci, ?1 mi, ?1 ca, ?1 ma) :
        dflt_init_ptr (di),
        destroy_ptr (de),
        copy_init_ptr (ci),
        move_init_ptr (mi),
        copy_assign_ptr (ca),
        move_assign_ptr (ma)
        {}
    };
  """;

  // Tricky! Declare incomplete type in header
  // Implement class in body
  header FelixValueType_class = "class FelixValueType;"
    requires FelixValueType_poly[binproc_t, address^2, unproc_t, get_size_t],
    package "flx_executil"
  ;

  type FelixValueType = "FelixValueType*" requires FelixValueType_class;

  ctor FelixValueType : copy_t * copy_t * copy_t * copy_t =
    "new FelixValueType ($1, $2, $3, $4)"
  ;

  ctor FelixValueType (x:DynamicMetaTyping::typedesc_t) =>
    FelixValueType (
      x.object_size,
      x.object_alignment,
      x.dflt_init,
      x.destroy_init,
      x.copy_init,
      x.move_init,
      x.copy_assign,
      x.move_assign
    )
  ;

  fun ValueType_from_FelixValueType: FelixValueType -> fcops_t = "(ValueType*)$1";

  object TupleType (tname:string, elts: list[typedesc_t]) implements typedesc_t =
  {
     fun align : size -> size =
       | 0uz => 0uz
       | 1uz => 1uz
       | 2uz => 2uz
       | 3uz => 4uz
       | 4uz => 4uz
       | 5uz => 8uz
       | 6uz => 8uz
       | 7uz => 8uz
       | 8uz => 8uz
       | _ => 16uz
     ;

     var n = len elts;
     assert n != 0uz;
println$ "Tuple " + tname + " with " + n.str + " fields";
     var aligned = varray[typedesc_t * size] n;
     var ofset = 0uz;
     var tl = elts;
     var counter = 0;
  next_elt:>
println$ "Offset " + ofset.str;
     match  tl with
     | #Empty => ;
     | Cons (head, (Cons (nxt, _) as tail)) =>
println$ "Add field " + counter.str + "/" + n.str;
       push_back (aligned, (head,ofset));
       // alignment rules: the offset of the next object is
       // aligned to the greater of the alignment of the current
       // and next objects
       var hz = head.len ();
       var nz = nxt.len ();
       var alignment = max (align hz, align nz);
       ofset = ((ofset + hz + alignment - 1) / alignment) * alignment;
       tl = tail ;
       ++counter;
       goto next_elt;

     | Cons (head, #Empty) =>
println$ "Add last field " + counter.str + "/" + n.str;
       push_back (aligned, (head,ofset));
       hz = head.len ();
       alignment = align hz;
       ofset = ((ofset + hz + alignment - 1) / alignment) * alignment;
     endmatch;
     var length = ofset;
     println$ "Tuple " + tname + " length= " + length.str;
     println$ "Tuple " + tname + " fields= ";
     for var i in 0uz upto n - 1uz do
       var typ,ofs = aligned.i;
       println$ "Field #"+i.str+ " at offset " + ofs.str + " type " + #(typ.name).str;
     done

    method fun len () => length;
    method fun name () => tname;

    method proc dflt_init (dst:address) =>
      for var i in 0uz upto n - 1uz do
         var typ,ofs = aligned.i;
         typ.dflt_init (dst + ofs);
      done

    method proc destroy(dst:address) =>
      for var i in 0uz upto n - 1uz do
         var typ,ofs = aligned.i;
         typ.destroy(dst + ofs);
      done



    method proc copy_init (dst:address, src:address) =>
      for var i in 0uz upto n - 1uz do
         var typ,ofs = aligned.i;
         typ.copy_init (dst + ofs, src + ofs);
      done

    method proc move_init (dst:address, src:address)  =>
     perform assert false;

    method proc copy_assign (dst:address, src:address) =>
      perform assert false;

    method proc move_assign(dst:address, src:address) =>
      perform assert false;

  }

} // end class DynamicMetaTyping