#include #include #include #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 - * * returns index (0..len - 1), or not_found (-1). */ fprintf(out->fp, "#include \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 - * * 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 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 \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 * _vec_find_by_ convention and let the parser deal with * semantics. Keys on unsupported fields are ignored. The first * valid find operation is also mapped to just
_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; }