aboutsummaryrefslogtreecommitdiff
path: root/flatcc/src/compiler/codegen_c_reader.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
commitb31e4bc16d1df62b50c6f77a77041f9e7b6c906d (patch)
tree024c74c13d918aa6bde302aab6836fa33607613c /flatcc/src/compiler/codegen_c_reader.c
parentba6815ef8fb8ae472412b5af2837a7caba2799c2 (diff)
parent5a40295c4cf0af5ea8da9ced04a4ce7d3621a080 (diff)
Merge commit '5a40295c4cf0af5ea8da9ced04a4ce7d3621a080' as 'flatcc'
Diffstat (limited to 'flatcc/src/compiler/codegen_c_reader.c')
-rw-r--r--flatcc/src/compiler/codegen_c_reader.c1928
1 files changed, 1928 insertions, 0 deletions
diff --git a/flatcc/src/compiler/codegen_c_reader.c b/flatcc/src/compiler/codegen_c_reader.c
new file mode 100644
index 0000000..6de0f21
--- /dev/null
+++ b/flatcc/src/compiler/codegen_c_reader.c
@@ -0,0 +1,1928 @@
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#include "codegen_c.h"
+#include "codegen_c_sort.h"
+
+static inline int match_kw_identifier(fb_symbol_t *sym)
+{
+ return (sym->ident->len == 10 &&
+ memcmp(sym->ident->text, "identifier", 10) == 0);
+}
+
+/*
+ * Use of file identifiers for undeclared roots is fuzzy, but we need an
+ * identifer for all, so we use the one defined for the current schema
+ * file and allow the user to override. This avoids tedious runtime file
+ * id arguments to all create calls.
+ *
+ * As later addition to FlatBuffers, type hashes may replace file
+ * identifiers when explicitly stated. These are FNV-1a hashes of the
+ * fully qualified type name (dot separated).
+ *
+ * We generate the type hash both as a native integer constants for use
+ * in switch statements, and encoded as a little endian C string for use
+ * as a file identifier.
+ */
+static void print_type_identifier(fb_output_t *out, fb_compound_type_t *ct)
+{
+ uint8_t buf[17];
+ uint8_t *p;
+ uint8_t x;
+ int i;
+ const char *nsc = out->nsc;
+ fb_scoped_name_t snt;
+ const char *name;
+ uint32_t type_hash;
+ int conflict = 0;
+ fb_symbol_t *sym;
+ const char *file_identifier;
+ int file_identifier_len;
+ const char *quote;
+
+ fb_clear(snt);
+
+ fb_compound_name(ct, &snt);
+ name = snt.text;
+ type_hash = ct->type_hash;
+
+ /*
+ * It's not practical to detect all possible name conflicts, but
+ * 'identifier' is common enough to require special handling.
+ */
+ for (sym = ct->members; sym; sym = sym->link) {
+ if (match_kw_identifier(sym)) {
+ conflict = 1;
+ break;
+ }
+ }
+ if (out->S->file_identifier.type == vt_string) {
+ quote = "\"";
+ file_identifier = out->S->file_identifier.s.s;
+ file_identifier_len = out->S->file_identifier.s.len;
+ } else {
+ quote = "";
+ file_identifier = "0";
+ file_identifier_len = 1;
+ }
+ fprintf(out->fp,
+ "#ifndef %s_file_identifier\n"
+ "#define %s_file_identifier %s%.*s%s\n"
+ "#endif\n",
+ name, name, quote, file_identifier_len, file_identifier, quote);
+ if (!conflict) {
+ /* For backwards compatibility. */
+ fprintf(out->fp,
+ "/* deprecated, use %s_file_identifier */\n"
+ "#ifndef %s_identifier\n"
+ "#define %s_identifier %s%.*s%s\n"
+ "#endif\n",
+ name, name, name, quote, file_identifier_len, file_identifier, quote);
+ }
+ fprintf(out->fp,
+ "#define %s_type_hash ((%sthash_t)0x%lx)\n",
+ name, nsc, (unsigned long)(type_hash));
+ p = buf;
+ i = 4;
+ while (i--) {
+ *p++ = '\\';
+ *p++ = 'x';
+ x = type_hash & 0x0f;
+ x += x > 9 ? 'a' - 10 : '0';
+ type_hash >>= 4;
+ p[1] = x;
+ x = type_hash & 0x0f;
+ x += x > 9 ? 'a' - 10 : '0';
+ type_hash >>= 4;
+ p[0] = x;
+ p += 2;
+ }
+ *p = '\0';
+ fprintf(out->fp,
+ "#define %s_type_identifier \"%s\"\n",
+ name, buf);
+}
+
+static void print_file_extension(fb_output_t *out, fb_compound_type_t *ct)
+{
+ fb_scoped_name_t snt;
+ const char *name;
+
+ fb_clear(snt);
+ fb_compound_name(ct, &snt);
+ name = snt.text;
+
+ if (out->S->file_extension.type == vt_string) {
+ fprintf(out->fp,
+ "#ifndef %s_file_extension\n"
+ "#define %s_file_extension \"%.*s\"\n"
+ "#endif\n",
+ name, name, out->S->file_extension.s.len, out->S->file_extension.s.s);
+ } else {
+ fprintf(out->fp,
+ "#ifndef %s_file_extension\n"
+ "#define %s_file_extension \"%s\"\n"
+ "#endif\n",
+ name, name, out->opts->default_bin_ext);
+ }
+}
+
+/* Finds first occurrence of matching key when vector is sorted on the named field. */
+static void gen_find(fb_output_t *out)
+{
+ const char *nsc = out->nsc;
+
+ /*
+ * E: Element accessor (elem = E(vector, index)).
+ * L: Length accessor (length = L(vector)).
+ * A: Field accessor (or the identity function), result must match the diff function D's first arg.
+ * V: The vector to search (assuming sorted).
+ * T: The scalar, enum or string key type, (either the element, or a field of the element).
+ * K: The search key.
+ * Kn: optional key length so external strings do not have to be zero terminated.
+ * D: the diff function D(v, K, Kn) :: v - <K, Kn>
+ *
+ * returns index (0..len - 1), or not_found (-1).
+ */
+ fprintf(out->fp,
+ "#include <string.h>\n"
+ "static const size_t %snot_found = (size_t)-1;\n"
+ "static const size_t %send = (size_t)-1;\n"
+ "#define __%sidentity(n) (n)\n"
+ "#define __%smin(a, b) ((a) < (b) ? (a) : (b))\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "/* Subtraction doesn't work for unsigned types. */\n"
+ "#define __%sscalar_cmp(x, y, n) ((x) < (y) ? -1 : (x) > (y))\n"
+ "static inline int __%sstring_n_cmp(%sstring_t v, const char *s, size_t n)\n"
+ "{ size_t nv = %sstring_len(v); int x = strncmp(v, s, nv < n ? nv : n);\n"
+ " return x != 0 ? x : nv < n ? -1 : nv > n; }\n"
+ "/* `n` arg unused, but needed by string find macro expansion. */\n"
+ "static inline int __%sstring_cmp(%sstring_t v, const char *s, size_t n) { (void)n; return strcmp(v, s); }\n",
+ nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "/* A = identity if searching scalar vectors rather than key fields. */\n"
+ "/* Returns lowest matching index or not_found. */\n"
+ "#define __%sfind_by_field(A, V, E, L, K, Kn, T, D)\\\n"
+ "{ T v__tmp; size_t a__tmp = 0, b__tmp, m__tmp; if (!(b__tmp = L(V))) { return %snot_found; }\\\n"
+ " --b__tmp;\\\n"
+ " while (a__tmp < b__tmp) {\\\n"
+ " m__tmp = a__tmp + ((b__tmp - a__tmp) >> 1);\\\n"
+ " v__tmp = A(E(V, m__tmp));\\\n"
+ " if ((D(v__tmp, (K), (Kn))) < 0) {\\\n"
+ " a__tmp = m__tmp + 1;\\\n"
+ " } else {\\\n"
+ " b__tmp = m__tmp;\\\n"
+ " }\\\n"
+ " }\\\n"
+ " if (a__tmp == b__tmp) {\\\n"
+ " v__tmp = A(E(V, a__tmp));\\\n"
+ " if (D(v__tmp, (K), (Kn)) == 0) {\\\n"
+ " return a__tmp;\\\n"
+ " }\\\n"
+ " }\\\n"
+ " return %snot_found;\\\n"
+ "}\n",
+ nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sfind_by_scalar_field(A, V, E, L, K, T)\\\n"
+ "__%sfind_by_field(A, V, E, L, K, 0, T, __%sscalar_cmp)\n"
+ "#define __%sfind_by_string_field(A, V, E, L, K)\\\n"
+ "__%sfind_by_field(A, V, E, L, K, 0, %sstring_t, __%sstring_cmp)\n"
+ "#define __%sfind_by_string_n_field(A, V, E, L, K, Kn)\\\n"
+ "__%sfind_by_field(A, V, E, L, K, Kn, %sstring_t, __%sstring_n_cmp)\n",
+ nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_find_by_scalar_field(N, NK, TK)\\\n"
+ "static inline size_t N ## _vec_find_by_ ## NK(N ## _vec_t vec__tmp, TK key__tmp)\\\n"
+ "__%sfind_by_scalar_field(N ## _ ## NK, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, TK)\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_scalar_find(N, T)\\\n"
+ "static inline size_t N ## _vec_find(N ## _vec_t vec__tmp, T key__tmp)\\\n"
+ "__%sfind_by_scalar_field(__%sidentity, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\n",
+ nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_find_by_string_field(N, NK) \\\n"
+ "/* Note: find only works on vectors sorted by this field. */\\\n"
+ "static inline size_t N ## _vec_find_by_ ## NK(N ## _vec_t vec__tmp, const char *s__tmp)\\\n"
+ "__%sfind_by_string_field(N ## _ ## NK, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp)\\\n"
+ "static inline size_t N ## _vec_find_n_by_ ## NK(N ## _vec_t vec__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "__%sfind_by_string_n_field(N ## _ ## NK, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp, n__tmp)\n",
+ nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_default_find_by_scalar_field(N, NK, TK)\\\n"
+ "static inline size_t N ## _vec_find(N ## _vec_t vec__tmp, TK key__tmp)\\\n"
+ "{ return N ## _vec_find_by_ ## NK(vec__tmp, key__tmp); }\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_default_find_by_string_field(N, NK) \\\n"
+ "static inline size_t N ## _vec_find(N ## _vec_t vec__tmp, const char *s__tmp)\\\n"
+ "{ return N ## _vec_find_by_ ## NK(vec__tmp, s__tmp); }\\\n"
+ "static inline size_t N ## _vec_find_n(N ## _vec_t vec__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "{ return N ## _vec_find_n_by_ ## NK(vec__tmp, s__tmp, n__tmp); }\n",
+ nsc);
+}
+
+static void gen_union(fb_output_t *out)
+{
+ const char *nsc = out->nsc;
+
+ fprintf(out->fp,
+ "typedef struct %sunion {\n"
+ " %sunion_type_t type;\n"
+ " %sgeneric_t value;\n"
+ "} %sunion_t;\n"
+ "typedef struct %sunion_vec {\n"
+ " const %sunion_type_t *type;\n"
+ " const %suoffset_t *value;\n"
+ "} %sunion_vec_t;\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "typedef struct %smutable_union {\n"
+ " %sunion_type_t type;\n"
+ " %smutable_generic_t value;\n"
+ "} %smutable_union_t;\n"
+ "typedef struct %smutable_union_vec {\n"
+ " %sunion_type_t *type;\n"
+ " %suoffset_t *value;\n"
+ "} %smutable_union_vec_t;\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "static inline %smutable_union_t %smutable_union_cast(%sunion_t u__tmp)\\\n"
+ "{ %smutable_union_t mu = { u__tmp.type, (%smutable_generic_t)u__tmp.value };\\\n"
+ " return mu; }\n",
+ nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "static inline %smutable_union_vec_t %smutable_union_vec_cast(%sunion_vec_t uv__tmp)\\\n"
+ "{ %smutable_union_vec_t muv =\\\n"
+ " { (%sunion_type_t *)uv__tmp.type, (%suoffset_t *)uv__tmp.value }; return muv; }\n",
+ nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sunion_type_field(ID, t)\\\n"
+ "{\\\n"
+ " __%sread_vt(ID, offset__tmp, t)\\\n"
+ " return offset__tmp ? __%sread_scalar_at_byteoffset(__%sutype, t, offset__tmp) : 0;\\\n"
+ "}\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "static inline %sstring_t %sstring_cast_from_union(const %sunion_t u__tmp)\\\n"
+ "{ return %sstring_cast_from_generic(u__tmp.value); }\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_union_field(NS, ID, N, NK, T, r)\\\n"
+ "static inline T ## _union_type_t N ## _ ## NK ## _type_get(N ## _table_t t__tmp)\\\n"
+ "__## NS ## union_type_field(((ID) - 1), t__tmp)\\\n"
+ "static inline NS ## generic_t N ## _ ## NK ## _get(N ## _table_t t__tmp)\\\n"
+ "__## NS ## table_field(NS ## generic_t, ID, t__tmp, r)\\\n", nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "static inline T ## _union_type_t N ## _ ## NK ## _type(N ## _table_t t__tmp)\\\n"
+ "__## NS ## union_type_field(((ID) - 1), t__tmp)\\\n"
+ "static inline NS ## generic_t N ## _ ## NK(N ## _table_t t__tmp)\\\n"
+ "__## NS ## table_field(NS ## generic_t, ID, t__tmp, r)\\\n");
+ }
+ fprintf(out->fp,
+ "static inline int N ## _ ## NK ## _is_present(N ## _table_t t__tmp)\\\n"
+ "__## NS ## field_present(ID, t__tmp)\\\n"
+ "static inline T ## _union_t N ## _ ## NK ## _union(N ## _table_t t__tmp)\\\n"
+ "{ T ## _union_t u__tmp = { 0, 0 }; u__tmp.type = N ## _ ## NK ## _type_get(t__tmp);\\\n"
+ " if (u__tmp.type == 0) return u__tmp; u__tmp.value = N ## _ ## NK ## _get(t__tmp); return u__tmp; }\\\n"
+ "static inline NS ## string_t N ## _ ## NK ## _as_string(N ## _table_t t__tmp)\\\n"
+ "{ return NS ## string_cast_from_generic(N ## _ ## NK ## _get(t__tmp)); }\\\n"
+ "\n");
+ fprintf(out->fp,
+ "#define __%sdefine_union_vector_ops(NS, T)\\\n"
+ "static inline size_t T ## _union_vec_len(T ## _union_vec_t uv__tmp)\\\n"
+ "{ return NS ## vec_len(uv__tmp.type); }\\\n"
+ "static inline T ## _union_t T ## _union_vec_at(T ## _union_vec_t uv__tmp, size_t i__tmp)\\\n"
+ "{ T ## _union_t u__tmp = { 0, 0 }; size_t n__tmp = NS ## vec_len(uv__tmp.type);\\\n"
+ " FLATCC_ASSERT(n__tmp > (i__tmp) && \"index out of range\"); u__tmp.type = uv__tmp.type[i__tmp];\\\n"
+ " /* Unknown type is treated as NONE for schema evolution. */\\\n"
+ " if (u__tmp.type == 0) return u__tmp;\\\n"
+ " u__tmp.value = NS ## generic_vec_at(uv__tmp.value, i__tmp); return u__tmp; }\\\n"
+ "static inline NS ## string_t T ## _union_vec_at_as_string(T ## _union_vec_t uv__tmp, size_t i__tmp)\\\n"
+ "{ return (NS ## string_t) NS ## generic_vec_at_as_string(uv__tmp.value, i__tmp); }\\\n"
+ "\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_union_vector(NS, T)\\\n"
+ "typedef NS ## union_vec_t T ## _union_vec_t;\\\n"
+ "typedef NS ## mutable_union_vec_t T ## _mutable_union_vec_t;\\\n"
+ "static inline T ## _mutable_union_vec_t T ## _mutable_union_vec_cast(T ## _union_vec_t u__tmp)\\\n"
+ "{ return NS ## mutable_union_vec_cast(u__tmp); }\\\n"
+ "__## NS ## define_union_vector_ops(NS, T)\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_union(NS, T)\\\n"
+ "typedef NS ## union_t T ## _union_t;\\\n"
+ "typedef NS ## mutable_union_t T ## _mutable_union_t;\\\n"
+ "static inline T ## _mutable_union_t T ## _mutable_union_cast(T ## _union_t u__tmp)\\\n"
+ "{ return NS ## mutable_union_cast(u__tmp); }\\\n"
+ "__## NS ## define_union_vector(NS, T)\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_union_vector_field(NS, ID, N, NK, T, r)\\\n"
+ "__## NS ## define_vector_field(ID - 1, N, NK ## _type, T ## _vec_t, r)\\\n"
+ "__## NS ## define_vector_field(ID, N, NK, flatbuffers_generic_vec_t, r)\\\n"
+ "static inline T ## _union_vec_t N ## _ ## NK ## _union(N ## _table_t t__tmp)\\\n"
+ "{ T ## _union_vec_t uv__tmp; uv__tmp.type = N ## _ ## NK ## _type_get(t__tmp);\\\n"
+ " uv__tmp.value = N ## _ ## NK(t__tmp);\\\n"
+ " FLATCC_ASSERT(NS ## vec_len(uv__tmp.type) == NS ## vec_len(uv__tmp.value)\\\n"
+ " && \"union vector type length mismatch\"); return uv__tmp; }\n",
+ nsc);
+}
+
+/* Linearly finds first occurrence of matching key, doesn't require vector to be sorted. */
+static void gen_scan(fb_output_t *out)
+{
+ const char *nsc = out->nsc;
+
+ /*
+ * E: Element accessor (elem = E(vector, index)).
+ * L: Length accessor (length = L(vector)).
+ * A: Field accessor (or the identity function), result must match the diff function D's first arg.
+ * V: The vector to search (assuming sorted).
+ * T: The scalar, enum or string key type, (either the element, or a field of the element).
+ * K: The search key.
+ * Kn: optional key length so external strings do not have to be zero terminated.
+ * D: the diff function D(v, K, Kn) :: v - <K, Kn>
+ *
+ * returns index (0..len - 1), or not_found (-1).
+ */
+ fprintf(out->fp,
+ "/* A = identity if searching scalar vectors rather than key fields. */\n"
+ "/* Returns lowest matching index or not_found. */\n"
+ "#define __%sscan_by_field(b, e, A, V, E, L, K, Kn, T, D)\\\n"
+ "{ T v__tmp; size_t i__tmp;\\\n"
+ " for (i__tmp = b; i__tmp < e; ++i__tmp) {\\\n"
+ " v__tmp = A(E(V, i__tmp));\\\n"
+ " if (D(v__tmp, (K), (Kn)) == 0) {\\\n"
+ " return i__tmp;\\\n"
+ " }\\\n"
+ " }\\\n"
+ " return %snot_found;\\\n"
+ "}\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%srscan_by_field(b, e, A, V, E, L, K, Kn, T, D)\\\n"
+ "{ T v__tmp; size_t i__tmp = e;\\\n"
+ " while (i__tmp-- > b) {\\\n"
+ " v__tmp = A(E(V, i__tmp));\\\n"
+ " if (D(v__tmp, (K), (Kn)) == 0) {\\\n"
+ " return i__tmp;\\\n"
+ " }\\\n"
+ " }\\\n"
+ " return %snot_found;\\\n"
+ "}\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sscan_by_scalar_field(b, e, A, V, E, L, K, T)\\\n"
+ "__%sscan_by_field(b, e, A, V, E, L, K, 0, T, __%sscalar_cmp)\n"
+ "#define __%sscan_by_string_field(b, e, A, V, E, L, K)\\\n"
+ "__%sscan_by_field(b, e, A, V, E, L, K, 0, %sstring_t, __%sstring_cmp)\n"
+ "#define __%sscan_by_string_n_field(b, e, A, V, E, L, K, Kn)\\\n"
+ "__%sscan_by_field(b, e, A, V, E, L, K, Kn, %sstring_t, __%sstring_n_cmp)\n",
+ nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%srscan_by_scalar_field(b, e, A, V, E, L, K, T)\\\n"
+ "__%srscan_by_field(b, e, A, V, E, L, K, 0, T, __%sscalar_cmp)\n"
+ "#define __%srscan_by_string_field(b, e, A, V, E, L, K)\\\n"
+ "__%srscan_by_field(b, e, A, V, E, L, K, 0, %sstring_t, __%sstring_cmp)\n"
+ "#define __%srscan_by_string_n_field(b, e, A, V, E, L, K, Kn)\\\n"
+ "__%srscan_by_field(b, e, A, V, E, L, K, Kn, %sstring_t, __%sstring_n_cmp)\n",
+ nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_scan_by_scalar_field(N, NK, T)\\\n"
+ "static inline size_t N ## _vec_scan_by_ ## NK(N ## _vec_t vec__tmp, T key__tmp)\\\n"
+ "__%sscan_by_scalar_field(0, N ## _vec_len(vec__tmp), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\\\n"
+ "static inline size_t N ## _vec_scan_ex_by_ ## NK(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, T key__tmp)\\\n"
+ "__%sscan_by_scalar_field(begin__tmp, __%smin(end__tmp, N ## _vec_len(vec__tmp)), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\\\n"
+ "static inline size_t N ## _vec_rscan_by_ ## NK(N ## _vec_t vec__tmp, T key__tmp)\\\n"
+ "__%srscan_by_scalar_field(0, N ## _vec_len(vec__tmp), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\\\n"
+ "static inline size_t N ## _vec_rscan_ex_by_ ## NK(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, T key__tmp)\\\n"
+ "__%srscan_by_scalar_field(begin__tmp, __%smin(end__tmp, N ## _vec_len(vec__tmp)), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_scalar_scan(N, T)\\\n"
+ "static inline size_t N ## _vec_scan(N ## _vec_t vec__tmp, T key__tmp)\\\n"
+ "__%sscan_by_scalar_field(0, N ## _vec_len(vec__tmp), __%sidentity, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\\\n"
+ "static inline size_t N ## _vec_scan_ex(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, T key__tmp)\\\n"
+ "__%sscan_by_scalar_field(begin__tmp, __%smin(end__tmp, N ## _vec_len(vec__tmp)), __%sidentity, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\\\n"
+ "static inline size_t N ## _vec_rscan(N ## _vec_t vec__tmp, T key__tmp)\\\n"
+ "__%srscan_by_scalar_field(0, N ## _vec_len(vec__tmp), __%sidentity, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\\\n"
+ "static inline size_t N ## _vec_rscan_ex(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, T key__tmp)\\\n"
+ "__%srscan_by_scalar_field(begin__tmp, __%smin(end__tmp, N ## _vec_len(vec__tmp)), __%sidentity, vec__tmp, N ## _vec_at, N ## _vec_len, key__tmp, T)\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_scan_by_string_field(N, NK) \\\n"
+ "static inline size_t N ## _vec_scan_by_ ## NK(N ## _vec_t vec__tmp, const char *s__tmp)\\\n"
+ "__%sscan_by_string_field(0, N ## _vec_len(vec__tmp), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp)\\\n"
+ "static inline size_t N ## _vec_scan_n_by_ ## NK(N ## _vec_t vec__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "__%sscan_by_string_n_field(0, N ## _vec_len(vec__tmp), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp, n__tmp)\\\n"
+ "static inline size_t N ## _vec_scan_ex_by_ ## NK(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp)\\\n"
+ "__%sscan_by_string_field(begin__tmp, __%smin(end__tmp, N ## _vec_len(vec__tmp)), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp)\\\n"
+ "static inline size_t N ## _vec_scan_ex_n_by_ ## NK(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "__%sscan_by_string_n_field(begin__tmp, __%smin( end__tmp, N ## _vec_len(vec__tmp)), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp, n__tmp)\\\n"
+ "static inline size_t N ## _vec_rscan_by_ ## NK(N ## _vec_t vec__tmp, const char *s__tmp)\\\n"
+ "__%srscan_by_string_field(0, N ## _vec_len(vec__tmp), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp)\\\n"
+ "static inline size_t N ## _vec_rscan_n_by_ ## NK(N ## _vec_t vec__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "__%srscan_by_string_n_field(0, N ## _vec_len(vec__tmp), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp, n__tmp)\\\n"
+ "static inline size_t N ## _vec_rscan_ex_by_ ## NK(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp)\\\n"
+ "__%srscan_by_string_field(begin__tmp, __%smin(end__tmp, N ## _vec_len(vec__tmp)), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp)\\\n"
+ "static inline size_t N ## _vec_rscan_ex_n_by_ ## NK(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "__%srscan_by_string_n_field(begin__tmp, __%smin( end__tmp, N ## _vec_len(vec__tmp)), N ## _ ## NK ## _get, vec__tmp, N ## _vec_at, N ## _vec_len, s__tmp, n__tmp)\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_default_scan_by_scalar_field(N, NK, TK)\\\n"
+ "static inline size_t N ## _vec_scan(N ## _vec_t vec__tmp, TK key__tmp)\\\n"
+ "{ return N ## _vec_scan_by_ ## NK(vec__tmp, key__tmp); }\\\n"
+ "static inline size_t N ## _vec_scan_ex(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, TK key__tmp)\\\n"
+ "{ return N ## _vec_scan_ex_by_ ## NK(vec__tmp, begin__tmp, end__tmp, key__tmp); }\\\n"
+ "static inline size_t N ## _vec_rscan(N ## _vec_t vec__tmp, TK key__tmp)\\\n"
+ "{ return N ## _vec_rscan_by_ ## NK(vec__tmp, key__tmp); }\\\n"
+ "static inline size_t N ## _vec_rscan_ex(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, TK key__tmp)\\\n"
+ "{ return N ## _vec_rscan_ex_by_ ## NK(vec__tmp, begin__tmp, end__tmp, key__tmp); }\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_default_scan_by_string_field(N, NK) \\\n"
+ "static inline size_t N ## _vec_scan(N ## _vec_t vec__tmp, const char *s__tmp)\\\n"
+ "{ return N ## _vec_scan_by_ ## NK(vec__tmp, s__tmp); }\\\n"
+ "static inline size_t N ## _vec_scan_n(N ## _vec_t vec__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "{ return N ## _vec_scan_n_by_ ## NK(vec__tmp, s__tmp, n__tmp); }\\\n"
+ "static inline size_t N ## _vec_scan_ex(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp)\\\n"
+ "{ return N ## _vec_scan_ex_by_ ## NK(vec__tmp, begin__tmp, end__tmp, s__tmp); }\\\n"
+ "static inline size_t N ## _vec_scan_ex_n(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "{ return N ## _vec_scan_ex_n_by_ ## NK(vec__tmp, begin__tmp, end__tmp, s__tmp, n__tmp); }\\\n"
+ "static inline size_t N ## _vec_rscan(N ## _vec_t vec__tmp, const char *s__tmp)\\\n"
+ "{ return N ## _vec_rscan_by_ ## NK(vec__tmp, s__tmp); }\\\n"
+ "static inline size_t N ## _vec_rscan_n(N ## _vec_t vec__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "{ return N ## _vec_rscan_n_by_ ## NK(vec__tmp, s__tmp, n__tmp); }\\\n"
+ "static inline size_t N ## _vec_rscan_ex(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp)\\\n"
+ "{ return N ## _vec_rscan_ex_by_ ## NK(vec__tmp, begin__tmp, end__tmp, s__tmp); }\\\n"
+ "static inline size_t N ## _vec_rscan_ex_n(N ## _vec_t vec__tmp, size_t begin__tmp, size_t end__tmp, const char *s__tmp, size_t n__tmp)\\\n"
+ "{ return N ## _vec_rscan_ex_n_by_ ## NK(vec__tmp, begin__tmp, end__tmp, s__tmp, n__tmp); }\n",
+ nsc);
+}
+
+static void gen_helpers(fb_output_t *out)
+{
+ const char *nsc = out->nsc;
+
+ fprintf(out->fp,
+ /*
+ * Include the basic primitives for accessing flatbuffer data types independent
+ * of endianness.
+ *
+ * The included file must define the basic types and accessors
+ * prefixed with the common namespace which by default is
+ * "flatbuffers_".
+ */
+ "#include \"flatcc/flatcc_flatbuffers.h\"\n"
+ "\n\n");
+ /*
+ * The remapping of basic types to the common namespace makes it
+ * possible to have different definitions. The generic
+ * `flatbuffers_uoffset_t` etc. cannot be trusted to have one specific
+ * size since it depends on the included `flatcc/flatcc_types.h`
+ * filer, but the namespace prefixed types can be trusted if used carefully.
+ * For example the common namespace could be `flatbuffers_large_`
+ * when allowing for 64 bit offsets.
+ */
+ if (strcmp(nsc, "flatbuffers_")) {
+ fprintf(out->fp,
+ "typedef flatbuffers_uoffset_t %suoffset_t;\n"
+ "typedef flatbuffers_soffset_t %ssoffset_t;\n"
+ "typedef flatbuffers_voffset_t %svoffset_t;\n"
+ "typedef flatbuffers_utype_t %sutype_t;\n"
+ "typedef flatbuffers_bool_t %sbool_t;\n"
+ "\n",
+ nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define %sendian flatbuffers_endian\n"
+ "__flatcc_define_basic_scalar_accessors(%s, flatbuffers_endian)"
+ "__flatcc_define_integer_accessors(%sbool, flatbuffers_bool_t,\\\n"
+ " FLATBUFFERS_BOOL_WIDTH, flatbuffers_endian)\\\n"
+ "__flatcc_define_integer_accessors(%sunion_type, flatbuffers_union_type_t,\n"
+ " FLATBUFFERS_UTYPE_WIDTH, flatbuffers_endian)\\\n",
+ "\n",
+ nsc, nsc, nsc);
+ fprintf(out->fp,
+ "__flatcc_define_integer_accessors(__%suoffset, flatbuffers_uoffset_t,\n"
+ " FLATBUFFERS_UOFFSET_WIDTH, flatbuffers_endian)\n"
+ "__flatcc_define_integer_accessors(__%ssoffset, flatbuffers_soffset_t,\n"
+ " FLATBUFFERS_SOFFSET_WIDTH, flatbuffers_endian)\n"
+ "__flatcc_define_integer_accessors(__%svoffset, flatbuffers_voffset_t,\n"
+ " FLATBUFFERS_VOFFSET_WIDTH, flatbuffers_endian)\n"
+ "__flatcc_define_integer_accessors(__%sutype, flatbuffers_utype_t,\n"
+ " FLATBUFFERS_UTYPE_WIDTH, flatbuffers_endian)\n"
+ "__flatcc_define_integer_accessors(__%sthash, flatbuffers_thash_t,\n"
+ " FLATBUFFERS_THASH_WIDTH, flatbuffers_endian)\n",
+ nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#ifndef %s_WRAP_NAMESPACE\n"
+ "#define %s_WRAP_NAMESPACE(ns, x) ns ## _ ## x\n"
+ "#endif\n",
+ out->nscup, out->nscup);
+ }
+ /* Build out a more elaborate type system based in the primitives included. */
+ fprintf(out->fp,
+ "#define __%sread_scalar_at_byteoffset(N, p, o) N ## _read_from_pe((uint8_t *)(p) + (o))\n"
+ "#define __%sread_scalar(N, p) N ## _read_from_pe(p)\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sread_vt(ID, offset, t)\\\n"
+ "%svoffset_t offset = 0;\\\n"
+ "{ %svoffset_t id__tmp, *vt__tmp;\\\n"
+ " FLATCC_ASSERT(t != 0 && \"null pointer table access\");\\\n"
+ " id__tmp = ID;\\\n"
+ " vt__tmp = (%svoffset_t *)((uint8_t *)(t) -\\\n"
+ " __%ssoffset_read_from_pe(t));\\\n"
+ " if (__%svoffset_read_from_pe(vt__tmp) >= sizeof(vt__tmp[0]) * (id__tmp + 3u)) {\\\n"
+ " offset = __%svoffset_read_from_pe(vt__tmp + id__tmp + 2);\\\n"
+ " }\\\n"
+ "}\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sfield_present(ID, t) { __%sread_vt(ID, offset__tmp, t) return offset__tmp != 0; }\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sscalar_field(T, ID, t)\\\n"
+ "{\\\n"
+ " __%sread_vt(ID, offset__tmp, t)\\\n"
+ " if (offset__tmp) {\\\n"
+ " return (const T *)((uint8_t *)(t) + offset__tmp);\\\n"
+ " }\\\n"
+ " return 0;\\\n"
+ "}\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_scalar_field(ID, N, NK, TK, T, V)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _table_t t__tmp)\\\n"
+ "{ __%sread_vt(ID, offset__tmp, t__tmp)\\\n"
+ " return offset__tmp ? __%sread_scalar_at_byteoffset(TK, t__tmp, offset__tmp) : V;\\\n"
+ "}\\\n", nsc, nsc, nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "static inline T N ## _ ## NK(N ## _table_t t__tmp)\\\n"
+ "{ __%sread_vt(ID, offset__tmp, t__tmp)\\\n"
+ " return offset__tmp ? __%sread_scalar_at_byteoffset(TK, t__tmp, offset__tmp) : V;\\\n"
+ "}\\\n", nsc, nsc);
+ }
+ fprintf(out->fp,
+ "static inline const T *N ## _ ## NK ## _get_ptr(N ## _table_t t__tmp)\\\n"
+ "__%sscalar_field(T, ID, t__tmp)\\\n", nsc);
+ fprintf(out->fp,
+ "static inline int N ## _ ## NK ## _is_present(N ## _table_t t__tmp)\\\n"
+ "__%sfield_present(ID, t__tmp)",nsc);
+ if (out->opts->allow_scan_for_all_fields) {
+ fprintf(out->fp, "\\\n__%sdefine_scan_by_scalar_field(N, NK, T)\n", nsc);
+ } else {
+ fprintf(out->fp, "\n");
+ }
+ fprintf(out->fp,
+ "#define __%sdefine_scalar_optional_field(ID, N, NK, TK, T, V)\\\n"
+ "__%sdefine_scalar_field(ID, N, NK, TK, T, V)\\\n"
+ "static inline TK ## _option_t N ## _ ## NK ## _option(N ## _table_t t__tmp)\\\n"
+ "{ TK ## _option_t ret; __%sread_vt(ID, offset__tmp, t__tmp)\\\n"
+ " ret.is_null = offset__tmp == 0; ret.value = offset__tmp ?\\\n"
+ " __%sread_scalar_at_byteoffset(TK, t__tmp, offset__tmp) : V;\\\n"
+ " return ret; }\n", nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sstruct_field(T, ID, t, r)\\\n"
+ "{\\\n"
+ " __%sread_vt(ID, offset__tmp, t)\\\n"
+ " if (offset__tmp) {\\\n"
+ " return (T)((uint8_t *)(t) + offset__tmp);\\\n"
+ " }\\\n"
+ " FLATCC_ASSERT(!(r) && \"required field missing\");\\\n"
+ " return 0;\\\n"
+ "}\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%soffset_field(T, ID, t, r, adjust)\\\n"
+ "{\\\n"
+ " %suoffset_t *elem__tmp;\\\n"
+ " __%sread_vt(ID, offset__tmp, t)\\\n"
+ " if (offset__tmp) {\\\n"
+ " elem__tmp = (%suoffset_t *)((uint8_t *)(t) + offset__tmp);\\\n"
+ " /* Add sizeof so C api can have raw access past header field. */\\\n"
+ " return (T)((uint8_t *)(elem__tmp) + adjust +\\\n"
+ " __%suoffset_read_from_pe(elem__tmp));\\\n"
+ " }\\\n"
+ " FLATCC_ASSERT(!(r) && \"required field missing\");\\\n"
+ " return 0;\\\n"
+ "}\n",
+ nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%svector_field(T, ID, t, r) __%soffset_field(T, ID, t, r, sizeof(%suoffset_t))\n"
+ "#define __%stable_field(T, ID, t, r) __%soffset_field(T, ID, t, r, 0)\n",
+ nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_struct_field(ID, N, NK, T, r)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _table_t t__tmp)\\\n"
+ "__%sstruct_field(T, ID, t__tmp, r)", nsc, nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline T N ## _ ## NK(N ## _table_t t__tmp)\\\n"
+ "__%sstruct_field(T, ID, t__tmp, r)", nsc);
+ }
+ fprintf(out->fp,
+ "\\\nstatic inline int N ## _ ## NK ## _is_present(N ## _table_t t__tmp)\\\n"
+ "__%sfield_present(ID, t__tmp)\n", nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_vector_field(ID, N, NK, T, r)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _table_t t__tmp)\\\n"
+ "__%svector_field(T, ID, t__tmp, r)", nsc, nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline T N ## _ ## NK(N ## _table_t t__tmp)\\\n"
+ "__%svector_field(T, ID, t__tmp, r)", nsc);
+ }
+ fprintf(out->fp,
+ "\\\nstatic inline int N ## _ ## NK ## _is_present(N ## _table_t t__tmp)\\\n"
+ "__%sfield_present(ID, t__tmp)\n", nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_table_field(ID, N, NK, T, r)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _table_t t__tmp)\\\n"
+ "__%stable_field(T, ID, t__tmp, r)", nsc, nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline T N ## _ ## NK(N ## _table_t t__tmp)\\\n"
+ "__%stable_field(T, ID, t__tmp, r)", nsc);
+ }
+ fprintf(out->fp,
+ "\\\nstatic inline int N ## _ ## NK ## _is_present(N ## _table_t t__tmp)\\\n"
+ "__%sfield_present(ID, t__tmp)\n", nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_string_field(ID, N, NK, r)\\\n"
+ "static inline %sstring_t N ## _ ## NK ## _get(N ## _table_t t__tmp)\\\n"
+ "__%svector_field(%sstring_t, ID, t__tmp, r)", nsc, nsc, nsc, nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline %sstring_t N ## _ ## NK(N ## _table_t t__tmp)\\\n"
+ "__%svector_field(%sstring_t, ID, t__tmp, r)", nsc, nsc, nsc);
+ }
+ fprintf(out->fp,
+ "\\\nstatic inline int N ## _ ## NK ## _is_present(N ## _table_t t__tmp)\\\n"
+ "__%sfield_present(ID, t__tmp)", nsc);
+ if (out->opts->allow_scan_for_all_fields) {
+ fprintf(out->fp, "\\\n__%sdefine_scan_by_string_field(N, NK)\n", nsc);
+ } else {
+ fprintf(out->fp, "\n");
+ }
+ fprintf(out->fp,
+ "#define __%svec_len(vec)\\\n"
+ "{ return (vec) ? (size_t)__%suoffset_read_from_pe((flatbuffers_uoffset_t *)vec - 1) : 0; }\n"
+ "#define __%sstring_len(s) __%svec_len(s)\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "static inline size_t %svec_len(const void *vec)\n"
+ "__%svec_len(vec)\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ /* Tb is the base type for loads. */
+ "#define __%sscalar_vec_at(N, vec, i)\\\n"
+ "{ FLATCC_ASSERT(%svec_len(vec) > (i) && \"index out of range\");\\\n"
+ " return __%sread_scalar(N, &(vec)[i]); }\n",
+ nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sstruct_vec_at(vec, i)\\\n"
+ "{ FLATCC_ASSERT(%svec_len(vec) > (i) && \"index out of range\"); return (vec) + (i); }\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "/* `adjust` skips past the header for string vectors. */\n"
+ "#define __%soffset_vec_at(T, vec, i, adjust)\\\n"
+ "{ const %suoffset_t *elem__tmp = (vec) + (i);\\\n"
+ " FLATCC_ASSERT(%svec_len(vec) > (i) && \"index out of range\");\\\n"
+ " return (T)((uint8_t *)(elem__tmp) + (size_t)__%suoffset_read_from_pe(elem__tmp) + (adjust)); }\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_scalar_vec_len(N)\\\n"
+ "static inline size_t N ## _vec_len(N ##_vec_t vec__tmp)\\\n"
+ "{ return %svec_len(vec__tmp); }\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sdefine_scalar_vec_at(N, T) \\\n"
+ "static inline T N ## _vec_at(N ## _vec_t vec__tmp, size_t i__tmp)\\\n"
+ "__%sscalar_vec_at(N, vec__tmp, i__tmp)\n",
+ nsc, nsc);
+ fprintf(out->fp,
+ "typedef const char *%sstring_t;\n"
+ "static inline size_t %sstring_len(%sstring_t s)\n"
+ "__%sstring_len(s)\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "typedef const %suoffset_t *%sstring_vec_t;\n"
+ "typedef %suoffset_t *%sstring_mutable_vec_t;\n"
+ "static inline size_t %sstring_vec_len(%sstring_vec_t vec)\n"
+ "__%svec_len(vec)\n"
+ "static inline %sstring_t %sstring_vec_at(%sstring_vec_t vec, size_t i)\n"
+ "__%soffset_vec_at(%sstring_t, vec, i, sizeof(vec[0]))\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp, "typedef const void *%sgeneric_t;\n", nsc);
+ fprintf(out->fp, "typedef void *%smutable_generic_t;\n", nsc);
+ fprintf(out->fp,
+ "static inline %sstring_t %sstring_cast_from_generic(const %sgeneric_t p)\n"
+ "{ return p ? ((const char *)p) + __%suoffset__size() : 0; }\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "typedef const %suoffset_t *%sgeneric_vec_t;\n"
+ "typedef %suoffset_t *%sgeneric_table_mutable_vec_t;\n"
+ "static inline size_t %sgeneric_vec_len(%sgeneric_vec_t vec)\n"
+ "__%svec_len(vec)\n"
+ "static inline %sgeneric_t %sgeneric_vec_at(%sgeneric_vec_t vec, size_t i)\n"
+ "__%soffset_vec_at(%sgeneric_t, vec, i, 0)\n"
+ "static inline %sgeneric_t %sgeneric_vec_at_as_string(%sgeneric_vec_t vec, size_t i)\n"
+ "__%soffset_vec_at(%sgeneric_t, vec, i, sizeof(vec[0]))\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ gen_union(out);
+ gen_find(out);
+ gen_scan(out);
+ if (out->opts->cgen_sort) {
+ gen_sort(out);
+ fprintf(out->fp,
+ "#define __%ssort_vector_field(N, NK, T, t)\\\n"
+ "{ T ## _mutable_vec_t v__tmp = (T ## _mutable_vec_t) N ## _ ## NK ## _get(t);\\\n"
+ " if (v__tmp) T ## _vec_sort(v__tmp); }\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%ssort_table_field(N, NK, T, t)\\\n"
+ "{ T ## _sort((T ## _mutable_table_t)N ## _ ## NK ## _get(t)); }\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%ssort_union_field(N, NK, T, t)\\\n"
+ "{ T ## _sort(T ## _mutable_union_cast(N ## _ ## NK ## _union(t))); }\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%ssort_table_vector_field_elements(N, NK, T, t)\\\n"
+ "{ T ## _vec_t v__tmp = N ## _ ## NK ## _get(t); size_t i__tmp, n__tmp;\\\n"
+ " n__tmp = T ## _vec_len(v__tmp); for (i__tmp = 0; i__tmp < n__tmp; ++i__tmp) {\\\n"
+ " T ## _sort((T ## _mutable_table_t)T ## _vec_at(v__tmp, i__tmp)); }}\n",
+ nsc);
+ fprintf(out->fp,
+ "#define __%ssort_union_vector_field_elements(N, NK, T, t)\\\n"
+ "{ T ## _union_vec_t v__tmp = N ## _ ## NK ## _union(t); size_t i__tmp, n__tmp;\\\n"
+ " n__tmp = T ## _union_vec_len(v__tmp); for (i__tmp = 0; i__tmp < n__tmp; ++i__tmp) {\\\n"
+ " T ## _sort(T ## _mutable_union_cast(T ## _union_vec_at(v__tmp, i__tmp))); }}\n",
+ nsc);
+ } else {
+ fprintf(out->fp, "/* sort disabled */\n");
+ }
+ fprintf(out->fp,
+ "#define __%sdefine_scalar_vector(N, T)\\\n"
+ "typedef const T *N ## _vec_t;\\\n"
+ "typedef T *N ## _mutable_vec_t;\\\n"
+ "__%sdefine_scalar_vec_len(N)\\\n"
+ "__%sdefine_scalar_vec_at(N, T)\\\n"
+ "__%sdefine_scalar_find(N, T)\\\n"
+ "__%sdefine_scalar_scan(N, T)",
+ nsc, nsc, nsc, nsc, nsc);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp, "\\\n__%sdefine_scalar_sort(N, T)\n", nsc);
+ } else {
+ fprintf(out->fp, "\n");
+ }
+ fprintf(out->fp, "\n");
+ /* Elaborate on the included basic type system. */
+ fprintf(out->fp,
+ "#define __%sdefine_integer_type(N, T, W)\\\n"
+ "__flatcc_define_integer_accessors(N, T, W, %sendian)\\\n"
+ "__%sdefine_scalar_vector(N, T)\n",
+ nsc, nsc, nsc);
+ fprintf(out->fp,
+ "__%sdefine_scalar_vector(%sbool, %sbool_t)\n"
+ "__%sdefine_scalar_vector(%schar, char)\n"
+ "__%sdefine_scalar_vector(%suint8, uint8_t)\n"
+ "__%sdefine_scalar_vector(%sint8, int8_t)\n"
+ "__%sdefine_scalar_vector(%suint16, uint16_t)\n"
+ "__%sdefine_scalar_vector(%sint16, int16_t)\n"
+ "__%sdefine_scalar_vector(%suint32, uint32_t)\n"
+ "__%sdefine_scalar_vector(%sint32, int32_t)\n"
+ "__%sdefine_scalar_vector(%suint64, uint64_t)\n"
+ "__%sdefine_scalar_vector(%sint64, int64_t)\n"
+ "__%sdefine_scalar_vector(%sfloat, float)\n"
+ "__%sdefine_scalar_vector(%sdouble, double)\n"
+ "__%sdefine_scalar_vector(%sunion_type, %sunion_type_t)\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "static inline size_t %sstring_vec_find(%sstring_vec_t vec, const char *s)\n"
+ "__%sfind_by_string_field(__%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s)\n"
+ "static inline size_t %sstring_vec_find_n(%sstring_vec_t vec, const char *s, size_t n)\n"
+ "__%sfind_by_string_n_field(__%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s, n)\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "static inline size_t %sstring_vec_scan(%sstring_vec_t vec, const char *s)\n"
+ "__%sscan_by_string_field(0, %sstring_vec_len(vec), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s)\n"
+ "static inline size_t %sstring_vec_scan_n(%sstring_vec_t vec, const char *s, size_t n)\n"
+ "__%sscan_by_string_n_field(0, %sstring_vec_len(vec), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s, n)\n"
+ "static inline size_t %sstring_vec_scan_ex(%sstring_vec_t vec, size_t begin, size_t end, const char *s)\n"
+ "__%sscan_by_string_field(begin, __%smin(end, %sstring_vec_len(vec)), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s)\n"
+ "static inline size_t %sstring_vec_scan_ex_n(%sstring_vec_t vec, size_t begin, size_t end, const char *s, size_t n)\n"
+ "__%sscan_by_string_n_field(begin, __%smin(end, %sstring_vec_len(vec)), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s, n)\n"
+ "static inline size_t %sstring_vec_rscan(%sstring_vec_t vec, const char *s)\n"
+ "__%srscan_by_string_field(0, %sstring_vec_len(vec), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s)\n"
+ "static inline size_t %sstring_vec_rscan_n(%sstring_vec_t vec, const char *s, size_t n)\n"
+ "__%srscan_by_string_n_field(0, %sstring_vec_len(vec), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s, n)\n"
+ "static inline size_t %sstring_vec_rscan_ex(%sstring_vec_t vec, size_t begin, size_t end, const char *s)\n"
+ "__%srscan_by_string_field(begin, __%smin(end, %sstring_vec_len(vec)), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s)\n"
+ "static inline size_t %sstring_vec_rscan_ex_n(%sstring_vec_t vec, size_t begin, size_t end, const char *s, size_t n)\n"
+ "__%srscan_by_string_n_field(begin, __%smin(end, %sstring_vec_len(vec)), __%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s, n)\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc,
+ nsc, nsc, nsc, nsc);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp, "__%sdefine_string_sort()\n", nsc);
+ }
+ fprintf(out->fp,
+ "#define __%sdefine_struct_scalar_fixed_array_field(N, NK, TK, T, L)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _struct_t t__tmp, size_t i__tmp)\\\n"
+ "{ if (!t__tmp || i__tmp >= L) return 0;\\\n"
+ " return __%sread_scalar(TK, &(t__tmp->NK[i__tmp])); }\\\n"
+ "static inline const T *N ## _ ## NK ## _get_ptr(N ## _struct_t t__tmp)\\\n"
+ "{ return t__tmp ? t__tmp->NK : 0; }\\\n"
+ "static inline size_t N ## _ ## NK ## _get_len(void) { return L; }",
+ nsc, nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline T N ## _ ## NK (N ## _struct_t t__tmp, size_t i__tmp)\\\n"
+ "{ return N ## _ ## NK ## _get(t__tmp, i__tmp); }");
+ }
+ fprintf(out->fp, "\n");;
+ fprintf(out->fp,
+ "#define __%sdefine_struct_struct_fixed_array_field(N, NK, T, L)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _struct_t t__tmp, size_t i__tmp)\\\n"
+ "{ if (!t__tmp || i__tmp >= L) return 0; return t__tmp->NK + i__tmp; }"
+ "static inline T N ## _ ## NK ## _get_ptr(N ## _struct_t t__tmp)\\\n"
+ "{ return t__tmp ? t__tmp->NK : 0; }\\\n"
+ "static inline size_t N ## _ ## NK ## _get_len(void) { return L; }",
+ nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline T N ## _ ## NK(N ## _struct_t t__tmp, size_t i__tmp)\\\n"
+ "{ if (!t__tmp || i__tmp >= L) return 0; return t__tmp->NK + i__tmp; }");
+ }
+ fprintf(out->fp, "\n");
+ fprintf(out->fp,
+ "#define __%sdefine_struct_scalar_field(N, NK, TK, T)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _struct_t t__tmp)\\\n"
+ "{ return t__tmp ? __%sread_scalar(TK, &(t__tmp->NK)) : 0; }\\\n"
+ "static inline const T *N ## _ ## NK ## _get_ptr(N ## _struct_t t__tmp)\\\n"
+ "{ return t__tmp ? &(t__tmp->NK) : 0; }",
+ nsc, nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline T N ## _ ## NK (N ## _struct_t t__tmp)\\\n"
+ "{ return t__tmp ? __%sread_scalar(TK, &(t__tmp->NK)) : 0; }",
+ nsc);
+ }
+ if (out->opts->allow_scan_for_all_fields) {
+ fprintf(out->fp, "\\\n__%sdefine_scan_by_scalar_field(N, NK, T)\n", nsc);
+ } else {
+ fprintf(out->fp, "\n");
+ }
+ fprintf(out->fp,
+ "#define __%sdefine_struct_struct_field(N, NK, T)\\\n"
+ "static inline T N ## _ ## NK ## _get(N ## _struct_t t__tmp) { return t__tmp ? &(t__tmp->NK) : 0; }",
+ nsc);
+ if (!out->opts->cgen_no_conflicts) {
+ fprintf(out->fp,
+ "\\\nstatic inline T N ## _ ## NK (N ## _struct_t t__tmp) { return t__tmp ? &(t__tmp->NK) : 0; }\n");
+ } else {
+ fprintf(out->fp, "\n");
+ }
+ fprintf(out->fp,
+ "/* If fid is null, the function returns true without testing as buffer is not expected to have any id. */\n"
+ "static inline int %shas_identifier(const void *buffer, const char *fid)\n"
+ "{ %sthash_t id, id2 = 0; if (fid == 0) { return 1; };\n"
+ " id2 = %stype_hash_from_string(fid);\n"
+ " id = __%sthash_read_from_pe(((%suoffset_t *)buffer) + 1);\n"
+ " return id2 == 0 || id == id2; }\n"
+ "static inline int %shas_type_hash(const void *buffer, %sthash_t thash)\n"
+ "{ return thash == 0 || (__%sthash_read_from_pe((%suoffset_t *)buffer + 1) == thash); }\n\n"
+ "static inline %sthash_t %sget_type_hash(const void *buffer)\n"
+ "{ return __%sthash_read_from_pe((flatbuffers_uoffset_t *)buffer + 1); }\n\n"
+ "#define %sverify_endian() %shas_identifier(\"\\x00\\x00\\x00\\x00\" \"1234\", \"1234\")\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "static inline void *%sread_size_prefix(void *b, size_t *size_out)\n"
+ "{ if (size_out) { *size_out = (size_t)__%suoffset_read_from_pe(b); }\n"
+ " return (uint8_t *)b + sizeof(%suoffset_t); }\n", nsc, nsc, nsc);
+ fprintf(out->fp,
+ "/* Null file identifier accepts anything, otherwise fid should be 4 characters. */\n"
+ "#define __%sread_root(T, K, buffer, fid)\\\n"
+ " ((!buffer || !%shas_identifier(buffer, fid)) ? 0 :\\\n"
+ " ((T ## _ ## K ## t)(((uint8_t *)buffer) +\\\n"
+ " __%suoffset_read_from_pe(buffer))))\n"
+ "#define __%sread_typed_root(T, K, buffer, thash)\\\n"
+ " ((!buffer || !%shas_type_hash(buffer, thash)) ? 0 :\\\n"
+ " ((T ## _ ## K ## t)(((uint8_t *)buffer) +\\\n"
+ " __%suoffset_read_from_pe(buffer))))\n",
+ nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%snested_buffer_as_root(C, N, T, K)\\\n"
+ "static inline T ## _ ## K ## t C ## _ ## N ## _as_root_with_identifier(C ## _ ## table_t t__tmp, const char *fid__tmp)\\\n"
+ "{ const uint8_t *buffer__tmp = C ## _ ## N(t__tmp); return __%sread_root(T, K, buffer__tmp, fid__tmp); }\\\n"
+ "static inline T ## _ ## K ## t C ## _ ## N ## _as_typed_root(C ## _ ## table_t t__tmp)\\\n"
+ "{ const uint8_t *buffer__tmp = C ## _ ## N(t__tmp); return __%sread_root(T, K, buffer__tmp, C ## _ ## type_identifier); }\\\n"
+ "static inline T ## _ ## K ## t C ## _ ## N ## _as_root(C ## _ ## table_t t__tmp)\\\n"
+ "{ const char *fid__tmp = T ## _file_identifier;\\\n"
+ " const uint8_t *buffer__tmp = C ## _ ## N(t__tmp); return __%sread_root(T, K, buffer__tmp, fid__tmp); }\n",
+ nsc, nsc, nsc, nsc);
+ fprintf(out->fp,
+ "#define __%sbuffer_as_root(N, K)\\\n"
+ "static inline N ## _ ## K ## t N ## _as_root_with_identifier(const void *buffer__tmp, const char *fid__tmp)\\\n"
+ "{ return __%sread_root(N, K, buffer__tmp, fid__tmp); }\\\n"
+ "static inline N ## _ ## K ## t N ## _as_root_with_type_hash(const void *buffer__tmp, %sthash_t thash__tmp)\\\n"
+ "{ return __%sread_typed_root(N, K, buffer__tmp, thash__tmp); }\\\n"
+ "static inline N ## _ ## K ## t N ## _as_root(const void *buffer__tmp)\\\n"
+ "{ const char *fid__tmp = N ## _file_identifier;\\\n"
+ " return __%sread_root(N, K, buffer__tmp, fid__tmp); }\\\n"
+ "static inline N ## _ ## K ## t N ## _as_typed_root(const void *buffer__tmp)\\\n"
+ "{ return __%sread_typed_root(N, K, buffer__tmp, N ## _type_hash); }\n"
+ "#define __%sstruct_as_root(N) __%sbuffer_as_root(N, struct_)\n"
+ "#define __%stable_as_root(N) __%sbuffer_as_root(N, table_)\n",
+ nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
+ fprintf(out->fp, "\n");
+}
+
+int fb_gen_common_c_header(fb_output_t *out)
+{
+ const char *nscup = out->nscup;
+
+ fprintf(out->fp,
+ "#ifndef %s_COMMON_READER_H\n"
+ "#define %s_COMMON_READER_H\n",
+ nscup, nscup);
+ fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n");
+ fprintf(out->fp, "/* Common FlatBuffers read functionality for C. */\n\n");
+ if (!out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "/*"
+ " * This code is generated without support for vector sort operations\n"
+ " * but find operations are supported on pre-sorted vectors.\n"
+ " */\n");
+ }
+ gen_prologue(out);
+ gen_helpers(out);
+ gen_epilogue(out);
+ fprintf(out->fp,
+ "#endif /* %s_COMMON_H */\n",
+ nscup);
+ return 0;
+}
+
+static void gen_pretext(fb_output_t *out)
+{
+ const char *nsc = out->nsc;
+ const char *nscup = out->nscup;
+
+ int do_pad = out->opts->cgen_pad;
+
+ fprintf(out->fp,
+ "#ifndef %s_READER_H\n"
+ "#define %s_READER_H\n",
+ out->S->basenameup, out->S->basenameup);
+
+ fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n");
+ if (do_pad) {
+ fprintf(out->fp,
+ "/*\n"
+ " * Generated with 'pad' option which expects #pragma pack(1) and\n"
+ " * #pragma pack() to be supported, and which adds extra padding\n"
+ " * fields to structs.\n"
+ " *\n"
+ " * This is mostly relevant for some micro controller platforms, but\n"
+ " * may also be needed with 'force_align' attributes > 16.\n"
+ " *\n"
+ " * The default output uses C11 <stdalign.h> alignas(n) which can be\n"
+ " * defined as `__attribute__((aligned (n)))` or similar on many\n"
+ " * older platforms.\n"
+ " */\n"
+ "\n");
+ }
+
+ fprintf(out->fp,
+ "#ifndef %s_COMMON_READER_H\n"
+ "#include \"%scommon_reader.h\"\n"
+ "#endif\n",
+ nscup, nsc);
+ fb_gen_c_includes(out, "_reader.h", "_READER_H");
+
+ /*
+ * Must be in included in every file using static_assert to ensure
+ * static_assert_scope.h counter can avoid conflicts.
+ */
+ fprintf(out->fp,
+ "#include \"flatcc/flatcc_flatbuffers.h\"\n");
+ if (!do_pad) {
+ fprintf(out->fp,
+ "#ifndef __alignas_is_defined\n"
+ "#include <stdalign.h>\n"
+ "#endif\n");
+ }
+ gen_prologue(out);
+ 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");
+}
+
+static void gen_footer(fb_output_t *out)
+{
+ gen_epilogue(out);
+ fprintf(out->fp, "#endif /* %s_READER_H */\n", out->S->basenameup);
+}
+
+static void gen_forward_decl(fb_output_t *out, fb_compound_type_t *ct)
+{
+ fb_scoped_name_t snt;
+ const char *nsc = out->nsc;
+
+ fb_clear(snt);
+
+ assert(ct->symbol.kind == fb_is_struct || ct->symbol.kind == fb_is_table);
+
+ fb_compound_name(ct, &snt);
+ if (ct->symbol.kind == fb_is_struct) {
+ if (ct->size == 0) {
+ gen_panic(out, "internal error: unexpected empty struct");
+ return;
+ } else {
+ fprintf(out->fp, "typedef struct %s %s_t;\n",
+ snt.text, snt.text);
+ }
+ fprintf(out->fp, "typedef const %s_t *%s_struct_t;\n",
+ snt.text, snt.text);
+ fprintf(out->fp, "typedef %s_t *%s_mutable_struct_t;\n",
+ snt.text, snt.text);
+ fprintf(out->fp, "typedef const %s_t *%s_vec_t;\n",
+ snt.text, snt.text);
+ fprintf(out->fp, "typedef %s_t *%s_mutable_vec_t;\n",
+ snt.text, snt.text);
+ } else {
+ fprintf(out->fp, "typedef const struct %s_table *%s_table_t;\n",
+ snt.text, snt.text);
+ fprintf(out->fp, "typedef struct %s_table *%s_mutable_table_t;\n",
+ snt.text, snt.text);
+ fprintf(out->fp, "typedef const %suoffset_t *%s_vec_t;\n", nsc, snt.text);
+ fprintf(out->fp, "typedef %suoffset_t *%s_mutable_vec_t;\n", nsc, snt.text);
+ }
+}
+
+static inline void print_doc(fb_output_t *out, const char *indent, fb_doc_t *doc)
+{
+ long ln = 0;
+ int first = 1;
+ if (doc == 0) {
+ return;
+ }
+ while (doc) {
+ if (ln != doc->ident->linenum) {
+ if (first) {
+ /* Not all C compilers understand // comments. */
+ fprintf(out->fp, "%s/** ", indent);
+ ln = doc->ident->linenum;
+ } else {
+ fprintf(out->fp, "\n%s * ", indent);
+ }
+ }
+ first = 0;
+ fprintf(out->fp, "%.*s", (int)doc->ident->len, doc->ident->text);
+ ln = doc->ident->linenum;
+ doc = doc->link;
+ }
+ fprintf(out->fp, " */\n");
+}
+
+static void gen_struct(fb_output_t *out, fb_compound_type_t *ct)
+{
+ fb_member_t *member;
+ fb_symbol_t *sym;
+ unsigned align;
+ size_t offset = 0;
+ const char *tname, *tname_ns, *tname_prefix;
+ int n, len;
+ const char *s;
+ unsigned pad_index = 0, deprecated_index = 0, pad;
+ const char *kind;
+ int do_pad = out->opts->cgen_pad;
+ int is_primary_key, current_key_processed;
+ const char *nsc = out->nsc;
+
+ fb_scoped_name_t snt;
+ fb_scoped_name_t snref;
+
+ fb_clear(snt);
+ fb_clear(snref);
+
+ assert(ct->symbol.kind == fb_is_struct);
+ assert(ct->align > 0 || ct->count == 0);
+ assert(ct->size > 0 || ct->count == 0);
+
+ fb_compound_name(ct, &snt);
+ print_doc(out, "", ct->doc);
+ if (ct->size == 0) {
+ gen_panic(out, "internal error: unexpected empty struct");
+ } else {
+ if (do_pad) {
+ fprintf(out->fp, "#pragma pack(1)\n");
+ }
+ /*
+ * Unfortunately the following is not valid in C11:
+ *
+ * struct alignas(4) mystruct { ... };
+ *
+ * we can only use alignas on members (unlike C++, and unlike
+ * non-portable C compiler variants).
+ *
+ * By padding the first element to the struct size we get around
+ * this problem. It shouldn't strictly be necessary to add padding
+ * fields, but compilers might not support padding above 16 bytes,
+ * so we do that as a precaution with an optional compiler flag.
+ */
+ fprintf(out->fp, "struct %s {\n", snt.text);
+ for (sym = ct->members; sym; sym = sym->link) {
+ current_key_processed = 0;
+ member = (fb_member_t *)sym;
+ is_primary_key = ct->primary_key == member;
+ print_doc(out, " ", member->doc);
+ symbol_name(sym, &n, &s);
+ align = offset == 0 ? ct->align : member->align;
+ if (do_pad && (pad = (unsigned)(member->offset - offset))) {
+ fprintf(out->fp, " uint8_t __padding%u[%u];\n",
+ pad_index++, pad);
+ }
+ if (member->metadata_flags & fb_f_deprecated) {
+ pad = (unsigned)member->size;
+ if (do_pad) {
+ fprintf(out->fp, " uint8_t __deprecated%u[%u]; /* was: '%.*s' */\n",
+ deprecated_index++, pad, n, s);
+ } else {
+ fprintf(out->fp, " alignas(%u) uint8_t __deprecated%u[%u]; /* was: '%.*s' */\n",
+ align, deprecated_index++, pad, n, s);
+ }
+ offset = (unsigned)(member->offset + member->size);
+ continue;
+ }
+ switch (member->type.type) {
+ case vt_fixed_array_type:
+ tname_ns = scalar_type_ns(member->type.st, nsc);
+ tname = scalar_type_name(member->type.st);
+ len = (int)member->type.len;
+ if (do_pad) {
+ fprintf(out->fp, " %s%s ", tname_ns, tname);
+ } else {
+ fprintf(out->fp, " alignas(%u) %s%s ", align, tname_ns, tname);
+ }
+ fprintf(out->fp, "%.*s[%d];\n", n, s, len);
+ break;
+ case vt_scalar_type:
+ tname_ns = scalar_type_ns(member->type.st, nsc);
+ tname = scalar_type_name(member->type.st);
+ if (do_pad) {
+ fprintf(out->fp, " %s%s ", tname_ns, tname);
+ } else {
+ fprintf(out->fp, " alignas(%u) %s%s ", align, tname_ns, tname);
+ }
+ fprintf(out->fp, "%.*s;\n", n, s);
+ break;
+ case vt_fixed_array_compound_type_ref:
+ assert(member->type.ct->symbol.kind == fb_is_struct || member->type.ct->symbol.kind == fb_is_enum);
+ kind = member->type.ct->symbol.kind == fb_is_struct ? "" : "enum_";
+ fb_compound_name(member->type.ct, &snref);
+ len = (int)member->type.len;
+ if (do_pad) {
+ fprintf(out->fp, " %s_%st ", snref.text, kind);
+ } else {
+ fprintf(out->fp, " alignas(%u) %s_%st ", align, snref.text, kind);
+ }
+ fprintf(out->fp, "%.*s[%d];\n", n, s, len);
+ break;
+ case vt_compound_type_ref:
+ assert(member->type.ct->symbol.kind == fb_is_struct || member->type.ct->symbol.kind == fb_is_enum);
+ kind = member->type.ct->symbol.kind == fb_is_struct ? "" : "enum_";
+ fb_compound_name(member->type.ct, &snref);
+ if (do_pad) {
+ fprintf(out->fp, " %s_%st ", snref.text, kind);
+ } else {
+ fprintf(out->fp, " alignas(%u) %s_%st ", align, snref.text, kind);
+ }
+ fprintf(out->fp, "%.*s;\n", n, s);
+ break;
+ default:
+ fprintf(out->fp, " %s ", __FLATCC_ERROR_TYPE);
+ fprintf(out->fp, "%.*s;\n", n, s);
+ gen_panic(out, "internal error: unexpected type during code generation");
+ break;
+ }
+ offset = (unsigned)(member->offset + member->size);
+ }
+ if (do_pad && (pad = (unsigned)(ct->size - offset))) {
+ fprintf(out->fp, " uint8_t __padding%u[%u];\n",
+ pad_index, pad);
+ }
+ fprintf(out->fp, "};\n");
+ if (do_pad) {
+ fprintf(out->fp, "#pragma pack()\n");
+ }
+ fprintf(out->fp,
+ "static_assert(sizeof(%s_t) == %"PRIu64", \"struct size mismatch\");\n\n",
+ snt.text, (uint64_t)ct->size);
+ fprintf(out->fp,
+ "static inline const %s_t *%s__const_ptr_add(const %s_t *p, size_t i) { return p + i; }\n", snt.text, snt.text, snt.text);
+ fprintf(out->fp,
+ "static inline %s_t *%s__ptr_add(%s_t *p, size_t i) { return p + i; }\n", snt.text, snt.text, snt.text);
+ fprintf(out->fp,
+ "static inline %s_struct_t %s_vec_at(%s_vec_t vec, size_t i)\n"
+ "__%sstruct_vec_at(vec, i)\n",
+ snt.text, snt.text, snt.text,
+ nsc);
+ }
+ fprintf(out->fp, "static inline size_t %s__size(void) { return %"PRIu64"; }\n",
+ snt.text, (uint64_t)ct->size);
+ fprintf(out->fp,
+ "static inline size_t %s_vec_len(%s_vec_t vec)\n"
+ "__%svec_len(vec)\n",
+ snt.text, snt.text, nsc);
+ fprintf(out->fp,
+ "__%sstruct_as_root(%s)\n",
+ nsc, snt.text);
+ fprintf(out->fp, "\n");
+
+ /* Create accessors which respect endianness and which return 0 on null struct access. */
+ for (sym = ct->members; sym; sym = sym->link) {
+ member = (fb_member_t *)sym;
+ is_primary_key = ct->primary_key == member;
+ if (member->metadata_flags & fb_f_deprecated) {
+ continue;
+ }
+ symbol_name(&member->symbol, &n, &s);
+ switch (member->type.type) {
+ case vt_fixed_array_type:
+ tname_ns = scalar_type_ns(member->type.st, nsc);
+ tname = scalar_type_name(member->type.st);
+ tname_prefix = scalar_type_prefix(member->type.st);
+ fprintf(out->fp,
+ "__%sdefine_struct_scalar_fixed_array_field(%s, %.*s, %s%s, %s%s, %d)\n",
+ nsc, snt.text, n, s, nsc, tname_prefix, tname_ns, tname, member->type.len);
+ /* TODO: if member->type.st == fb_char add string specific methods. */
+ break;
+ case vt_scalar_type:
+ tname_ns = scalar_type_ns(member->type.st, nsc);
+ tname = scalar_type_name(member->type.st);
+ tname_prefix = scalar_type_prefix(member->type.st);
+ fprintf(out->fp,
+ "__%sdefine_struct_scalar_field(%s, %.*s, %s%s, %s%s)\n",
+ nsc, snt.text, n, s, nsc, tname_prefix, tname_ns, tname);
+ if (!out->opts->allow_scan_for_all_fields && (member->metadata_flags & fb_f_key)) {
+ fprintf(out->fp,
+ "__%sdefine_scan_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ }
+ if (member->metadata_flags & fb_f_key) {
+ if (!is_primary_key) {
+ fprintf(out->fp, "/* Note: this is not the primary key field on this struct. */\n");
+ }
+ fprintf(out->fp, "/* Note: find only works on vectors sorted by this field. */\n");
+ fprintf(out->fp,
+ "__%sdefine_find_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "__%sdefine_struct_sort_by_scalar_field(%s, %.*s, %s%s, %s_t)\n",
+ nsc, snt.text, n, s, tname_ns, tname, snt.text);
+ }
+ if (is_primary_key) {
+ fprintf(out->fp,
+ "__%sdefine_default_find_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ fprintf(out->fp,
+ "__%sdefine_default_scan_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
+ snt.text, snt.text, n, s);
+ }
+ }
+ current_key_processed = 1;
+ }
+ break;
+ case vt_fixed_array_compound_type_ref:
+ fb_compound_name(member->type.ct, &snref);
+ switch (member->type.ct->symbol.kind) {
+ case fb_is_enum:
+ fprintf(out->fp,
+ "__%sdefine_struct_scalar_fixed_array_field(%s, %.*s, %s, %s_enum_t, %d)\n",
+ nsc, snt.text, n, s, snref.text, snref.text, member->type.len);
+ break;
+ case fb_is_struct:
+ fprintf(out->fp,
+ "__%sdefine_struct_struct_fixed_array_field(%s, %.*s, %s_struct_t, %d)\n",
+ nsc, snt.text, n, s, snref.text, member->type.len);
+ break;
+ }
+ break;
+
+ case vt_compound_type_ref:
+ fb_compound_name(member->type.ct, &snref);
+ switch (member->type.ct->symbol.kind) {
+ case fb_is_enum:
+ fprintf(out->fp,
+ "__%sdefine_struct_scalar_field(%s, %.*s, %s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text, snref.text);
+ if (!out->opts->allow_scan_for_all_fields && (member->metadata_flags & fb_f_key)) {
+ fprintf(out->fp,
+ "__%sdefine_scan_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ }
+ if (member->metadata_flags & fb_f_key) {
+ if (!is_primary_key) {
+ fprintf(out->fp, "/* Note: this is not the primary key of this table. */\n");
+ }
+ fprintf(out->fp, "/* Note: find only works on vectors sorted by this field. */\n");
+ fprintf(out->fp,
+ "__%sdefine_find_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "__%sdefine_struct_sort_by_scalar_field(%s, %.*s, %s_enum_t, %s_t)\n",
+ nsc, snt.text, n, s, snref.text, snt.text);
+ }
+ if (is_primary_key) {
+ fprintf(out->fp,
+ "__%sdefine_default_find_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ fprintf(out->fp,
+ "__%sdefine_default_scan_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
+ snt.text, snt.text, n, s);
+ }
+ }
+ current_key_processed = 1;
+ }
+ break;
+ case fb_is_struct:
+ /*
+ * For completeness provide an accessor which returns member pointer
+ * or null if container struct is null.
+ */
+ fprintf(out->fp,
+ "__%sdefine_struct_struct_field(%s, %.*s, %s_struct_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ break;
+ }
+
+ }
+ if ((member->metadata_flags & fb_f_key) && !current_key_processed) {
+ fprintf(out->fp,
+ "/* Note: field has key, but there is no support for find by fields of this type. */\n");
+ /*
+ * If the first key already exists, but was for an unsupported
+ * type, we do not map the next possible key to generic find.
+ */
+ }
+ }
+ fprintf(out->fp, "\n");
+}
+
+/*
+ * Enums are integers, but we cannot control the size.
+ * To produce a typesafe and portable result, we generate constants
+ * instead.
+ */
+static void gen_enum(fb_output_t *out, fb_compound_type_t *ct)
+{
+ fb_member_t *member;
+ fb_symbol_t *sym;
+ const char *tname, *tname_ns, *s, *kind;
+ fb_literal_t literal;
+ int n, w;
+ int is_union;
+ fb_scoped_name_t snt;
+ const char *nsc = out->nsc;
+
+ fb_clear(snt);
+
+ assert(ct->symbol.kind == fb_is_enum || ct->symbol.kind == fb_is_union);
+ assert(ct->type.type == vt_scalar_type);
+
+ tname_ns = scalar_type_ns(ct->type.st, nsc);
+ tname = scalar_type_name(ct->type.st);
+
+ w = (int)ct->size * 8;
+
+ is_union = ct->symbol.kind != fb_is_enum;
+ kind = is_union ? "union_type" : "enum";
+ fb_compound_name(ct, &snt);
+ print_doc(out, "", ct->doc);
+ fprintf(out->fp,
+ "typedef %s%s %s_%s_t;\n",
+ tname_ns, tname, snt.text, kind);
+ fprintf(out->fp,
+ "__%sdefine_integer_type(%s, %s_%s_t, %u)\n",
+ nsc, snt.text, snt.text, kind, w);
+ if (is_union) {
+ fprintf(out->fp,
+ "__%sdefine_union(%s, %s)\n",
+ nsc, nsc, snt.text);
+ }
+ for (sym = ct->members; sym; sym = sym->link) {
+ member = (fb_member_t *)sym;
+ print_doc(out, "", member->doc);
+ symbol_name(&member->symbol, &n, &s);
+ print_literal(ct->type.st, &member->value, literal);
+ /*
+ * This must be a define, not a static const integer, otherwise it
+ * won't work in switch statements - except with GNU extensions.
+ */
+ fprintf(out->fp,
+ "#define %s_%.*s ((%s_%s_t)%s)\n",
+ snt.text, n, s, snt.text, kind, literal);
+ }
+ fprintf(out->fp, "\n");
+
+ if (is_union) {
+ fprintf(out->fp, "static inline const char *%s_type_name(%s_union_type_t type)\n"
+ "{\n",
+ snt.text, snt.text);
+ } else {
+ fprintf(out->fp, "static inline const char *%s_name(%s_enum_t value)\n"
+ "{\n",
+ snt.text, snt.text);
+ }
+
+
+ if (is_union) {
+ fprintf(out->fp, " switch (type) {\n");
+ } else {
+ fprintf(out->fp, " switch (value) {\n");
+ }
+ for (sym = ct->members; sym; sym = sym->link) {
+ member = (fb_member_t *)sym;
+ symbol_name(&member->symbol, &n, &s);
+ if (sym->flags & fb_duplicate) {
+ fprintf(out->fp,
+ " /* case %s_%.*s: return \"%.*s\"; (duplicate) */\n",
+ snt.text, n, s, n, s);
+ } else {
+ fprintf(out->fp,
+ " case %s_%.*s: return \"%.*s\";\n",
+ snt.text, n, s, n, s);
+ }
+ }
+ fprintf(out->fp,
+ " default: return \"\";\n"
+ " }\n"
+ "}\n");
+ fprintf(out->fp, "\n");
+
+ if (is_union) {
+ fprintf(out->fp, "static inline int %s_is_known_type(%s_union_type_t type)\n"
+ "{\n",
+ snt.text, snt.text);
+ } else {
+ fprintf(out->fp, "static inline int %s_is_known_value(%s_enum_t value)\n"
+ "{\n",
+ snt.text, snt.text);
+ }
+ if (is_union) {
+ fprintf(out->fp, " switch (type) {\n");
+ } else {
+ fprintf(out->fp, " switch (value) {\n");
+ }
+ for (sym = ct->members; sym; sym = sym->link) {
+ member = (fb_member_t *)sym;
+ symbol_name(&member->symbol, &n, &s);
+ if (sym->flags & fb_duplicate) {
+ fprintf(out->fp,
+ " /* case %s_%.*s: return 1; (duplicate) */\n",
+ snt.text, n, s);
+ } else {
+ fprintf(out->fp,
+ " case %s_%.*s: return 1;\n",
+ snt.text, n, s);
+ }
+ }
+ fprintf(out->fp,
+ " default: return 0;\n"
+ " }\n"
+ "}\n");
+ fprintf(out->fp, "\n");
+
+}
+
+static void gen_nested_root(fb_output_t *out, fb_symbol_t *root_type, fb_symbol_t *container, fb_symbol_t *member)
+{
+ const char *s;
+ int n;
+ const char *kind;
+ const char *nsc = out->nsc;
+ fb_scoped_name_t snt;
+ fb_scoped_name_t snc;
+
+ fb_clear(snt);
+ fb_clear(snc);
+ if (!root_type) {
+ return;
+ }
+ /*
+ * Current flatc compiler only accepts tables, but here we support
+ * both tables and structs in so far the parser and analyzer
+ * allows for it.
+ */
+ switch (root_type->kind) {
+ case fb_is_table:
+ kind = "table_";
+ break;
+ case fb_is_struct:
+ kind = "struct_";
+ break;
+ default:
+ gen_panic(out, "internal error: roots can only be structs or tables");
+ return;
+ }
+ fb_compound_name((fb_compound_type_t *)root_type, &snt);
+ assert(container->kind == fb_is_table);
+ fb_compound_name((fb_compound_type_t *)container, &snc);
+ symbol_name(member, &n, &s);
+ fprintf(out->fp, "__%snested_buffer_as_root(%s, %.*s, %s, %s)\n", nsc, snc.text, n, s, snt.text, kind);
+}
+
+static void gen_table(fb_output_t *out, fb_compound_type_t *ct)
+{
+ fb_member_t *member;
+ fb_symbol_t *sym;
+ const char *s, *tname, *tname_ns, *tname_prefix;
+ int n, r;
+ int is_primary_key, current_key_processed;
+ const char *nsc = out->nsc;
+ fb_scoped_name_t snt;
+ fb_scoped_name_t snref;
+ fb_literal_t literal;
+ int is_optional;
+
+ assert(ct->symbol.kind == fb_is_table);
+
+ fb_clear(snt);
+ fb_clear(snref);
+
+ fprintf(out->fp, "\n");
+ fb_compound_name(ct, &snt);
+ print_doc(out, "", ct->doc);
+ fprintf(out->fp,
+ /*
+ * We don't really need the struct, but it provides better
+ * type safety than a typedef void *.
+ */
+ "struct %s_table { uint8_t unused__; };\n"
+ "\n",
+ snt.text);
+ fprintf(out->fp,
+ "static inline size_t %s_vec_len(%s_vec_t vec)\n"
+ "__%svec_len(vec)\n",
+ snt.text, snt.text, nsc);
+ fprintf(out->fp,
+ "static inline %s_table_t %s_vec_at(%s_vec_t vec, size_t i)\n"
+ "__%soffset_vec_at(%s_table_t, vec, i, 0)\n",
+ snt.text, snt.text, snt.text, nsc, snt.text);
+ fprintf(out->fp,
+ "__%stable_as_root(%s)\n",
+ nsc, snt.text);
+ fprintf(out->fp, "\n");
+
+ for (sym = ct->members; sym; sym = sym->link) {
+ current_key_processed = 0;
+ member = (fb_member_t *)sym;
+ is_primary_key = ct->primary_key == member;
+ is_optional = !!(member->flags & fb_fm_optional);
+ print_doc(out, "", member->doc);
+ /*
+ * In flatc, there can at most one key field, and it should be
+ * scalar or string. Here we export all keys using the
+ * <table>_vec_find_by_<fieldname> convention and let the parser deal with
+ * semantics. Keys on unsupported fields are ignored. The first
+ * valid find operation is also mapped to just <table>_vec_find.
+ */
+ symbol_name(&member->symbol, &n, &s);
+ if (member->metadata_flags & fb_f_deprecated) {
+ fprintf(out->fp, "/* Skipping deprecated field: '%s_%.*s' */\n\n", snt.text, n, s);
+ continue;
+ }
+ r = (member->metadata_flags & fb_f_required) != 0;
+ switch (member->type.type) {
+ case vt_scalar_type:
+ tname_ns = scalar_type_ns(member->type.st, nsc);
+ tname = scalar_type_name(member->type.st);
+ tname_prefix = scalar_type_prefix(member->type.st);
+ print_literal(member->type.st, &member->value, literal);
+ if (is_optional) {
+ fprintf(out->fp,
+ "__%sdefine_scalar_optional_field(%"PRIu64", %s, %.*s, %s%s, %s%s, %s)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, nsc, tname_prefix, tname_ns, tname, literal);
+ } else {
+ fprintf(out->fp,
+ "__%sdefine_scalar_field(%"PRIu64", %s, %.*s, %s%s, %s%s, %s)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, nsc, tname_prefix, tname_ns, tname, literal);
+ }
+ if (!out->opts->allow_scan_for_all_fields && (member->metadata_flags & fb_f_key)) {
+ fprintf(out->fp,
+ "__%sdefine_scan_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ }
+ if (member->metadata_flags & fb_f_key) {
+ if (!is_primary_key) {
+ fprintf(out->fp, "/* Note: this is not the primary key of this table. */\n");
+ }
+ fprintf(out->fp, "/* Note: find only works on vectors sorted by this field. */\n");
+ fprintf(out->fp,
+ "__%sdefine_find_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "__%sdefine_table_sort_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ }
+ if (is_primary_key) {
+ fprintf(out->fp,
+ "__%sdefine_default_find_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ fprintf(out->fp,
+ "__%sdefine_default_scan_by_scalar_field(%s, %.*s, %s%s)\n",
+ nsc, snt.text, n, s, tname_ns, tname);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
+ snt.text, snt.text, n, s);
+ }
+ }
+ current_key_processed = 1;
+ }
+ break;
+ case vt_vector_type:
+ /* They all use a namespace. */
+ tname = scalar_vector_type_name(member->type.st);
+ tname_ns = nsc;
+ fprintf(out->fp,
+ "__%sdefine_vector_field(%"PRIu64", %s, %.*s, %s%s, %u)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, tname_ns, tname, r);
+ if (member->nest) {
+ gen_nested_root(out, &member->nest->symbol, &ct->symbol, &member->symbol);
+ }
+ break;
+ case vt_string_type:
+ fprintf(out->fp,
+ "__%sdefine_string_field(%"PRIu64", %s, %.*s, %u)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, r);
+ if (!out->opts->allow_scan_for_all_fields && (member->metadata_flags & fb_f_key)) {
+ fprintf(out->fp,
+ "__%sdefine_scan_by_string_field(%s, %.*s)\n",
+ nsc, snt.text, n, s);
+ }
+ if (member->metadata_flags & fb_f_key) {
+ if (!is_primary_key) {
+ fprintf(out->fp, "/* Note: this is not the primary key of this table. */\n");
+ }
+ fprintf(out->fp,
+ "__%sdefine_find_by_string_field(%s, %.*s)\n",
+ nsc, snt.text, n, s);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "__%sdefine_table_sort_by_string_field(%s, %.*s)\n",
+ nsc, snt.text, n, s);
+ }
+ if (is_primary_key) {
+ fprintf(out->fp,
+ "__%sdefine_default_find_by_string_field(%s, %.*s)\n",
+ nsc, snt.text, n, s);
+ fprintf(out->fp,
+ "__%sdefine_default_scan_by_string_field(%s, %.*s)\n",
+ nsc, snt.text, n, s);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
+ snt.text, snt.text, n, s);
+ }
+ }
+ current_key_processed = 1;
+ }
+ break;
+ case vt_vector_string_type:
+ fprintf(out->fp,
+ "__%sdefine_vector_field(%"PRIu64", %s, %.*s, %sstring_vec_t, %u)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, nsc, r);
+ 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,
+ "__%sdefine_struct_field(%"PRIu64", %s, %.*s, %s_struct_t, %u)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, snref.text, r);
+ break;
+ case fb_is_table:
+ fprintf(out->fp,
+ "__%sdefine_table_field(%"PRIu64", %s, %.*s, %s_table_t, %u)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, snref.text, r);
+ break;
+ case fb_is_enum:
+ print_literal(member->type.ct->type.st, &member->value, literal);
+ if (is_optional) {
+ fprintf(out->fp,
+ "__%sdefine_scalar_optional_field(%"PRIu64", %s, %.*s, %s, %s_enum_t, %s)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, snref.text, snref.text, literal);
+ } else {
+ fprintf(out->fp,
+ "__%sdefine_scalar_field(%"PRIu64", %s, %.*s, %s, %s_enum_t, %s)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, snref.text, snref.text, literal);
+ }
+ if (!out->opts->allow_scan_for_all_fields && (member->metadata_flags & fb_f_key)) {
+ fprintf(out->fp,
+ "__%sdefine_scan_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ }
+ if (member->metadata_flags & fb_f_key) {
+ if (!is_primary_key) {
+ fprintf(out->fp, "/* Note: this is not the primary key of this table. */\n");
+ }
+ fprintf(out->fp, "/* Note: find only works on vectors sorted by this field. */\n");
+ fprintf(out->fp,
+ "__%sdefine_find_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "__%sdefine_table_sort_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ }
+ if (is_primary_key) {
+ fprintf(out->fp,
+ "__%sdefine_default_find_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ fprintf(out->fp,
+ "__%sdefine_default_scan_by_scalar_field(%s, %.*s, %s_enum_t)\n",
+ nsc, snt.text, n, s, snref.text);
+ if (out->opts->cgen_sort) {
+ fprintf(out->fp,
+ "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
+ snt.text, snt.text, n, s);
+ }
+ }
+ current_key_processed = 1;
+ }
+ break;
+ case fb_is_union:
+ fprintf(out->fp,
+ "__%sdefine_union_field(%s, %"PRIu64", %s, %.*s, %s, %u)\n",
+ nsc, nsc, (uint64_t)member->id, snt.text, n, s, snref.text, r);
+ 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:
+ break;
+ case fb_is_table:
+ break;
+ case fb_is_enum:
+ break;
+ case fb_is_union:
+ break;
+ default:
+ gen_panic(out, "internal error: unexpected vector compound type in table during code generation");
+ break;
+ }
+ if (member->type.ct->symbol.kind == fb_is_union) {
+ fprintf(out->fp,
+ "__%sdefine_union_vector_field(%s, %"PRIu64", %s, %.*s, %s, %u)\n",
+ nsc, nsc, (uint64_t)member->id, snt.text, n, s, snref.text, r);
+ } else {
+ fprintf(out->fp,
+ "__%sdefine_vector_field(%"PRIu64", %s, %.*s, %s_vec_t, %u)\n",
+ nsc, (uint64_t)member->id, snt.text, n, s, snref.text, r);
+ }
+ break;
+ default:
+ gen_panic(out, "internal error: unexpected table member type during code generation");
+ break;
+ }
+ if ((member->metadata_flags & fb_f_key) && !current_key_processed) {
+ fprintf(out->fp,
+ "/* Note: field has key, but there is no support for find by fields of this type. */\n");
+ /*
+ * If the first key already exists, but was for an unsupported
+ * type, we do not map the next possible key to generic find.
+ */
+ }
+ }
+}
+
+int fb_gen_c_reader(fb_output_t *out)
+{
+ fb_symbol_t *sym;
+ fb_compound_type_t *ct;
+
+ gen_pretext(out);
+
+ for (ct = out->S->ordered_structs; ct; ct = ct->order) {
+ gen_forward_decl(out, ct);
+ }
+ fprintf(out->fp, "\n");
+ for (sym = out->S->symbols; sym; sym = sym->link) {
+ switch (sym->kind) {
+ case fb_is_table:
+ gen_forward_decl(out, (fb_compound_type_t *)sym);
+ break;
+ }
+ }
+ /* Must be placed early due to nested buffer circular references. */
+ for (sym = out->S->symbols; sym; sym = sym->link) {
+ switch (sym->kind) {
+ case fb_is_struct:
+ /* Fall through. */
+ case fb_is_table:
+ print_type_identifier(out, (fb_compound_type_t *)sym);
+ print_file_extension(out, (fb_compound_type_t *)sym);
+ break;
+ }
+ }
+ fprintf(out->fp, "\n");
+ for (sym = out->S->symbols; sym; sym = sym->link) {
+ switch (sym->kind) {
+ /* Enums must come before structs in case they are referenced. */
+ case fb_is_enum:
+ gen_enum(out, (fb_compound_type_t *)sym);
+ break;
+ }
+ }
+ fprintf(out->fp, "\n");
+ /* Generate structs in topologically sorted order. */
+ for (ct = out->S->ordered_structs; ct; ct = ct->order) {
+ gen_struct(out, ct);
+ }
+ for (sym = out->S->symbols; sym; sym = sym->link) {
+ switch (sym->kind) {
+ case fb_is_enum:
+ case fb_is_struct:
+ /* Already generated. */
+ break;
+ case fb_is_union:
+ gen_enum(out, (fb_compound_type_t *)sym);
+ break;
+ case fb_is_table:
+ gen_table(out, (fb_compound_type_t *)sym);
+ break;
+ case fb_is_rpc_service:
+ /* Ignore. */
+ break;
+ default:
+ gen_panic(out, "internal error: unexpected schema component");
+ break;
+ }
+ }
+ fprintf(out->fp, "\n");
+
+ if (out->opts->cgen_sort) {
+ fb_gen_c_sorter(out);
+ }
+
+ gen_footer(out);
+ return 0;
+}