nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

codegen_c_builder.c (104287B)


      1 #include <string.h>
      2 
      3 #include "codegen_c.h"
      4 
      5 int fb_gen_common_c_builder_header(fb_output_t *out)
      6 {
      7     const char *nsc = out->nsc;
      8     const char *nscup = out->nscup;
      9 
     10     fprintf(out->fp, "#ifndef %s_COMMON_BUILDER_H\n", nscup);
     11     fprintf(out->fp, "#define %s_COMMON_BUILDER_H\n", nscup);
     12     fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n");
     13     fprintf(out->fp, "/* Common FlatBuffers build functionality for C. */\n\n");
     14     gen_prologue(out);
     15 
     16     fprintf(out->fp, "#ifndef FLATBUILDER_H\n");
     17     fprintf(out->fp, "#include \"flatcc/flatcc_builder.h\"\n");
     18     fprintf(out->fp, "#endif\n");
     19     if (strcmp(nsc, "flatcc_builder_")) {
     20         fprintf(out->fp, "typedef flatcc_builder_t %sbuilder_t;\n", nsc);
     21         fprintf(out->fp, "typedef flatcc_builder_ref_t %sref_t;\n", nsc);
     22         fprintf(out->fp, "typedef flatcc_builder_ref_t %svec_ref_t;\n", nsc);
     23         fprintf(out->fp, "typedef flatcc_builder_union_ref_t %sunion_ref_t;\n", nsc);
     24         fprintf(out->fp, "typedef flatcc_builder_union_vec_ref_t %sunion_vec_ref_t;\n", nsc);
     25         fprintf(out->fp, "/* integer return code (ref and ptr always fail on 0) */\n"
     26                 "#define %sfailed(x) ((x) < 0)\n", nsc);
     27     }
     28     fprintf(out->fp, "typedef %sref_t %sroot_t;\n", nsc, nsc);
     29     fprintf(out->fp, "#define %sroot(ref) ((%sroot_t)(ref))\n", nsc, nsc);
     30     if (strcmp(nsc, "flatbuffers_")) {
     31         fprintf(out->fp, "#define %sis_native_pe flatbuffers_is_native_pe\n", nsc);
     32         fprintf(out->fp, "typedef flatbuffers_fid_t %sfid_t;\n", nsc);
     33     }
     34     fprintf(out->fp, "\n");
     35 
     36     fprintf(out->fp,
     37         "#define __%smemoize_begin(B, src)\\\n"
     38         "do { flatcc_builder_ref_t _ref; if ((_ref = flatcc_builder_refmap_find((B), (src)))) return _ref; } while (0)\n"
     39         "#define __%smemoize_end(B, src, op) do { return flatcc_builder_refmap_insert((B), (src), (op)); } while (0)\n"
     40         "#define __%smemoize(B, src, op) do { __%smemoize_begin(B, src); __%smemoize_end(B, src, op); } while (0)\n"
     41         "\n",
     42         nsc, nsc, nsc, nsc, nsc);
     43 
     44     fprintf(out->fp,
     45         "#define __%sbuild_buffer(NS)\\\n"
     46         "typedef NS ## ref_t NS ## buffer_ref_t;\\\n"
     47         "static inline int NS ## buffer_start(NS ## builder_t *B, const NS ##fid_t fid)\\\n"
     48         "{ return flatcc_builder_start_buffer(B, fid, 0, 0); }\\\n"
     49         "static inline int NS ## buffer_start_with_size(NS ## builder_t *B, const NS ##fid_t fid)\\\n"
     50         "{ return flatcc_builder_start_buffer(B, fid, 0, flatcc_builder_with_size); }\\\n"
     51         "static inline int NS ## buffer_start_aligned(NS ## builder_t *B, NS ##fid_t fid, uint16_t block_align)\\\n"
     52         "{ return flatcc_builder_start_buffer(B, fid, block_align, 0); }\\\n"
     53         "static inline int NS ## buffer_start_aligned_with_size(NS ## builder_t *B, NS ##fid_t fid, uint16_t block_align)\\\n"
     54         "{ return flatcc_builder_start_buffer(B, fid, block_align, flatcc_builder_with_size); }\\\n"
     55         "static inline NS ## buffer_ref_t NS ## buffer_end(NS ## builder_t *B, NS ## ref_t root)\\\n"
     56         "{ return flatcc_builder_end_buffer(B, root); }\n"
     57         "\n",
     58         nsc);
     59 
     60     fprintf(out->fp,
     61         "#define __%sbuild_table_root(NS, N, FID, TFID)\\\n"
     62         "static inline int N ## _start_as_root(NS ## builder_t *B)\\\n"
     63         "{ return NS ## buffer_start(B, FID) ? -1 : N ## _start(B); }\\\n"
     64         "static inline int N ## _start_as_root_with_size(NS ## builder_t *B)\\\n"
     65         "{ return NS ## buffer_start_with_size(B, FID) ? -1 : N ## _start(B); }\\\n"
     66         "static inline int N ## _start_as_typed_root(NS ## builder_t *B)\\\n"
     67         "{ return NS ## buffer_start(B, TFID) ? -1 : N ## _start(B); }\\\n"
     68         "static inline int N ## _start_as_typed_root_with_size(NS ## builder_t *B)\\\n"
     69         "{ return NS ## buffer_start_with_size(B, TFID) ? -1 : N ## _start(B); }\\\n"
     70         "static inline NS ## buffer_ref_t N ## _end_as_root(NS ## builder_t *B)\\\n"
     71         "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n"
     72         "static inline NS ## buffer_ref_t N ## _end_as_typed_root(NS ## builder_t *B)\\\n"
     73         "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n"
     74         /*
     75          * Unlike structs, we do no use flatcc_builder_create_buffer
     76          * because we would have to manage alignment, and we save very
     77          * little because tables require stack allocations in any case.
     78          */
     79         "static inline NS ## buffer_ref_t N ## _create_as_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
     80         "{ if (NS ## buffer_start(B, FID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n"
     81         "static inline NS ## buffer_ref_t N ## _create_as_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
     82         "{ if (NS ## buffer_start_with_size(B, FID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n"
     83         "static inline NS ## buffer_ref_t N ## _create_as_typed_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
     84         "{ if (NS ## buffer_start(B, TFID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n"
     85         "static inline NS ## buffer_ref_t N ## _create_as_typed_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
     86         "{ if (NS ## buffer_start_with_size(B, TFID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n"
     87         "static inline NS ## buffer_ref_t N ## _clone_as_root(NS ## builder_t *B, N ## _table_t t)\\\n"
     88         "{ if (NS ## buffer_start(B, FID)) return 0; return NS ## buffer_end(B, N ## _clone(B, t)); }\\\n"
     89         "static inline NS ## buffer_ref_t N ## _clone_as_root_with_size(NS ## builder_t *B, N ## _table_t t)\\\n"
     90         "{ if (NS ## buffer_start_with_size(B, FID)) return 0; return NS ## buffer_end(B, N ## _clone(B, t)); }\\\n"
     91         "static inline NS ## buffer_ref_t N ## _clone_as_typed_root(NS ## builder_t *B, N ## _table_t t)\\\n"
     92         "{ if (NS ## buffer_start(B, TFID)) return 0;return NS ## buffer_end(B, N ## _clone(B, t)); }\\\n"
     93         "static inline NS ## buffer_ref_t N ## _clone_as_typed_root_with_size(NS ## builder_t *B, N ## _table_t t)\\\n"
     94         "{ if (NS ## buffer_start_with_size(B, TFID)) return 0; return NS ## buffer_end(B, N ## _clone(B, t)); }\n"
     95         "\n",
     96         nsc);
     97 
     98     fprintf(out->fp,
     99         "#define __%sbuild_table_prolog(NS, N, FID, TFID)\\\n"
    100         "__%sbuild_table_vector_ops(NS, N ## _vec, N)\\\n"
    101         "__%sbuild_table_root(NS, N, FID, TFID)\n"
    102         "\n",
    103         nsc, nsc, nsc);
    104 
    105 
    106     fprintf(out->fp,
    107         "#define __%sbuild_struct_root(NS, N, A, FID, TFID)\\\n"
    108         "static inline N ## _t *N ## _start_as_root(NS ## builder_t *B)\\\n"
    109         "{ return NS ## buffer_start(B, FID) ? 0 : N ## _start(B); }\\\n"
    110         "static inline N ## _t *N ## _start_as_root_with_size(NS ## builder_t *B)\\\n"
    111         "{ return NS ## buffer_start_with_size(B, FID) ? 0 : N ## _start(B); }\\\n"
    112         "static inline N ## _t *N ## _start_as_typed_root(NS ## builder_t *B)\\\n"
    113         "{ return NS ## buffer_start(B, TFID) ? 0 : N ## _start(B); }\\\n"
    114         "static inline N ## _t *N ## _start_as_typed_root_with_size(NS ## builder_t *B)\\\n"
    115         "{ return NS ## buffer_start_with_size(B, TFID) ? 0 : N ## _start(B); }\\\n"
    116         "static inline NS ## buffer_ref_t N ## _end_as_root(NS ## builder_t *B)\\\n"
    117         "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n"
    118         "static inline NS ## buffer_ref_t N ## _end_as_typed_root(NS ## builder_t *B)\\\n"
    119         "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n"
    120         "static inline NS ## buffer_ref_t N ## _end_pe_as_root(NS ## builder_t *B)\\\n"
    121         "{ return NS ## buffer_end(B, N ## _end_pe(B)); }\\\n"
    122         "static inline NS ## buffer_ref_t N ## _end_pe_as_typed_root(NS ## builder_t *B)\\\n"
    123         "{ return NS ## buffer_end(B, N ## _end_pe(B)); }\\\n"
    124         "static inline NS ## buffer_ref_t N ## _create_as_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
    125         "{ return flatcc_builder_create_buffer(B, FID, 0,\\\n"
    126         "  N ## _create(B __ ## N ## _call_args), A, 0); }\\\n"
    127         "static inline NS ## buffer_ref_t N ## _create_as_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
    128         "{ return flatcc_builder_create_buffer(B, FID, 0,\\\n"
    129         "  N ## _create(B __ ## N ## _call_args), A, flatcc_builder_with_size); }\\\n"
    130         "static inline NS ## buffer_ref_t N ## _create_as_typed_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
    131         "{ return flatcc_builder_create_buffer(B, TFID, 0,\\\n"
    132         "  N ## _create(B __ ## N ## _call_args), A, 0); }\\\n"
    133         "static inline NS ## buffer_ref_t N ## _create_as_typed_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
    134         "{ return flatcc_builder_create_buffer(B, TFID, 0,\\\n"
    135         "  N ## _create(B __ ## N ## _call_args), A, flatcc_builder_with_size); }\\\n"
    136         "static inline NS ## buffer_ref_t N ## _clone_as_root(NS ## builder_t *B, N ## _struct_t p)\\\n"
    137         "{ return flatcc_builder_create_buffer(B, FID, 0, N ## _clone(B, p), A, 0); }\\\n"
    138         "static inline NS ## buffer_ref_t N ## _clone_as_root_with_size(NS ## builder_t *B, N ## _struct_t p)\\\n"
    139         "{ return flatcc_builder_create_buffer(B, FID, 0, N ## _clone(B, p), A, flatcc_builder_with_size); }\\\n"
    140         "static inline NS ## buffer_ref_t N ## _clone_as_typed_root(NS ## builder_t *B, N ## _struct_t p)\\\n"
    141         "{ return flatcc_builder_create_buffer(B, TFID, 0, N ## _clone(B, p), A, 0); }\\\n"
    142         "static inline NS ## buffer_ref_t N ## _clone_as_typed_root_with_size(NS ## builder_t *B, N ## _struct_t p)\\\n"
    143         "{ return flatcc_builder_create_buffer(B, TFID, 0, N ## _clone(B, p), A, flatcc_builder_with_size); }\n"
    144         "\n",
    145         nsc);
    146 
    147     fprintf(out->fp,
    148         "#define __%sbuild_nested_table_root(NS, N, TN, FID, TFID)\\\n"
    149         "static inline int N ## _start_as_root(NS ## builder_t *B)\\\n"
    150         "{ return NS ## buffer_start(B, FID) ? -1 : TN ## _start(B); }\\\n"
    151         "static inline int N ## _start_as_typed_root(NS ## builder_t *B)\\\n"
    152         "{ return NS ## buffer_start(B, TFID) ? -1 : TN ## _start(B); }\\\n"
    153         "static inline int N ## _end_as_root(NS ## builder_t *B)\\\n"
    154         "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n"
    155         "static inline int N ## _end_as_typed_root(NS ## builder_t *B)\\\n"
    156         "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n"
    157         "static inline int N ## _nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n"
    158         "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n"
    159         "  align ? align : 8, FLATBUFFERS_COUNT_MAX(1))); }\\\n"
    160         "static inline int N ## _typed_nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n"
    161         "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n"
    162         "  align ? align : 8, FLATBUFFERS_COUNT_MAX(1))); }\\\n"
    163         "static inline int N ## _clone_as_root(NS ## builder_t *B, TN ## _table_t t)\\\n"
    164         "{ return N ## _add(B, TN ## _clone_as_root(B, t)); }\\\n"
    165         "static inline int N ## _clone_as_typed_root(NS ## builder_t *B, TN ## _table_t t)\\\n"
    166         "{ return N ## _add(B, TN ## _clone_as_typed_root(B, t)); }\n"
    167         "\n",
    168         nsc);
    169 
    170     fprintf(out->fp,
    171         "#define __%sbuild_nested_struct_root(NS, N, TN, A, FID, TFID)\\\n"
    172         "static inline TN ## _t *N ## _start_as_root(NS ## builder_t *B)\\\n"
    173         "{ return NS ## buffer_start(B, FID) ? 0 : TN ## _start(B); }\\\n"
    174         "static inline TN ## _t *N ## _start_as_typed_root(NS ## builder_t *B)\\\n"
    175         "{ return NS ## buffer_start(B, FID) ? 0 : TN ## _start(B); }\\\n"
    176         "static inline int N ## _end_as_root(NS ## builder_t *B)\\\n"
    177         "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n"
    178         "static inline int N ## _end_as_typed_root(NS ## builder_t *B)\\\n"
    179         "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n"
    180         "static inline int N ## _end_pe_as_root(NS ## builder_t *B)\\\n"
    181         "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end_pe(B))); }\\\n"
    182         "static inline int N ## _create_as_root(NS ## builder_t *B __ ## TN ## _formal_args)\\\n"
    183         "{ return N ## _add(B, flatcc_builder_create_buffer(B, FID, 0,\\\n"
    184         "  TN ## _create(B __ ## TN ## _call_args), A, flatcc_builder_is_nested)); }\\\n"
    185         "static inline int N ## _create_as_typed_root(NS ## builder_t *B __ ## TN ## _formal_args)\\\n"
    186         "{ return N ## _add(B, flatcc_builder_create_buffer(B, TFID, 0,\\\n"
    187         "  TN ## _create(B __ ## TN ## _call_args), A, flatcc_builder_is_nested)); }\\\n"
    188         "static inline int N ## _nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n"
    189         "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n"
    190         "  align < A ? A : align, FLATBUFFERS_COUNT_MAX(1))); }\\\n"
    191         "static inline int N ## _typed_nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n"
    192         "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n"
    193         "  align < A ? A : align, FLATBUFFERS_COUNT_MAX(1))); }\\\n"
    194         "static inline int N ## _clone_as_root(NS ## builder_t *B, TN ## _struct_t p)\\\n"
    195         "{ return N ## _add(B, TN ## _clone_as_root(B, p)); }\\\n"
    196         "static inline int N ## _clone_as_typed_root(NS ## builder_t *B, TN ## _struct_t p)\\\n"
    197         "{ return N ## _add(B, TN ## _clone_as_typed_root(B, p)); }\n"
    198         "\n",
    199         nsc);
    200 
    201     fprintf(out->fp,
    202         "#define __%sbuild_vector_ops(NS, V, N, TN, T)\\\n"
    203         "static inline T *V ## _extend(NS ## builder_t *B, size_t len)\\\n"
    204         "{ return (T *)flatcc_builder_extend_vector(B, len); }\\\n"
    205         "static inline T *V ## _append(NS ## builder_t *B, const T *data, size_t len)\\\n"
    206         "{ return (T *)flatcc_builder_append_vector(B, data, len); }\\\n"
    207         "static inline int V ## _truncate(NS ## builder_t *B, size_t len)\\\n"
    208         "{ return flatcc_builder_truncate_vector(B, len); }\\\n"
    209         "static inline T *V ## _edit(NS ## builder_t *B)\\\n"
    210         "{ return (T *)flatcc_builder_vector_edit(B); }\\\n"
    211         "static inline size_t V ## _reserved_len(NS ## builder_t *B)\\\n"
    212         "{ return flatcc_builder_vector_count(B); }\\\n"
    213         "static inline T *V ## _push(NS ## builder_t *B, const T *p)\\\n"
    214         "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? (memcpy(_p, p, TN ## __size()), _p) : 0; }\\\n"
    215         "static inline T *V ## _push_copy(NS ## builder_t *B, const T *p)\\\n"
    216         "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? TN ## _copy(_p, p) : 0; }\\\n"
    217         /* push_clone is the same as a for push_copy for scalar and struct vectors
    218          * but copy has different semantics as a standalone operation so we can't use
    219          * clone to implement push_clone - it would create a reference to a struct. */
    220         "static inline T *V ## _push_clone(NS ## builder_t *B, const T *p)\\\n"
    221         "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? TN ## _copy(_p, p) : 0; }\\\n"
    222         "static inline T *V ## _push_create(NS ## builder_t *B __ ## TN ## _formal_args)\\\n"
    223         "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? TN ## _assign(_p __ ## TN ## _call_args) : 0; }\n"
    224         "\n",
    225         nsc);
    226 
    227     fprintf(out->fp,
    228         /* NS: common namespace, N: typename, T: element type, S: elem size, A: alignment */
    229         "#define __%sbuild_vector(NS, N, T, S, A)\\\n"
    230         "typedef NS ## ref_t N ## _vec_ref_t;\\\n"
    231         "static inline int N ## _vec_start(NS ## builder_t *B)\\\n"
    232         "{ return flatcc_builder_start_vector(B, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n"
    233         "static inline N ## _vec_ref_t N ## _vec_end_pe(NS ## builder_t *B)\\\n"
    234         "{ return flatcc_builder_end_vector(B); }\\\n"
    235         "static inline N ## _vec_ref_t N ## _vec_end(NS ## builder_t *B)\\\n"
    236         "{ if (!NS ## is_native_pe()) { size_t i, n; T *p = (T *)flatcc_builder_vector_edit(B);\\\n"
    237         "    for (i = 0, n = flatcc_builder_vector_count(B); i < n; ++i)\\\n"
    238         "    { N ## _to_pe(N ## __ptr_add(p, i)); }} return flatcc_builder_end_vector(B); }\\\n"
    239         "static inline N ## _vec_ref_t N ## _vec_create_pe(NS ## builder_t *B, const T *data, size_t len)\\\n"
    240         "{ return flatcc_builder_create_vector(B, data, len, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n"
    241         "static inline N ## _vec_ref_t N ## _vec_create(NS ## builder_t *B, const T *data, size_t len)\\\n"
    242         "{ if (!NS ## is_native_pe()) { size_t i; T *p; int ret = flatcc_builder_start_vector(B, S, A, FLATBUFFERS_COUNT_MAX(S)); if (ret) { return ret; }\\\n"
    243         "  p = (T *)flatcc_builder_extend_vector(B, len); if (!p) return 0;\\\n"
    244         "  for (i = 0; i < len; ++i) { N ## _copy_to_pe(N ## __ptr_add(p, i), N ## __const_ptr_add(data, i)); }\\\n"
    245         "  return flatcc_builder_end_vector(B); } else return flatcc_builder_create_vector(B, data, len, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n"
    246         "static inline N ## _vec_ref_t N ## _vec_clone(NS ## builder_t *B, N ##_vec_t vec)\\\n"
    247         "{ __%smemoize(B, vec, flatcc_builder_create_vector(B, vec, N ## _vec_len(vec), S, A, FLATBUFFERS_COUNT_MAX(S))); }\\\n"
    248         "static inline N ## _vec_ref_t N ## _vec_slice(NS ## builder_t *B, N ##_vec_t vec, size_t index, size_t len)\\\n"
    249         "{ size_t n = N ## _vec_len(vec); if (index >= n) index = n; n -= index; if (len > n) len = n;\\\n"
    250         "  return flatcc_builder_create_vector(B, N ## __const_ptr_add(vec, index), len, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n"
    251         "__%sbuild_vector_ops(NS, N ## _vec, N, N, T)\n"
    252         "\n",
    253         nsc, nsc, nsc);
    254 
    255     fprintf(out->fp,
    256         "#define __%sbuild_union_vector_ops(NS, V, N, TN)\\\n"
    257         "static inline TN ## _union_ref_t *V ## _extend(NS ## builder_t *B, size_t len)\\\n"
    258         "{ return flatcc_builder_extend_union_vector(B, len); }\\\n"
    259         "static inline TN ## _union_ref_t *V ## _append(NS ## builder_t *B, const TN ## _union_ref_t *data, size_t len)\\\n"
    260         "{ return flatcc_builder_append_union_vector(B, data, len); }\\\n"
    261         "static inline int V ## _truncate(NS ## builder_t *B, size_t len)\\\n"
    262         "{ return flatcc_builder_truncate_union_vector(B, len); }\\\n"
    263         "static inline TN ## _union_ref_t *V ## _edit(NS ## builder_t *B)\\\n"
    264         "{ return (TN ## _union_ref_t *) flatcc_builder_union_vector_edit(B); }\\\n"
    265         "static inline size_t V ## _reserved_len(NS ## builder_t *B)\\\n"
    266         "{ return flatcc_builder_union_vector_count(B); }\\\n"
    267         "static inline TN ## _union_ref_t *V ## _push(NS ## builder_t *B, const TN ## _union_ref_t ref)\\\n"
    268         "{ return flatcc_builder_union_vector_push(B, ref); }\\\n"
    269         "static inline TN ## _union_ref_t *V ## _push_clone(NS ## builder_t *B, TN ## _union_t u)\\\n"
    270         "{ return TN ## _vec_push(B, TN ## _clone(B, u)); }\n"
    271         "\n",
    272         nsc);
    273 
    274     fprintf(out->fp,
    275         "#define __%sbuild_union_vector(NS, N)\\\n"
    276         "static inline int N ## _vec_start(NS ## builder_t *B)\\\n"
    277         "{ return flatcc_builder_start_union_vector(B); }\\\n"
    278         "static inline N ## _union_vec_ref_t N ## _vec_end(NS ## builder_t *B)\\\n"
    279         "{ return flatcc_builder_end_union_vector(B); }\\\n"
    280         "static inline N ## _union_vec_ref_t N ## _vec_create(NS ## builder_t *B, const N ## _union_ref_t *data, size_t len)\\\n"
    281         "{ return flatcc_builder_create_union_vector(B, data, len); }\\\n"
    282         "__%sbuild_union_vector_ops(NS, N ## _vec, N, N)\\\n"
    283         "/* Preserves DAG structure separately for type and value vector, so a type vector could be shared for many value vectors. */\\\n"
    284         "static inline N ## _union_vec_ref_t N ## _vec_clone(NS ## builder_t *B, N ##_union_vec_t vec)\\\n"
    285         "{ N ## _union_vec_ref_t _uvref, _ret = { 0, 0 }; NS ## union_ref_t _uref; size_t _i, _len;\\\n"
    286         "  if (vec.type == 0) return _ret;\\\n"
    287         "  _uvref.type = flatcc_builder_refmap_find(B, vec.type); _uvref.value = flatcc_builder_refmap_find(B, vec.value);\\\n"
    288         "  _len = N ## _union_vec_len(vec); if (_uvref.type == 0) {\\\n"
    289         "  _uvref.type = flatcc_builder_refmap_insert(B, vec.type, (flatcc_builder_create_type_vector(B, vec.type, _len))); }\\\n"
    290         "  if (_uvref.type == 0) return _ret; if (_uvref.value == 0) {\\\n"
    291         "  if (flatcc_builder_start_offset_vector(B)) return _ret;\\\n"
    292         "  for (_i = 0; _i < _len; ++_i) { _uref = N ## _clone(B, N ## _union_vec_at(vec, _i));\\\n"
    293         "    if (!_uref.value || !(flatcc_builder_offset_vector_push(B, _uref.value))) return _ret; }\\\n"
    294         "  _uvref.value = flatcc_builder_refmap_insert(B, vec.value, flatcc_builder_end_offset_vector(B));\\\n"
    295         "  if (_uvref.value == 0) return _ret; } return _uvref; }\n"
    296         "\n",
    297         nsc, nsc);
    298 
    299     /* In addtion to offset_vector_ops... */
    300     fprintf(out->fp,
    301         "#define __%sbuild_string_vector_ops(NS, N)\\\n"
    302         "static inline int N ## _push_start(NS ## builder_t *B)\\\n"
    303         "{ return NS ## string_start(B); }\\\n"
    304         "static inline NS ## string_ref_t *N ## _push_end(NS ## builder_t *B)\\\n"
    305         "{ return NS ## string_vec_push(B, NS ## string_end(B)); }\\\n"
    306         "static inline NS ## string_ref_t *N ## _push_create(NS ## builder_t *B, const char *s, size_t len)\\\n"
    307         "{ return NS ## string_vec_push(B, NS ## string_create(B, s, len)); }\\\n"
    308         "static inline NS ## string_ref_t *N ## _push_create_str(NS ## builder_t *B, const char *s)\\\n"
    309         "{ return NS ## string_vec_push(B, NS ## string_create_str(B, s)); }\\\n"
    310         "static inline NS ## string_ref_t *N ## _push_create_strn(NS ## builder_t *B, const char *s, size_t max_len)\\\n"
    311         "{ return NS ## string_vec_push(B, NS ## string_create_strn(B, s, max_len)); }\\\n"
    312         "static inline NS ## string_ref_t *N ## _push_clone(NS ## builder_t *B, NS ## string_t string)\\\n"
    313         "{ return NS ## string_vec_push(B, NS ## string_clone(B, string)); }\\\n"
    314         "static inline NS ## string_ref_t *N ## _push_slice(NS ## builder_t *B, NS ## string_t string, size_t index, size_t len)\\\n"
    315         "{ return NS ## string_vec_push(B, NS ## string_slice(B, string, index, len)); }\n"
    316         "\n",
    317         nsc);
    318 
    319     /* In addtion to offset_vector_ops... */
    320     fprintf(out->fp,
    321         "#define __%sbuild_table_vector_ops(NS, N, TN)\\\n"
    322         "static inline int N ## _push_start(NS ## builder_t *B)\\\n"
    323         "{ return TN ## _start(B); }\\\n"
    324         "static inline TN ## _ref_t *N ## _push_end(NS ## builder_t *B)\\\n"
    325         "{ return N ## _push(B, TN ## _end(B)); }\\\n"
    326         "static inline TN ## _ref_t *N ## _push_create(NS ## builder_t *B __ ## TN ##_formal_args)\\\n"
    327         "{ return N ## _push(B, TN ## _create(B __ ## TN ## _call_args)); }\n"
    328         "\n",
    329         nsc);
    330 
    331     fprintf(out->fp,
    332         "#define __%sbuild_offset_vector_ops(NS, V, N, TN)\\\n"
    333         "static inline TN ## _ref_t *V ## _extend(NS ## builder_t *B, size_t len)\\\n"
    334         "{ return flatcc_builder_extend_offset_vector(B, len); }\\\n"
    335         "static inline TN ## _ref_t *V ## _append(NS ## builder_t *B, const TN ## _ref_t *data, size_t len)\\\n"
    336         "{ return flatcc_builder_append_offset_vector(B, data, len); }\\\n"
    337         "static inline int V ## _truncate(NS ## builder_t *B, size_t len)\\\n"
    338         "{ return flatcc_builder_truncate_offset_vector(B, len); }\\\n"
    339         "static inline TN ## _ref_t *V ## _edit(NS ## builder_t *B)\\\n"
    340         "{ return (TN ## _ref_t *)flatcc_builder_offset_vector_edit(B); }\\\n"
    341         "static inline size_t V ## _reserved_len(NS ## builder_t *B)\\\n"
    342         "{ return flatcc_builder_offset_vector_count(B); }\\\n"
    343         "static inline TN ## _ref_t *V ## _push(NS ## builder_t *B, const TN ## _ref_t ref)\\\n"
    344         "{ return ref ? flatcc_builder_offset_vector_push(B, ref) : 0; }\n"
    345         "\n",
    346         nsc);
    347 
    348     fprintf(out->fp,
    349         "#define __%sbuild_offset_vector(NS, N)\\\n"
    350         "typedef NS ## ref_t N ## _vec_ref_t;\\\n"
    351         "static inline int N ## _vec_start(NS ## builder_t *B)\\\n"
    352         "{ return flatcc_builder_start_offset_vector(B); }\\\n"
    353         "static inline N ## _vec_ref_t N ## _vec_end(NS ## builder_t *B)\\\n"
    354         "{ return flatcc_builder_end_offset_vector(B); }\\\n"
    355         "static inline N ## _vec_ref_t N ## _vec_create(NS ## builder_t *B, const N ## _ref_t *data, size_t len)\\\n"
    356         "{ return flatcc_builder_create_offset_vector(B, data, len); }\\\n"
    357         "__%sbuild_offset_vector_ops(NS, N ## _vec, N, N)\\\n"
    358         "static inline N ## _vec_ref_t N ## _vec_clone(NS ## builder_t *B, N ##_vec_t vec)\\\n"
    359         "{ int _ret; N ## _ref_t _e; size_t _i, _len; __%smemoize_begin(B, vec);\\\n"
    360         " _len = N ## _vec_len(vec); if (flatcc_builder_start_offset_vector(B)) return 0;\\\n"
    361         "  for (_i = 0; _i < _len; ++_i) { if (!(_e = N ## _clone(B, N ## _vec_at(vec, _i)))) return 0;\\\n"
    362         "    if (!flatcc_builder_offset_vector_push(B, _e)) return 0; }\\\n"
    363         "  __%smemoize_end(B, vec, flatcc_builder_end_offset_vector(B)); }\\\n"
    364         "\n",
    365         nsc, nsc, nsc, nsc);
    366 
    367     fprintf(out->fp,
    368         "#define __%sbuild_string_ops(NS, N)\\\n"
    369         "static inline char *N ## _append(NS ## builder_t *B, const char *s, size_t len)\\\n"
    370         "{ return flatcc_builder_append_string(B, s, len); }\\\n"
    371         "static inline char *N ## _append_str(NS ## builder_t *B, const char *s)\\\n"
    372         "{ return flatcc_builder_append_string_str(B, s); }\\\n"
    373         "static inline char *N ## _append_strn(NS ## builder_t *B, const char *s, size_t len)\\\n"
    374         "{ return flatcc_builder_append_string_strn(B, s, len); }\\\n"
    375         "static inline size_t N ## _reserved_len(NS ## builder_t *B)\\\n"
    376         "{ return flatcc_builder_string_len(B); }\\\n"
    377         "static inline char *N ## _extend(NS ## builder_t *B, size_t len)\\\n"
    378         "{ return flatcc_builder_extend_string(B, len); }\\\n"
    379         "static inline char *N ## _edit(NS ## builder_t *B)\\\n"
    380         "{ return flatcc_builder_string_edit(B); }\\\n"
    381         "static inline int N ## _truncate(NS ## builder_t *B, size_t len)\\\n"
    382         "{ return flatcc_builder_truncate_string(B, len); }\n"
    383         "\n",
    384         nsc);
    385 
    386     fprintf(out->fp,
    387         "#define __%sbuild_string(NS)\\\n"
    388         "typedef NS ## ref_t NS ## string_ref_t;\\\n"
    389         "static inline int NS ## string_start(NS ## builder_t *B)\\\n"
    390         "{ return flatcc_builder_start_string(B); }\\\n"
    391         "static inline NS ## string_ref_t NS ## string_end(NS ## builder_t *B)\\\n"
    392         "{ return flatcc_builder_end_string(B); }\\\n"
    393         "static inline NS ## ref_t NS ## string_create(NS ## builder_t *B, const char *s, size_t len)\\\n"
    394         "{ return flatcc_builder_create_string(B, s, len); }\\\n"
    395         "static inline NS ## ref_t NS ## string_create_str(NS ## builder_t *B, const char *s)\\\n"
    396         "{ return flatcc_builder_create_string_str(B, s); }\\\n"
    397         "static inline NS ## ref_t NS ## string_create_strn(NS ## builder_t *B, const char *s, size_t len)\\\n"
    398         "{ return flatcc_builder_create_string_strn(B, s, len); }\\\n"
    399         "static inline NS ## string_ref_t NS ## string_clone(NS ## builder_t *B, NS ## string_t string)\\\n"
    400         "{ __%smemoize(B, string, flatcc_builder_create_string(B, string, NS ## string_len(string))); }\\\n"
    401         "static inline NS ## string_ref_t NS ## string_slice(NS ## builder_t *B, NS ## string_t string, size_t index, size_t len)\\\n"
    402         "{ size_t n = NS ## string_len(string); if (index >= n) index = n; n -= index; if (len > n) len = n;\\\n"
    403         "  return flatcc_builder_create_string(B, string + index, len); }\\\n"
    404         "__%sbuild_string_ops(NS, NS ## string)\\\n"
    405         "__%sbuild_offset_vector(NS, NS ## string)\n"
    406         "\n",
    407         nsc, nsc, nsc, nsc);
    408     fprintf(out->fp,
    409         "#define __%scopy_from_pe(P, P2, N) (*(P) = N ## _read_from_pe(P2), (P))\n"
    410         "#define __%sfrom_pe(P, N) (*(P) = N ## _read_from_pe(P), (P))\n"
    411         "#define __%scopy_to_pe(P, P2, N) (N ## _write_to_pe((P), *(P2)), (P))\n"
    412         "#define __%sto_pe(P, N) (N ## _write_to_pe((P), *(P)), (P))\n",
    413         nsc, nsc, nsc, nsc);
    414     fprintf(out->fp,
    415         "#define __%sdefine_fixed_array_primitives(NS, N, T)\\\n"
    416         "static inline T *N ## _array_copy(T *p, const T *p2, size_t n)\\\n"
    417         "{ memcpy(p, p2, n * sizeof(T)); return p; }\\\n"
    418         "static inline T *N ## _array_copy_from_pe(T *p, const T *p2, size_t n)\\\n"
    419         "{ size_t i; if (NS ## is_native_pe()) memcpy(p, p2, n * sizeof(T)); else\\\n"
    420         "  for (i = 0; i < n; ++i) N ## _copy_from_pe(&p[i], &p2[i]); return p; }\\\n"
    421         "static inline T *N ## _array_copy_to_pe(T *p, const T *p2, size_t n)\\\n"
    422         "{ size_t i; if (NS ## is_native_pe()) memcpy(p, p2, n * sizeof(T)); else\\\n"
    423         "  for (i = 0; i < n; ++i) N ## _copy_to_pe(&p[i], &p2[i]); return p; }\n",
    424         nsc);
    425     fprintf(out->fp,
    426         "#define __%sdefine_scalar_primitives(NS, N, T)\\\n"
    427         "static inline T *N ## _from_pe(T *p) { return __ ## NS ## from_pe(p, N); }\\\n"
    428         "static inline T *N ## _to_pe(T *p) { return __ ## NS ## to_pe(p, N); }\\\n"
    429         "static inline T *N ## _copy(T *p, const T *p2) { *p = *p2; return p; }\\\n"
    430         "static inline T *N ## _copy_from_pe(T *p, const T *p2)\\\n"
    431         "{ return __ ## NS ## copy_from_pe(p, p2, N); }\\\n"
    432         "static inline T *N ## _copy_to_pe(T *p, const T *p2) \\\n"
    433         "{ return __ ## NS ## copy_to_pe(p, p2, N); }\\\n"
    434         "static inline T *N ## _assign(T *p, const T v0) { *p = v0; return p; }\\\n"
    435         "static inline T *N ## _assign_from_pe(T *p, T v0)\\\n"
    436         "{ *p = N ## _read_from_pe(&v0); return p; }\\\n"
    437         "static inline T *N ## _assign_to_pe(T *p, T v0)\\\n"
    438         "{ N ## _write_to_pe(p, v0); return p; }\n"
    439         "#define __%sbuild_scalar(NS, N, T)\\\n"
    440         "__ ## NS ## define_scalar_primitives(NS, N, T)\\\n"
    441         "__ ## NS ## define_fixed_array_primitives(NS, N, T)\\\n"
    442         "__ ## NS ## build_vector(NS, N, T, sizeof(T), sizeof(T))\n",
    443         nsc, nsc);
    444 
    445     fprintf(out->fp,
    446         "/* Depends on generated copy_to/from_pe functions, and the type. */\n"
    447         "#define __%sdefine_struct_primitives(NS, N)\\\n"
    448         "static inline N ## _t *N ##_to_pe(N ## _t *p)\\\n"
    449         "{ if (!NS ## is_native_pe()) { N ## _copy_to_pe(p, p); }; return p; }\\\n"
    450         "static inline N ## _t *N ##_from_pe(N ## _t *p)\\\n"
    451         "{ if (!NS ## is_native_pe()) { N ## _copy_from_pe(p, p); }; return p; }\\\n"
    452         "static inline N ## _t *N ## _clear(N ## _t *p) { return (N ## _t *)memset(p, 0, N ## __size()); }\n"
    453         "\n"
    454 
    455         /*
    456          * NOTE: structs can both be inline and independent blocks. They
    457          * are independent as buffer roots, and also as union members.
    458          * _clone applied to a struct type name creates a reference to
    459          * an independent block, but this is ambigous. Structs also
    460          * support _copy which is the inline equivalent of _clone for
    461          * inline. There is also the distinction between _clone applied
    462          * to a field name, clone applied to a type name, and _clone
    463          * applied to a _vec_push operation. For field names and push
    464          * operations, _clone is unambigiously inline and similar to
    465          * _copy. So the ambigiouty is when applying _clone to a type
    466          * name where _copy and _clone are different. Unions can safely
    467          * implement clone on structs members via _clone because union
    468          * members are indendendent blocks whereas push_clone must be
    469          * implemented with _copy because structs are inline in
    470          * (non-union) vectors. Structs in union-vectors are independent
    471          * but these simply the unions clone operation (which is a
    472          * generated function).
    473          */
    474         "/* Depends on generated copy/assign_to/from_pe functions, and the type. */\n"
    475         "#define __%sbuild_struct(NS, N, S, A, FID, TFID)\\\n"
    476         "__ ## NS ## define_struct_primitives(NS, N)\\\n"
    477         "typedef NS ## ref_t N ## _ref_t;\\\n"
    478         "static inline N ## _t *N ## _start(NS ## builder_t *B)\\\n"
    479         "{ return (N ## _t *)flatcc_builder_start_struct(B, S, A); }\\\n"
    480         "static inline N ## _ref_t N ## _end(NS ## builder_t *B)\\\n"
    481         "{ if (!NS ## is_native_pe()) { N ## _to_pe((N ## _t *)flatcc_builder_struct_edit(B)); }\\\n"
    482         "  return flatcc_builder_end_struct(B); }\\\n"
    483         "static inline N ## _ref_t N ## _end_pe(NS ## builder_t *B)\\\n"
    484         "{ return flatcc_builder_end_struct(B); }\\\n"
    485         "static inline N ## _ref_t N ## _create(NS ## builder_t *B __ ## N ## _formal_args)\\\n"
    486         "{ N ## _t *_p = N ## _start(B); if (!_p) return 0; N ##_assign_to_pe(_p __ ## N ## _call_args);\\\n"
    487         "  return N ## _end_pe(B); }\\\n"
    488         "static inline N ## _ref_t N ## _clone(NS ## builder_t *B, N ## _struct_t p)\\\n"
    489         "{ N ## _t *_p; __%smemoize_begin(B, p); _p = N ## _start(B); if (!_p) return 0;\\\n"
    490         "  N ## _copy(_p, p); __%smemoize_end(B, p, N ##_end_pe(B)); }\\\n"
    491         "__%sbuild_vector(NS, N, N ## _t, S, A)\\\n"
    492         "__%sbuild_struct_root(NS, N, A, FID, TFID)\\\n"
    493         "\n",
    494         nsc, nsc, nsc, nsc, nsc, nsc);
    495     fprintf(out->fp,
    496         "#define __%sstruct_clear_field(p) memset((p), 0, sizeof(*(p)))\n",
    497         nsc);
    498 
    499     fprintf(out->fp,
    500         "#define __%sbuild_table(NS, N, K)\\\n"
    501         "static inline int N ## _start(NS ## builder_t *B)\\\n"
    502         "{ return flatcc_builder_start_table(B, K); }\\\n"
    503         "static inline N ## _ref_t N ## _end(NS ## builder_t *B)\\\n"
    504         "{ FLATCC_ASSERT(flatcc_builder_check_required(B, __ ## N ## _required,\\\n"
    505         "  sizeof(__ ## N ## _required) / sizeof(__ ## N ## _required[0]) - 1));\\\n"
    506         "  return flatcc_builder_end_table(B); }\\\n"
    507         "__%sbuild_offset_vector(NS, N)\n"
    508         "\n",
    509         nsc, nsc);
    510 
    511     fprintf(out->fp,
    512         "#define __%sbuild_table_field(ID, NS, N, TN, TT)\\\n"
    513         "static inline int N ## _add(NS ## builder_t *B, TN ## _ref_t ref)\\\n"
    514         "{ TN ## _ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ?\\\n"
    515         "  ((*_p = ref), 0) : -1; }\\\n"
    516         "static inline int N ## _start(NS ## builder_t *B)\\\n"
    517         "{ return TN ## _start(B); }\\\n"
    518         "static inline int N ## _end(NS ## builder_t *B)\\\n"
    519         "{ return N ## _add(B, TN ## _end(B)); }\\\n"
    520         "static inline TN ## _ref_t N ## _create(NS ## builder_t *B __ ## TN ##_formal_args)\\\n"
    521         "{ return N ## _add(B, TN ## _create(B __ ## TN ## _call_args)); }\\\n"
    522         "static inline int N ## _clone(NS ## builder_t *B, TN ## _table_t p)\\\n"
    523         "{ return N ## _add(B, TN ## _clone(B, p)); }\\\n"
    524         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    525         "{ TN ## _table_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n"
    526         "\n",
    527         nsc);
    528 
    529     fprintf(out->fp,
    530         "#define __%sbuild_union_field(ID, NS, N, TN, TT)\\\n"
    531         "static inline int N ## _add(NS ## builder_t *B, TN ## _union_ref_t uref)\\\n"
    532         "{ NS ## ref_t *_p; TN ## _union_type_t *_pt; if (uref.type == TN ## _NONE) return 0; if (uref.value == 0) return -1;\\\n"
    533         "  if (!(_pt = (TN ## _union_type_t *)flatcc_builder_table_add(B, ID - 1, sizeof(*_pt), sizeof(*_pt)))) return -1;\\\n"
    534         "  *_pt = uref.type; if (!(_p = flatcc_builder_table_add_offset(B, ID))) return -1; *_p = uref.value; return 0; }\\\n"
    535         "static inline int N ## _add_type(NS ## builder_t *B, TN ## _union_type_t type)\\\n"
    536         "{ TN ## _union_type_t *_pt; if (type == TN ## _NONE) return 0; return (_pt = (TN ## _union_type_t *)flatcc_builder_table_add(B, ID - 1,\\\n"
    537         "  sizeof(*_pt), sizeof(*_pt))) ? ((*_pt = type), 0) : -1; }\\\n"
    538         "static inline int N ## _add_value(NS ## builder_t *B, TN ## _union_ref_t uref)\\\n"
    539         "{ NS ## ref_t *p; if (uref.type == TN ## _NONE) return 0; return (p = flatcc_builder_table_add_offset(B, ID)) ?\\\n"
    540         "  ((*p = uref.value), 0) : -1; }\\\n"
    541         "static inline int N ## _clone(NS ## builder_t *B, TN ## _union_t p)\\\n"
    542         "{ return N ## _add(B, TN ## _clone(B, p)); }\\\n"
    543         /* `_pick` is not supported on specific union members because the source dictates the type. */
    544         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    545         "{ TN ## _union_t _p = N ## _union(t); return _p.type ? N ## _clone(B, _p) : 0; }\n"
    546         "\n",
    547         nsc);
    548 
    549     fprintf(out->fp,
    550         "/* M is the union value name and T is its type, i.e. the qualified name. */\n"
    551         "#define __%sbuild_union_table_value_field(NS, N, NU, M, T)\\\n"
    552         "static inline int N ## _ ## M ## _add(NS ## builder_t *B, T ## _ref_t ref)\\\n"
    553         "{ return N ## _add(B, NU ## _as_ ## M (ref)); }\\\n"
    554         "static inline int N ## _ ## M ## _start(NS ## builder_t *B)\\\n"
    555         "{ return T ## _start(B); }\\\n"
    556         "static inline int N ## _ ## M ## _end(NS ## builder_t *B)\\\n"
    557         "{ T ## _ref_t ref = T ## _end(B);\\\n"
    558         "  return ref ? N ## _ ## M ## _add(B, ref) : -1; }\\\n"
    559         "static inline int N ## _ ## M ## _create(NS ## builder_t *B __ ## T ##_formal_args)\\\n"
    560         "{ T ## _ref_t ref = T ## _create(B __ ## T ## _call_args);\\\n"
    561         "  return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\\\n"
    562         "static inline int N ## _ ## M ## _clone(NS ## builder_t *B, T ## _table_t t)\\\n"
    563         "{ T ## _ref_t ref = T ## _clone(B, t);\\\n"
    564         "  return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\n"
    565         "\n",
    566         nsc);
    567 
    568     fprintf(out->fp,
    569         "/* M is the union value name and T is its type, i.e. the qualified name. */\n"
    570         "#define __%sbuild_union_struct_value_field(NS, N, NU, M, T)\\\n"
    571         "static inline int N ## _ ## M ## _add(NS ## builder_t *B, T ## _ref_t ref)\\\n"
    572         "{ return N ## _add(B, NU ## _as_ ## M (ref)); }\\\n"
    573         "static inline T ## _t *N ## _ ## M ## _start(NS ## builder_t *B)\\\n"
    574         "{ return T ## _start(B); }\\\n"
    575         "static inline int N ## _ ## M ## _end(NS ## builder_t *B)\\\n"
    576         "{ T ## _ref_t ref = T ## _end(B);\\\n"
    577         "  return ref ? N ## _ ## M ## _add(B, ref) : -1; }\\\n"
    578         "static inline int N ## _ ## M ## _create(NS ## builder_t *B __ ## T ##_formal_args)\\\n"
    579         "{ T ## _ref_t ref = T ## _create(B __ ## T ## _call_args);\\\n"
    580         "  return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\\\n"
    581         "static inline int N ## _ ## M ## _end_pe(NS ## builder_t *B)\\\n"
    582         "{ T ## _ref_t ref = T ## _end_pe(B);\\\n"
    583         "  return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\\\n"
    584         "static inline int N ## _ ## M ## _clone(NS ## builder_t *B, T ## _struct_t p)\\\n"
    585         "{ T ## _ref_t ref = T ## _clone(B, p);\\\n"
    586         "  return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\n",
    587         nsc);
    588 
    589     fprintf(out->fp,
    590         "#define __%sbuild_union_string_value_field(NS, N, NU, M)\\\n"
    591         "static inline int N ## _ ## M ## _add(NS ## builder_t *B, NS ## string_ref_t ref)\\\n"
    592         "{ return N ## _add(B, NU ## _as_ ## M (ref)); }\\\n"
    593         "__%sbuild_string_field_ops(NS, N ## _ ## M)\n"
    594         "\n",
    595         nsc, nsc);
    596 
    597     fprintf(out->fp,
    598         "/* NS: common namespace, ID: table field id (not offset), TN: name of type T, TT: name of table type\n"
    599         " * S: sizeof of scalar type, A: alignment of type T, default value V of type T. */\n"
    600         "#define __%sbuild_scalar_field(ID, NS, N, TN, T, S, A, V, TT)\\\n"
    601         "static inline int N ## _add(NS ## builder_t *B, const T v)\\\n"
    602         "{ T *_p; if (v == V) return 0; if (!(_p = (T *)flatcc_builder_table_add(B, ID, S, A))) return -1;\\\n"
    603         "  TN ## _assign_to_pe(_p, v); return 0; }\\\n"
    604         "static inline int N ## _force_add(NS ## builder_t *B, const T v)\\\n"
    605         "{ T *_p; if (!(_p = (T *)flatcc_builder_table_add(B, ID, S, A))) return -1;\\\n"
    606         "  TN ## _assign_to_pe(_p, v); return 0; }\\\n"
    607         "/* Clone does not skip default values and expects pe endian content. */\\\n"
    608         "static inline int N ## _clone(NS ## builder_t *B, const T *p)\\\n"
    609         "{ return 0 == flatcc_builder_table_add_copy(B, ID, p, S, A) ? -1 : 0; }\\\n"
    610         "/* Transferring a missing field is a nop success with 0 as result. */\\\n"
    611         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    612         "{ const T *_p = N ## _get_ptr(t); return _p ? N ## _clone(B, _p) : 0; }\n"
    613         "\n",
    614         nsc);
    615 
    616     fprintf(out->fp,
    617         "/* NS: common namespace, ID: table field id (not offset), TN: name of type T, TT: name of table type\n"
    618         " * S: sizeof of scalar type, A: alignment of type T. */\n"
    619         "#define __%sbuild_scalar_optional_field(ID, NS, N, TN, T, S, A, TT)\\\n"
    620         "static inline int N ## _add(NS ## builder_t *B, const T v)\\\n"
    621         "{ T *_p; if (!(_p = (T *)flatcc_builder_table_add(B, ID, S, A))) return -1;\\\n"
    622         "  TN ## _assign_to_pe(_p, v); return 0; }\\\n"
    623         "/* Clone does not skip default values and expects pe endian content. */\\\n"
    624         "static inline int N ## _clone(NS ## builder_t *B, const T *p)\\\n"
    625         "{ return 0 == flatcc_builder_table_add_copy(B, ID, p, S, A) ? -1 : 0; }\\\n"
    626         "/* Transferring a missing field is a nop success with 0 as result. */\\\n"
    627         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    628         "{ const T *_p = N ## _get_ptr(t); return _p ? N ## _clone(B, _p) : 0; }\n"
    629         "\n",
    630         nsc);
    631 
    632     fprintf(out->fp,
    633         "#define __%sbuild_struct_field(ID, NS, N, TN, S, A, TT)\\\n"
    634         "static inline TN ## _t *N ## _start(NS ## builder_t *B)\\\n"
    635         "{ return (TN ## _t *)flatcc_builder_table_add(B, ID, S, A); }\\\n"
    636         "static inline int N ## _end(NS ## builder_t *B)\\\n"
    637         "{ if (!NS ## is_native_pe()) { TN ## _to_pe((TN ## _t *)flatcc_builder_table_edit(B, S)); } return 0; }\\\n"
    638         "static inline int N ## _end_pe(NS ## builder_t *B) { return 0; }\\\n"
    639         "static inline int N ## _create(NS ## builder_t *B __ ## TN ## _formal_args)\\\n"
    640         "{ TN ## _t *_p = N ## _start(B); if (!_p) return -1; TN ##_assign_to_pe(_p __ ## TN ## _call_args);\\\n"
    641         "  return 0; }\\\n"
    642         "static inline int N ## _add(NS ## builder_t *B, const TN ## _t *p)\\\n"
    643         "{ TN ## _t *_p = N ## _start(B); if (!_p) return -1; TN ##_copy_to_pe(_p, p); return 0; }\\\n"
    644         "static inline int N ## _clone(NS ## builder_t *B, TN ## _struct_t p)\\\n"
    645         "{ return 0 == flatcc_builder_table_add_copy(B, ID, p, S, A) ? -1 : 0; }\\\n"
    646         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    647         "{ TN ## _struct_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n"
    648         "\n",
    649         nsc);
    650 
    651     /* This goes for scalar, struct, and enum vectors. */
    652     fprintf(out->fp,
    653         "#define __%sbuild_vector_field(ID, NS, N, TN, T, TT)\\\n"
    654         "static inline int N ## _add(NS ## builder_t *B, TN ## _vec_ref_t ref)\\\n"
    655         "{ TN ## _vec_ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ? ((*_p = ref), 0) : -1; }\\\n"
    656         "static inline int N ## _start(NS ## builder_t *B)\\\n"
    657         "{ return TN ## _vec_start(B); }\\\n"
    658         "static inline int N ## _end_pe(NS ## builder_t *B)\\\n"
    659         "{ return N ## _add(B, TN ## _vec_end_pe(B)); }\\\n"
    660         "static inline int N ## _end(NS ## builder_t *B)\\\n"
    661         "{ return N ## _add(B, TN ## _vec_end(B)); }\\\n"
    662         "static inline int N ## _create_pe(NS ## builder_t *B, const T *data, size_t len)\\\n"
    663         "{ return N ## _add(B, TN ## _vec_create_pe(B, data, len)); }\\\n"
    664         "static inline int N ## _create(NS ## builder_t *B, const T *data, size_t len)\\\n"
    665         "{ return N ## _add(B, TN ## _vec_create(B, data, len)); }\\\n"
    666         "static inline int N ## _slice(NS ## builder_t *B, TN ## _vec_t vec, size_t index, size_t len)\\\n"
    667         "{ return N ## _add(B, TN ## _vec_slice(B, vec, index, len)); }\\\n"
    668         "static inline int N ## _clone(NS ## builder_t *B, TN ## _vec_t vec)\\\n"
    669         "{ return N ## _add(B, TN ## _vec_clone(B, vec)); }\\\n"
    670         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    671         "{ TN ## _vec_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\\\n"
    672         "__%sbuild_vector_ops(NS, N, N, TN, T)\\\n"
    673         "\n",
    674         nsc, nsc);
    675 
    676     fprintf(out->fp,
    677         "#define __%sbuild_offset_vector_field(ID, NS, N, TN, TT)\\\n"
    678         "static inline int N ## _add(NS ## builder_t *B, TN ## _vec_ref_t ref)\\\n"
    679         "{ TN ## _vec_ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ? ((*_p = ref), 0) : -1; }\\\n"
    680         "static inline int N ## _start(NS ## builder_t *B)\\\n"
    681         "{ return flatcc_builder_start_offset_vector(B); }\\\n"
    682         "static inline int N ## _end(NS ## builder_t *B)\\\n"
    683         "{ return N ## _add(B, flatcc_builder_end_offset_vector(B)); }\\\n"
    684         "static inline int N ## _create(NS ## builder_t *B, const TN ## _ref_t *data, size_t len)\\\n"
    685         "{ return N ## _add(B, flatcc_builder_create_offset_vector(B, data, len)); }\\\n"
    686         "__%sbuild_offset_vector_ops(NS, N, N, TN)\\\n"
    687         "static inline int N ## _clone(NS ## builder_t *B, TN ## _vec_t vec)\\\n"
    688         "{ return N ## _add(B, TN ## _vec_clone(B, vec)); }\\\n"
    689         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    690         "{ TN ## _vec_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n"
    691         "\n",
    692         nsc, nsc);
    693 
    694     fprintf(out->fp,
    695         "/* depends on N ## _add which differs for union member fields and ordinary fields */\\\n"
    696         "#define __%sbuild_string_field_ops(NS, N)\\\n"
    697         "static inline int N ## _start(NS ## builder_t *B)\\\n"
    698         "{ return flatcc_builder_start_string(B); }\\\n"
    699         "static inline int N ## _end(NS ## builder_t *B)\\\n"
    700         "{ return N ## _add(B, flatcc_builder_end_string(B)); }\\\n"
    701         "static inline int N ## _create(NS ## builder_t *B, const char *s, size_t len)\\\n"
    702         "{ return N ## _add(B, flatcc_builder_create_string(B, s, len)); }\\\n"
    703         "static inline int N ## _create_str(NS ## builder_t *B, const char *s)\\\n"
    704         "{ return N ## _add(B, flatcc_builder_create_string_str(B, s)); }\\\n"
    705         "static inline int N ## _create_strn(NS ## builder_t *B, const char *s, size_t max_len)\\\n"
    706         "{ return N ## _add(B, flatcc_builder_create_string_strn(B, s, max_len)); }\\\n"
    707         "static inline int N ## _clone(NS ## builder_t *B, NS ## string_t string)\\\n"
    708         "{ return N ## _add(B, NS ## string_clone(B, string)); }\\\n"
    709         "static inline int N ## _slice(NS ## builder_t *B, NS ## string_t string, size_t index, size_t len)\\\n"
    710         "{ return N ## _add(B, NS ## string_slice(B, string, index, len)); }\\\n"
    711         "__%sbuild_string_ops(NS, N)\n"
    712         "\n",
    713         nsc, nsc);
    714 
    715     fprintf(out->fp,
    716         "#define __%sbuild_string_field(ID, NS, N, TT)\\\n"
    717         "static inline int N ## _add(NS ## builder_t *B, NS ## string_ref_t ref)\\\n"
    718         "{ NS ## string_ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ? ((*_p = ref), 0) : -1; }\\\n"
    719         "__%sbuild_string_field_ops(NS, N)\\\n"
    720         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    721         "{ NS ## string_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n"
    722         "\n",
    723         nsc, nsc);
    724 
    725     fprintf(out->fp,
    726         "#define __%sbuild_table_vector_field(ID, NS, N, TN, TT)\\\n"
    727         "__%sbuild_offset_vector_field(ID, NS, N, TN, TT)\\\n"
    728         "__%sbuild_table_vector_ops(NS, N, TN)\n"
    729         "\n",
    730         nsc, nsc, nsc);
    731 
    732     fprintf(out->fp,
    733         "#define __%sbuild_union_vector_field(ID, NS, N, TN, TT)\\\n"
    734         "static inline int N ## _add(NS ## builder_t *B, TN ## _union_vec_ref_t uvref)\\\n"
    735         "{ NS ## vec_ref_t *_p; if (!uvref.type || !uvref.value) return uvref.type == uvref.value ? 0 : -1;\\\n"
    736         "  if (!(_p = flatcc_builder_table_add_offset(B, ID - 1))) return -1; *_p = uvref.type;\\\n"
    737         "  if (!(_p = flatcc_builder_table_add_offset(B, ID))) return -1; *_p = uvref.value; return 0; }\\\n"
    738         "static inline int N ## _start(NS ## builder_t *B)\\\n"
    739         "{ return flatcc_builder_start_union_vector(B); }\\\n"
    740         "static inline int N ## _end(NS ## builder_t *B)\\\n"
    741         "{ return N ## _add(B, flatcc_builder_end_union_vector(B)); }\\\n"
    742         "static inline int N ## _create(NS ## builder_t *B, const TN ## _union_ref_t *data, size_t len)\\\n"
    743         "{ return N ## _add(B, flatcc_builder_create_union_vector(B, data, len)); }\\\n"
    744         "__%sbuild_union_vector_ops(NS, N, N, TN)\\\n"
    745         "static inline int N ## _clone(NS ## builder_t *B, TN ## _union_vec_t vec)\\\n"
    746         "{ return N ## _add(B, TN ## _vec_clone(B, vec)); }\\\n"
    747         "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n"
    748         "{ TN ## _union_vec_t _p = N ## _union(t); return _p.type ? N ## _clone(B, _p) : 0; }\n"
    749         "\n",
    750         nsc, nsc);
    751 
    752     fprintf(out->fp,
    753         "#define __%sbuild_union_table_vector_value_field(NS, N, NU, M, T)\\\n"
    754         "static inline int N ## _ ## M ## _push_start(NS ## builder_t *B)\\\n"
    755         "{ return T ## _start(B); }\\\n"
    756         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_end(NS ## builder_t *B)\\\n"
    757         "{ return NU ## _vec_push(B, NU ## _as_ ## M (T ## _end(B))); }\\\n"
    758         "static inline NU ## _union_ref_t *N ## _ ## M ## _push(NS ## builder_t *B, T ## _ref_t ref)\\\n"
    759         "{ return NU ## _vec_push(B, NU ## _as_ ## M (ref)); }\\\n"
    760         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create(NS ## builder_t *B __ ## T ##_formal_args)\\\n"
    761         "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _create(B __ ## T ## _call_args))); }\\\n"
    762         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_clone(NS ## builder_t *B, T ## _table_t t)\\\n"
    763         "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _clone(B, t))); }\n"
    764         "\n",
    765         nsc);
    766 
    767     fprintf(out->fp,
    768         "#define __%sbuild_union_struct_vector_value_field(NS, N, NU, M, T)\\\n"
    769         "static inline T ## _t *N ## _ ## M ## _push_start(NS ## builder_t *B)\\\n"
    770         "{ return T ## _start(B); }\\\n"
    771         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_end(NS ## builder_t *B)\\\n"
    772         "{ return NU ## _vec_push(B, NU ## _as_ ## M (T ## _end(B))); }\\\n"
    773         "static inline NU ## _union_ref_t *N ## _ ## M ## _push(NS ## builder_t *B, T ## _ref_t ref)\\\n"
    774         "{ return NU ## _vec_push(B, NU ## _as_ ## M (ref)); }\\\n"
    775         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create(NS ## builder_t *B __ ## T ##_formal_args)\\\n"
    776         "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _create(B __ ## T ## _call_args))); }\\\n"
    777         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_clone(NS ## builder_t *B, T ## _struct_t p)\\\n"
    778         /* Here we create an independent struct block, so T ## _clone is appropriate as opposed to T ## _copy. */
    779         "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _clone(B, p))); }\n"
    780         "\n",
    781         nsc);
    782 
    783     fprintf(out->fp,
    784         "#define __%sbuild_union_string_vector_value_field(NS, N, NU, M)\\\n"
    785         "static inline NU ## _union_ref_t *N ## _ ## M ## _push(NS ## builder_t *B, NS ## string_ref_t ref)\\\n"
    786         "{ return NU ## _vec_push(B, NU ## _as_ ## M (ref)); }\\\n"
    787         "static inline int N ## _ ## M ## _push_start(NS ## builder_t *B)\\\n"
    788         "{ return NS ## string_start(B); }\\\n"
    789         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_end(NS ## builder_t *B)\\\n"
    790         "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_end(B))); }\\\n"
    791         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create(NS ## builder_t *B, const char *s, size_t len)\\\n"
    792         "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_create(B, s, len))); }\\\n"
    793         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create_str(NS ## builder_t *B, const char *s)\\\n"
    794         "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_create_str(B, s))); }\\\n"
    795         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create_strn(NS ## builder_t *B, const char *s, size_t max_len)\\\n"
    796         "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_create_strn(B, s, max_len))); }\\\n"
    797         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_clone(NS ## builder_t *B, NS ## string_t string)\\\n"
    798         "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_clone(B, string))); }\\\n"
    799         "static inline NU ## _union_ref_t *N ## _ ## M ## _push_slice(NS ## builder_t *B, NS ## string_t string, size_t index, size_t len)\\\n"
    800         "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_slice(B, string, index, len))); }\n"
    801         "\n",
    802         nsc);
    803 
    804      fprintf(out->fp,
    805         "#define __%sbuild_string_vector_field(ID, NS, N, TT)\\\n"
    806         "__%sbuild_offset_vector_field(ID, NS, N, NS ## string, TT)\\\n"
    807         "__%sbuild_string_vector_ops(NS, N)\n"
    808         "\n",
    809         nsc, nsc, nsc);
    810 
    811     fprintf(out->fp, "#define __%schar_formal_args , char v0\n", nsc);
    812     fprintf(out->fp, "#define __%schar_call_args , v0\n", nsc);
    813     fprintf(out->fp, "#define __%suint8_formal_args , uint8_t v0\n", nsc);
    814     fprintf(out->fp, "#define __%suint8_call_args , v0\n", nsc);
    815     fprintf(out->fp, "#define __%sint8_formal_args , int8_t v0\n", nsc);
    816     fprintf(out->fp, "#define __%sint8_call_args , v0\n", nsc);
    817     fprintf(out->fp, "#define __%sbool_formal_args , %sbool_t v0\n", nsc, nsc);
    818     fprintf(out->fp, "#define __%sbool_call_args , v0\n", nsc);
    819     fprintf(out->fp, "#define __%suint16_formal_args , uint16_t v0\n", nsc);
    820     fprintf(out->fp, "#define __%suint16_call_args , v0\n", nsc);
    821     fprintf(out->fp, "#define __%suint32_formal_args , uint32_t v0\n", nsc);
    822     fprintf(out->fp, "#define __%suint32_call_args , v0\n", nsc);
    823     fprintf(out->fp, "#define __%suint64_formal_args , uint64_t v0\n", nsc);
    824     fprintf(out->fp, "#define __%suint64_call_args , v0\n", nsc);
    825     fprintf(out->fp, "#define __%sint16_formal_args , int16_t v0\n", nsc);
    826     fprintf(out->fp, "#define __%sint16_call_args , v0\n", nsc);
    827     fprintf(out->fp, "#define __%sint32_formal_args , int32_t v0\n", nsc);
    828     fprintf(out->fp, "#define __%sint32_call_args , v0\n", nsc);
    829     fprintf(out->fp, "#define __%sint64_formal_args , int64_t v0\n", nsc);
    830     fprintf(out->fp, "#define __%sint64_call_args , v0\n", nsc);
    831     fprintf(out->fp, "#define __%sfloat_formal_args , float v0\n", nsc);
    832     fprintf(out->fp, "#define __%sfloat_call_args , v0\n", nsc);
    833     fprintf(out->fp, "#define __%sdouble_formal_args , double v0\n", nsc);
    834     fprintf(out->fp, "#define __%sdouble_call_args , v0\n", nsc);
    835     fprintf(out->fp, "\n");
    836     fprintf(out->fp, "__%sbuild_scalar(%s, %schar, char)\n", nsc, nsc, nsc);
    837     fprintf(out->fp, "__%sbuild_scalar(%s, %suint8, uint8_t)\n", nsc, nsc, nsc);
    838     fprintf(out->fp, "__%sbuild_scalar(%s, %sint8, int8_t)\n", nsc, nsc, nsc);
    839     fprintf(out->fp, "__%sbuild_scalar(%s, %sbool, %sbool_t)\n", nsc, nsc, nsc, nsc);
    840     fprintf(out->fp, "__%sbuild_scalar(%s, %suint16, uint16_t)\n", nsc, nsc, nsc);
    841     fprintf(out->fp, "__%sbuild_scalar(%s, %suint32, uint32_t)\n", nsc, nsc, nsc);
    842     fprintf(out->fp, "__%sbuild_scalar(%s, %suint64, uint64_t)\n", nsc, nsc, nsc);
    843     fprintf(out->fp, "__%sbuild_scalar(%s, %sint16, int16_t)\n", nsc, nsc, nsc);
    844     fprintf(out->fp, "__%sbuild_scalar(%s, %sint32, int32_t)\n", nsc, nsc, nsc);
    845     fprintf(out->fp, "__%sbuild_scalar(%s, %sint64, int64_t)\n", nsc, nsc, nsc);
    846     fprintf(out->fp, "__%sbuild_scalar(%s, %sfloat, float)\n", nsc, nsc, nsc);
    847     fprintf(out->fp, "__%sbuild_scalar(%s, %sdouble, double)\n", nsc, nsc, nsc);
    848     fprintf(out->fp, "\n");
    849     fprintf(out->fp, "__%sbuild_string(%s)\n", nsc, nsc);
    850     fprintf(out->fp, "\n");
    851 
    852     fprintf(out->fp, "__%sbuild_buffer(%s)\n", nsc, nsc);
    853     gen_epilogue(out);
    854     fprintf(out->fp, "#endif /* %s_COMMON_BUILDER_H */\n", nscup);
    855     return 0;
    856 }
    857 
    858 static int gen_builder_pretext(fb_output_t *out)
    859 {
    860     const char *nsc = out->nsc;
    861     const char *nscup = out->nscup;
    862 
    863     fprintf(out->fp,
    864         "#ifndef %s_BUILDER_H\n"
    865         "#define %s_BUILDER_H\n",
    866         out->S->basenameup, out->S->basenameup);
    867 
    868     fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n");
    869     fprintf(out->fp, "#ifndef %s_READER_H\n", out->S->basenameup);
    870     fprintf(out->fp, "#include \"%s_reader.h\"\n", out->S->basename);
    871     fprintf(out->fp, "#endif\n");
    872     fprintf(out->fp, "#ifndef %s_COMMON_BUILDER_H\n", nscup);
    873     fprintf(out->fp, "#include \"%scommon_builder.h\"\n", nsc);
    874     fprintf(out->fp, "#endif\n");
    875 
    876     fb_gen_c_includes(out, "_builder.h", "_BUILDER_H");
    877 
    878     gen_prologue(out);
    879 
    880     /*
    881      * Even if defined in the reader header, we must redefine it here
    882      * because another file might sneak in and update.
    883      */
    884     if (out->S->file_identifier.type == vt_string) {
    885         fprintf(out->fp,
    886             "#undef %sidentifier\n"
    887             "#define %sidentifier \"%.*s\"\n",
    888             nsc,
    889             nsc, out->S->file_identifier.s.len, out->S->file_identifier.s.s);
    890     } else {
    891         fprintf(out->fp,
    892             "#ifndef %sidentifier\n"
    893             "#define %sidentifier 0\n"
    894             "#endif\n",
    895             nsc, nsc);
    896     }
    897     if (out->S->file_extension.type == vt_string) {
    898         fprintf(out->fp,
    899             "#undef %sextension\n"
    900             "#define %sextension \"%.*s\"\n",
    901             nsc,
    902             nsc, out->S->file_extension.s.len, out->S->file_extension.s.s);
    903     } else {
    904         fprintf(out->fp,
    905             "#ifndef %sextension\n"
    906             "#define %sextension \"%s\"\n"
    907             "#endif\n",
    908             nsc, nsc, out->opts->default_bin_ext);
    909     }
    910     fprintf(out->fp, "\n");
    911     return 0;
    912 }
    913 
    914 static int get_total_struct_field_count(fb_compound_type_t *ct)
    915 {
    916     fb_member_t *member;
    917     fb_symbol_t *sym;
    918     int count = 0;
    919 
    920     for (sym = ct->members; sym; sym = sym->link) {
    921         member = (fb_member_t *)sym;
    922         if (member->metadata_flags & fb_f_deprecated) {
    923             continue;
    924         }
    925         switch (member->type.type) {
    926         /* struct arrays count as 1 but struct fields are expanded */
    927         case vt_compound_type_ref:
    928             if (member->type.ct->symbol.kind == fb_is_struct) {
    929                 count += get_total_struct_field_count(member->type.ct);
    930                 continue;
    931             }
    932             ++count;
    933             break;
    934         default:
    935             ++count;
    936             break;
    937         }
    938     }
    939     return count;
    940 }
    941 
    942 static inline void gen_comma(fb_output_t *out, int index, int count, int is_macro)
    943 {
    944     char *cont = is_macro ? "\\\n" : "\n";
    945 
    946     if (count == 0) {
    947         return;
    948     }
    949     if (index == 0) {
    950         if (count > 4) {
    951             fprintf(out->fp, ",%s  ", cont);
    952         } else {
    953             fprintf(out->fp, ", ");
    954         }
    955     } else {
    956         if (index % 4 || count - index <= 2) {
    957             fprintf(out->fp, ", ");
    958         } else {
    959             fprintf(out->fp, ",%s  ", cont);
    960         }
    961     }
    962 }
    963 
    964 static int gen_builder_struct_args(fb_output_t *out, fb_compound_type_t *ct, int index, int len, int is_macro)
    965 {
    966     const char *nsc = out->nsc;
    967     fb_member_t *member;
    968     fb_symbol_t *sym;
    969     const char *tname, *tname_ns;
    970     fb_scoped_name_t snref;
    971 
    972     fb_clear(snref);
    973 
    974     for (sym = ct->members; sym; sym = sym->link) {
    975         member = (fb_member_t *)sym;
    976         if (member->metadata_flags & fb_f_deprecated) {
    977             continue;
    978         }
    979         switch (member->type.type) {
    980         case vt_fixed_array_compound_type_ref:
    981             gen_comma(out, index, len, is_macro);
    982             fb_compound_name(member->type.ct, &snref);
    983             if (member->type.ct->symbol.kind == fb_is_struct) {
    984                 fprintf(out->fp, "const %s_t v%i[%i]", snref.text, index++, (int)member->type.len);
    985             } else {
    986                 fprintf(out->fp, "%s_enum_t v%i[%i]", snref.text, index++, (int)member->type.len);
    987             }
    988             break;
    989         case vt_compound_type_ref:
    990             if (member->type.ct->symbol.kind == fb_is_struct) {
    991                 index = gen_builder_struct_args(out, member->type.ct, index, len, is_macro);
    992                 continue;
    993             }
    994             gen_comma(out, index, len, is_macro);
    995             fb_compound_name(member->type.ct, &snref);
    996             fprintf(out->fp, "%s_enum_t v%i", snref.text, index++);
    997             break;
    998         case vt_fixed_array_type:
    999             gen_comma(out, index, len, is_macro);
   1000             tname_ns = scalar_type_ns(member->type.st, nsc);
   1001             tname = scalar_type_name(member->type.st);
   1002             fprintf(out->fp, "const %s%s v%i[%i]", tname_ns, tname, index++, (int)member->type.len);
   1003             break;
   1004         case vt_scalar_type:
   1005             gen_comma(out, index, len, is_macro);
   1006             tname_ns = scalar_type_ns(member->type.st, nsc);
   1007             tname = scalar_type_name(member->type.st);
   1008             fprintf(out->fp, "%s%s v%i", tname_ns, tname, index++);
   1009             break;
   1010         default:
   1011             gen_panic(out, "internal error: unexpected struct member type");
   1012             continue;
   1013         }
   1014     }
   1015     return index;
   1016 }
   1017 
   1018 static int gen_builder_struct_call_list(fb_output_t *out, fb_compound_type_t *ct, int index, int arg_count, int is_macro)
   1019 {
   1020     int i;
   1021     int len = get_total_struct_field_count(ct);
   1022 
   1023     for (i = 0; i < len; ++i) {
   1024         gen_comma(out, i, arg_count, is_macro);
   1025         fprintf(out->fp, "v%i", index++);
   1026     }
   1027     return index;
   1028 }
   1029 
   1030 enum { no_conversion, convert_from_pe, convert_to_pe };
   1031 
   1032 /* Note: returned index is not correct when using from_ptr since it doesn't track arguments, but it shouldn't matter. */
   1033 static int gen_builder_struct_field_assign(fb_output_t *out, fb_compound_type_t *ct, int index, int arg_count,
   1034         int conversion, int from_ptr)
   1035 {
   1036     const char *nsc = out->nsc;
   1037     fb_member_t *member;
   1038     fb_symbol_t *sym;
   1039     int n, len;
   1040     const char *s;
   1041     int deprecated_index = 0;
   1042     const char *kind, *tprefix;
   1043     fb_scoped_name_t snref;
   1044 
   1045     fb_clear(snref);
   1046     switch (conversion) {
   1047     case convert_to_pe: kind = "_to_pe"; break;
   1048     case convert_from_pe: kind = "_from_pe"; break;
   1049     default: kind = ""; break;
   1050     }
   1051     for (sym = ct->members; sym; sym = sym->link) {
   1052         member = (fb_member_t *)sym;
   1053         symbol_name(sym, &n, &s);
   1054 
   1055         if (index > 0) {
   1056             if (index % 4 == 0) {
   1057                 fprintf(out->fp, ";\n  ");
   1058             } else {
   1059                 fprintf(out->fp, "; ");
   1060             }
   1061         }
   1062         switch (member->type.type) {
   1063         case vt_fixed_array_compound_type_ref:
   1064             len = (int)member->type.len;
   1065             fb_compound_name(member->type.ct, &snref);
   1066             if (member->metadata_flags & fb_f_deprecated) {
   1067                 fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)",
   1068                         nsc, deprecated_index);
   1069                 ++deprecated_index;
   1070                 ++index;
   1071                 continue;
   1072             }
   1073             if (from_ptr) {
   1074                 fprintf(out->fp, "%s_array_copy%s(p->%.*s, p2->%.*s, %d)",
   1075                         snref.text, kind, n, s, n, s, len);
   1076             } else {
   1077                 fprintf(out->fp, "%s_array_copy%s(p->%.*s, v%i, %d)",
   1078                         snref.text, kind, n, s, index, len);
   1079             }
   1080             ++index;
   1081             continue;
   1082         case vt_compound_type_ref:
   1083             fb_compound_name(member->type.ct, &snref);
   1084             if (member->type.ct->symbol.kind == fb_is_struct) {
   1085                 if (member->metadata_flags & fb_f_deprecated) {
   1086                     fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)",
   1087                             nsc, deprecated_index);
   1088                     deprecated_index++;
   1089                     index += get_total_struct_field_count(member->type.ct);
   1090                     continue;
   1091                 }
   1092                 if (from_ptr) {
   1093                     fprintf(out->fp, "%s_copy%s(&p->%.*s, &p2->%.*s)", snref.text, kind, n, s, n, s);
   1094                     /* `index` does not count children, but it doesn't matter here. */
   1095                     ++index;
   1096                 } else {
   1097                     fprintf(out->fp, "%s_assign%s(&p->%.*s", snref.text, kind, n, s);
   1098                     index = gen_builder_struct_call_list(out, member->type.ct, index, arg_count, 0);
   1099                     fprintf(out->fp, ")");
   1100                 }
   1101                 continue;
   1102             }
   1103             if (member->metadata_flags & fb_f_deprecated) {
   1104                 fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)",
   1105                         nsc, deprecated_index);
   1106                 ++deprecated_index;
   1107                 ++index;
   1108                 continue;
   1109             }
   1110             switch (member->size == 1 ? no_conversion : conversion) {
   1111             case convert_from_pe:
   1112                 if (from_ptr) {
   1113                     fprintf(out->fp, "%s_copy_from_pe(&p->%.*s, &p2->%.*s)",
   1114                             snref.text, n, s, n, s);
   1115                 } else {
   1116                     fprintf(out->fp, "%s_assign_from_pe(&p->%.*s, v%i)",
   1117                             snref.text, n, s, index);
   1118                 }
   1119                 break;
   1120             case convert_to_pe:
   1121                 if (from_ptr) {
   1122                     fprintf(out->fp, "%s_copy_to_pe(&p->%.*s, &p2->%.*s)",
   1123                             snref.text, n, s, n, s);
   1124                 } else {
   1125                     fprintf(out->fp, "%s_assign_to_pe(&p->%.*s, v%i)",
   1126                             snref.text, n, s, index);
   1127                 }
   1128                 break;
   1129             default:
   1130                 if (from_ptr) {
   1131                     fprintf(out->fp, "p->%.*s = p2->%.*s", n, s, n, s);
   1132                 } else {
   1133                     fprintf(out->fp, "p->%.*s = v%i", n, s, index);
   1134                 }
   1135                 break;
   1136             }
   1137             ++index;
   1138             continue;
   1139         case vt_fixed_array_type:
   1140             tprefix = scalar_type_prefix(member->type.st);
   1141             len = (int)member->type.len;
   1142             if (member->metadata_flags & fb_f_deprecated) {
   1143                 fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)",
   1144                         nsc, deprecated_index);
   1145                 ++deprecated_index;
   1146                 ++index;
   1147                 continue;
   1148             }
   1149             if (from_ptr) {
   1150                 fprintf(out->fp, "%s%s_array_copy%s(p->%.*s, p2->%.*s, %d)",
   1151                         nsc, tprefix, kind, n, s, n, s, len);
   1152             } else {
   1153                 fprintf(out->fp, "%s%s_array_copy%s(p->%.*s, v%i, %d)",
   1154                         nsc, tprefix, kind, n, s, index, len);
   1155             }
   1156             ++index;
   1157             break;
   1158         case vt_scalar_type:
   1159             tprefix = scalar_type_prefix(member->type.st);
   1160             if (member->metadata_flags & fb_f_deprecated) {
   1161                 fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)",
   1162                         nsc, deprecated_index);
   1163                 ++deprecated_index;
   1164                 ++index;
   1165                 continue;
   1166             }
   1167             switch (member->size == 1 ? no_conversion : conversion) {
   1168             case convert_from_pe:
   1169                 if (from_ptr) {
   1170                     fprintf(out->fp, "%s%s_copy_from_pe(&p->%.*s, &p2->%.*s)",
   1171                             nsc, tprefix, n, s, n, s);
   1172                 } else {
   1173                     fprintf(out->fp, "%s%s_assign_from_pe(&p->%.*s, v%i)",
   1174                             nsc, tprefix, n, s, index);
   1175                 }
   1176                 break;
   1177             case convert_to_pe:
   1178                 if (from_ptr) {
   1179                     fprintf(out->fp, "%s%s_copy_to_pe(&p->%.*s, &p2->%.*s)",
   1180                             nsc, tprefix, n, s, n, s);
   1181                 } else {
   1182                     fprintf(out->fp, "%s%s_assign_to_pe(&p->%.*s, v%i)",
   1183                             nsc, tprefix, n, s, index);
   1184                 }
   1185                 break;
   1186             default:
   1187                 if (from_ptr) {
   1188                     fprintf(out->fp, "p->%.*s = p2->%.*s", n, s, n, s);
   1189                 } else {
   1190                     fprintf(out->fp, "p->%.*s = v%i", n, s, index);
   1191                 }
   1192                 break;
   1193             }
   1194             ++index;
   1195             break;
   1196         default:
   1197             gen_panic(out, "internal error: type error");
   1198             continue;
   1199         }
   1200     }
   1201     if (arg_count > 0) {
   1202         fprintf(out->fp, ";\n  ");
   1203     }
   1204     return index;
   1205 }
   1206 
   1207 static void gen_builder_struct(fb_output_t *out, fb_compound_type_t *ct)
   1208 {
   1209     const char *nsc = out->nsc;
   1210     int arg_count;
   1211     fb_scoped_name_t snt;
   1212 
   1213     fb_clear(snt);
   1214     assert(ct->symbol.kind == fb_is_struct);
   1215 
   1216     fb_compound_name(ct, &snt);
   1217 
   1218     arg_count = get_total_struct_field_count(ct);
   1219     fprintf(out->fp, "#define __%s_formal_args ", snt.text);
   1220     gen_builder_struct_args(out, ct, 0, arg_count, 1);
   1221     fprintf(out->fp, "\n#define __%s_call_args ", snt.text);
   1222     gen_builder_struct_call_list(out, ct, 0, arg_count, 1);
   1223     fprintf(out->fp, "\n");
   1224     fprintf(out->fp,
   1225             "static inline %s_t *%s_assign(%s_t *p",
   1226             snt.text, snt.text, snt.text);
   1227     gen_builder_struct_args(out, ct, 0, arg_count, 0);
   1228     fprintf(out->fp, ")\n{ ");
   1229     gen_builder_struct_field_assign(out, ct, 0, arg_count, no_conversion, 0);
   1230     fprintf(out->fp, "return p; }\n");
   1231     fprintf(out->fp,
   1232             "static inline %s_t *%s_copy(%s_t *p, const %s_t *p2)\n",
   1233             snt.text, snt.text, snt.text, snt.text);
   1234     fprintf(out->fp, "{ ");
   1235     gen_builder_struct_field_assign(out, ct, 0, arg_count, no_conversion, 1);
   1236     fprintf(out->fp, "return p; }\n");
   1237     fprintf(out->fp,
   1238             "static inline %s_t *%s_assign_to_pe(%s_t *p",
   1239             snt.text, snt.text, snt.text);
   1240     gen_builder_struct_args(out, ct, 0, arg_count, 0);
   1241     fprintf(out->fp, ")\n{ ");
   1242     gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_to_pe, 0);
   1243     fprintf(out->fp, "return p; }\n");
   1244     fprintf(out->fp,
   1245             "static inline %s_t *%s_copy_to_pe(%s_t *p, const %s_t *p2)\n",
   1246             snt.text, snt.text, snt.text, snt.text);
   1247     fprintf(out->fp, "{ ");
   1248     gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_to_pe, 1);
   1249     fprintf(out->fp, "return p; }\n");
   1250     fprintf(out->fp,
   1251             "static inline %s_t *%s_assign_from_pe(%s_t *p",
   1252             snt.text, snt.text, snt.text);
   1253     gen_builder_struct_args(out, ct, 0, arg_count, 0);
   1254     fprintf(out->fp, ")\n{ ");
   1255     gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_from_pe, 0);
   1256     fprintf(out->fp, "return p; }\n");
   1257     fprintf(out->fp,
   1258             "static inline %s_t *%s_copy_from_pe(%s_t *p, const %s_t *p2)\n",
   1259             snt.text, snt.text, snt.text, snt.text);
   1260     fprintf(out->fp, "{ ");
   1261     gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_from_pe, 1);
   1262     fprintf(out->fp, "return p; }\n");
   1263     fprintf(out->fp, "__%sbuild_struct(%s, %s, %"PRIu64", %u, %s_file_identifier, %s_type_identifier)\n",
   1264             nsc, nsc, snt.text, (uint64_t)ct->size, ct->align, snt.text, snt.text);
   1265 
   1266     if (ct->size > 0) {
   1267         fprintf(out->fp, "__%sdefine_fixed_array_primitives(%s, %s, %s_t)\n",
   1268                 nsc, nsc, snt.text, snt.text);
   1269     }
   1270 }
   1271 
   1272 static int get_create_table_arg_count(fb_compound_type_t *ct)
   1273 {
   1274     fb_member_t *member;
   1275     fb_symbol_t *sym;
   1276     int count = 0;
   1277 
   1278     for (sym = ct->members; sym; sym = sym->link) {
   1279         member = (fb_member_t *)sym;
   1280         if (member->metadata_flags & fb_f_deprecated) {
   1281             continue;
   1282         }
   1283         ++count;
   1284     }
   1285     return count;
   1286 }
   1287 
   1288 static int gen_builder_table_call_list(fb_output_t *out, fb_compound_type_t *ct, int arg_count, int is_macro)
   1289 {
   1290     fb_member_t *member;
   1291     fb_symbol_t *sym;
   1292     int index = 0;
   1293 
   1294     for (sym = ct->members; sym; sym = sym->link) {
   1295         member = (fb_member_t *)sym;
   1296         if (member->metadata_flags & fb_f_deprecated) {
   1297             continue;
   1298         }
   1299         gen_comma(out, index, arg_count, is_macro);
   1300         fprintf(out->fp, "v%"PRIu64"", (uint64_t)member->id);
   1301         ++index;
   1302     }
   1303     return index;
   1304 }
   1305 
   1306 
   1307 static int gen_required_table_fields(fb_output_t *out, fb_compound_type_t *ct)
   1308 {
   1309     const char *nsc = out->nsc;
   1310     fb_member_t *member;
   1311     fb_symbol_t *sym;
   1312     int index;
   1313     int arg_count;
   1314     fb_scoped_name_t snt;
   1315 
   1316     fb_clear(snt);
   1317     arg_count = get_create_table_arg_count(ct);
   1318     index = 0;
   1319     fb_compound_name(ct, &snt);
   1320     fprintf(out->fp, "static const %svoffset_t __%s_required[] = {", nsc, snt.text);
   1321     for (sym = ct->members; sym; sym = sym->link) {
   1322         member = (fb_member_t *)sym;
   1323         if (member->metadata_flags & fb_f_deprecated) {
   1324             continue;
   1325         }
   1326         if (member->metadata_flags & fb_f_required) {
   1327             if (index > 0) {
   1328                 gen_comma(out, index, arg_count, 0);
   1329             } else {
   1330                 fprintf(out->fp, " ");
   1331             }
   1332             fprintf(out->fp, "%u", (unsigned)member->id);
   1333             index++;
   1334         }
   1335     }
   1336     /* Add extra element to avoid null arrays. */
   1337     if (index > 0) {
   1338         fprintf(out->fp, ", 0 };\n");
   1339     } else {
   1340         fprintf(out->fp, " 0 };\n");
   1341     }
   1342     return index;
   1343 }
   1344 
   1345 static int gen_builder_table_args(fb_output_t *out, fb_compound_type_t *ct, int arg_count, int is_macro)
   1346 {
   1347     const char *nsc = out->nsc;
   1348     fb_symbol_t *sym;
   1349     fb_member_t *member;
   1350     const char *tname, *tname_ns;
   1351     int index;
   1352     fb_scoped_name_t snref;
   1353 
   1354     fb_clear(snref);
   1355     /* Just to help the comma. */
   1356     index = 0;
   1357     /* We use the id to name arguments so sorted assignment can find the arguments trivially. */
   1358     for (sym = ct->members; sym; sym = sym->link) {
   1359         member = (fb_member_t *)sym;
   1360         if (member->metadata_flags & fb_f_deprecated) {
   1361             continue;
   1362         }
   1363         gen_comma(out, index++, arg_count, is_macro);
   1364         switch (member->type.type) {
   1365         case vt_compound_type_ref:
   1366             fb_compound_name(member->type.ct, &snref);
   1367             switch (member->type.ct->symbol.kind) {
   1368             case fb_is_struct:
   1369                 fprintf(out->fp, "%s_t *v%"PRIu64"", snref.text, (uint64_t)member->id);
   1370                 break;
   1371             case fb_is_enum:
   1372                 fprintf(out->fp, "%s_enum_t v%"PRIu64"", snref.text, (uint64_t)member->id);
   1373                 break;
   1374             case fb_is_table:
   1375                 fprintf(out->fp, "%s_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id);
   1376                 break;
   1377             case fb_is_union:
   1378                 /* Unions jump an index because it is two fields. */
   1379                 fprintf(out->fp, "%s_union_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id);
   1380                 break;
   1381             default:
   1382                 gen_panic(out, "internal error: unexpected table field type");
   1383                 continue;
   1384             }
   1385             break;
   1386         case vt_vector_compound_type_ref:
   1387             fb_compound_name(member->type.ct, &snref);
   1388             switch (member->type.ct->symbol.kind) {
   1389             case fb_is_struct:
   1390             case fb_is_enum:
   1391             case fb_is_table:
   1392                 fprintf(out->fp, "%s_vec_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id);
   1393                 break;
   1394             case fb_is_union:
   1395                 fprintf(out->fp, "%s_union_vec_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id);
   1396                 break;
   1397             default:
   1398                 gen_panic(out, "internal error: unexpected table table type");
   1399                 continue;
   1400             }
   1401             break;
   1402         case vt_scalar_type:
   1403             tname_ns = scalar_type_ns(member->type.st, nsc);
   1404             tname = scalar_type_name(member->type.st);
   1405             fprintf(out->fp, "%s%s v%"PRIu64"", tname_ns, tname, (uint64_t)member->id);
   1406             break;
   1407         case vt_vector_type:
   1408             tname = scalar_type_prefix(member->type.st);
   1409             fprintf(out->fp, "%s%s_vec_ref_t v%"PRIu64"", nsc, tname, (uint64_t)member->id);
   1410             break;
   1411         case vt_string_type:
   1412             fprintf(out->fp, "%sstring_ref_t v%"PRIu64"", nsc, (uint64_t)member->id);
   1413             break;
   1414         case vt_vector_string_type:
   1415             fprintf(out->fp, "%sstring_vec_ref_t v%"PRIu64"", nsc, (uint64_t)member->id);
   1416             break;
   1417         default:
   1418             gen_panic(out, "internal error: unexpected table member type");
   1419             continue;
   1420         }
   1421     }
   1422     return index;
   1423 }
   1424 
   1425 static int gen_builder_create_table_decl(fb_output_t *out, fb_compound_type_t *ct)
   1426 {
   1427     const char *nsc = out->nsc;
   1428     int arg_count;
   1429     fb_scoped_name_t snt;
   1430 
   1431     fb_clear(snt);
   1432     fb_compound_name(ct, &snt);
   1433 
   1434     arg_count = get_create_table_arg_count(ct);
   1435     fprintf(out->fp, "#define __%s_formal_args ", snt.text);
   1436     gen_builder_table_args(out, ct, arg_count, 1);
   1437     fprintf(out->fp, "\n#define __%s_call_args ", snt.text);
   1438     gen_builder_table_call_list(out, ct, arg_count, 1);
   1439     fprintf(out->fp, "\n");
   1440 
   1441     /* `_clone` fw decl must be place before build_table macro and `_create` must be placed after. */
   1442     fprintf(out->fp,
   1443             "static inline %s_ref_t %s_create(%sbuilder_t *B __%s_formal_args);\n",
   1444             snt.text, snt.text, nsc, snt.text);
   1445     return 0;
   1446 }
   1447 
   1448 static int gen_builder_create_table(fb_output_t *out, fb_compound_type_t *ct)
   1449 {
   1450     const char *nsc = out->nsc;
   1451     fb_member_t *member;
   1452     int n;
   1453     const char *s;
   1454     int patch_union = !(ct->metadata_flags & fb_f_original_order);
   1455     int has_union = 0;
   1456     fb_scoped_name_t snt;
   1457 
   1458     fb_clear(snt);
   1459     fb_compound_name(ct, &snt);
   1460 
   1461     fprintf(out->fp,
   1462             "static inline %s_ref_t %s_create(%sbuilder_t *B __%s_formal_args)\n",
   1463             snt.text, snt.text, nsc, snt.text);
   1464 
   1465     fprintf(out->fp, "{\n    if (%s_start(B)", snt.text);
   1466     for (member = ct->ordered_members; member; member = member->order) {
   1467         if (member->metadata_flags & fb_f_deprecated) {
   1468             continue;
   1469         }
   1470         symbol_name(&member->symbol, &n, &s);
   1471         if (member->type.type == vt_compound_type_ref && member->type.ct->symbol.kind == fb_is_union) {
   1472             has_union = 1;
   1473             if (patch_union) {
   1474                 fprintf(out->fp, "\n        || %s_%.*s_add_value(B, v%"PRIu64")", snt.text, n, s, (uint64_t)member->id);
   1475                 continue;
   1476             }
   1477         }
   1478         fprintf(out->fp, "\n        || %s_%.*s_add(B, v%"PRIu64")", snt.text, n, s, (uint64_t)member->id);
   1479     }
   1480     if (patch_union && has_union) {
   1481         for (member = ct->ordered_members; member; member = member->order) {
   1482             if (member->metadata_flags & fb_f_deprecated) {
   1483                 continue;
   1484             }
   1485             if (member->type.type == vt_compound_type_ref && member->type.ct->symbol.kind == fb_is_union) {
   1486                 symbol_name(&member->symbol, &n, &s);
   1487                 fprintf(out->fp, "\n        || %s_%.*s_add_type(B, v%"PRIu64".type)", snt.text, n, s, (uint64_t)member->id);
   1488             }
   1489         }
   1490     }
   1491     fprintf(out->fp, ") {\n        return 0;\n    }\n    return %s_end(B);\n}\n\n", snt.text);
   1492     return 0;
   1493 }
   1494 
   1495 static int gen_builder_structs(fb_output_t *out)
   1496 {
   1497     fb_compound_type_t *ct;
   1498 
   1499     /* Generate structs in topologically sorted order. */
   1500     for (ct = out->S->ordered_structs; ct; ct = ct->order) {
   1501         gen_builder_struct(out, ct);
   1502         fprintf(out->fp, "\n");
   1503     }
   1504     return 0;
   1505 }
   1506 
   1507 static int gen_builder_table(fb_output_t *out, fb_compound_type_t *ct)
   1508 {
   1509     const char *nsc = out->nsc;
   1510     fb_scoped_name_t snt;
   1511 
   1512     fb_clear(snt);
   1513     fb_compound_name(ct, &snt);
   1514 
   1515     fprintf(out->fp,
   1516             "typedef %sref_t %s_ref_t;\n",
   1517             nsc, snt.text);
   1518     fprintf(out->fp,
   1519             "static %s_ref_t %s_clone(%sbuilder_t *B, %s_table_t t);\n",
   1520             snt.text, snt.text, nsc, snt.text);
   1521     fprintf(out->fp, "__%sbuild_table(%s, %s, %"PRIu64")\n",
   1522             nsc, nsc, snt.text, (uint64_t)ct->count);
   1523     return 0;
   1524 }
   1525 
   1526 static int gen_builder_table_prolog(fb_output_t *out, fb_compound_type_t *ct)
   1527 {
   1528     const char *nsc = out->nsc;
   1529     fb_scoped_name_t snt;
   1530 
   1531     fb_clear(snt);
   1532     fb_compound_name(ct, &snt);
   1533 
   1534     fprintf(out->fp, "__%sbuild_table_prolog(%s, %s, %s_file_identifier, %s_type_identifier)\n",
   1535             nsc, nsc, snt.text, snt.text, snt.text);
   1536     return 0;
   1537 }
   1538 
   1539 static int gen_union_fields(fb_output_t *out, const char *st, int n, const char *s,
   1540         fb_compound_type_t *ct, int is_vector)
   1541 {
   1542     const char *nsc = out->nsc;
   1543     fb_symbol_t *sym;
   1544     fb_member_t *member;
   1545     const char *su;
   1546     int nu;
   1547     fb_scoped_name_t snref;
   1548     fb_scoped_name_t snu;
   1549     const char *kind = is_vector ? "vector_value" : "value";
   1550 
   1551     fb_clear(snref);
   1552     fb_clear(snu);
   1553     fb_compound_name(ct, &snref);
   1554     for (sym = ct->members; sym; sym = sym->link) {
   1555         member = (fb_member_t *)sym;
   1556         symbol_name(sym, &nu, &su);
   1557         switch (member->type.type) {
   1558         case vt_missing:
   1559             break;
   1560         case vt_compound_type_ref:
   1561             fb_compound_name(member->type.ct, &snu);
   1562             switch (member->type.ct->symbol.kind) {
   1563             case fb_is_table:
   1564                 fprintf(out->fp,
   1565                         "__%sbuild_union_table_%s_field(%s, %s_%.*s, %s, %.*s, %s)\n",
   1566                         nsc, kind, nsc, st, n, s, snref.text, nu, su, snu.text);
   1567                 break;
   1568             case fb_is_struct:
   1569                 fprintf(out->fp,
   1570                         "__%sbuild_union_struct_%s_field(%s, %s_%.*s, %s, %.*s, %s)\n",
   1571                         nsc, kind, nsc, st, n, s, snref.text, nu, su, snu.text);
   1572                 break;
   1573             default:
   1574                 gen_panic(out, "internal error: unexpected union member compound type");
   1575                 return -1;
   1576             }
   1577             break;
   1578         case vt_string_type:
   1579             fprintf(out->fp,
   1580                     "__%sbuild_union_string_%s_field(%s, %s_%.*s, %s, %.*s)\n",
   1581                     nsc, kind, nsc, st, n, s, snref.text, nu, su);
   1582             break;
   1583         default:
   1584             gen_panic(out, "internal error: unexpected union member type");
   1585             return -1;
   1586         }
   1587     }
   1588     return 0;
   1589 }
   1590 
   1591 static int gen_builder_table_fields(fb_output_t *out, fb_compound_type_t *ct)
   1592 {
   1593     const char *nsc = out->nsc;
   1594     fb_member_t *member;
   1595     fb_symbol_t *sym;
   1596     const char *s, *tprefix, *tname, *tname_ns;
   1597     int n;
   1598     int is_optional;
   1599     fb_scoped_name_t snt;
   1600     fb_scoped_name_t snref;
   1601     fb_literal_t literal;
   1602 
   1603     fb_clear(snt);
   1604     fb_clear(snref);
   1605     fb_compound_name(ct, &snt);
   1606 
   1607     for (sym = ct->members; sym; sym = sym->link) {
   1608         member = (fb_member_t *)sym;
   1609         symbol_name(&member->symbol, &n, &s);
   1610         if (member->metadata_flags & fb_f_deprecated) {
   1611             fprintf(out->fp, "/* Skipping build of deprecated field: '%s_%.*s' */\n\n", snt.text, n, s);
   1612             continue;
   1613         }
   1614         is_optional = member->flags & fb_fm_optional;
   1615         switch (member->type.type) {
   1616         case vt_scalar_type:
   1617             tname_ns = scalar_type_ns(member->type.st, nsc);
   1618             tname = scalar_type_name(member->type.st);
   1619             tprefix = scalar_type_prefix(member->type.st);
   1620             if (is_optional) {
   1621                 fprintf(out->fp,
   1622                     "__%sbuild_scalar_optional_field(%"PRIu64", %s, %s_%.*s, %s%s, %s%s, %"PRIu64", %u, %s)\n",
   1623                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, nsc, tprefix, tname_ns, tname,
   1624                     (uint64_t)member->size, member->align, snt.text);
   1625             } else {
   1626                 print_literal(member->type.st, &member->value, literal);
   1627                 fprintf(out->fp,
   1628                     "__%sbuild_scalar_field(%"PRIu64", %s, %s_%.*s, %s%s, %s%s, %"PRIu64", %u, %s, %s)\n",
   1629                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, nsc, tprefix, tname_ns, tname,
   1630                     (uint64_t)member->size, member->align, literal, snt.text);
   1631             }
   1632             break;
   1633         case vt_vector_type:
   1634             tname_ns = scalar_type_ns(member->type.st, nsc);
   1635             tname = scalar_type_name(member->type.st);
   1636             tprefix = scalar_type_prefix(member->type.st);
   1637             fprintf(out->fp,
   1638                 "__%sbuild_vector_field(%"PRIu64", %s, %s_%.*s, %s%s, %s%s, %s)\n",
   1639                 nsc, (uint64_t)member->id, nsc, snt.text, n, s, nsc, tprefix, tname_ns, tname, snt.text);
   1640             /* [ubyte] vectors can nest buffers. */
   1641             if (member->nest) {
   1642                 switch (member->nest->symbol.kind) {
   1643                 case fb_is_table:
   1644                     fb_compound_name((fb_compound_type_t *)(&member->nest->symbol), &snref);
   1645                     fprintf(out->fp, "__%sbuild_nested_table_root(%s, %s_%.*s, %s, %s_identifier, %s_type_identifier)\n",
   1646                         nsc, nsc, snt.text, n, s, snref.text, snref.text, snref.text);
   1647                     break;
   1648                 case fb_is_struct:
   1649                     fb_compound_name((fb_compound_type_t *)(&member->nest->symbol), &snref);
   1650                     fprintf(out->fp, "__%sbuild_nested_struct_root(%s, %s_%.*s, %s, %u, %s_identifier, %s_type_identifier)\n",
   1651                         nsc, nsc, snt.text, n, s, snref.text,
   1652                         (unsigned)((fb_compound_type_t *)(member->nest))->align, snref.text, snref.text);
   1653                     break;
   1654                 default:
   1655                     gen_panic(out, "internal error: unexpected nested type");
   1656                     continue;
   1657                 }
   1658             }
   1659             break;
   1660         case vt_string_type:
   1661             fprintf(out->fp,
   1662                 "__%sbuild_string_field(%"PRIu64", %s, %s_%.*s, %s)\n",
   1663                 nsc, (uint64_t)member->id, nsc, snt.text, n, s, snt.text);
   1664             break;
   1665         case vt_vector_string_type:
   1666             fprintf(out->fp,
   1667                 "__%sbuild_string_vector_field(%"PRIu64", %s, %s_%.*s, %s)\n",
   1668                 nsc, (uint64_t)member->id, nsc, snt.text, n, s, snt.text);
   1669             break;
   1670         case vt_compound_type_ref:
   1671             fb_compound_name(member->type.ct, &snref);
   1672             switch (member->type.ct->symbol.kind) {
   1673             case fb_is_struct:
   1674                 fprintf(out->fp,
   1675                     "__%sbuild_struct_field(%"PRIu64", %s, %s_%.*s, %s, %"PRIu64", %u, %s)\n",
   1676                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, (uint64_t)member->size, member->align, snt.text);
   1677                 break;
   1678             case fb_is_table:
   1679                 fprintf(out->fp,
   1680                     "__%sbuild_table_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n",
   1681                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text);
   1682                 break;
   1683             case fb_is_enum:
   1684                 if (is_optional) {
   1685                     fprintf(out->fp,
   1686                         "__%sbuild_scalar_optional_field(%"PRIu64", %s, %s_%.*s, %s, %s_enum_t, %"PRIu64", %u, %s)\n",
   1687                         nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text,
   1688                         (uint64_t)member->size, member->align, snt.text);
   1689                 } else {
   1690                     print_literal(member->type.ct->type.st, &member->value, literal);
   1691                     fprintf(out->fp,
   1692                         "__%sbuild_scalar_field(%"PRIu64", %s, %s_%.*s, %s, %s_enum_t, %"PRIu64", %u, %s, %s)\n",
   1693                         nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text,
   1694                         (uint64_t)member->size, member->align, literal, snt.text);
   1695                 }
   1696                 break;
   1697             case fb_is_union:
   1698                 fprintf(out->fp,
   1699                     "__%sbuild_union_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n",
   1700                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text);
   1701                 gen_union_fields(out, snt.text, n, s, member->type.ct, 0);
   1702                 break;
   1703             default:
   1704                 gen_panic(out, "internal error: unexpected compound type in table during code generation");
   1705                 break;
   1706             }
   1707             break;
   1708         case vt_vector_compound_type_ref:
   1709             fb_compound_name(member->type.ct, &snref);
   1710             switch (member->type.ct->symbol.kind) {
   1711             case fb_is_struct:
   1712                 if (member->type.ct->symbol.flags & fb_indexed) {
   1713                     fprintf(out->fp, "/* vector has keyed elements */\n");
   1714                 }
   1715                 fprintf(out->fp,
   1716                     "__%sbuild_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s_t, %s)\n",
   1717                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text, snt.text);
   1718                 break;
   1719             case fb_is_table:
   1720                 if (member->type.ct->symbol.flags & fb_indexed) {
   1721                     fprintf(out->fp, "/* vector has keyed elements */\n");
   1722                 }
   1723                 fprintf(out->fp,
   1724                     "__%sbuild_table_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n",
   1725                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text);
   1726                 break;
   1727             case fb_is_enum:
   1728                 fprintf(out->fp,
   1729                     "__%sbuild_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s_enum_t, %s)\n",
   1730                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text, snt.text);
   1731                 break;
   1732             case fb_is_union:
   1733                 fprintf(out->fp,
   1734                     "__%sbuild_union_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n",
   1735                     nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text);
   1736                 gen_union_fields(out, snt.text, n, s, member->type.ct, 1);
   1737                 break;
   1738             default:
   1739                 gen_panic(out, "internal error: unexpected vector compound type in table during code generation");
   1740                 break;
   1741             }
   1742             break;
   1743         default:
   1744             gen_panic(out, "internal error: unexpected table member type during code generation");
   1745             break;
   1746         }
   1747     }
   1748     fprintf(out->fp, "\n");
   1749     return 0;
   1750 }
   1751 
   1752 /*
   1753  * NOTE:
   1754  *
   1755  * Cloning a table might lead to a combinatorial explosion if the source
   1756  * has many shared references in a DAG. In many cases this might not be
   1757  * an issue, but it it is deduplication will be necessary. Deduplication
   1758  * is not specific to cloning but especially relevant here. Because
   1759  * deduplication carries an overhead in runtime and complexity it is not
   1760  * part of the core cloning operation. Cloning of unions and vectors with
   1761  * references have similar concerns.
   1762  *
   1763  * A deduplication operation would internally look like like this:
   1764  *
   1765  *   dedup_clone_table(builder, dedup_map, src_ptr)
   1766  *   {
   1767  *      ref = get_cloned_ref(dedup_map, src_ptr)
   1768  *      if (!ref) {
   1769  *          ref = clone_table(builder, src_ptr);
   1770  *          set_cloned_ref(dedup_map, src_ptr, ref);
   1771  *      }
   1772  *      return ref;
   1773  *   }
   1774  *
   1775  * where dedup_map is a map from a pointer to a builder reference and
   1776  * where the dedup_map is dedicated to a single builder and may cover
   1777  * multiple source buffers as long as they have separate memory
   1778  * locations - otherwise a separate dedup map must be used for each
   1779  * source buffer.
   1780  *
   1781  * Note that the clone operation is not safe without a safe source
   1782  * buffer so clone cannot be used to make a buffer with overlapping data
   1783  * safe (e.g. a string and a table referencing the same memory). Even if
   1784  * the source passes basic verification the result might not. To make
   1785  * clone safe it would be necessariry to remember the type as well, for
   1786  * example by adding a type specifier to the dedup_map.
   1787  *
   1788  * In the following we do not implement deduplication.
   1789  */
   1790 static int gen_builder_clone_table(fb_output_t *out, fb_compound_type_t *ct)
   1791 {
   1792     const char *nsc = out->nsc;
   1793     fb_member_t *member;
   1794     const char *s;
   1795     int n;
   1796     fb_scoped_name_t snt;
   1797     fb_scoped_name_t snref;
   1798 
   1799     fb_clear(snt);
   1800     fb_clear(snref);
   1801     fb_compound_name(ct, &snt);
   1802 
   1803     /*
   1804      * We could optimize this by cloning the entire table memory block
   1805      * and then update update only the references. The builder has
   1806      * direct vtable operations to support this - this would not work
   1807      * properly if there are deprecated fields to be stripped or if the
   1808      * default value has changed - and, more complicated: it is
   1809      * necessary to know what table alignment needs to be which require
   1810      * inspection of all fields, or a worst case assumption. So at least
   1811      * for now, we clone by picking one field at a time.
   1812      */
   1813 
   1814     fprintf(out->fp,
   1815             "static %s_ref_t %s_clone(%sbuilder_t *B, %s_table_t t)\n",
   1816             snt.text, snt.text, nsc, snt.text);
   1817 
   1818     fprintf(out->fp,
   1819             "{\n"
   1820             "    __%smemoize_begin(B, t);\n"
   1821             "    if (%s_start(B)", nsc, snt.text);
   1822     for (member = ct->ordered_members; member; member = member->order) {
   1823         if (member->metadata_flags & fb_f_deprecated) {
   1824             continue;
   1825         }
   1826         symbol_name(&member->symbol, &n, &s);
   1827         switch (member->type.type) {
   1828         case vt_scalar_type:
   1829         case vt_vector_type: /* This includes nested buffers - they are just transferred as bytes. */
   1830         case vt_string_type:
   1831         case vt_vector_string_type:
   1832             fprintf(out->fp, "\n        || %s_%.*s_pick(B, t)", snt.text, n, s);
   1833             break;
   1834         case vt_compound_type_ref:
   1835             fb_compound_name(member->type.ct, &snref);
   1836             switch (member->type.ct->symbol.kind) {
   1837             case fb_is_struct:
   1838             case fb_is_table:
   1839             case fb_is_enum:
   1840             case fb_is_union:
   1841                 fprintf(out->fp, "\n        || %s_%.*s_pick(B, t)", snt.text, n, s);
   1842                 break;
   1843             default:
   1844                 gen_panic(out, "internal error: unexpected compound type in table during code generation");
   1845                 break;
   1846             }
   1847             break;
   1848         case vt_vector_compound_type_ref:
   1849             fb_compound_name(member->type.ct, &snref);
   1850             switch (member->type.ct->symbol.kind) {
   1851             case fb_is_struct:
   1852             case fb_is_table:
   1853             case fb_is_enum:
   1854             case fb_is_union:
   1855                 fprintf(out->fp, "\n        || %s_%.*s_pick(B, t)", snt.text, n, s);
   1856                 break;
   1857             default:
   1858                 gen_panic(out, "internal error: unexpected vector compound type in table during code generation");
   1859                 break;
   1860             }
   1861             break;
   1862         default:
   1863             gen_panic(out, "internal error: unexpected table member type during code generation");
   1864             break;
   1865         }
   1866     }
   1867     fprintf(out->fp, ") {\n"
   1868             "        return 0;\n"
   1869             "    }\n"
   1870             "    __%smemoize_end(B, t, %s_end(B));\n}\n", nsc, snt.text);
   1871     return 0;
   1872 }
   1873 
   1874 static int gen_builder_enums(fb_output_t *out)
   1875 {
   1876     const char *nsc = out->nsc;
   1877     fb_symbol_t *sym;
   1878     int was_here = 0;
   1879     fb_scoped_name_t snt;
   1880 
   1881     fb_clear(snt);
   1882 
   1883     for (sym = out->S->symbols; sym; sym = sym->link) {
   1884         switch (sym->kind) {
   1885         case fb_is_enum:
   1886             fb_compound_name((fb_compound_type_t *)sym, &snt);
   1887             fprintf(out->fp,
   1888                 "#define __%s_formal_args , %s_enum_t v0\n"
   1889                 "#define __%s_call_args , v0\n",
   1890                 snt.text, snt.text,
   1891                 snt.text);
   1892             fprintf(out->fp, "__%sbuild_scalar(%s, %s, %s_enum_t)\n",
   1893                 nsc, nsc, snt.text, snt.text);
   1894             was_here = 1;
   1895             break;
   1896         default:
   1897             continue;
   1898         }
   1899     }
   1900     if (was_here) {
   1901         fprintf(out->fp, "\n");
   1902     }
   1903     return 0;
   1904 }
   1905 
   1906 /*
   1907  * Scope resolution is a bit fuzzy in unions -
   1908  *
   1909  * Googles flatc compiler allows dot notation in unions but not enums.
   1910  * C++ generates unqualified enum members (i.e. MyGame.Example.Monster
   1911  * becomes Monster) in the generated enum but still refers to the
   1912  * specific table type in the given namespace. This makes it possible
   1913  * to have name conflicts, and flatc raises these like other enum
   1914  * conficts.
   1915  *
   1916  * We use the same approach and this is why we both look up compound
   1917  * name and symbol name for the same member but the code generator
   1918  * is not concerned with how the scope is parsed or how errors are
   1919  * flagged - it just expects members to be unique.
   1920  */
   1921 static int gen_union(fb_output_t *out, fb_compound_type_t *ct)
   1922 {
   1923     const char *nsc = out->nsc;
   1924     fb_member_t *member;
   1925     fb_symbol_t *sym;
   1926     const char *s;
   1927     int n;
   1928     fb_scoped_name_t snt;
   1929     fb_scoped_name_t snref;
   1930 
   1931     fb_clear(snt);
   1932     fb_clear(snref);
   1933     fb_compound_name(ct, &snt);
   1934 
   1935     for (sym = ct->members; sym; sym = sym->link) {
   1936         member = (fb_member_t *)sym;
   1937         switch (member->type.type) {
   1938         case vt_compound_type_ref:
   1939             fb_compound_name((fb_compound_type_t *)member->type.ct, &snref);
   1940             symbol_name(sym, &n, &s);
   1941             fprintf(out->fp,
   1942                 "static inline %s_union_ref_t %s_as_%.*s(%s_ref_t ref)\n"
   1943                 "{ %s_union_ref_t uref; uref.type = %s_%.*s; uref.value = ref; return uref; }\n",
   1944                 snt.text, snt.text, n, s, snref.text,
   1945                 snt.text, snt.text, n, s);
   1946             break;
   1947         case vt_string_type:
   1948             symbol_name(sym, &n, &s);
   1949             fprintf(out->fp,
   1950                 "static inline %s_union_ref_t %s_as_%.*s(%sstring_ref_t ref)\n"
   1951                 "{ %s_union_ref_t uref; uref.type = %s_%.*s; uref.value = ref; return uref; }\n",
   1952                 snt.text, snt.text, n, s, nsc,
   1953                 snt.text, snt.text, n, s);
   1954             break;
   1955         case vt_missing:
   1956             fprintf(out->fp,
   1957                 "static inline %s_union_ref_t %s_as_NONE(void)\n"
   1958                 "{ %s_union_ref_t uref; uref.type = %s_NONE; uref.value = 0; return uref; }\n",
   1959                 snt.text, snt.text, snt.text, snt.text);
   1960             break;
   1961         default:
   1962             gen_panic(out, "internal error: unexpected union value type");
   1963             break;
   1964         }
   1965     }
   1966     fprintf(out->fp,
   1967         "__%sbuild_union_vector(%s, %s)\n\n",
   1968         nsc, nsc, snt.text);
   1969     return 0;
   1970 }
   1971 
   1972 static int gen_union_clone(fb_output_t *out, fb_compound_type_t *ct)
   1973 {
   1974     const char *nsc = out->nsc;
   1975     fb_member_t *member;
   1976     fb_symbol_t *sym;
   1977     const char *s;
   1978     int n;
   1979     fb_scoped_name_t snt;
   1980     fb_scoped_name_t snref;
   1981 
   1982     fb_clear(snt);
   1983     fb_clear(snref);
   1984     fb_compound_name(ct, &snt);
   1985 
   1986     fprintf(out->fp,
   1987             "static %s_union_ref_t %s_clone(%sbuilder_t *B, %s_union_t u)\n{\n    switch (u.type) {\n",
   1988             snt.text, snt.text, nsc, snt.text);
   1989 
   1990     for (sym = ct->members; sym; sym = sym->link) {
   1991         member = (fb_member_t *)sym;
   1992         switch (member->type.type) {
   1993         case vt_compound_type_ref:
   1994             fb_compound_name((fb_compound_type_t *)member->type.ct, &snref);
   1995             symbol_name(sym, &n, &s);
   1996             switch (member->type.ct->symbol.kind) {
   1997             case fb_is_table:
   1998                 fprintf(out->fp,
   1999                     "    case %u: return %s_as_%.*s(%s_clone(B, (%s_table_t)u.value));\n",
   2000                     (unsigned)member->value.u, snt.text, n, s, snref.text, snref.text);
   2001                 break;
   2002             case fb_is_struct:
   2003                 fprintf(out->fp,
   2004                     "    case %u: return %s_as_%.*s(%s_clone(B, (%s_struct_t)u.value));\n",
   2005                     (unsigned)member->value.u, snt.text, n, s, snref.text, snref.text);
   2006                 break;
   2007             default:
   2008                 gen_panic(out, "internal error: unexpected union value type");
   2009                 break;
   2010             }
   2011             break;
   2012         case vt_string_type:
   2013             symbol_name(sym, &n, &s);
   2014             fprintf(out->fp,
   2015                 "    case %u: return %s_as_%.*s(%sstring_clone(B, u.value));\n",
   2016                 (unsigned)member->value.u, snt.text, n, s, nsc);
   2017             break;
   2018         case vt_missing:
   2019             break;
   2020         default:
   2021             gen_panic(out, "internal error: unexpected union value type");
   2022             break;
   2023         }
   2024     }
   2025 
   2026     /* Unknown unions are dropped. */
   2027     fprintf(out->fp,
   2028             "    default: return %s_as_NONE();\n"
   2029             "    }\n}\n",
   2030             snt.text);
   2031     return 0;
   2032 }
   2033 
   2034 
   2035 static int gen_builder_union_decls(fb_output_t *out)
   2036 {
   2037     const char *nsc = out->nsc;
   2038     fb_symbol_t *sym;
   2039     int was_here = 0;
   2040     fb_scoped_name_t snt;
   2041 
   2042     fb_clear(snt);
   2043 
   2044     for (sym = out->S->symbols; sym; sym = sym->link) {
   2045         switch (sym->kind) {
   2046         case fb_is_union:
   2047             fb_compound_name((fb_compound_type_t *)sym, &snt);
   2048             fprintf(out->fp,
   2049                 "typedef %sunion_ref_t %s_union_ref_t;\n"
   2050                 "typedef %sunion_vec_ref_t %s_union_vec_ref_t;\n",
   2051                 nsc, snt.text, nsc, snt.text);
   2052             fprintf(out->fp,
   2053                 "static %s_union_ref_t %s_clone(%sbuilder_t *B, %s_union_t t);\n",
   2054                 snt.text, snt.text, nsc, snt.text);
   2055             was_here = 1;
   2056             break;
   2057         default:
   2058             continue;
   2059         }
   2060     }
   2061     if (was_here) {
   2062         fprintf(out->fp, "\n");
   2063     }
   2064     return 0;
   2065 }
   2066 
   2067 static int gen_builder_unions(fb_output_t *out)
   2068 {
   2069     fb_symbol_t *sym;
   2070 
   2071     for (sym = out->S->symbols; sym; sym = sym->link) {
   2072         switch (sym->kind) {
   2073         case fb_is_union:
   2074             gen_union(out, (fb_compound_type_t *)sym);
   2075             gen_union_clone(out, (fb_compound_type_t *)sym);
   2076             fprintf(out->fp, "\n");
   2077             break;
   2078         default:
   2079             continue;
   2080         }
   2081     }
   2082     return 0;
   2083 }
   2084 
   2085 static int gen_builder_table_decls(fb_output_t *out)
   2086 {
   2087     fb_symbol_t *sym;
   2088 
   2089     /*
   2090      * Because tables are recursive, we need the type and `start/end/add`
   2091      * operations before the fields. We also need create for push_create
   2092      * but it needs all dependent types, so create is fw declared
   2093      * in a subsequent step. The actual create impl. then follows
   2094      * after the table fields.
   2095      */
   2096     for (sym = out->S->symbols; sym; sym = sym->link) {
   2097         switch (sym->kind) {
   2098         case fb_is_table:
   2099             gen_required_table_fields(out, (fb_compound_type_t *)sym);
   2100             gen_builder_table(out, (fb_compound_type_t *)sym);
   2101             fprintf(out->fp, "\n");
   2102             break;
   2103         default:
   2104             continue;
   2105         }
   2106     }
   2107     for (sym = out->S->symbols; sym; sym = sym->link) {
   2108         switch (sym->kind) {
   2109         case fb_is_table:
   2110             gen_builder_create_table_decl(out, (fb_compound_type_t *)sym);
   2111             gen_builder_table_prolog(out, (fb_compound_type_t *)sym);
   2112             fprintf(out->fp, "\n");
   2113             break;
   2114         default:
   2115             continue;
   2116         }
   2117     }
   2118     return 0;
   2119 }
   2120 
   2121 static int gen_builder_tables(fb_output_t *out)
   2122 {
   2123     fb_symbol_t *sym;
   2124     for (sym = out->S->symbols; sym; sym = sym->link) {
   2125         switch (sym->kind) {
   2126         case fb_is_table:
   2127             gen_builder_table_fields(out, (fb_compound_type_t *)sym);
   2128             gen_builder_create_table(out, (fb_compound_type_t *)sym);
   2129             gen_builder_clone_table(out, (fb_compound_type_t *)sym);
   2130             fprintf(out->fp, "\n");
   2131             break;
   2132         default:
   2133             continue;
   2134         }
   2135     }
   2136     return 0;
   2137 }
   2138 
   2139 static int gen_builder_footer(fb_output_t *out)
   2140 {
   2141     gen_epilogue(out);
   2142     fprintf(out->fp,
   2143         "#endif /* %s_BUILDER_H */\n",
   2144         out->S->basenameup);
   2145     return 0;
   2146 }
   2147 
   2148 int fb_gen_c_builder(fb_output_t *out)
   2149 {
   2150     gen_builder_pretext(out);
   2151     gen_builder_enums(out);
   2152     gen_builder_structs(out);
   2153     gen_builder_union_decls(out);
   2154     gen_builder_table_decls(out);
   2155     gen_builder_unions(out);
   2156     gen_builder_tables(out);
   2157     gen_builder_footer(out);
   2158     return 0;
   2159 }