aboutsummaryrefslogtreecommitdiff
path: root/src/compiler/codegen_c_builder.c
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2023-07-16 02:03:33 +0200
committerToni Uhlig <matzeton@googlemail.com>2023-07-16 02:03:33 +0200
commit5a40295c4cf0af5ea8da9ced04a4ce7d3621a080 (patch)
treecb21506e7b04d10b45d6066a0ee1655563d5d52b /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.c2159
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;
+}