#line 934 "/home/travis/build/felix-lang/felix/src/packages/trees.fdoc"
  
  // NOTES: The Felix type 'address' is the correct type for Judy Word
  // However it is also an unsigned integer type (int or long depending
  // on platform)
  //
  // But Felix doesn't support automatic int/address conversions
  //
  // So we will (later) use a typeset to fix this!
  class Judy
  {
    requires package "judy";
    requires header "#include <Judy.h>";
    open C_hack;
  
    type word = "Word_t";
    ctor word: !ints = "(Word_t)$1";
    ctor word: address = "(Word_t)$1";
    ctor int: word = "(int)$1";
    ctor uint: word = "(int)$1";
    ctor ulong: word = "(unsigned long)$1";
    ctor size: word = "(size_t)$1";
    ctor address: word = "(void*)$1";
    fun isNULL: word -> bool = "$1==0";
    fun isNULL: &word -> bool = "$1==0";
  
    type JError_t = "JError_t";
  
    private body mkjudy =
      """
        static void **_mkjudy(FLX_APAR_DECL ::flx::gc::generic::gc_shape_t *jptr_map){
          typedef void *voidp; // syntax
          void **m = new (*PTF gcp, *jptr_map, false) voidp;
          *m=0;
          return m;
        }
      """
    ;
  
    // the "value" of a judy array is just a void*
    // to mutate it though, we need it to be on the heap
    // and use the pointer to that object as the array,
    // so that it can be copied about
    private body j1free =
      """
        static void _j1free(::flx::gc::generic::collector_t*,void *p) {
          //printf("Free J1Array %p\\n",p);
          JError_t je;
          Judy1FreeArray((void**)p, &je);
        }
      """
    ;
    private type J1Array_ = "void*"
      requires
        scanner "::flx::gc::generic::Judy1_scanner",
        header '#include "flx_judy_scanner.hpp"',
        finaliser '_j1free',
        j1free
    ;
    _gc_pointer _gc_type J1Array_ type J1Array = "void**" requires property "needs_gc";
  
    gen _ctor_J1Array: 1 -> J1Array = "_mkjudy(FLX_POINTER_TO_THREAD_FRAME, &@0)"
      requires
        mkjudy,
        property "needs_gc"
    ;
  
    proc free: J1Array = "_j1free(NULL,$1);" requires j1free;
  
    proc Judy1Set: J1Array * word * &JError_t * &int =
      "*$4=Judy1Set($1,$2,$3);";
  
    proc Judy1Unset: J1Array * word * &JError_t * &int =
      "*$4=Judy1Unset($1,$2,$3);";
  
    proc Judy1Test: J1Array * word * &JError_t * &int =
      "*$4=Judy1Test(*$1,$2,$3);";
  
    instance Set[J1Array,word] {
      fun \(\in\) (x:word, a:J1Array) : bool = {
        var e:JError_t;
        var r:int;
        Judy1Test(a,x,&e,&r);
        return r == 1;
      }
    }
    proc Judy1Count: J1Array * word * word* &JError_t * &word =
      "*$5=Judy1Count(*$1,$2,$3,$4);";
  
    proc Judy1ByCount: J1Array * word * &word * &JError_t * &word =
      "*$5=Judy1ByCount(*$1,$2,$3,$4);";
  
    proc Judy1FreeArray: J1Array * &JError_t * &word =
      "*$3=Judy1FreeArray($1,$2);";
  
    proc Judy1MemUsed: J1Array * &word = "*$2=Judy1MemUsed(*$1);";
  
    proc Judy1First: J1Array * &word * &JError_t * &int =
      "*$4=Judy1First(*$1,$2,$3);";
  
    proc Judy1Next: J1Array * &word * &JError_t * &int =
      "*$4=Judy1Next(*$1,$2,$3);";
  
    proc Judy1Last: J1Array * &word * &JError_t * &int =
      "*$4=Judy1Last(*$1,$2,$3);";
  
    proc Judy1Prev: J1Array * &word * &JError_t * &int =
      "*$4=Judy1Prev(*$1,$2,$3);";
  
    proc Judy1FirstEmpty: J1Array * &word * &JError_t * &int =
      "*$4=Judy1FirstEmpty(*$1,$2,$3);";
  
    proc Judy1NextEmpty: J1Array * &word * &JError_t * &int =
      "*$4=Judy1NextEmpty(*$1,$2,$3);";
  
    proc Judy1LastEmpty: J1Array * &word * &JError_t * &int =
      "*$4=Judy1LastEmpty(*$1,$2,$3);";
  
    proc Judy1PrevEmpty: J1Array * &word * &JError_t * &int =
      "*$4=Judy1PrevEmpty(*$1,$2,$3);";
  
  ///////////////////////////////////////
    private body jLfree =
      """
        static void _jLfree(::flx::gc::generic::collector_t*,void *p) {
          //printf("Free JLArray %p\\n",p);
          JError_t je;
          JudyLFreeArray((void**)p, &je);
        }
      """
    ;
    private type JLArray_ = "void*"
      requires
        scanner "::flx::gc::generic::JudyL_scanner",
        header '#include "flx_judy_scanner.hpp"',
        finaliser '_jLfree',
        jLfree
    ;
    _gc_pointer _gc_type JLArray_ type JLArray = "void**" requires property "needs_gc";
  
    gen _ctor_JLArray: 1 -> JLArray = "_mkjudy(FLX_POINTER_TO_THREAD_FRAME, &@0)"
      requires
        mkjudy,
        property "needs_gc"
    ;
  
    proc free: JLArray = "_jLfree(NULL,$1);" requires jLfree;
  
  
    proc JudyLIns: JLArray * word * &JError_t * &&word =
      "*(Word_t**)$4=(Word_t*)JudyLIns($1,$2,$3);";
  
    proc JudyLDel: JLArray * word * &JError_t * &int =
      "*$4=JudyLDel($1,$2,$3);";
  
    proc JudyLGet: JLArray * word * &JError_t * &&word =
      "*$4=(Word_t*)JudyLGet(*$1,$2,$3);";
  
    proc JudyLCount: JLArray * word * word * &JError_t * &word =
      "*$5=JudyLCount(*$1,$2,$3,$4);";
  
    proc JudyLByCount: JLArray * word * &word * &JError_t * &&word =
      "*$5=JudyLCount(*$1,$2,$3,$4);";
  
    proc JudyLFreeArray: JLArray * &JError_t * &word =
      "*$3=JudyLFree($1,$2);";
  
    proc JudyLMemUsed: JLArray * &word =
      "*$2=JudyLMemUsed(*$1);";
  
    proc JudyLFirst: JLArray * &word * &JError_t * &&word =
      "*(Word_t**)$4=(Word_t*)JudyLFirst(*$1,$2,$3);";
  
    proc JudyLNext: JLArray * &word * &JError_t * &&word =
      "*(Word_t**)$4=(Word_t*)JudyLNext(*$1,$2,$3);";
  
    proc JudyLLast: JLArray * &word * &JError_t * &&word =
      "*(Word_t**)$4=(Word_t*)JudyLLast(*$1,$2,$3);";
  
    proc JudyLPrev: JLArray * &word * &JError_t * &&word =
      "*(Word_t**)$4=(Word_t*)JudyLPrev(*$1,$2,$3);";
  
    proc JudyLFirstEmpty: JLArray * &word * &JError_t * &word =
      "*$4=JudyLFirstEmpty(*$1,$2,$3);";
  
    proc JudyLNextEmpty: JLArray * &word * &JError_t * &word =
      "*$4=JudyLNextEmpty(*$1,$2,$3);";
  
    proc JudyLLastEmpty: JLArray * &word * &JError_t * &word =
      "*$4=JudyLLastEmpty(*$1,$2,$3);";
  
    proc JudyLPrevEmpty: JLArray * &word * &JError_t * &word =
      "*$4=JudyLPrevEmpty(*$1,$2,$3);";
  
  ///////////////////////////////////////
  // We should improve the safety here, unbounded string
  // lengths .. yuck. char *buffer for results .. overruns possible!
  
    body JudySL_maxlen = "#define JUDY_SL_MAXLEN 10000";
    body jSLfree =
      """
        static void _jSLfree(::flx::gc::generic::collector_t*,void *p) {
          //printf("Free JSLArray %p\\n",p);
          JError_t je;
          JudySLFreeArray((void**)p, &je);
        }
      """
    ;
    private type JSLArray_ = "void*"
      requires
        scanner "::flx::gc::generic::JudySL_scanner",
        header '#include "flx_judy_scanner.hpp"',
        finaliser '_jSLfree',
        jSLfree, JudySL_maxlen
    ;
    _gc_pointer _gc_type JSLArray_ type JSLArray = "void**" requires property "needs_gc";
  
    gen _ctor_JSLArray: 1 -> JSLArray = "_mkjudy(FLX_POINTER_TO_THREAD_FRAME, &@0)"
      requires
        mkjudy ,
        property "needs_gc"
    ;
  
    proc free: JSLArray = "_jSLfree(NULL,$1);" requires jSLfree;
  
    const JUDY_SL_MAXLEN : int = "JUDY_SL_MAXLEN";
  
    proc JudySLIns: JSLArray * +char * &JError_t * &&word =
      """
        if (::std::strlen($2) >= JUDY_SL_MAXLEN) throw "JudySLIns strlen>10000";
        *(Word_t**)$4=(Word_t*)JudySLIns($1,(unsigned char*)$2,$3);
      """ requires Cxx_headers::cstring;
  
    proc JudySLDel: JSLArray * +char * &JError_t * &int =
      "*$4=JudySLDel($1,(unsigned char*)$2,$3);";
  
    proc JudySLGet: JSLArray * +char * &JError_t * &&word =
      "*$4=(Word_t*)JudySLGet(*$1,(unsigned char*)$2,$3);";
  
    proc JudySLFirst: JSLArray * +char * &JError_t * &&word =
      "*(Word_t**)$4=(Word_t*)JudySLFirst(*$1,(unsigned char*)$2,$3);";
  
    proc JudySLNext: JSLArray * +char * &JError_t * &&word =
      "*(Word_t**)$4=(Word_t*)JudySLNext(*$1,(unsigned char*)$2,$3);";
  
    proc JudySLLast: JSLArray * +char * &JError_t * &&word =
      "*$4=JudySLLast(*$1,(unsigned char*)$2,$3);";
  
    proc JudySLPrev: JSLArray * +char * &JError_t * &&word =
      "*$4=JudySLPrev(*$1,(unsigned char*)$2,$3);";
  
  ///////////////////////////////////////
  
  /* JUDYHS is not supported because there's no way to iterate
     which is required for the GC to work
  
    type JHSArray = "void**";
    gen _ctor_JHSArray: 1 -> JHSArray = "_mkjudy()" requires mkjudy;
  
    proc free: JHSArray = "_jHSfree($1);" requires body
      """
        void _jHSfree(void **p) { JudyHSFreeArray(p); free(p); }
      """;
  
    proc JudyHSIns: JHSArray * address * word * &JError_t * &&word =
      "*$5=(Word_t*)JudyHSIns($1,$2,$3,$4);";
  
    proc JudyHSDel: JHSArray * address * word * &JError_t * &int =
      "*$5=JudyHSDel($1,$2,$3,$4);";
  
    proc JudyHSGet: JHSArray * address * word * &JError_t * &&word =
      "*$5=(Word_t*)JudyHSGet(*$1,$2,$3);";
  */
  
  }
  
  open Set[Judy::J1Array,Judy::word];