diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2023-07-16 02:03:33 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2023-07-16 02:03:33 +0200 |
commit | 5a40295c4cf0af5ea8da9ced04a4ce7d3621a080 (patch) | |
tree | cb21506e7b04d10b45d6066a0ee1655563d5d52b /src/compiler/codegen_c_builder.c |
Squashed 'flatcc/' content from commit 473da2a
git-subtree-dir: flatcc
git-subtree-split: 473da2afa5ca435363f8c5e6569167aee6bc31c5
Diffstat (limited to 'src/compiler/codegen_c_builder.c')
-rw-r--r-- | src/compiler/codegen_c_builder.c | 2159 |
1 files changed, 2159 insertions, 0 deletions
diff --git a/src/compiler/codegen_c_builder.c b/src/compiler/codegen_c_builder.c new file mode 100644 index 0000000..ffa105d --- /dev/null +++ b/src/compiler/codegen_c_builder.c @@ -0,0 +1,2159 @@ +#include <string.h> + +#include "codegen_c.h" + +int fb_gen_common_c_builder_header(fb_output_t *out) +{ + const char *nsc = out->nsc; + const char *nscup = out->nscup; + + fprintf(out->fp, "#ifndef %s_COMMON_BUILDER_H\n", nscup); + fprintf(out->fp, "#define %s_COMMON_BUILDER_H\n", nscup); + fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n"); + fprintf(out->fp, "/* Common FlatBuffers build functionality for C. */\n\n"); + gen_prologue(out); + + fprintf(out->fp, "#ifndef FLATBUILDER_H\n"); + fprintf(out->fp, "#include \"flatcc/flatcc_builder.h\"\n"); + fprintf(out->fp, "#endif\n"); + if (strcmp(nsc, "flatcc_builder_")) { + fprintf(out->fp, "typedef flatcc_builder_t %sbuilder_t;\n", nsc); + fprintf(out->fp, "typedef flatcc_builder_ref_t %sref_t;\n", nsc); + fprintf(out->fp, "typedef flatcc_builder_ref_t %svec_ref_t;\n", nsc); + fprintf(out->fp, "typedef flatcc_builder_union_ref_t %sunion_ref_t;\n", nsc); + fprintf(out->fp, "typedef flatcc_builder_union_vec_ref_t %sunion_vec_ref_t;\n", nsc); + fprintf(out->fp, "/* integer return code (ref and ptr always fail on 0) */\n" + "#define %sfailed(x) ((x) < 0)\n", nsc); + } + fprintf(out->fp, "typedef %sref_t %sroot_t;\n", nsc, nsc); + fprintf(out->fp, "#define %sroot(ref) ((%sroot_t)(ref))\n", nsc, nsc); + if (strcmp(nsc, "flatbuffers_")) { + fprintf(out->fp, "#define %sis_native_pe flatbuffers_is_native_pe\n", nsc); + fprintf(out->fp, "typedef flatbuffers_fid_t %sfid_t;\n", nsc); + } + fprintf(out->fp, "\n"); + + fprintf(out->fp, + "#define __%smemoize_begin(B, src)\\\n" + "do { flatcc_builder_ref_t _ref; if ((_ref = flatcc_builder_refmap_find((B), (src)))) return _ref; } while (0)\n" + "#define __%smemoize_end(B, src, op) do { return flatcc_builder_refmap_insert((B), (src), (op)); } while (0)\n" + "#define __%smemoize(B, src, op) do { __%smemoize_begin(B, src); __%smemoize_end(B, src, op); } while (0)\n" + "\n", + nsc, nsc, nsc, nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_buffer(NS)\\\n" + "typedef NS ## ref_t NS ## buffer_ref_t;\\\n" + "static inline int NS ## buffer_start(NS ## builder_t *B, const NS ##fid_t fid)\\\n" + "{ return flatcc_builder_start_buffer(B, fid, 0, 0); }\\\n" + "static inline int NS ## buffer_start_with_size(NS ## builder_t *B, const NS ##fid_t fid)\\\n" + "{ return flatcc_builder_start_buffer(B, fid, 0, flatcc_builder_with_size); }\\\n" + "static inline int NS ## buffer_start_aligned(NS ## builder_t *B, NS ##fid_t fid, uint16_t block_align)\\\n" + "{ return flatcc_builder_start_buffer(B, fid, block_align, 0); }\\\n" + "static inline int NS ## buffer_start_aligned_with_size(NS ## builder_t *B, NS ##fid_t fid, uint16_t block_align)\\\n" + "{ return flatcc_builder_start_buffer(B, fid, block_align, flatcc_builder_with_size); }\\\n" + "static inline NS ## buffer_ref_t NS ## buffer_end(NS ## builder_t *B, NS ## ref_t root)\\\n" + "{ return flatcc_builder_end_buffer(B, root); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_table_root(NS, N, FID, TFID)\\\n" + "static inline int N ## _start_as_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, FID) ? -1 : N ## _start(B); }\\\n" + "static inline int N ## _start_as_root_with_size(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start_with_size(B, FID) ? -1 : N ## _start(B); }\\\n" + "static inline int N ## _start_as_typed_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, TFID) ? -1 : N ## _start(B); }\\\n" + "static inline int N ## _start_as_typed_root_with_size(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start_with_size(B, TFID) ? -1 : N ## _start(B); }\\\n" + "static inline NS ## buffer_ref_t N ## _end_as_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n" + "static inline NS ## buffer_ref_t N ## _end_as_typed_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n" + /* + * Unlike structs, we do no use flatcc_builder_create_buffer + * because we would have to manage alignment, and we save very + * little because tables require stack allocations in any case. + */ + "static inline NS ## buffer_ref_t N ## _create_as_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ if (NS ## buffer_start(B, FID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n" + "static inline NS ## buffer_ref_t N ## _create_as_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ if (NS ## buffer_start_with_size(B, FID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n" + "static inline NS ## buffer_ref_t N ## _create_as_typed_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ if (NS ## buffer_start(B, TFID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n" + "static inline NS ## buffer_ref_t N ## _create_as_typed_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ if (NS ## buffer_start_with_size(B, TFID)) return 0; return NS ## buffer_end(B, N ## _create(B __ ## N ## _call_args)); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_root(NS ## builder_t *B, N ## _table_t t)\\\n" + "{ if (NS ## buffer_start(B, FID)) return 0; return NS ## buffer_end(B, N ## _clone(B, t)); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_root_with_size(NS ## builder_t *B, N ## _table_t t)\\\n" + "{ if (NS ## buffer_start_with_size(B, FID)) return 0; return NS ## buffer_end(B, N ## _clone(B, t)); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_typed_root(NS ## builder_t *B, N ## _table_t t)\\\n" + "{ if (NS ## buffer_start(B, TFID)) return 0;return NS ## buffer_end(B, N ## _clone(B, t)); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_typed_root_with_size(NS ## builder_t *B, N ## _table_t t)\\\n" + "{ if (NS ## buffer_start_with_size(B, TFID)) return 0; return NS ## buffer_end(B, N ## _clone(B, t)); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_table_prolog(NS, N, FID, TFID)\\\n" + "__%sbuild_table_vector_ops(NS, N ## _vec, N)\\\n" + "__%sbuild_table_root(NS, N, FID, TFID)\n" + "\n", + nsc, nsc, nsc); + + + fprintf(out->fp, + "#define __%sbuild_struct_root(NS, N, A, FID, TFID)\\\n" + "static inline N ## _t *N ## _start_as_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, FID) ? 0 : N ## _start(B); }\\\n" + "static inline N ## _t *N ## _start_as_root_with_size(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start_with_size(B, FID) ? 0 : N ## _start(B); }\\\n" + "static inline N ## _t *N ## _start_as_typed_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, TFID) ? 0 : N ## _start(B); }\\\n" + "static inline N ## _t *N ## _start_as_typed_root_with_size(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start_with_size(B, TFID) ? 0 : N ## _start(B); }\\\n" + "static inline NS ## buffer_ref_t N ## _end_as_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n" + "static inline NS ## buffer_ref_t N ## _end_as_typed_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_end(B, N ## _end(B)); }\\\n" + "static inline NS ## buffer_ref_t N ## _end_pe_as_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_end(B, N ## _end_pe(B)); }\\\n" + "static inline NS ## buffer_ref_t N ## _end_pe_as_typed_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_end(B, N ## _end_pe(B)); }\\\n" + "static inline NS ## buffer_ref_t N ## _create_as_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ return flatcc_builder_create_buffer(B, FID, 0,\\\n" + " N ## _create(B __ ## N ## _call_args), A, 0); }\\\n" + "static inline NS ## buffer_ref_t N ## _create_as_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ return flatcc_builder_create_buffer(B, FID, 0,\\\n" + " N ## _create(B __ ## N ## _call_args), A, flatcc_builder_with_size); }\\\n" + "static inline NS ## buffer_ref_t N ## _create_as_typed_root(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ return flatcc_builder_create_buffer(B, TFID, 0,\\\n" + " N ## _create(B __ ## N ## _call_args), A, 0); }\\\n" + "static inline NS ## buffer_ref_t N ## _create_as_typed_root_with_size(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ return flatcc_builder_create_buffer(B, TFID, 0,\\\n" + " N ## _create(B __ ## N ## _call_args), A, flatcc_builder_with_size); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_root(NS ## builder_t *B, N ## _struct_t p)\\\n" + "{ return flatcc_builder_create_buffer(B, FID, 0, N ## _clone(B, p), A, 0); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_root_with_size(NS ## builder_t *B, N ## _struct_t p)\\\n" + "{ return flatcc_builder_create_buffer(B, FID, 0, N ## _clone(B, p), A, flatcc_builder_with_size); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_typed_root(NS ## builder_t *B, N ## _struct_t p)\\\n" + "{ return flatcc_builder_create_buffer(B, TFID, 0, N ## _clone(B, p), A, 0); }\\\n" + "static inline NS ## buffer_ref_t N ## _clone_as_typed_root_with_size(NS ## builder_t *B, N ## _struct_t p)\\\n" + "{ return flatcc_builder_create_buffer(B, TFID, 0, N ## _clone(B, p), A, flatcc_builder_with_size); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_nested_table_root(NS, N, TN, FID, TFID)\\\n" + "static inline int N ## _start_as_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, FID) ? -1 : TN ## _start(B); }\\\n" + "static inline int N ## _start_as_typed_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, TFID) ? -1 : TN ## _start(B); }\\\n" + "static inline int N ## _end_as_root(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n" + "static inline int N ## _end_as_typed_root(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n" + "static inline int N ## _nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n" + "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n" + " align ? align : 8, FLATBUFFERS_COUNT_MAX(1))); }\\\n" + "static inline int N ## _typed_nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n" + "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n" + " align ? align : 8, FLATBUFFERS_COUNT_MAX(1))); }\\\n" + "static inline int N ## _clone_as_root(NS ## builder_t *B, TN ## _table_t t)\\\n" + "{ return N ## _add(B, TN ## _clone_as_root(B, t)); }\\\n" + "static inline int N ## _clone_as_typed_root(NS ## builder_t *B, TN ## _table_t t)\\\n" + "{ return N ## _add(B, TN ## _clone_as_typed_root(B, t)); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_nested_struct_root(NS, N, TN, A, FID, TFID)\\\n" + "static inline TN ## _t *N ## _start_as_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, FID) ? 0 : TN ## _start(B); }\\\n" + "static inline TN ## _t *N ## _start_as_typed_root(NS ## builder_t *B)\\\n" + "{ return NS ## buffer_start(B, FID) ? 0 : TN ## _start(B); }\\\n" + "static inline int N ## _end_as_root(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n" + "static inline int N ## _end_as_typed_root(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end(B))); }\\\n" + "static inline int N ## _end_pe_as_root(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, NS ## buffer_end(B, TN ## _end_pe(B))); }\\\n" + "static inline int N ## _create_as_root(NS ## builder_t *B __ ## TN ## _formal_args)\\\n" + "{ return N ## _add(B, flatcc_builder_create_buffer(B, FID, 0,\\\n" + " TN ## _create(B __ ## TN ## _call_args), A, flatcc_builder_is_nested)); }\\\n" + "static inline int N ## _create_as_typed_root(NS ## builder_t *B __ ## TN ## _formal_args)\\\n" + "{ return N ## _add(B, flatcc_builder_create_buffer(B, TFID, 0,\\\n" + " TN ## _create(B __ ## TN ## _call_args), A, flatcc_builder_is_nested)); }\\\n" + "static inline int N ## _nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n" + "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n" + " align < A ? A : align, FLATBUFFERS_COUNT_MAX(1))); }\\\n" + "static inline int N ## _typed_nest(NS ## builder_t *B, void *data, size_t size, uint16_t align)\\\n" + "{ return N ## _add(B, flatcc_builder_create_vector(B, data, size, 1,\\\n" + " align < A ? A : align, FLATBUFFERS_COUNT_MAX(1))); }\\\n" + "static inline int N ## _clone_as_root(NS ## builder_t *B, TN ## _struct_t p)\\\n" + "{ return N ## _add(B, TN ## _clone_as_root(B, p)); }\\\n" + "static inline int N ## _clone_as_typed_root(NS ## builder_t *B, TN ## _struct_t p)\\\n" + "{ return N ## _add(B, TN ## _clone_as_typed_root(B, p)); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_vector_ops(NS, V, N, TN, T)\\\n" + "static inline T *V ## _extend(NS ## builder_t *B, size_t len)\\\n" + "{ return (T *)flatcc_builder_extend_vector(B, len); }\\\n" + "static inline T *V ## _append(NS ## builder_t *B, const T *data, size_t len)\\\n" + "{ return (T *)flatcc_builder_append_vector(B, data, len); }\\\n" + "static inline int V ## _truncate(NS ## builder_t *B, size_t len)\\\n" + "{ return flatcc_builder_truncate_vector(B, len); }\\\n" + "static inline T *V ## _edit(NS ## builder_t *B)\\\n" + "{ return (T *)flatcc_builder_vector_edit(B); }\\\n" + "static inline size_t V ## _reserved_len(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_vector_count(B); }\\\n" + "static inline T *V ## _push(NS ## builder_t *B, const T *p)\\\n" + "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? (memcpy(_p, p, TN ## __size()), _p) : 0; }\\\n" + "static inline T *V ## _push_copy(NS ## builder_t *B, const T *p)\\\n" + "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? TN ## _copy(_p, p) : 0; }\\\n" + /* push_clone is the same as a for push_copy for scalar and struct vectors + * but copy has different semantics as a standalone operation so we can't use + * clone to implement push_clone - it would create a reference to a struct. */ + "static inline T *V ## _push_clone(NS ## builder_t *B, const T *p)\\\n" + "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? TN ## _copy(_p, p) : 0; }\\\n" + "static inline T *V ## _push_create(NS ## builder_t *B __ ## TN ## _formal_args)\\\n" + "{ T *_p; return (_p = (T *)flatcc_builder_extend_vector(B, 1)) ? TN ## _assign(_p __ ## TN ## _call_args) : 0; }\n" + "\n", + nsc); + + fprintf(out->fp, + /* NS: common namespace, N: typename, T: element type, S: elem size, A: alignment */ + "#define __%sbuild_vector(NS, N, T, S, A)\\\n" + "typedef NS ## ref_t N ## _vec_ref_t;\\\n" + "static inline int N ## _vec_start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_vector(B, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_end_pe(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_end_vector(B); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_end(NS ## builder_t *B)\\\n" + "{ if (!NS ## is_native_pe()) { size_t i, n; T *p = (T *)flatcc_builder_vector_edit(B);\\\n" + " for (i = 0, n = flatcc_builder_vector_count(B); i < n; ++i)\\\n" + " { N ## _to_pe(N ## __ptr_add(p, i)); }} return flatcc_builder_end_vector(B); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_create_pe(NS ## builder_t *B, const T *data, size_t len)\\\n" + "{ return flatcc_builder_create_vector(B, data, len, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_create(NS ## builder_t *B, const T *data, size_t len)\\\n" + "{ 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" + " p = (T *)flatcc_builder_extend_vector(B, len); if (!p) return 0;\\\n" + " for (i = 0; i < len; ++i) { N ## _copy_to_pe(N ## __ptr_add(p, i), N ## __const_ptr_add(data, i)); }\\\n" + " return flatcc_builder_end_vector(B); } else return flatcc_builder_create_vector(B, data, len, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_clone(NS ## builder_t *B, N ##_vec_t vec)\\\n" + "{ __%smemoize(B, vec, flatcc_builder_create_vector(B, vec, N ## _vec_len(vec), S, A, FLATBUFFERS_COUNT_MAX(S))); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_slice(NS ## builder_t *B, N ##_vec_t vec, size_t index, size_t len)\\\n" + "{ size_t n = N ## _vec_len(vec); if (index >= n) index = n; n -= index; if (len > n) len = n;\\\n" + " return flatcc_builder_create_vector(B, N ## __const_ptr_add(vec, index), len, S, A, FLATBUFFERS_COUNT_MAX(S)); }\\\n" + "__%sbuild_vector_ops(NS, N ## _vec, N, N, T)\n" + "\n", + nsc, nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_union_vector_ops(NS, V, N, TN)\\\n" + "static inline TN ## _union_ref_t *V ## _extend(NS ## builder_t *B, size_t len)\\\n" + "{ return flatcc_builder_extend_union_vector(B, len); }\\\n" + "static inline TN ## _union_ref_t *V ## _append(NS ## builder_t *B, const TN ## _union_ref_t *data, size_t len)\\\n" + "{ return flatcc_builder_append_union_vector(B, data, len); }\\\n" + "static inline int V ## _truncate(NS ## builder_t *B, size_t len)\\\n" + "{ return flatcc_builder_truncate_union_vector(B, len); }\\\n" + "static inline TN ## _union_ref_t *V ## _edit(NS ## builder_t *B)\\\n" + "{ return (TN ## _union_ref_t *) flatcc_builder_union_vector_edit(B); }\\\n" + "static inline size_t V ## _reserved_len(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_union_vector_count(B); }\\\n" + "static inline TN ## _union_ref_t *V ## _push(NS ## builder_t *B, const TN ## _union_ref_t ref)\\\n" + "{ return flatcc_builder_union_vector_push(B, ref); }\\\n" + "static inline TN ## _union_ref_t *V ## _push_clone(NS ## builder_t *B, TN ## _union_t u)\\\n" + "{ return TN ## _vec_push(B, TN ## _clone(B, u)); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_union_vector(NS, N)\\\n" + "static inline int N ## _vec_start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_union_vector(B); }\\\n" + "static inline N ## _union_vec_ref_t N ## _vec_end(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_end_union_vector(B); }\\\n" + "static inline N ## _union_vec_ref_t N ## _vec_create(NS ## builder_t *B, const N ## _union_ref_t *data, size_t len)\\\n" + "{ return flatcc_builder_create_union_vector(B, data, len); }\\\n" + "__%sbuild_union_vector_ops(NS, N ## _vec, N, N)\\\n" + "/* Preserves DAG structure separately for type and value vector, so a type vector could be shared for many value vectors. */\\\n" + "static inline N ## _union_vec_ref_t N ## _vec_clone(NS ## builder_t *B, N ##_union_vec_t vec)\\\n" + "{ N ## _union_vec_ref_t _uvref, _ret = { 0, 0 }; NS ## union_ref_t _uref; size_t _i, _len;\\\n" + " if (vec.type == 0) return _ret;\\\n" + " _uvref.type = flatcc_builder_refmap_find(B, vec.type); _uvref.value = flatcc_builder_refmap_find(B, vec.value);\\\n" + " _len = N ## _union_vec_len(vec); if (_uvref.type == 0) {\\\n" + " _uvref.type = flatcc_builder_refmap_insert(B, vec.type, (flatcc_builder_create_type_vector(B, vec.type, _len))); }\\\n" + " if (_uvref.type == 0) return _ret; if (_uvref.value == 0) {\\\n" + " if (flatcc_builder_start_offset_vector(B)) return _ret;\\\n" + " for (_i = 0; _i < _len; ++_i) { _uref = N ## _clone(B, N ## _union_vec_at(vec, _i));\\\n" + " if (!_uref.value || !(flatcc_builder_offset_vector_push(B, _uref.value))) return _ret; }\\\n" + " _uvref.value = flatcc_builder_refmap_insert(B, vec.value, flatcc_builder_end_offset_vector(B));\\\n" + " if (_uvref.value == 0) return _ret; } return _uvref; }\n" + "\n", + nsc, nsc); + + /* In addtion to offset_vector_ops... */ + fprintf(out->fp, + "#define __%sbuild_string_vector_ops(NS, N)\\\n" + "static inline int N ## _push_start(NS ## builder_t *B)\\\n" + "{ return NS ## string_start(B); }\\\n" + "static inline NS ## string_ref_t *N ## _push_end(NS ## builder_t *B)\\\n" + "{ return NS ## string_vec_push(B, NS ## string_end(B)); }\\\n" + "static inline NS ## string_ref_t *N ## _push_create(NS ## builder_t *B, const char *s, size_t len)\\\n" + "{ return NS ## string_vec_push(B, NS ## string_create(B, s, len)); }\\\n" + "static inline NS ## string_ref_t *N ## _push_create_str(NS ## builder_t *B, const char *s)\\\n" + "{ return NS ## string_vec_push(B, NS ## string_create_str(B, s)); }\\\n" + "static inline NS ## string_ref_t *N ## _push_create_strn(NS ## builder_t *B, const char *s, size_t max_len)\\\n" + "{ return NS ## string_vec_push(B, NS ## string_create_strn(B, s, max_len)); }\\\n" + "static inline NS ## string_ref_t *N ## _push_clone(NS ## builder_t *B, NS ## string_t string)\\\n" + "{ return NS ## string_vec_push(B, NS ## string_clone(B, string)); }\\\n" + "static inline NS ## string_ref_t *N ## _push_slice(NS ## builder_t *B, NS ## string_t string, size_t index, size_t len)\\\n" + "{ return NS ## string_vec_push(B, NS ## string_slice(B, string, index, len)); }\n" + "\n", + nsc); + + /* In addtion to offset_vector_ops... */ + fprintf(out->fp, + "#define __%sbuild_table_vector_ops(NS, N, TN)\\\n" + "static inline int N ## _push_start(NS ## builder_t *B)\\\n" + "{ return TN ## _start(B); }\\\n" + "static inline TN ## _ref_t *N ## _push_end(NS ## builder_t *B)\\\n" + "{ return N ## _push(B, TN ## _end(B)); }\\\n" + "static inline TN ## _ref_t *N ## _push_create(NS ## builder_t *B __ ## TN ##_formal_args)\\\n" + "{ return N ## _push(B, TN ## _create(B __ ## TN ## _call_args)); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_offset_vector_ops(NS, V, N, TN)\\\n" + "static inline TN ## _ref_t *V ## _extend(NS ## builder_t *B, size_t len)\\\n" + "{ return flatcc_builder_extend_offset_vector(B, len); }\\\n" + "static inline TN ## _ref_t *V ## _append(NS ## builder_t *B, const TN ## _ref_t *data, size_t len)\\\n" + "{ return flatcc_builder_append_offset_vector(B, data, len); }\\\n" + "static inline int V ## _truncate(NS ## builder_t *B, size_t len)\\\n" + "{ return flatcc_builder_truncate_offset_vector(B, len); }\\\n" + "static inline TN ## _ref_t *V ## _edit(NS ## builder_t *B)\\\n" + "{ return (TN ## _ref_t *)flatcc_builder_offset_vector_edit(B); }\\\n" + "static inline size_t V ## _reserved_len(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_offset_vector_count(B); }\\\n" + "static inline TN ## _ref_t *V ## _push(NS ## builder_t *B, const TN ## _ref_t ref)\\\n" + "{ return ref ? flatcc_builder_offset_vector_push(B, ref) : 0; }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_offset_vector(NS, N)\\\n" + "typedef NS ## ref_t N ## _vec_ref_t;\\\n" + "static inline int N ## _vec_start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_offset_vector(B); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_end(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_end_offset_vector(B); }\\\n" + "static inline N ## _vec_ref_t N ## _vec_create(NS ## builder_t *B, const N ## _ref_t *data, size_t len)\\\n" + "{ return flatcc_builder_create_offset_vector(B, data, len); }\\\n" + "__%sbuild_offset_vector_ops(NS, N ## _vec, N, N)\\\n" + "static inline N ## _vec_ref_t N ## _vec_clone(NS ## builder_t *B, N ##_vec_t vec)\\\n" + "{ int _ret; N ## _ref_t _e; size_t _i, _len; __%smemoize_begin(B, vec);\\\n" + " _len = N ## _vec_len(vec); if (flatcc_builder_start_offset_vector(B)) return 0;\\\n" + " for (_i = 0; _i < _len; ++_i) { if (!(_e = N ## _clone(B, N ## _vec_at(vec, _i)))) return 0;\\\n" + " if (!flatcc_builder_offset_vector_push(B, _e)) return 0; }\\\n" + " __%smemoize_end(B, vec, flatcc_builder_end_offset_vector(B)); }\\\n" + "\n", + nsc, nsc, nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_string_ops(NS, N)\\\n" + "static inline char *N ## _append(NS ## builder_t *B, const char *s, size_t len)\\\n" + "{ return flatcc_builder_append_string(B, s, len); }\\\n" + "static inline char *N ## _append_str(NS ## builder_t *B, const char *s)\\\n" + "{ return flatcc_builder_append_string_str(B, s); }\\\n" + "static inline char *N ## _append_strn(NS ## builder_t *B, const char *s, size_t len)\\\n" + "{ return flatcc_builder_append_string_strn(B, s, len); }\\\n" + "static inline size_t N ## _reserved_len(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_string_len(B); }\\\n" + "static inline char *N ## _extend(NS ## builder_t *B, size_t len)\\\n" + "{ return flatcc_builder_extend_string(B, len); }\\\n" + "static inline char *N ## _edit(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_string_edit(B); }\\\n" + "static inline int N ## _truncate(NS ## builder_t *B, size_t len)\\\n" + "{ return flatcc_builder_truncate_string(B, len); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_string(NS)\\\n" + "typedef NS ## ref_t NS ## string_ref_t;\\\n" + "static inline int NS ## string_start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_string(B); }\\\n" + "static inline NS ## string_ref_t NS ## string_end(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_end_string(B); }\\\n" + "static inline NS ## ref_t NS ## string_create(NS ## builder_t *B, const char *s, size_t len)\\\n" + "{ return flatcc_builder_create_string(B, s, len); }\\\n" + "static inline NS ## ref_t NS ## string_create_str(NS ## builder_t *B, const char *s)\\\n" + "{ return flatcc_builder_create_string_str(B, s); }\\\n" + "static inline NS ## ref_t NS ## string_create_strn(NS ## builder_t *B, const char *s, size_t len)\\\n" + "{ return flatcc_builder_create_string_strn(B, s, len); }\\\n" + "static inline NS ## string_ref_t NS ## string_clone(NS ## builder_t *B, NS ## string_t string)\\\n" + "{ __%smemoize(B, string, flatcc_builder_create_string(B, string, NS ## string_len(string))); }\\\n" + "static inline NS ## string_ref_t NS ## string_slice(NS ## builder_t *B, NS ## string_t string, size_t index, size_t len)\\\n" + "{ size_t n = NS ## string_len(string); if (index >= n) index = n; n -= index; if (len > n) len = n;\\\n" + " return flatcc_builder_create_string(B, string + index, len); }\\\n" + "__%sbuild_string_ops(NS, NS ## string)\\\n" + "__%sbuild_offset_vector(NS, NS ## string)\n" + "\n", + nsc, nsc, nsc, nsc); + fprintf(out->fp, + "#define __%scopy_from_pe(P, P2, N) (*(P) = N ## _read_from_pe(P2), (P))\n" + "#define __%sfrom_pe(P, N) (*(P) = N ## _read_from_pe(P), (P))\n" + "#define __%scopy_to_pe(P, P2, N) (N ## _write_to_pe((P), *(P2)), (P))\n" + "#define __%sto_pe(P, N) (N ## _write_to_pe((P), *(P)), (P))\n", + nsc, nsc, nsc, nsc); + fprintf(out->fp, + "#define __%sdefine_fixed_array_primitives(NS, N, T)\\\n" + "static inline T *N ## _array_copy(T *p, const T *p2, size_t n)\\\n" + "{ memcpy(p, p2, n * sizeof(T)); return p; }\\\n" + "static inline T *N ## _array_copy_from_pe(T *p, const T *p2, size_t n)\\\n" + "{ size_t i; if (NS ## is_native_pe()) memcpy(p, p2, n * sizeof(T)); else\\\n" + " for (i = 0; i < n; ++i) N ## _copy_from_pe(&p[i], &p2[i]); return p; }\\\n" + "static inline T *N ## _array_copy_to_pe(T *p, const T *p2, size_t n)\\\n" + "{ size_t i; if (NS ## is_native_pe()) memcpy(p, p2, n * sizeof(T)); else\\\n" + " for (i = 0; i < n; ++i) N ## _copy_to_pe(&p[i], &p2[i]); return p; }\n", + nsc); + fprintf(out->fp, + "#define __%sdefine_scalar_primitives(NS, N, T)\\\n" + "static inline T *N ## _from_pe(T *p) { return __ ## NS ## from_pe(p, N); }\\\n" + "static inline T *N ## _to_pe(T *p) { return __ ## NS ## to_pe(p, N); }\\\n" + "static inline T *N ## _copy(T *p, const T *p2) { *p = *p2; return p; }\\\n" + "static inline T *N ## _copy_from_pe(T *p, const T *p2)\\\n" + "{ return __ ## NS ## copy_from_pe(p, p2, N); }\\\n" + "static inline T *N ## _copy_to_pe(T *p, const T *p2) \\\n" + "{ return __ ## NS ## copy_to_pe(p, p2, N); }\\\n" + "static inline T *N ## _assign(T *p, const T v0) { *p = v0; return p; }\\\n" + "static inline T *N ## _assign_from_pe(T *p, T v0)\\\n" + "{ *p = N ## _read_from_pe(&v0); return p; }\\\n" + "static inline T *N ## _assign_to_pe(T *p, T v0)\\\n" + "{ N ## _write_to_pe(p, v0); return p; }\n" + "#define __%sbuild_scalar(NS, N, T)\\\n" + "__ ## NS ## define_scalar_primitives(NS, N, T)\\\n" + "__ ## NS ## define_fixed_array_primitives(NS, N, T)\\\n" + "__ ## NS ## build_vector(NS, N, T, sizeof(T), sizeof(T))\n", + nsc, nsc); + + fprintf(out->fp, + "/* Depends on generated copy_to/from_pe functions, and the type. */\n" + "#define __%sdefine_struct_primitives(NS, N)\\\n" + "static inline N ## _t *N ##_to_pe(N ## _t *p)\\\n" + "{ if (!NS ## is_native_pe()) { N ## _copy_to_pe(p, p); }; return p; }\\\n" + "static inline N ## _t *N ##_from_pe(N ## _t *p)\\\n" + "{ if (!NS ## is_native_pe()) { N ## _copy_from_pe(p, p); }; return p; }\\\n" + "static inline N ## _t *N ## _clear(N ## _t *p) { return (N ## _t *)memset(p, 0, N ## __size()); }\n" + "\n" + + /* + * NOTE: structs can both be inline and independent blocks. They + * are independent as buffer roots, and also as union members. + * _clone applied to a struct type name creates a reference to + * an independent block, but this is ambigous. Structs also + * support _copy which is the inline equivalent of _clone for + * inline. There is also the distinction between _clone applied + * to a field name, clone applied to a type name, and _clone + * applied to a _vec_push operation. For field names and push + * operations, _clone is unambigiously inline and similar to + * _copy. So the ambigiouty is when applying _clone to a type + * name where _copy and _clone are different. Unions can safely + * implement clone on structs members via _clone because union + * members are indendendent blocks whereas push_clone must be + * implemented with _copy because structs are inline in + * (non-union) vectors. Structs in union-vectors are independent + * but these simply the unions clone operation (which is a + * generated function). + */ + "/* Depends on generated copy/assign_to/from_pe functions, and the type. */\n" + "#define __%sbuild_struct(NS, N, S, A, FID, TFID)\\\n" + "__ ## NS ## define_struct_primitives(NS, N)\\\n" + "typedef NS ## ref_t N ## _ref_t;\\\n" + "static inline N ## _t *N ## _start(NS ## builder_t *B)\\\n" + "{ return (N ## _t *)flatcc_builder_start_struct(B, S, A); }\\\n" + "static inline N ## _ref_t N ## _end(NS ## builder_t *B)\\\n" + "{ if (!NS ## is_native_pe()) { N ## _to_pe((N ## _t *)flatcc_builder_struct_edit(B)); }\\\n" + " return flatcc_builder_end_struct(B); }\\\n" + "static inline N ## _ref_t N ## _end_pe(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_end_struct(B); }\\\n" + "static inline N ## _ref_t N ## _create(NS ## builder_t *B __ ## N ## _formal_args)\\\n" + "{ N ## _t *_p = N ## _start(B); if (!_p) return 0; N ##_assign_to_pe(_p __ ## N ## _call_args);\\\n" + " return N ## _end_pe(B); }\\\n" + "static inline N ## _ref_t N ## _clone(NS ## builder_t *B, N ## _struct_t p)\\\n" + "{ N ## _t *_p; __%smemoize_begin(B, p); _p = N ## _start(B); if (!_p) return 0;\\\n" + " N ## _copy(_p, p); __%smemoize_end(B, p, N ##_end_pe(B)); }\\\n" + "__%sbuild_vector(NS, N, N ## _t, S, A)\\\n" + "__%sbuild_struct_root(NS, N, A, FID, TFID)\\\n" + "\n", + nsc, nsc, nsc, nsc, nsc, nsc); + fprintf(out->fp, + "#define __%sstruct_clear_field(p) memset((p), 0, sizeof(*(p)))\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_table(NS, N, K)\\\n" + "static inline int N ## _start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_table(B, K); }\\\n" + "static inline N ## _ref_t N ## _end(NS ## builder_t *B)\\\n" + "{ FLATCC_ASSERT(flatcc_builder_check_required(B, __ ## N ## _required,\\\n" + " sizeof(__ ## N ## _required) / sizeof(__ ## N ## _required[0]) - 1));\\\n" + " return flatcc_builder_end_table(B); }\\\n" + "__%sbuild_offset_vector(NS, N)\n" + "\n", + nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_table_field(ID, NS, N, TN, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, TN ## _ref_t ref)\\\n" + "{ TN ## _ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ?\\\n" + " ((*_p = ref), 0) : -1; }\\\n" + "static inline int N ## _start(NS ## builder_t *B)\\\n" + "{ return TN ## _start(B); }\\\n" + "static inline int N ## _end(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, TN ## _end(B)); }\\\n" + "static inline TN ## _ref_t N ## _create(NS ## builder_t *B __ ## TN ##_formal_args)\\\n" + "{ return N ## _add(B, TN ## _create(B __ ## TN ## _call_args)); }\\\n" + "static inline int N ## _clone(NS ## builder_t *B, TN ## _table_t p)\\\n" + "{ return N ## _add(B, TN ## _clone(B, p)); }\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ TN ## _table_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_union_field(ID, NS, N, TN, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, TN ## _union_ref_t uref)\\\n" + "{ NS ## ref_t *_p; TN ## _union_type_t *_pt; if (uref.type == TN ## _NONE) return 0; if (uref.value == 0) return -1;\\\n" + " if (!(_pt = (TN ## _union_type_t *)flatcc_builder_table_add(B, ID - 1, sizeof(*_pt), sizeof(*_pt)))) return -1;\\\n" + " *_pt = uref.type; if (!(_p = flatcc_builder_table_add_offset(B, ID))) return -1; *_p = uref.value; return 0; }\\\n" + "static inline int N ## _add_type(NS ## builder_t *B, TN ## _union_type_t type)\\\n" + "{ 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" + " sizeof(*_pt), sizeof(*_pt))) ? ((*_pt = type), 0) : -1; }\\\n" + "static inline int N ## _add_value(NS ## builder_t *B, TN ## _union_ref_t uref)\\\n" + "{ NS ## ref_t *p; if (uref.type == TN ## _NONE) return 0; return (p = flatcc_builder_table_add_offset(B, ID)) ?\\\n" + " ((*p = uref.value), 0) : -1; }\\\n" + "static inline int N ## _clone(NS ## builder_t *B, TN ## _union_t p)\\\n" + "{ return N ## _add(B, TN ## _clone(B, p)); }\\\n" + /* `_pick` is not supported on specific union members because the source dictates the type. */ + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ TN ## _union_t _p = N ## _union(t); return _p.type ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc); + + fprintf(out->fp, + "/* M is the union value name and T is its type, i.e. the qualified name. */\n" + "#define __%sbuild_union_table_value_field(NS, N, NU, M, T)\\\n" + "static inline int N ## _ ## M ## _add(NS ## builder_t *B, T ## _ref_t ref)\\\n" + "{ return N ## _add(B, NU ## _as_ ## M (ref)); }\\\n" + "static inline int N ## _ ## M ## _start(NS ## builder_t *B)\\\n" + "{ return T ## _start(B); }\\\n" + "static inline int N ## _ ## M ## _end(NS ## builder_t *B)\\\n" + "{ T ## _ref_t ref = T ## _end(B);\\\n" + " return ref ? N ## _ ## M ## _add(B, ref) : -1; }\\\n" + "static inline int N ## _ ## M ## _create(NS ## builder_t *B __ ## T ##_formal_args)\\\n" + "{ T ## _ref_t ref = T ## _create(B __ ## T ## _call_args);\\\n" + " return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\\\n" + "static inline int N ## _ ## M ## _clone(NS ## builder_t *B, T ## _table_t t)\\\n" + "{ T ## _ref_t ref = T ## _clone(B, t);\\\n" + " return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\n" + "\n", + nsc); + + fprintf(out->fp, + "/* M is the union value name and T is its type, i.e. the qualified name. */\n" + "#define __%sbuild_union_struct_value_field(NS, N, NU, M, T)\\\n" + "static inline int N ## _ ## M ## _add(NS ## builder_t *B, T ## _ref_t ref)\\\n" + "{ return N ## _add(B, NU ## _as_ ## M (ref)); }\\\n" + "static inline T ## _t *N ## _ ## M ## _start(NS ## builder_t *B)\\\n" + "{ return T ## _start(B); }\\\n" + "static inline int N ## _ ## M ## _end(NS ## builder_t *B)\\\n" + "{ T ## _ref_t ref = T ## _end(B);\\\n" + " return ref ? N ## _ ## M ## _add(B, ref) : -1; }\\\n" + "static inline int N ## _ ## M ## _create(NS ## builder_t *B __ ## T ##_formal_args)\\\n" + "{ T ## _ref_t ref = T ## _create(B __ ## T ## _call_args);\\\n" + " return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\\\n" + "static inline int N ## _ ## M ## _end_pe(NS ## builder_t *B)\\\n" + "{ T ## _ref_t ref = T ## _end_pe(B);\\\n" + " return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\\\n" + "static inline int N ## _ ## M ## _clone(NS ## builder_t *B, T ## _struct_t p)\\\n" + "{ T ## _ref_t ref = T ## _clone(B, p);\\\n" + " return ref ? N ## _add(B, NU ## _as_ ## M(ref)) : -1; }\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_union_string_value_field(NS, N, NU, M)\\\n" + "static inline int N ## _ ## M ## _add(NS ## builder_t *B, NS ## string_ref_t ref)\\\n" + "{ return N ## _add(B, NU ## _as_ ## M (ref)); }\\\n" + "__%sbuild_string_field_ops(NS, N ## _ ## M)\n" + "\n", + nsc, nsc); + + fprintf(out->fp, + "/* NS: common namespace, ID: table field id (not offset), TN: name of type T, TT: name of table type\n" + " * S: sizeof of scalar type, A: alignment of type T, default value V of type T. */\n" + "#define __%sbuild_scalar_field(ID, NS, N, TN, T, S, A, V, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, const T v)\\\n" + "{ T *_p; if (v == V) return 0; if (!(_p = (T *)flatcc_builder_table_add(B, ID, S, A))) return -1;\\\n" + " TN ## _assign_to_pe(_p, v); return 0; }\\\n" + "static inline int N ## _force_add(NS ## builder_t *B, const T v)\\\n" + "{ T *_p; if (!(_p = (T *)flatcc_builder_table_add(B, ID, S, A))) return -1;\\\n" + " TN ## _assign_to_pe(_p, v); return 0; }\\\n" + "/* Clone does not skip default values and expects pe endian content. */\\\n" + "static inline int N ## _clone(NS ## builder_t *B, const T *p)\\\n" + "{ return 0 == flatcc_builder_table_add_copy(B, ID, p, S, A) ? -1 : 0; }\\\n" + "/* Transferring a missing field is a nop success with 0 as result. */\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ const T *_p = N ## _get_ptr(t); return _p ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc); + + fprintf(out->fp, + "/* NS: common namespace, ID: table field id (not offset), TN: name of type T, TT: name of table type\n" + " * S: sizeof of scalar type, A: alignment of type T. */\n" + "#define __%sbuild_scalar_optional_field(ID, NS, N, TN, T, S, A, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, const T v)\\\n" + "{ T *_p; if (!(_p = (T *)flatcc_builder_table_add(B, ID, S, A))) return -1;\\\n" + " TN ## _assign_to_pe(_p, v); return 0; }\\\n" + "/* Clone does not skip default values and expects pe endian content. */\\\n" + "static inline int N ## _clone(NS ## builder_t *B, const T *p)\\\n" + "{ return 0 == flatcc_builder_table_add_copy(B, ID, p, S, A) ? -1 : 0; }\\\n" + "/* Transferring a missing field is a nop success with 0 as result. */\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ const T *_p = N ## _get_ptr(t); return _p ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_struct_field(ID, NS, N, TN, S, A, TT)\\\n" + "static inline TN ## _t *N ## _start(NS ## builder_t *B)\\\n" + "{ return (TN ## _t *)flatcc_builder_table_add(B, ID, S, A); }\\\n" + "static inline int N ## _end(NS ## builder_t *B)\\\n" + "{ if (!NS ## is_native_pe()) { TN ## _to_pe((TN ## _t *)flatcc_builder_table_edit(B, S)); } return 0; }\\\n" + "static inline int N ## _end_pe(NS ## builder_t *B) { return 0; }\\\n" + "static inline int N ## _create(NS ## builder_t *B __ ## TN ## _formal_args)\\\n" + "{ TN ## _t *_p = N ## _start(B); if (!_p) return -1; TN ##_assign_to_pe(_p __ ## TN ## _call_args);\\\n" + " return 0; }\\\n" + "static inline int N ## _add(NS ## builder_t *B, const TN ## _t *p)\\\n" + "{ TN ## _t *_p = N ## _start(B); if (!_p) return -1; TN ##_copy_to_pe(_p, p); return 0; }\\\n" + "static inline int N ## _clone(NS ## builder_t *B, TN ## _struct_t p)\\\n" + "{ return 0 == flatcc_builder_table_add_copy(B, ID, p, S, A) ? -1 : 0; }\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ TN ## _struct_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc); + + /* This goes for scalar, struct, and enum vectors. */ + fprintf(out->fp, + "#define __%sbuild_vector_field(ID, NS, N, TN, T, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, TN ## _vec_ref_t ref)\\\n" + "{ TN ## _vec_ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ? ((*_p = ref), 0) : -1; }\\\n" + "static inline int N ## _start(NS ## builder_t *B)\\\n" + "{ return TN ## _vec_start(B); }\\\n" + "static inline int N ## _end_pe(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, TN ## _vec_end_pe(B)); }\\\n" + "static inline int N ## _end(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, TN ## _vec_end(B)); }\\\n" + "static inline int N ## _create_pe(NS ## builder_t *B, const T *data, size_t len)\\\n" + "{ return N ## _add(B, TN ## _vec_create_pe(B, data, len)); }\\\n" + "static inline int N ## _create(NS ## builder_t *B, const T *data, size_t len)\\\n" + "{ return N ## _add(B, TN ## _vec_create(B, data, len)); }\\\n" + "static inline int N ## _slice(NS ## builder_t *B, TN ## _vec_t vec, size_t index, size_t len)\\\n" + "{ return N ## _add(B, TN ## _vec_slice(B, vec, index, len)); }\\\n" + "static inline int N ## _clone(NS ## builder_t *B, TN ## _vec_t vec)\\\n" + "{ return N ## _add(B, TN ## _vec_clone(B, vec)); }\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ TN ## _vec_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\\\n" + "__%sbuild_vector_ops(NS, N, N, TN, T)\\\n" + "\n", + nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_offset_vector_field(ID, NS, N, TN, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, TN ## _vec_ref_t ref)\\\n" + "{ TN ## _vec_ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ? ((*_p = ref), 0) : -1; }\\\n" + "static inline int N ## _start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_offset_vector(B); }\\\n" + "static inline int N ## _end(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, flatcc_builder_end_offset_vector(B)); }\\\n" + "static inline int N ## _create(NS ## builder_t *B, const TN ## _ref_t *data, size_t len)\\\n" + "{ return N ## _add(B, flatcc_builder_create_offset_vector(B, data, len)); }\\\n" + "__%sbuild_offset_vector_ops(NS, N, N, TN)\\\n" + "static inline int N ## _clone(NS ## builder_t *B, TN ## _vec_t vec)\\\n" + "{ return N ## _add(B, TN ## _vec_clone(B, vec)); }\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ TN ## _vec_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc, nsc); + + fprintf(out->fp, + "/* depends on N ## _add which differs for union member fields and ordinary fields */\\\n" + "#define __%sbuild_string_field_ops(NS, N)\\\n" + "static inline int N ## _start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_string(B); }\\\n" + "static inline int N ## _end(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, flatcc_builder_end_string(B)); }\\\n" + "static inline int N ## _create(NS ## builder_t *B, const char *s, size_t len)\\\n" + "{ return N ## _add(B, flatcc_builder_create_string(B, s, len)); }\\\n" + "static inline int N ## _create_str(NS ## builder_t *B, const char *s)\\\n" + "{ return N ## _add(B, flatcc_builder_create_string_str(B, s)); }\\\n" + "static inline int N ## _create_strn(NS ## builder_t *B, const char *s, size_t max_len)\\\n" + "{ return N ## _add(B, flatcc_builder_create_string_strn(B, s, max_len)); }\\\n" + "static inline int N ## _clone(NS ## builder_t *B, NS ## string_t string)\\\n" + "{ return N ## _add(B, NS ## string_clone(B, string)); }\\\n" + "static inline int N ## _slice(NS ## builder_t *B, NS ## string_t string, size_t index, size_t len)\\\n" + "{ return N ## _add(B, NS ## string_slice(B, string, index, len)); }\\\n" + "__%sbuild_string_ops(NS, N)\n" + "\n", + nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_string_field(ID, NS, N, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, NS ## string_ref_t ref)\\\n" + "{ NS ## string_ref_t *_p; return (ref && (_p = flatcc_builder_table_add_offset(B, ID))) ? ((*_p = ref), 0) : -1; }\\\n" + "__%sbuild_string_field_ops(NS, N)\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ NS ## string_t _p = N ## _get(t); return _p ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_table_vector_field(ID, NS, N, TN, TT)\\\n" + "__%sbuild_offset_vector_field(ID, NS, N, TN, TT)\\\n" + "__%sbuild_table_vector_ops(NS, N, TN)\n" + "\n", + nsc, nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_union_vector_field(ID, NS, N, TN, TT)\\\n" + "static inline int N ## _add(NS ## builder_t *B, TN ## _union_vec_ref_t uvref)\\\n" + "{ NS ## vec_ref_t *_p; if (!uvref.type || !uvref.value) return uvref.type == uvref.value ? 0 : -1;\\\n" + " if (!(_p = flatcc_builder_table_add_offset(B, ID - 1))) return -1; *_p = uvref.type;\\\n" + " if (!(_p = flatcc_builder_table_add_offset(B, ID))) return -1; *_p = uvref.value; return 0; }\\\n" + "static inline int N ## _start(NS ## builder_t *B)\\\n" + "{ return flatcc_builder_start_union_vector(B); }\\\n" + "static inline int N ## _end(NS ## builder_t *B)\\\n" + "{ return N ## _add(B, flatcc_builder_end_union_vector(B)); }\\\n" + "static inline int N ## _create(NS ## builder_t *B, const TN ## _union_ref_t *data, size_t len)\\\n" + "{ return N ## _add(B, flatcc_builder_create_union_vector(B, data, len)); }\\\n" + "__%sbuild_union_vector_ops(NS, N, N, TN)\\\n" + "static inline int N ## _clone(NS ## builder_t *B, TN ## _union_vec_t vec)\\\n" + "{ return N ## _add(B, TN ## _vec_clone(B, vec)); }\\\n" + "static inline int N ## _pick(NS ## builder_t *B, TT ## _table_t t)\\\n" + "{ TN ## _union_vec_t _p = N ## _union(t); return _p.type ? N ## _clone(B, _p) : 0; }\n" + "\n", + nsc, nsc); + + fprintf(out->fp, + "#define __%sbuild_union_table_vector_value_field(NS, N, NU, M, T)\\\n" + "static inline int N ## _ ## M ## _push_start(NS ## builder_t *B)\\\n" + "{ return T ## _start(B); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_end(NS ## builder_t *B)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M (T ## _end(B))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push(NS ## builder_t *B, T ## _ref_t ref)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M (ref)); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create(NS ## builder_t *B __ ## T ##_formal_args)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _create(B __ ## T ## _call_args))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_clone(NS ## builder_t *B, T ## _table_t t)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _clone(B, t))); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_union_struct_vector_value_field(NS, N, NU, M, T)\\\n" + "static inline T ## _t *N ## _ ## M ## _push_start(NS ## builder_t *B)\\\n" + "{ return T ## _start(B); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_end(NS ## builder_t *B)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M (T ## _end(B))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push(NS ## builder_t *B, T ## _ref_t ref)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M (ref)); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create(NS ## builder_t *B __ ## T ##_formal_args)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _create(B __ ## T ## _call_args))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_clone(NS ## builder_t *B, T ## _struct_t p)\\\n" + /* Here we create an independent struct block, so T ## _clone is appropriate as opposed to T ## _copy. */ + "{ return NU ## _vec_push(B, NU ## _as_ ## M(T ## _clone(B, p))); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_union_string_vector_value_field(NS, N, NU, M)\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push(NS ## builder_t *B, NS ## string_ref_t ref)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M (ref)); }\\\n" + "static inline int N ## _ ## M ## _push_start(NS ## builder_t *B)\\\n" + "{ return NS ## string_start(B); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_end(NS ## builder_t *B)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_end(B))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create(NS ## builder_t *B, const char *s, size_t len)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_create(B, s, len))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create_str(NS ## builder_t *B, const char *s)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_create_str(B, s))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_create_strn(NS ## builder_t *B, const char *s, size_t max_len)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_create_strn(B, s, max_len))); }\\\n" + "static inline NU ## _union_ref_t *N ## _ ## M ## _push_clone(NS ## builder_t *B, NS ## string_t string)\\\n" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_clone(B, string))); }\\\n" + "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" + "{ return NU ## _vec_push(B, NU ## _as_ ## M(NS ## string_slice(B, string, index, len))); }\n" + "\n", + nsc); + + fprintf(out->fp, + "#define __%sbuild_string_vector_field(ID, NS, N, TT)\\\n" + "__%sbuild_offset_vector_field(ID, NS, N, NS ## string, TT)\\\n" + "__%sbuild_string_vector_ops(NS, N)\n" + "\n", + nsc, nsc, nsc); + + fprintf(out->fp, "#define __%schar_formal_args , char v0\n", nsc); + fprintf(out->fp, "#define __%schar_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%suint8_formal_args , uint8_t v0\n", nsc); + fprintf(out->fp, "#define __%suint8_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%sint8_formal_args , int8_t v0\n", nsc); + fprintf(out->fp, "#define __%sint8_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%sbool_formal_args , %sbool_t v0\n", nsc, nsc); + fprintf(out->fp, "#define __%sbool_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%suint16_formal_args , uint16_t v0\n", nsc); + fprintf(out->fp, "#define __%suint16_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%suint32_formal_args , uint32_t v0\n", nsc); + fprintf(out->fp, "#define __%suint32_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%suint64_formal_args , uint64_t v0\n", nsc); + fprintf(out->fp, "#define __%suint64_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%sint16_formal_args , int16_t v0\n", nsc); + fprintf(out->fp, "#define __%sint16_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%sint32_formal_args , int32_t v0\n", nsc); + fprintf(out->fp, "#define __%sint32_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%sint64_formal_args , int64_t v0\n", nsc); + fprintf(out->fp, "#define __%sint64_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%sfloat_formal_args , float v0\n", nsc); + fprintf(out->fp, "#define __%sfloat_call_args , v0\n", nsc); + fprintf(out->fp, "#define __%sdouble_formal_args , double v0\n", nsc); + fprintf(out->fp, "#define __%sdouble_call_args , v0\n", nsc); + fprintf(out->fp, "\n"); + fprintf(out->fp, "__%sbuild_scalar(%s, %schar, char)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %suint8, uint8_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %sint8, int8_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %sbool, %sbool_t)\n", nsc, nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %suint16, uint16_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %suint32, uint32_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %suint64, uint64_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %sint16, int16_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %sint32, int32_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %sint64, int64_t)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %sfloat, float)\n", nsc, nsc, nsc); + fprintf(out->fp, "__%sbuild_scalar(%s, %sdouble, double)\n", nsc, nsc, nsc); + fprintf(out->fp, "\n"); + fprintf(out->fp, "__%sbuild_string(%s)\n", nsc, nsc); + fprintf(out->fp, "\n"); + + fprintf(out->fp, "__%sbuild_buffer(%s)\n", nsc, nsc); + gen_epilogue(out); + fprintf(out->fp, "#endif /* %s_COMMON_BUILDER_H */\n", nscup); + return 0; +} + +static int gen_builder_pretext(fb_output_t *out) +{ + const char *nsc = out->nsc; + const char *nscup = out->nscup; + + fprintf(out->fp, + "#ifndef %s_BUILDER_H\n" + "#define %s_BUILDER_H\n", + out->S->basenameup, out->S->basenameup); + + fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n"); + fprintf(out->fp, "#ifndef %s_READER_H\n", out->S->basenameup); + fprintf(out->fp, "#include \"%s_reader.h\"\n", out->S->basename); + fprintf(out->fp, "#endif\n"); + fprintf(out->fp, "#ifndef %s_COMMON_BUILDER_H\n", nscup); + fprintf(out->fp, "#include \"%scommon_builder.h\"\n", nsc); + fprintf(out->fp, "#endif\n"); + + fb_gen_c_includes(out, "_builder.h", "_BUILDER_H"); + + gen_prologue(out); + + /* + * Even if defined in the reader header, we must redefine it here + * because another file might sneak in and update. + */ + if (out->S->file_identifier.type == vt_string) { + fprintf(out->fp, + "#undef %sidentifier\n" + "#define %sidentifier \"%.*s\"\n", + nsc, + nsc, out->S->file_identifier.s.len, out->S->file_identifier.s.s); + } else { + fprintf(out->fp, + "#ifndef %sidentifier\n" + "#define %sidentifier 0\n" + "#endif\n", + nsc, nsc); + } + if (out->S->file_extension.type == vt_string) { + fprintf(out->fp, + "#undef %sextension\n" + "#define %sextension \"%.*s\"\n", + nsc, + nsc, out->S->file_extension.s.len, out->S->file_extension.s.s); + } else { + fprintf(out->fp, + "#ifndef %sextension\n" + "#define %sextension \"%s\"\n" + "#endif\n", + nsc, nsc, out->opts->default_bin_ext); + } + fprintf(out->fp, "\n"); + return 0; +} + +static int get_total_struct_field_count(fb_compound_type_t *ct) +{ + fb_member_t *member; + fb_symbol_t *sym; + int count = 0; + + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + switch (member->type.type) { + /* struct arrays count as 1 but struct fields are expanded */ + case vt_compound_type_ref: + if (member->type.ct->symbol.kind == fb_is_struct) { + count += get_total_struct_field_count(member->type.ct); + continue; + } + ++count; + break; + default: + ++count; + break; + } + } + return count; +} + +static inline void gen_comma(fb_output_t *out, int index, int count, int is_macro) +{ + char *cont = is_macro ? "\\\n" : "\n"; + + if (count == 0) { + return; + } + if (index == 0) { + if (count > 4) { + fprintf(out->fp, ",%s ", cont); + } else { + fprintf(out->fp, ", "); + } + } else { + if (index % 4 || count - index <= 2) { + fprintf(out->fp, ", "); + } else { + fprintf(out->fp, ",%s ", cont); + } + } +} + +static int gen_builder_struct_args(fb_output_t *out, fb_compound_type_t *ct, int index, int len, int is_macro) +{ + const char *nsc = out->nsc; + fb_member_t *member; + fb_symbol_t *sym; + const char *tname, *tname_ns; + fb_scoped_name_t snref; + + fb_clear(snref); + + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + switch (member->type.type) { + case vt_fixed_array_compound_type_ref: + gen_comma(out, index, len, is_macro); + fb_compound_name(member->type.ct, &snref); + if (member->type.ct->symbol.kind == fb_is_struct) { + fprintf(out->fp, "const %s_t v%i[%i]", snref.text, index++, (int)member->type.len); + } else { + fprintf(out->fp, "%s_enum_t v%i[%i]", snref.text, index++, (int)member->type.len); + } + break; + case vt_compound_type_ref: + if (member->type.ct->symbol.kind == fb_is_struct) { + index = gen_builder_struct_args(out, member->type.ct, index, len, is_macro); + continue; + } + gen_comma(out, index, len, is_macro); + fb_compound_name(member->type.ct, &snref); + fprintf(out->fp, "%s_enum_t v%i", snref.text, index++); + break; + case vt_fixed_array_type: + gen_comma(out, index, len, is_macro); + tname_ns = scalar_type_ns(member->type.st, nsc); + tname = scalar_type_name(member->type.st); + fprintf(out->fp, "const %s%s v%i[%i]", tname_ns, tname, index++, (int)member->type.len); + break; + case vt_scalar_type: + gen_comma(out, index, len, is_macro); + tname_ns = scalar_type_ns(member->type.st, nsc); + tname = scalar_type_name(member->type.st); + fprintf(out->fp, "%s%s v%i", tname_ns, tname, index++); + break; + default: + gen_panic(out, "internal error: unexpected struct member type"); + continue; + } + } + return index; +} + +static int gen_builder_struct_call_list(fb_output_t *out, fb_compound_type_t *ct, int index, int arg_count, int is_macro) +{ + int i; + int len = get_total_struct_field_count(ct); + + for (i = 0; i < len; ++i) { + gen_comma(out, i, arg_count, is_macro); + fprintf(out->fp, "v%i", index++); + } + return index; +} + +enum { no_conversion, convert_from_pe, convert_to_pe }; + +/* Note: returned index is not correct when using from_ptr since it doesn't track arguments, but it shouldn't matter. */ +static int gen_builder_struct_field_assign(fb_output_t *out, fb_compound_type_t *ct, int index, int arg_count, + int conversion, int from_ptr) +{ + const char *nsc = out->nsc; + fb_member_t *member; + fb_symbol_t *sym; + int n, len; + const char *s; + int deprecated_index = 0; + const char *kind, *tprefix; + fb_scoped_name_t snref; + + fb_clear(snref); + switch (conversion) { + case convert_to_pe: kind = "_to_pe"; break; + case convert_from_pe: kind = "_from_pe"; break; + default: kind = ""; break; + } + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + symbol_name(sym, &n, &s); + + if (index > 0) { + if (index % 4 == 0) { + fprintf(out->fp, ";\n "); + } else { + fprintf(out->fp, "; "); + } + } + switch (member->type.type) { + case vt_fixed_array_compound_type_ref: + len = (int)member->type.len; + fb_compound_name(member->type.ct, &snref); + if (member->metadata_flags & fb_f_deprecated) { + fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)", + nsc, deprecated_index); + ++deprecated_index; + ++index; + continue; + } + if (from_ptr) { + fprintf(out->fp, "%s_array_copy%s(p->%.*s, p2->%.*s, %d)", + snref.text, kind, n, s, n, s, len); + } else { + fprintf(out->fp, "%s_array_copy%s(p->%.*s, v%i, %d)", + snref.text, kind, n, s, index, len); + } + ++index; + continue; + case vt_compound_type_ref: + fb_compound_name(member->type.ct, &snref); + if (member->type.ct->symbol.kind == fb_is_struct) { + if (member->metadata_flags & fb_f_deprecated) { + fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)", + nsc, deprecated_index); + deprecated_index++; + index += get_total_struct_field_count(member->type.ct); + continue; + } + if (from_ptr) { + fprintf(out->fp, "%s_copy%s(&p->%.*s, &p2->%.*s)", snref.text, kind, n, s, n, s); + /* `index` does not count children, but it doesn't matter here. */ + ++index; + } else { + fprintf(out->fp, "%s_assign%s(&p->%.*s", snref.text, kind, n, s); + index = gen_builder_struct_call_list(out, member->type.ct, index, arg_count, 0); + fprintf(out->fp, ")"); + } + continue; + } + if (member->metadata_flags & fb_f_deprecated) { + fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)", + nsc, deprecated_index); + ++deprecated_index; + ++index; + continue; + } + switch (member->size == 1 ? no_conversion : conversion) { + case convert_from_pe: + if (from_ptr) { + fprintf(out->fp, "%s_copy_from_pe(&p->%.*s, &p2->%.*s)", + snref.text, n, s, n, s); + } else { + fprintf(out->fp, "%s_assign_from_pe(&p->%.*s, v%i)", + snref.text, n, s, index); + } + break; + case convert_to_pe: + if (from_ptr) { + fprintf(out->fp, "%s_copy_to_pe(&p->%.*s, &p2->%.*s)", + snref.text, n, s, n, s); + } else { + fprintf(out->fp, "%s_assign_to_pe(&p->%.*s, v%i)", + snref.text, n, s, index); + } + break; + default: + if (from_ptr) { + fprintf(out->fp, "p->%.*s = p2->%.*s", n, s, n, s); + } else { + fprintf(out->fp, "p->%.*s = v%i", n, s, index); + } + break; + } + ++index; + continue; + case vt_fixed_array_type: + tprefix = scalar_type_prefix(member->type.st); + len = (int)member->type.len; + if (member->metadata_flags & fb_f_deprecated) { + fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)", + nsc, deprecated_index); + ++deprecated_index; + ++index; + continue; + } + if (from_ptr) { + fprintf(out->fp, "%s%s_array_copy%s(p->%.*s, p2->%.*s, %d)", + nsc, tprefix, kind, n, s, n, s, len); + } else { + fprintf(out->fp, "%s%s_array_copy%s(p->%.*s, v%i, %d)", + nsc, tprefix, kind, n, s, index, len); + } + ++index; + break; + case vt_scalar_type: + tprefix = scalar_type_prefix(member->type.st); + if (member->metadata_flags & fb_f_deprecated) { + fprintf(out->fp, "__%sstruct_clear_field(p->__deprecated%i)", + nsc, deprecated_index); + ++deprecated_index; + ++index; + continue; + } + switch (member->size == 1 ? no_conversion : conversion) { + case convert_from_pe: + if (from_ptr) { + fprintf(out->fp, "%s%s_copy_from_pe(&p->%.*s, &p2->%.*s)", + nsc, tprefix, n, s, n, s); + } else { + fprintf(out->fp, "%s%s_assign_from_pe(&p->%.*s, v%i)", + nsc, tprefix, n, s, index); + } + break; + case convert_to_pe: + if (from_ptr) { + fprintf(out->fp, "%s%s_copy_to_pe(&p->%.*s, &p2->%.*s)", + nsc, tprefix, n, s, n, s); + } else { + fprintf(out->fp, "%s%s_assign_to_pe(&p->%.*s, v%i)", + nsc, tprefix, n, s, index); + } + break; + default: + if (from_ptr) { + fprintf(out->fp, "p->%.*s = p2->%.*s", n, s, n, s); + } else { + fprintf(out->fp, "p->%.*s = v%i", n, s, index); + } + break; + } + ++index; + break; + default: + gen_panic(out, "internal error: type error"); + continue; + } + } + if (arg_count > 0) { + fprintf(out->fp, ";\n "); + } + return index; +} + +static void gen_builder_struct(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + int arg_count; + fb_scoped_name_t snt; + + fb_clear(snt); + assert(ct->symbol.kind == fb_is_struct); + + fb_compound_name(ct, &snt); + + arg_count = get_total_struct_field_count(ct); + fprintf(out->fp, "#define __%s_formal_args ", snt.text); + gen_builder_struct_args(out, ct, 0, arg_count, 1); + fprintf(out->fp, "\n#define __%s_call_args ", snt.text); + gen_builder_struct_call_list(out, ct, 0, arg_count, 1); + fprintf(out->fp, "\n"); + fprintf(out->fp, + "static inline %s_t *%s_assign(%s_t *p", + snt.text, snt.text, snt.text); + gen_builder_struct_args(out, ct, 0, arg_count, 0); + fprintf(out->fp, ")\n{ "); + gen_builder_struct_field_assign(out, ct, 0, arg_count, no_conversion, 0); + fprintf(out->fp, "return p; }\n"); + fprintf(out->fp, + "static inline %s_t *%s_copy(%s_t *p, const %s_t *p2)\n", + snt.text, snt.text, snt.text, snt.text); + fprintf(out->fp, "{ "); + gen_builder_struct_field_assign(out, ct, 0, arg_count, no_conversion, 1); + fprintf(out->fp, "return p; }\n"); + fprintf(out->fp, + "static inline %s_t *%s_assign_to_pe(%s_t *p", + snt.text, snt.text, snt.text); + gen_builder_struct_args(out, ct, 0, arg_count, 0); + fprintf(out->fp, ")\n{ "); + gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_to_pe, 0); + fprintf(out->fp, "return p; }\n"); + fprintf(out->fp, + "static inline %s_t *%s_copy_to_pe(%s_t *p, const %s_t *p2)\n", + snt.text, snt.text, snt.text, snt.text); + fprintf(out->fp, "{ "); + gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_to_pe, 1); + fprintf(out->fp, "return p; }\n"); + fprintf(out->fp, + "static inline %s_t *%s_assign_from_pe(%s_t *p", + snt.text, snt.text, snt.text); + gen_builder_struct_args(out, ct, 0, arg_count, 0); + fprintf(out->fp, ")\n{ "); + gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_from_pe, 0); + fprintf(out->fp, "return p; }\n"); + fprintf(out->fp, + "static inline %s_t *%s_copy_from_pe(%s_t *p, const %s_t *p2)\n", + snt.text, snt.text, snt.text, snt.text); + fprintf(out->fp, "{ "); + gen_builder_struct_field_assign(out, ct, 0, arg_count, convert_from_pe, 1); + fprintf(out->fp, "return p; }\n"); + fprintf(out->fp, "__%sbuild_struct(%s, %s, %"PRIu64", %u, %s_file_identifier, %s_type_identifier)\n", + nsc, nsc, snt.text, (uint64_t)ct->size, ct->align, snt.text, snt.text); + + if (ct->size > 0) { + fprintf(out->fp, "__%sdefine_fixed_array_primitives(%s, %s, %s_t)\n", + nsc, nsc, snt.text, snt.text); + } +} + +static int get_create_table_arg_count(fb_compound_type_t *ct) +{ + fb_member_t *member; + fb_symbol_t *sym; + int count = 0; + + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + ++count; + } + return count; +} + +static int gen_builder_table_call_list(fb_output_t *out, fb_compound_type_t *ct, int arg_count, int is_macro) +{ + fb_member_t *member; + fb_symbol_t *sym; + int index = 0; + + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + gen_comma(out, index, arg_count, is_macro); + fprintf(out->fp, "v%"PRIu64"", (uint64_t)member->id); + ++index; + } + return index; +} + + +static int gen_required_table_fields(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_member_t *member; + fb_symbol_t *sym; + int index; + int arg_count; + fb_scoped_name_t snt; + + fb_clear(snt); + arg_count = get_create_table_arg_count(ct); + index = 0; + fb_compound_name(ct, &snt); + fprintf(out->fp, "static const %svoffset_t __%s_required[] = {", nsc, snt.text); + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + if (member->metadata_flags & fb_f_required) { + if (index > 0) { + gen_comma(out, index, arg_count, 0); + } else { + fprintf(out->fp, " "); + } + fprintf(out->fp, "%u", (unsigned)member->id); + index++; + } + } + /* Add extra element to avoid null arrays. */ + if (index > 0) { + fprintf(out->fp, ", 0 };\n"); + } else { + fprintf(out->fp, " 0 };\n"); + } + return index; +} + +static int gen_builder_table_args(fb_output_t *out, fb_compound_type_t *ct, int arg_count, int is_macro) +{ + const char *nsc = out->nsc; + fb_symbol_t *sym; + fb_member_t *member; + const char *tname, *tname_ns; + int index; + fb_scoped_name_t snref; + + fb_clear(snref); + /* Just to help the comma. */ + index = 0; + /* We use the id to name arguments so sorted assignment can find the arguments trivially. */ + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + gen_comma(out, index++, arg_count, is_macro); + switch (member->type.type) { + case vt_compound_type_ref: + fb_compound_name(member->type.ct, &snref); + switch (member->type.ct->symbol.kind) { + case fb_is_struct: + fprintf(out->fp, "%s_t *v%"PRIu64"", snref.text, (uint64_t)member->id); + break; + case fb_is_enum: + fprintf(out->fp, "%s_enum_t v%"PRIu64"", snref.text, (uint64_t)member->id); + break; + case fb_is_table: + fprintf(out->fp, "%s_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id); + break; + case fb_is_union: + /* Unions jump an index because it is two fields. */ + fprintf(out->fp, "%s_union_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id); + break; + default: + gen_panic(out, "internal error: unexpected table field type"); + continue; + } + break; + case vt_vector_compound_type_ref: + fb_compound_name(member->type.ct, &snref); + switch (member->type.ct->symbol.kind) { + case fb_is_struct: + case fb_is_enum: + case fb_is_table: + fprintf(out->fp, "%s_vec_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id); + break; + case fb_is_union: + fprintf(out->fp, "%s_union_vec_ref_t v%"PRIu64"", snref.text, (uint64_t)member->id); + break; + default: + gen_panic(out, "internal error: unexpected table table type"); + continue; + } + break; + case vt_scalar_type: + tname_ns = scalar_type_ns(member->type.st, nsc); + tname = scalar_type_name(member->type.st); + fprintf(out->fp, "%s%s v%"PRIu64"", tname_ns, tname, (uint64_t)member->id); + break; + case vt_vector_type: + tname = scalar_type_prefix(member->type.st); + fprintf(out->fp, "%s%s_vec_ref_t v%"PRIu64"", nsc, tname, (uint64_t)member->id); + break; + case vt_string_type: + fprintf(out->fp, "%sstring_ref_t v%"PRIu64"", nsc, (uint64_t)member->id); + break; + case vt_vector_string_type: + fprintf(out->fp, "%sstring_vec_ref_t v%"PRIu64"", nsc, (uint64_t)member->id); + break; + default: + gen_panic(out, "internal error: unexpected table member type"); + continue; + } + } + return index; +} + +static int gen_builder_create_table_decl(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + int arg_count; + fb_scoped_name_t snt; + + fb_clear(snt); + fb_compound_name(ct, &snt); + + arg_count = get_create_table_arg_count(ct); + fprintf(out->fp, "#define __%s_formal_args ", snt.text); + gen_builder_table_args(out, ct, arg_count, 1); + fprintf(out->fp, "\n#define __%s_call_args ", snt.text); + gen_builder_table_call_list(out, ct, arg_count, 1); + fprintf(out->fp, "\n"); + + /* `_clone` fw decl must be place before build_table macro and `_create` must be placed after. */ + fprintf(out->fp, + "static inline %s_ref_t %s_create(%sbuilder_t *B __%s_formal_args);\n", + snt.text, snt.text, nsc, snt.text); + return 0; +} + +static int gen_builder_create_table(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_member_t *member; + int n; + const char *s; + int patch_union = !(ct->metadata_flags & fb_f_original_order); + int has_union = 0; + fb_scoped_name_t snt; + + fb_clear(snt); + fb_compound_name(ct, &snt); + + fprintf(out->fp, + "static inline %s_ref_t %s_create(%sbuilder_t *B __%s_formal_args)\n", + snt.text, snt.text, nsc, snt.text); + + fprintf(out->fp, "{\n if (%s_start(B)", snt.text); + for (member = ct->ordered_members; member; member = member->order) { + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + symbol_name(&member->symbol, &n, &s); + if (member->type.type == vt_compound_type_ref && member->type.ct->symbol.kind == fb_is_union) { + has_union = 1; + if (patch_union) { + fprintf(out->fp, "\n || %s_%.*s_add_value(B, v%"PRIu64")", snt.text, n, s, (uint64_t)member->id); + continue; + } + } + fprintf(out->fp, "\n || %s_%.*s_add(B, v%"PRIu64")", snt.text, n, s, (uint64_t)member->id); + } + if (patch_union && has_union) { + for (member = ct->ordered_members; member; member = member->order) { + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + if (member->type.type == vt_compound_type_ref && member->type.ct->symbol.kind == fb_is_union) { + symbol_name(&member->symbol, &n, &s); + fprintf(out->fp, "\n || %s_%.*s_add_type(B, v%"PRIu64".type)", snt.text, n, s, (uint64_t)member->id); + } + } + } + fprintf(out->fp, ") {\n return 0;\n }\n return %s_end(B);\n}\n\n", snt.text); + return 0; +} + +static int gen_builder_structs(fb_output_t *out) +{ + fb_compound_type_t *ct; + + /* Generate structs in topologically sorted order. */ + for (ct = out->S->ordered_structs; ct; ct = ct->order) { + gen_builder_struct(out, ct); + fprintf(out->fp, "\n"); + } + return 0; +} + +static int gen_builder_table(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_scoped_name_t snt; + + fb_clear(snt); + fb_compound_name(ct, &snt); + + fprintf(out->fp, + "typedef %sref_t %s_ref_t;\n", + nsc, snt.text); + fprintf(out->fp, + "static %s_ref_t %s_clone(%sbuilder_t *B, %s_table_t t);\n", + snt.text, snt.text, nsc, snt.text); + fprintf(out->fp, "__%sbuild_table(%s, %s, %"PRIu64")\n", + nsc, nsc, snt.text, (uint64_t)ct->count); + return 0; +} + +static int gen_builder_table_prolog(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_scoped_name_t snt; + + fb_clear(snt); + fb_compound_name(ct, &snt); + + fprintf(out->fp, "__%sbuild_table_prolog(%s, %s, %s_file_identifier, %s_type_identifier)\n", + nsc, nsc, snt.text, snt.text, snt.text); + return 0; +} + +static int gen_union_fields(fb_output_t *out, const char *st, int n, const char *s, + fb_compound_type_t *ct, int is_vector) +{ + const char *nsc = out->nsc; + fb_symbol_t *sym; + fb_member_t *member; + const char *su; + int nu; + fb_scoped_name_t snref; + fb_scoped_name_t snu; + const char *kind = is_vector ? "vector_value" : "value"; + + fb_clear(snref); + fb_clear(snu); + fb_compound_name(ct, &snref); + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + symbol_name(sym, &nu, &su); + switch (member->type.type) { + case vt_missing: + break; + case vt_compound_type_ref: + fb_compound_name(member->type.ct, &snu); + switch (member->type.ct->symbol.kind) { + case fb_is_table: + fprintf(out->fp, + "__%sbuild_union_table_%s_field(%s, %s_%.*s, %s, %.*s, %s)\n", + nsc, kind, nsc, st, n, s, snref.text, nu, su, snu.text); + break; + case fb_is_struct: + fprintf(out->fp, + "__%sbuild_union_struct_%s_field(%s, %s_%.*s, %s, %.*s, %s)\n", + nsc, kind, nsc, st, n, s, snref.text, nu, su, snu.text); + break; + default: + gen_panic(out, "internal error: unexpected union member compound type"); + return -1; + } + break; + case vt_string_type: + fprintf(out->fp, + "__%sbuild_union_string_%s_field(%s, %s_%.*s, %s, %.*s)\n", + nsc, kind, nsc, st, n, s, snref.text, nu, su); + break; + default: + gen_panic(out, "internal error: unexpected union member type"); + return -1; + } + } + return 0; +} + +static int gen_builder_table_fields(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_member_t *member; + fb_symbol_t *sym; + const char *s, *tprefix, *tname, *tname_ns; + int n; + int is_optional; + fb_scoped_name_t snt; + fb_scoped_name_t snref; + fb_literal_t literal; + + fb_clear(snt); + fb_clear(snref); + fb_compound_name(ct, &snt); + + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + symbol_name(&member->symbol, &n, &s); + if (member->metadata_flags & fb_f_deprecated) { + fprintf(out->fp, "/* Skipping build of deprecated field: '%s_%.*s' */\n\n", snt.text, n, s); + continue; + } + is_optional = member->flags & fb_fm_optional; + switch (member->type.type) { + case vt_scalar_type: + tname_ns = scalar_type_ns(member->type.st, nsc); + tname = scalar_type_name(member->type.st); + tprefix = scalar_type_prefix(member->type.st); + if (is_optional) { + fprintf(out->fp, + "__%sbuild_scalar_optional_field(%"PRIu64", %s, %s_%.*s, %s%s, %s%s, %"PRIu64", %u, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, nsc, tprefix, tname_ns, tname, + (uint64_t)member->size, member->align, snt.text); + } else { + print_literal(member->type.st, &member->value, literal); + fprintf(out->fp, + "__%sbuild_scalar_field(%"PRIu64", %s, %s_%.*s, %s%s, %s%s, %"PRIu64", %u, %s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, nsc, tprefix, tname_ns, tname, + (uint64_t)member->size, member->align, literal, snt.text); + } + break; + case vt_vector_type: + tname_ns = scalar_type_ns(member->type.st, nsc); + tname = scalar_type_name(member->type.st); + tprefix = scalar_type_prefix(member->type.st); + fprintf(out->fp, + "__%sbuild_vector_field(%"PRIu64", %s, %s_%.*s, %s%s, %s%s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, nsc, tprefix, tname_ns, tname, snt.text); + /* [ubyte] vectors can nest buffers. */ + if (member->nest) { + switch (member->nest->symbol.kind) { + case fb_is_table: + fb_compound_name((fb_compound_type_t *)(&member->nest->symbol), &snref); + fprintf(out->fp, "__%sbuild_nested_table_root(%s, %s_%.*s, %s, %s_identifier, %s_type_identifier)\n", + nsc, nsc, snt.text, n, s, snref.text, snref.text, snref.text); + break; + case fb_is_struct: + fb_compound_name((fb_compound_type_t *)(&member->nest->symbol), &snref); + fprintf(out->fp, "__%sbuild_nested_struct_root(%s, %s_%.*s, %s, %u, %s_identifier, %s_type_identifier)\n", + nsc, nsc, snt.text, n, s, snref.text, + (unsigned)((fb_compound_type_t *)(member->nest))->align, snref.text, snref.text); + break; + default: + gen_panic(out, "internal error: unexpected nested type"); + continue; + } + } + break; + case vt_string_type: + fprintf(out->fp, + "__%sbuild_string_field(%"PRIu64", %s, %s_%.*s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snt.text); + break; + case vt_vector_string_type: + fprintf(out->fp, + "__%sbuild_string_vector_field(%"PRIu64", %s, %s_%.*s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snt.text); + break; + case vt_compound_type_ref: + fb_compound_name(member->type.ct, &snref); + switch (member->type.ct->symbol.kind) { + case fb_is_struct: + fprintf(out->fp, + "__%sbuild_struct_field(%"PRIu64", %s, %s_%.*s, %s, %"PRIu64", %u, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, (uint64_t)member->size, member->align, snt.text); + break; + case fb_is_table: + fprintf(out->fp, + "__%sbuild_table_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text); + break; + case fb_is_enum: + if (is_optional) { + fprintf(out->fp, + "__%sbuild_scalar_optional_field(%"PRIu64", %s, %s_%.*s, %s, %s_enum_t, %"PRIu64", %u, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text, + (uint64_t)member->size, member->align, snt.text); + } else { + print_literal(member->type.ct->type.st, &member->value, literal); + fprintf(out->fp, + "__%sbuild_scalar_field(%"PRIu64", %s, %s_%.*s, %s, %s_enum_t, %"PRIu64", %u, %s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text, + (uint64_t)member->size, member->align, literal, snt.text); + } + break; + case fb_is_union: + fprintf(out->fp, + "__%sbuild_union_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text); + gen_union_fields(out, snt.text, n, s, member->type.ct, 0); + break; + default: + gen_panic(out, "internal error: unexpected compound type in table during code generation"); + break; + } + break; + case vt_vector_compound_type_ref: + fb_compound_name(member->type.ct, &snref); + switch (member->type.ct->symbol.kind) { + case fb_is_struct: + if (member->type.ct->symbol.flags & fb_indexed) { + fprintf(out->fp, "/* vector has keyed elements */\n"); + } + fprintf(out->fp, + "__%sbuild_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s_t, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text, snt.text); + break; + case fb_is_table: + if (member->type.ct->symbol.flags & fb_indexed) { + fprintf(out->fp, "/* vector has keyed elements */\n"); + } + fprintf(out->fp, + "__%sbuild_table_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text); + break; + case fb_is_enum: + fprintf(out->fp, + "__%sbuild_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s_enum_t, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snref.text, snt.text); + break; + case fb_is_union: + fprintf(out->fp, + "__%sbuild_union_vector_field(%"PRIu64", %s, %s_%.*s, %s, %s)\n", + nsc, (uint64_t)member->id, nsc, snt.text, n, s, snref.text, snt.text); + gen_union_fields(out, snt.text, n, s, member->type.ct, 1); + break; + default: + gen_panic(out, "internal error: unexpected vector compound type in table during code generation"); + break; + } + break; + default: + gen_panic(out, "internal error: unexpected table member type during code generation"); + break; + } + } + fprintf(out->fp, "\n"); + return 0; +} + +/* + * NOTE: + * + * Cloning a table might lead to a combinatorial explosion if the source + * has many shared references in a DAG. In many cases this might not be + * an issue, but it it is deduplication will be necessary. Deduplication + * is not specific to cloning but especially relevant here. Because + * deduplication carries an overhead in runtime and complexity it is not + * part of the core cloning operation. Cloning of unions and vectors with + * references have similar concerns. + * + * A deduplication operation would internally look like like this: + * + * dedup_clone_table(builder, dedup_map, src_ptr) + * { + * ref = get_cloned_ref(dedup_map, src_ptr) + * if (!ref) { + * ref = clone_table(builder, src_ptr); + * set_cloned_ref(dedup_map, src_ptr, ref); + * } + * return ref; + * } + * + * where dedup_map is a map from a pointer to a builder reference and + * where the dedup_map is dedicated to a single builder and may cover + * multiple source buffers as long as they have separate memory + * locations - otherwise a separate dedup map must be used for each + * source buffer. + * + * Note that the clone operation is not safe without a safe source + * buffer so clone cannot be used to make a buffer with overlapping data + * safe (e.g. a string and a table referencing the same memory). Even if + * the source passes basic verification the result might not. To make + * clone safe it would be necessariry to remember the type as well, for + * example by adding a type specifier to the dedup_map. + * + * In the following we do not implement deduplication. + */ +static int gen_builder_clone_table(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_member_t *member; + const char *s; + int n; + fb_scoped_name_t snt; + fb_scoped_name_t snref; + + fb_clear(snt); + fb_clear(snref); + fb_compound_name(ct, &snt); + + /* + * We could optimize this by cloning the entire table memory block + * and then update update only the references. The builder has + * direct vtable operations to support this - this would not work + * properly if there are deprecated fields to be stripped or if the + * default value has changed - and, more complicated: it is + * necessary to know what table alignment needs to be which require + * inspection of all fields, or a worst case assumption. So at least + * for now, we clone by picking one field at a time. + */ + + fprintf(out->fp, + "static %s_ref_t %s_clone(%sbuilder_t *B, %s_table_t t)\n", + snt.text, snt.text, nsc, snt.text); + + fprintf(out->fp, + "{\n" + " __%smemoize_begin(B, t);\n" + " if (%s_start(B)", nsc, snt.text); + for (member = ct->ordered_members; member; member = member->order) { + if (member->metadata_flags & fb_f_deprecated) { + continue; + } + symbol_name(&member->symbol, &n, &s); + switch (member->type.type) { + case vt_scalar_type: + case vt_vector_type: /* This includes nested buffers - they are just transferred as bytes. */ + case vt_string_type: + case vt_vector_string_type: + fprintf(out->fp, "\n || %s_%.*s_pick(B, t)", snt.text, n, s); + break; + case vt_compound_type_ref: + fb_compound_name(member->type.ct, &snref); + switch (member->type.ct->symbol.kind) { + case fb_is_struct: + case fb_is_table: + case fb_is_enum: + case fb_is_union: + fprintf(out->fp, "\n || %s_%.*s_pick(B, t)", snt.text, n, s); + break; + default: + gen_panic(out, "internal error: unexpected compound type in table during code generation"); + break; + } + break; + case vt_vector_compound_type_ref: + fb_compound_name(member->type.ct, &snref); + switch (member->type.ct->symbol.kind) { + case fb_is_struct: + case fb_is_table: + case fb_is_enum: + case fb_is_union: + fprintf(out->fp, "\n || %s_%.*s_pick(B, t)", snt.text, n, s); + break; + default: + gen_panic(out, "internal error: unexpected vector compound type in table during code generation"); + break; + } + break; + default: + gen_panic(out, "internal error: unexpected table member type during code generation"); + break; + } + } + fprintf(out->fp, ") {\n" + " return 0;\n" + " }\n" + " __%smemoize_end(B, t, %s_end(B));\n}\n", nsc, snt.text); + return 0; +} + +static int gen_builder_enums(fb_output_t *out) +{ + const char *nsc = out->nsc; + fb_symbol_t *sym; + int was_here = 0; + fb_scoped_name_t snt; + + fb_clear(snt); + + for (sym = out->S->symbols; sym; sym = sym->link) { + switch (sym->kind) { + case fb_is_enum: + fb_compound_name((fb_compound_type_t *)sym, &snt); + fprintf(out->fp, + "#define __%s_formal_args , %s_enum_t v0\n" + "#define __%s_call_args , v0\n", + snt.text, snt.text, + snt.text); + fprintf(out->fp, "__%sbuild_scalar(%s, %s, %s_enum_t)\n", + nsc, nsc, snt.text, snt.text); + was_here = 1; + break; + default: + continue; + } + } + if (was_here) { + fprintf(out->fp, "\n"); + } + return 0; +} + +/* + * Scope resolution is a bit fuzzy in unions - + * + * Googles flatc compiler allows dot notation in unions but not enums. + * C++ generates unqualified enum members (i.e. MyGame.Example.Monster + * becomes Monster) in the generated enum but still refers to the + * specific table type in the given namespace. This makes it possible + * to have name conflicts, and flatc raises these like other enum + * conficts. + * + * We use the same approach and this is why we both look up compound + * name and symbol name for the same member but the code generator + * is not concerned with how the scope is parsed or how errors are + * flagged - it just expects members to be unique. + */ +static int gen_union(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_member_t *member; + fb_symbol_t *sym; + const char *s; + int n; + fb_scoped_name_t snt; + fb_scoped_name_t snref; + + fb_clear(snt); + fb_clear(snref); + fb_compound_name(ct, &snt); + + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + switch (member->type.type) { + case vt_compound_type_ref: + fb_compound_name((fb_compound_type_t *)member->type.ct, &snref); + symbol_name(sym, &n, &s); + fprintf(out->fp, + "static inline %s_union_ref_t %s_as_%.*s(%s_ref_t ref)\n" + "{ %s_union_ref_t uref; uref.type = %s_%.*s; uref.value = ref; return uref; }\n", + snt.text, snt.text, n, s, snref.text, + snt.text, snt.text, n, s); + break; + case vt_string_type: + symbol_name(sym, &n, &s); + fprintf(out->fp, + "static inline %s_union_ref_t %s_as_%.*s(%sstring_ref_t ref)\n" + "{ %s_union_ref_t uref; uref.type = %s_%.*s; uref.value = ref; return uref; }\n", + snt.text, snt.text, n, s, nsc, + snt.text, snt.text, n, s); + break; + case vt_missing: + fprintf(out->fp, + "static inline %s_union_ref_t %s_as_NONE(void)\n" + "{ %s_union_ref_t uref; uref.type = %s_NONE; uref.value = 0; return uref; }\n", + snt.text, snt.text, snt.text, snt.text); + break; + default: + gen_panic(out, "internal error: unexpected union value type"); + break; + } + } + fprintf(out->fp, + "__%sbuild_union_vector(%s, %s)\n\n", + nsc, nsc, snt.text); + return 0; +} + +static int gen_union_clone(fb_output_t *out, fb_compound_type_t *ct) +{ + const char *nsc = out->nsc; + fb_member_t *member; + fb_symbol_t *sym; + const char *s; + int n; + fb_scoped_name_t snt; + fb_scoped_name_t snref; + + fb_clear(snt); + fb_clear(snref); + fb_compound_name(ct, &snt); + + fprintf(out->fp, + "static %s_union_ref_t %s_clone(%sbuilder_t *B, %s_union_t u)\n{\n switch (u.type) {\n", + snt.text, snt.text, nsc, snt.text); + + for (sym = ct->members; sym; sym = sym->link) { + member = (fb_member_t *)sym; + switch (member->type.type) { + case vt_compound_type_ref: + fb_compound_name((fb_compound_type_t *)member->type.ct, &snref); + symbol_name(sym, &n, &s); + switch (member->type.ct->symbol.kind) { + case fb_is_table: + fprintf(out->fp, + " case %u: return %s_as_%.*s(%s_clone(B, (%s_table_t)u.value));\n", + (unsigned)member->value.u, snt.text, n, s, snref.text, snref.text); + break; + case fb_is_struct: + fprintf(out->fp, + " case %u: return %s_as_%.*s(%s_clone(B, (%s_struct_t)u.value));\n", + (unsigned)member->value.u, snt.text, n, s, snref.text, snref.text); + break; + default: + gen_panic(out, "internal error: unexpected union value type"); + break; + } + break; + case vt_string_type: + symbol_name(sym, &n, &s); + fprintf(out->fp, + " case %u: return %s_as_%.*s(%sstring_clone(B, u.value));\n", + (unsigned)member->value.u, snt.text, n, s, nsc); + break; + case vt_missing: + break; + default: + gen_panic(out, "internal error: unexpected union value type"); + break; + } + } + + /* Unknown unions are dropped. */ + fprintf(out->fp, + " default: return %s_as_NONE();\n" + " }\n}\n", + snt.text); + return 0; +} + + +static int gen_builder_union_decls(fb_output_t *out) +{ + const char *nsc = out->nsc; + fb_symbol_t *sym; + int was_here = 0; + fb_scoped_name_t snt; + + fb_clear(snt); + + for (sym = out->S->symbols; sym; sym = sym->link) { + switch (sym->kind) { + case fb_is_union: + fb_compound_name((fb_compound_type_t *)sym, &snt); + fprintf(out->fp, + "typedef %sunion_ref_t %s_union_ref_t;\n" + "typedef %sunion_vec_ref_t %s_union_vec_ref_t;\n", + nsc, snt.text, nsc, snt.text); + fprintf(out->fp, + "static %s_union_ref_t %s_clone(%sbuilder_t *B, %s_union_t t);\n", + snt.text, snt.text, nsc, snt.text); + was_here = 1; + break; + default: + continue; + } + } + if (was_here) { + fprintf(out->fp, "\n"); + } + return 0; +} + +static int gen_builder_unions(fb_output_t *out) +{ + fb_symbol_t *sym; + + for (sym = out->S->symbols; sym; sym = sym->link) { + switch (sym->kind) { + case fb_is_union: + gen_union(out, (fb_compound_type_t *)sym); + gen_union_clone(out, (fb_compound_type_t *)sym); + fprintf(out->fp, "\n"); + break; + default: + continue; + } + } + return 0; +} + +static int gen_builder_table_decls(fb_output_t *out) +{ + fb_symbol_t *sym; + + /* + * Because tables are recursive, we need the type and `start/end/add` + * operations before the fields. We also need create for push_create + * but it needs all dependent types, so create is fw declared + * in a subsequent step. The actual create impl. then follows + * after the table fields. + */ + for (sym = out->S->symbols; sym; sym = sym->link) { + switch (sym->kind) { + case fb_is_table: + gen_required_table_fields(out, (fb_compound_type_t *)sym); + gen_builder_table(out, (fb_compound_type_t *)sym); + fprintf(out->fp, "\n"); + break; + default: + continue; + } + } + for (sym = out->S->symbols; sym; sym = sym->link) { + switch (sym->kind) { + case fb_is_table: + gen_builder_create_table_decl(out, (fb_compound_type_t *)sym); + gen_builder_table_prolog(out, (fb_compound_type_t *)sym); + fprintf(out->fp, "\n"); + break; + default: + continue; + } + } + return 0; +} + +static int gen_builder_tables(fb_output_t *out) +{ + fb_symbol_t *sym; + for (sym = out->S->symbols; sym; sym = sym->link) { + switch (sym->kind) { + case fb_is_table: + gen_builder_table_fields(out, (fb_compound_type_t *)sym); + gen_builder_create_table(out, (fb_compound_type_t *)sym); + gen_builder_clone_table(out, (fb_compound_type_t *)sym); + fprintf(out->fp, "\n"); + break; + default: + continue; + } + } + return 0; +} + +static int gen_builder_footer(fb_output_t *out) +{ + gen_epilogue(out); + fprintf(out->fp, + "#endif /* %s_BUILDER_H */\n", + out->S->basenameup); + return 0; +} + +int fb_gen_c_builder(fb_output_t *out) +{ + gen_builder_pretext(out); + gen_builder_enums(out); + gen_builder_structs(out); + gen_builder_union_decls(out); + gen_builder_table_decls(out); + gen_builder_unions(out); + gen_builder_tables(out); + gen_builder_footer(out); + return 0; +} |