LCOV - code coverage report
Current view: top level - src/compiler - codegen_c_reader.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 397 434 91.5 %
Date: 2016-11-30 13:12:14 Functions: 13 13 100.0 %
Branches: 153 206 74.3 %

           Branch data     Line data    Source code
       1                 :            : #include <stdio.h>
       2                 :            : #include <assert.h>
       3                 :            : #include <string.h>
       4                 :            : 
       5                 :            : #include "codegen_c.h"
       6                 :            : #include "codegen_c_sort.h"
       7                 :            : 
       8                 :            : #define llu(x) (long long unsigned int)(x)
       9                 :            : #define lld(x) (long long int)(x)
      10                 :            : 
      11                 :            : 
      12                 :            : /*
      13                 :            :  * Use of file identifiers for undeclared roots is fuzzy, but we need an
      14                 :            :  * identifer for all, so we use the one defined for the current schema
      15                 :            :  * file and allow the user to override. This avoids tedious runtime file
      16                 :            :  * id arguments to all create calls.
      17                 :            :  *
      18                 :            :  * As later addition to FlatBuffers, type hashes may replace file
      19                 :            :  * identifiers when explicitly stated. These are FNV-1a hashes of the
      20                 :            :  * fully qualified type name (dot separated).
      21                 :            :  *
      22                 :            :  * We generate the type hash both as a native integer constants for use
      23                 :            :  * in switch statements, and encoded as a little endian C string for use
      24                 :            :  * as a file identifier.
      25                 :            :  */
      26                 :        105 : static void print_type_identifier(fb_output_t *out, const char *name, uint32_t type_hash)
      27                 :            : {
      28                 :            :     uint8_t buf[17];
      29                 :            :     uint8_t *p;
      30                 :            :     uint8_t x;
      31                 :            :     int i;
      32                 :        105 :     const char *nsc = out->nsc;
      33                 :            : 
      34                 :        105 :     fprintf(out->fp,
      35                 :            :             "#ifndef %s_identifier\n"
      36                 :            :             "#define %s_identifier %sidentifier\n"
      37                 :            :             "#endif\n",
      38                 :            :             name, name, nsc);
      39                 :        105 :     fprintf(out->fp,
      40                 :            :         "#define %s_type_hash ((%sthash_t)0x%lx)\n",
      41                 :            :         name, nsc, (unsigned long)(type_hash));
      42                 :            :     p = buf;
      43                 :            :     i = 4;
      44         [ +  + ]:        525 :     while (i--) {
      45                 :        420 :         *p++ = '\\';
      46                 :        420 :         *p++ = 'x';
      47                 :        420 :         x = type_hash & 0x0f;
      48         [ +  + ]:        420 :         x += x > 9 ? 'a' - 10 : '0';
      49                 :        420 :         type_hash >>= 4;
      50                 :        420 :         p[1] = x;
      51                 :        420 :         x = type_hash & 0x0f;
      52         [ +  + ]:        420 :         x += x > 9 ? 'a' - 10 : '0';
      53                 :        420 :         type_hash >>= 4;
      54                 :        420 :         p[0] = x;
      55                 :        420 :         p += 2;
      56                 :            :     }
      57                 :        105 :     *p = '\0';
      58                 :        105 :     fprintf(out->fp,
      59                 :            :         "#define %s_type_identifier \"%s\"\n",
      60                 :            :         name, buf);
      61                 :        105 : }
      62                 :            : 
      63                 :            : /* Finds first occurrence of matching key when vector is sorted on the named field. */
      64                 :         10 : static void gen_find(fb_output_t *out)
      65                 :            : {
      66                 :         10 :     const char *nsc = out->nsc;
      67                 :            : 
      68                 :            :     /*
      69                 :            :      * E: Element accessor (elem = E(vector, index)).
      70                 :            :      * A: Field accessor (or the identity function), result must match the diff function D's first arg.
      71                 :            :      * V: The vector to search (assuming sorted).
      72                 :            :      * T: The scalar, enum or string key type, (either the element, or a field of the element).
      73                 :            :      * K: The search key.
      74                 :            :      * Kn: optional key length so external strings do not have to be zero terminated.
      75                 :            :      * D: the diff function D(v, K, Kn) :: v - <K, Kn>
      76                 :            :      *
      77                 :            :      * returns index (0..len - 1), or not_found (-1).
      78                 :            :      */
      79                 :         10 :     fprintf(out->fp,
      80                 :            :         "#include <string.h>\n"
      81                 :            :         "static size_t %snot_found = (size_t)-1;\n"
      82                 :            :         "#define __%sidentity(n) (n)\n",
      83                 :            :         nsc, nsc);
      84                 :         10 :     fprintf(out->fp,
      85                 :            :         "/* Subtraction doesn't work for unsigned types. */\n"
      86                 :            :         "#define __%sscalar_cmp(x, y, n) ((x) < (y) ? -1 : (x) > (y))\n"
      87                 :            :         "static inline int __%sstring_n_cmp(%sstring_t v, const char *s, size_t n)\n"
      88                 :            :         "{ size_t nv = %sstring_len(v); int x = strncmp(v, s, nv < n ? nv : n);\n"
      89                 :            :         "  return x != 0 ? x : nv < n ? -1 : nv > n; }\n"
      90                 :            :         "/* `n` arg unused, but needed by string find macro expansion. */\n"
      91                 :            :         "static inline int __%sstring_cmp(%sstring_t v, const char *s, size_t n) { (void)n; return strcmp(v, s); }\n",
      92                 :            :         nsc, nsc, nsc, nsc, nsc, nsc);
      93                 :         10 :     fprintf(out->fp,
      94                 :            :         "/* A = identity if searching scalar vectors rather than key fields. */\n"
      95                 :            :         "/* Returns lowest matching index not_found. */\n"
      96                 :            :         "#define __%sfind_by_field(A, V, E, L, K, Kn, T, D)\\\n"
      97                 :            :         "{ T v; size_t a = 0, b, m; if (!(b = L(V))) { return %snot_found; }\\\n"
      98                 :            :         "  --b;\\\n"
      99                 :            :         "  while (a < b) {\\\n"
     100                 :            :         "    m = a + ((b - a) >> 1);\\\n"
     101                 :            :         "    v = A(E(V, m));\\\n"
     102                 :            :         "    if ((D(v, (K), (Kn))) < 0) {\\\n"
     103                 :            :         "      a = m + 1;\\\n"
     104                 :            :         "    } else {\\\n"
     105                 :            :         "      b = m;\\\n"
     106                 :            :         "    }\\\n"
     107                 :            :         "  }\\\n"
     108                 :            :         "  if (a == b) {\\\n"
     109                 :            :         "    v = A(E(V, a));\\\n"
     110                 :            :         "    if (D(v, (K), (Kn)) == 0) {\\\n"
     111                 :            :         "       return a;\\\n"
     112                 :            :         "    }\\\n"
     113                 :            :         "  }\\\n"
     114                 :            :         "  return %snot_found;\\\n"
     115                 :            :         "}\n",
     116                 :            :         nsc, nsc, nsc);
     117                 :         10 :     fprintf(out->fp,
     118                 :            :         "#define __%sfind_by_scalar_field(A, V, E, L, K, T)\\\n"
     119                 :            :         "__%sfind_by_field(A, V, E, L, K, 0, T, __%sscalar_cmp)\n"
     120                 :            :         "#define __%sfind_by_string_field(A, V, E, L, K)\\\n"
     121                 :            :         "__%sfind_by_field(A, V, E, L, K, 0, %sstring_t, __%sstring_cmp)\n"
     122                 :            :         "#define __%sfind_by_string_n_field(A, V, E, L, K, Kn)\\\n"
     123                 :            :         "__%sfind_by_field(A, V, E, L, K, Kn, %sstring_t, __%sstring_n_cmp)\n",
     124                 :            :         nsc, nsc, nsc, nsc, nsc,
     125                 :            :         nsc, nsc, nsc, nsc, nsc, nsc);
     126                 :         10 :     fprintf(out->fp,
     127                 :            :         "#define __%sdefine_find_by_scalar_field(N, NK, TK)\\\n"
     128                 :            :         "static inline size_t N ## _vec_find_by_ ## NK(N ## _vec_t vec, TK key)\\\n"
     129                 :            :         "__%sfind_by_scalar_field(N ## _ ## NK, vec, N ## _vec_at, N ## _vec_len, key, TK)\n",
     130                 :            :         nsc, nsc);
     131                 :         10 :     fprintf(out->fp,
     132                 :            :         "#define __%sdefine_scalar_find(N, T)\\\n"
     133                 :            :         "static inline size_t N ## _vec_find(N ## _vec_t vec, T key)\\\n"
     134                 :            :         "__%sfind_by_scalar_field(__%sidentity, vec, N ## _vec_at, N ## _vec_len, key, T)\n",
     135                 :            :         nsc, nsc, nsc);
     136                 :         10 : }
     137                 :            : 
     138                 :         10 : static void gen_helpers(fb_output_t *out)
     139                 :            : {
     140                 :         10 :     const char *nsc = out->nsc;
     141                 :            : 
     142                 :         10 :     fprintf(out->fp,
     143                 :            :         /*
     144                 :            :          * Include the basic primitives for accessing flatbuffer datatypes independent
     145                 :            :          * of endianness.
     146                 :            :          *
     147                 :            :          * The included file must define the basic types and accessors
     148                 :            :          * prefixed with the common namespace which by default is
     149                 :            :          * "flatbuffers_".
     150                 :            :          */
     151                 :            :         "#include \"flatcc/flatcc_flatbuffers.h\"\n"
     152                 :            :         "\n\n");
     153                 :            :     /*
     154                 :            :      * The remapping of basic types to the common namespace makes it
     155                 :            :      * possible to have different definitions. The generic
     156                 :            :      * `flatbuffers_uoffset_t` etc. cannot be trusted to have one specific
     157                 :            :      * size since it depends on the included `flatcc/flatcc_types.h`
     158                 :            :      * filer, but the namespace prefixed types can be trusted if used carefully.
     159                 :            :      * For example the common namespace could be `flatbuffers_large_`
     160                 :            :      * when allowing for 64 bit offsets.
     161                 :            :      */
     162         [ -  + ]:         10 :     if (strcmp(nsc, "flatbuffers_")) {
     163                 :          0 :         fprintf(out->fp,
     164                 :            :                 "typedef flatbuffers_uoffset_t %suoffset_t;\n"
     165                 :            :                 "typedef flatbuffers_soffset_t %ssoffset_t;\n"
     166                 :            :                 "typedef flatbuffers_voffset_t %svoffset_t;\n"
     167                 :            :                 "typedef flatbuffers_utype_t %sutype_t;\n"
     168                 :            :                 "typedef flatbuffers_bool_t %sbool_t;\n"
     169                 :            :                 "\n",
     170                 :            :                 nsc, nsc, nsc, nsc, nsc);
     171                 :          0 :         fprintf(out->fp,
     172                 :            :                 "#define %sendian flatbuffers_endian\n"
     173                 :            :                 "__flatcc_define_basic_scalar_accessors(%s, flatbuffers_endian)"
     174                 :            :                 "__flatcc_define_integer_accessors(%sbool, flatbuffers_bool_t,\\\n"
     175                 :            :                 "        FLATBUFFERS_BOOL_WIDTH, flatbuffers_endian)\n",
     176                 :            :                 nsc, nsc, nsc);
     177                 :          0 :         fprintf(out->fp,
     178                 :            :                 "__flatcc_define_integer_accessors(__%suoffset, flatbuffers_uoffset_t,\n"
     179                 :            :                 "        FLATBUFFERS_UOFFSET_WIDTH, flatbuffers_endian)\n"
     180                 :            :                 "__flatcc_define_integer_accessors(__%ssoffset, flatbuffers_soffset_t,\n"
     181                 :            :                 "        FLATBUFFERS_SOFFSET_WIDTH, flatbuffers_endian)\n"
     182                 :            :                 "__flatcc_define_integer_accessors(__%svoffset, flatbuffers_voffset_t,\n"
     183                 :            :                 "        FLATBUFFERS_VOFFSET_WIDTH, flatbuffers_endian)\n"
     184                 :            :                 "__flatcc_define_integer_accessors(__%sutype, flatbuffers_utype_t,\n"
     185                 :            :                 "        FLATBUFFERS_UTYPE_WIDTH, flatbuffers_endian)\n"
     186                 :            :                 "__flatcc_define_integer_accessors(__%sthash, flatbuffers_thash_t,\n"
     187                 :            :                 "        FLATBUFFERS_THASH_WIDTH, flatbuffers_endian)\n",
     188                 :            :                 nsc, nsc, nsc, nsc, nsc);
     189                 :          0 :         fprintf(out->fp,
     190                 :            :                 "#ifndef %s_WRAP_NAMESPACE\n"
     191                 :            :                 "#define %s_WRAP_NAMESPACE(ns, x) ns ## _ ## x\n"
     192                 :            :                 "#endif\n",
     193                 :          0 :                 out->nscup, out->nscup);
     194                 :            :     }
     195                 :            :     /* Build out a more elaborate type system based in the primitives included. */
     196                 :         10 :     fprintf(out->fp,
     197                 :            :         "#define __%sread_scalar_at_byteoffset(N, p, o) N ## _read_from_pe((uint8_t *)(p) + (o))\n"
     198                 :            :         "#define __%sread_scalar(N, p) N ## _read_from_pe(p)\n",
     199                 :            :         nsc, nsc);
     200                 :         10 :     fprintf(out->fp,
     201                 :            :         "#define __%sread_vt(ID, offset, t)\\\n"
     202                 :            :         "%svoffset_t offset = 0;\\\n"
     203                 :            :         "{   %svoffset_t id, *vt;\\\n"
     204                 :            :         "    assert(t != 0 && \"null pointer table access\");\\\n"
     205                 :            :         "    id = ID;\\\n"
     206                 :            :         "    vt = (%svoffset_t *)((uint8_t *)(t) -\\\n"
     207                 :            :         "        __%ssoffset_read_from_pe(t));\\\n"
     208                 :            :         "    if (__%svoffset_read_from_pe(vt) >= sizeof(vt[0]) * (id + 3)) {\\\n"
     209                 :            :         "        offset = __%svoffset_read_from_pe(vt + id + 2);\\\n"
     210                 :            :         "    }\\\n"
     211                 :            :         "}\n",
     212                 :            :         nsc, nsc, nsc, nsc, nsc, nsc, nsc);
     213                 :         10 :     fprintf(out->fp,
     214                 :            :             "#define __%sfield_present(ID, t) { __%sread_vt(ID, offset, t) return offset != 0; }\n",
     215                 :            :             nsc, nsc);
     216                 :         10 :     fprintf(out->fp,
     217                 :            :         "#define __%sscalar_field(N, ID, V, t)\\\n"
     218                 :            :         "{\\\n"
     219                 :            :         "    __%sread_vt(ID, offset, t)\\\n"
     220                 :            :         "    return offset ? __%sread_scalar_at_byteoffset(N, t, offset) : V;\\\n"
     221                 :            :         "}\n",
     222                 :            :         nsc, nsc, nsc);
     223                 :         10 :     fprintf(out->fp,
     224                 :            :         "#define __%sstruct_field(T, ID, t, r)\\\n"
     225                 :            :         "{\\\n"
     226                 :            :         "    __%sread_vt(ID, offset, t)\\\n"
     227                 :            :         "    if (offset) {\\\n"
     228                 :            :         "        return (T)((uint8_t *)(t) + offset);\\\n"
     229                 :            :         "    }\\\n"
     230                 :            :         "    assert(!(r) && \"required field missing\");\\\n"
     231                 :            :         "    return 0;\\\n"
     232                 :            :         "}\n",
     233                 :            :         nsc, nsc);
     234                 :         10 :     fprintf(out->fp,
     235                 :            :         "#define __%soffset_field(T, ID, t, r, adjust)\\\n"
     236                 :            :         "{\\\n"
     237                 :            :         "    %suoffset_t *elem;\\\n"
     238                 :            :         "    __%sread_vt(ID, offset, t)\\\n"
     239                 :            :         "    if (offset) {\\\n"
     240                 :            :         "        elem = (%suoffset_t *)((uint8_t *)(t) + offset);\\\n"
     241                 :            :         "        /* Add sizeof so C api can have raw access past header field. */\\\n"
     242                 :            :         "        return (T)((uint8_t *)(elem) + adjust +\\\n"
     243                 :            :         "              __%suoffset_read_from_pe(elem));\\\n"
     244                 :            :         "    }\\\n"
     245                 :            :         "    assert(!(r) && \"required field missing\");\\\n"
     246                 :            :         "    return 0;\\\n"
     247                 :            :         "}\n",
     248                 :            :         nsc, nsc, nsc, nsc, nsc);
     249                 :         10 :     fprintf(out->fp,
     250                 :            :         "#define __%svector_field(T, ID, t, r) __%soffset_field(T, ID, t, r, sizeof(%suoffset_t))\n"
     251                 :            :         "#define __%stable_field(T, ID, t, r) __%soffset_field(T, ID, t, r, 0)\n",
     252                 :            :         nsc, nsc, nsc, nsc, nsc);
     253                 :         10 :     fprintf(out->fp,
     254                 :            :         "#define __%svec_len(vec)\\\n"
     255                 :            :         "{ return (vec) ? (size_t)__%suoffset_read_from_pe((flatbuffers_uoffset_t *)vec - 1) : 0; }\n"
     256                 :            :         "#define __%sstring_len(s) __%svec_len(s)\n",
     257                 :            :         nsc, nsc, nsc, nsc);
     258                 :         10 :     fprintf(out->fp,
     259                 :            :         "static inline size_t %svec_len(const void *vec)\n"
     260                 :            :         "__%svec_len(vec)\n",
     261                 :            :         nsc, nsc);
     262                 :         10 :     fprintf(out->fp,
     263                 :            :         /* Tb is the base type for loads. */
     264                 :            :         "#define __%sscalar_vec_at(N, vec, i)\\\n"
     265                 :            :         "{ assert(%svec_len(vec) > (i) && \"index out of range\");\\\n"
     266                 :            :         "  return __%sread_scalar(N, &(vec)[i]); }\n",
     267                 :            :         nsc, nsc, nsc);
     268                 :         10 :     fprintf(out->fp,
     269                 :            :         "#define __%sstruct_vec_at(vec, i)\\\n"
     270                 :            :         "{ assert(%svec_len(vec) > (i) && \"index out of range\"); return (vec) + (i); }\n",
     271                 :            :         nsc, nsc);
     272                 :         10 :     fprintf(out->fp,
     273                 :            :         "/* `adjust` skips past the header for string vectors. */\n"
     274                 :            :         "#define __%soffset_vec_at(T, vec, i, adjust)\\\n"
     275                 :            :         "{ const %suoffset_t *elem = (vec) + (i);\\\n"
     276                 :            :         "  assert(%svec_len(vec) > (i) && \"index out of range\");\\\n"
     277                 :            :         "  return (T)((uint8_t *)(elem) + (size_t)__%suoffset_read_from_pe(elem) + adjust); }\n",
     278                 :            :         nsc, nsc, nsc, nsc);
     279                 :         10 :     fprintf(out->fp,
     280                 :            :             "#define __%sdefine_scalar_vec_len(N) \\\n"
     281                 :            :             "static inline size_t N ## _vec_len(N ##_vec_t vec)\\\n"
     282                 :            :             "{ return %svec_len(vec); }\n",
     283                 :            :             nsc, nsc);
     284                 :         10 :     fprintf(out->fp,
     285                 :            :             "#define __%sdefine_scalar_vec_at(N, T) \\\n"
     286                 :            :             "static inline T N ## _vec_at(N ## _vec_t vec, size_t i)\\\n"
     287                 :            :             "__%sscalar_vec_at(N, vec, i)\n",
     288                 :            :             nsc, nsc);
     289                 :         10 :     fprintf(out->fp,
     290                 :            :             "typedef const char *%sstring_t;\n"
     291                 :            :             "static inline size_t %sstring_len(%sstring_t s)\n"
     292                 :            :             "__%sstring_len(s)\n",
     293                 :            :             nsc, nsc, nsc, nsc);
     294                 :         10 :     fprintf(out->fp,
     295                 :            :             "typedef const %suoffset_t *%sstring_vec_t;\n"
     296                 :            :             "typedef %suoffset_t *%sstring_mutable_vec_t;\n"
     297                 :            :             "static inline size_t %sstring_vec_len(%sstring_vec_t vec)\n"
     298                 :            :             "__%svec_len(vec)\n"
     299                 :            :             "static inline %sstring_t %sstring_vec_at(%sstring_vec_t vec, size_t i)\n"
     300                 :            :             "__%soffset_vec_at(%sstring_t, vec, i, sizeof(vec[0]))\n",
     301                 :            :             nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
     302                 :         10 :     fprintf(out->fp,
     303                 :            :             "typedef const void *%sgeneric_table_t;\n",
     304                 :            :             nsc);
     305                 :         10 :     gen_find(out);
     306         [ +  - ]:         10 :     if (out->opts->cgen_sort) {
     307                 :         10 :         gen_sort(out);
     308                 :            :     } else {
     309                 :          0 :         fprintf(out->fp, "/* sort disabled */\n");
     310                 :            :     }
     311                 :         10 :     fprintf(out->fp,
     312                 :            :             "#define __%sdefine_scalar_vector(N, T)\\\n"
     313                 :            :             "typedef const T *N ## _vec_t;\\\n"
     314                 :            :             "typedef T *N ## _mutable_vec_t;\\\n"
     315                 :            :             "__%sdefine_scalar_vec_len(N)\\\n"
     316                 :            :             "__%sdefine_scalar_vec_at(N, T)\\\n"
     317                 :            :             "__%sdefine_scalar_find(N, T)\\\n",
     318                 :            :             nsc, nsc, nsc, nsc);
     319         [ +  - ]:         10 :     if (out->opts->cgen_sort) {
     320                 :         10 :         fprintf(out->fp, "\\\n__%sdefine_scalar_sort(N, T)\n", nsc);
     321                 :            :     }
     322                 :         10 :     fprintf(out->fp, "\n");
     323                 :            :     /* Elaborate on the included basic type system. */
     324                 :         10 :     fprintf(out->fp,
     325                 :            :             "#define __%sdefine_integer_type(N, T, W)\\\n"
     326                 :            :             "__flatcc_define_integer_accessors(N, T, W, %sendian)\\\n"
     327                 :            :             "__%sdefine_scalar_vector(N, T)\n",
     328                 :            :             nsc, nsc, nsc);
     329                 :         10 :     fprintf(out->fp,
     330                 :            :             "__%sdefine_scalar_vector(%sbool, %sbool_t)\n"
     331                 :            :             "__%sdefine_scalar_vector(%suint8, uint8_t)\n"
     332                 :            :             "__%sdefine_scalar_vector(%sint8, int8_t)\n"
     333                 :            :             "__%sdefine_scalar_vector(%suint16, uint16_t)\n"
     334                 :            :             "__%sdefine_scalar_vector(%sint16, int16_t)\n"
     335                 :            :             "__%sdefine_scalar_vector(%suint32, uint32_t)\n"
     336                 :            :             "__%sdefine_scalar_vector(%sint32, int32_t)\n"
     337                 :            :             "__%sdefine_scalar_vector(%suint64, uint64_t)\n"
     338                 :            :             "__%sdefine_scalar_vector(%sint64, int64_t)\n"
     339                 :            :             "__%sdefine_scalar_vector(%sfloat, float)\n"
     340                 :            :             "__%sdefine_scalar_vector(%sdouble, double)\n",
     341                 :            :             nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc,
     342                 :            :             nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
     343                 :         10 :     fprintf(out->fp,
     344                 :            :             "static inline size_t %sstring_vec_find(%sstring_vec_t vec, const char *s)\n"
     345                 :            :             "__%sfind_by_string_field(__%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s)\n"
     346                 :            :             "static inline size_t %sstring_vec_find_n(%sstring_vec_t vec, const char *s, size_t n)\n"
     347                 :            :             "__%sfind_by_string_n_field(__%sidentity, vec, %sstring_vec_at, %sstring_vec_len, s, n)\n",
     348                 :            :             nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
     349         [ +  - ]:         10 :     if (out->opts->cgen_sort) {
     350                 :         10 :         fprintf(out->fp, "__%sdefine_string_sort()\n", nsc);
     351                 :            :     }
     352                 :         10 :     fprintf(out->fp,
     353                 :            :             "#define __%sstruct_scalar_field(t, M, N)\\\n"
     354                 :            :             "{ return t ? __%sread_scalar(N, &(t->M)) : 0; }\n"
     355                 :            :             "#define __%sstruct_struct_field(t, M) { return t ? &(t->M) : 0; }\n",
     356                 :            :             nsc, nsc, nsc);
     357                 :         10 :     fprintf(out->fp,
     358                 :            :             "/* If fid is null, the function returns true without testing as buffer is not expected to have any id. */\n"
     359                 :            :             "static inline int %shas_identifier(const void *buffer, const char *fid)\n"
     360                 :            :             "{ %sthash_t id, id2 = 0; if (fid == 0) { return 1; };\n"
     361                 :            :             "  strncpy((char *)&id2, fid, sizeof(id2));\n"
     362                 :            :             "  /* Identifier strings are always considered little endian. */\n"
     363                 :            :             "  id2 = __%sthash_cast_from_le(id2);\n"
     364                 :            :             "  id = __%sthash_read_from_pe(((%suoffset_t *)buffer) + 1);\n"
     365                 :            :             "  return id2 == 0 || id == id2; }\n"
     366                 :            :             "static inline int %shas_type_hash(const void *buffer, %sthash_t thash)\n"
     367                 :            :             "{ return thash == 0 || (__%sthash_read_from_pe((%suoffset_t *)buffer + 1) == thash); }\n\n"
     368                 :            :             "static inline %sthash_t %sget_type_hash(const void *buffer)\n"
     369                 :            :             "{ return __%sthash_read_from_pe((flatbuffers_uoffset_t *)buffer + 1); }\n\n"
     370                 :            :             "#define %sverify_endian() %shas_identifier(\"\\x00\\x00\\x00\\x00\" \"1234\", \"1234\")\n",
     371                 :            :             nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
     372                 :         10 :     fprintf(out->fp,
     373                 :            :             "static inline void *%sread_size_prefix(void *b, size_t *size_out)\n"
     374                 :            :             "{ if (size_out) { *size_out = (size_t)__%suoffset_read_from_pe(b); }\n"
     375                 :            :             "  return (uint8_t *)b + sizeof(%suoffset_t); }\n", nsc, nsc, nsc);
     376                 :         10 :     fprintf(out->fp,
     377                 :            :             "/* Null file identifier accepts anything, otherwise fid should be 4 characters. */\n"
     378                 :            :             "#define __%sread_root(T, K, buffer, fid)\\\n"
     379                 :            :             "  ((!buffer || !%shas_identifier(buffer, fid)) ? 0 :\\\n"
     380                 :            :             "  ((T ## _ ## K ## t)(((uint8_t *)buffer) +\\\n"
     381                 :            :             "    __%suoffset_read_from_pe(buffer))))\n"
     382                 :            :             "#define __%sread_typed_root(T, K, buffer, thash)\\\n"
     383                 :            :             "  ((!buffer || !%shas_type_hash(buffer, thash)) ? 0 :\\\n"
     384                 :            :             "  ((T ## _ ## K ## t)(((uint8_t *)buffer) +\\\n"
     385                 :            :             "    __%suoffset_read_from_pe(buffer))))\n",
     386                 :            :             nsc, nsc, nsc, nsc, nsc, nsc);
     387                 :         10 :     fprintf(out->fp,
     388                 :            :             "#define __%snested_buffer_as_root(C, N, T, K)\\\n"
     389                 :            :             "static inline T ## _ ## K ## t C ## _ ## N ## _as_root_with_identifier(C ## _ ## table_t t, const char *fid)\\\n"
     390                 :            :             "{ const uint8_t *buffer = C ## _ ## N(t); return __%sread_root(T, K, buffer, fid); }\\\n"
     391                 :            :             "static inline T ## _ ## K ## t C ## _ ## N ## _as_typed_root(C ## _ ## table_t t)\\\n"
     392                 :            :             "{ const uint8_t *buffer = C ## _ ## N(t); return __%sread_root(T, K, buffer, C ## _ ## type_identifier); }\\\n"
     393                 :            :             "static inline T ## _ ## K ## t C ## _ ## N ## _as_root(C ## _ ## table_t t)\\\n"
     394                 :            :             "{ const char *fid = T ## _identifier;\\\n"
     395                 :            :             "  const uint8_t *buffer = C ## _ ## N(t); return __%sread_root(T, K, buffer, fid); }\n",
     396                 :            :             nsc, nsc, nsc, nsc);
     397                 :         10 :     fprintf(out->fp,
     398                 :            :             "#define __%sbuffer_as_root(N, K)\\\n"
     399                 :            :             "static inline N ## _ ## K ## t N ## _as_root_with_identifier(const void *buffer, const char *fid)\\\n"
     400                 :            :             "{ return __%sread_root(N, K, buffer, fid); }\\\n"
     401                 :            :             "static inline N ## _ ## K ## t N ## _as_root_with_type_hash(const void *buffer, %sthash_t thash)\\\n"
     402                 :            :             "{ return __%sread_typed_root(N, K, buffer, thash); }\\\n"
     403                 :            :             "static inline N ## _ ## K ## t N ## _as_root(const void *buffer)\\\n"
     404                 :            :             "{ const char *fid = N ## _identifier;\\\n"
     405                 :            :             "  return __%sread_root(N, K, buffer, fid); }\\\n"
     406                 :            :             "static inline N ## _ ## K ## t N ## _as_typed_root(const void *buffer)\\\n"
     407                 :            :             "{ return __%sread_typed_root(N, K, buffer, N ## _type_hash); }\n"
     408                 :            :             "#define __%sstruct_as_root(N) __%sbuffer_as_root(N, struct_)\n"
     409                 :            :             "#define __%stable_as_root(N) __%sbuffer_as_root(N, table_)\n",
     410                 :            :             nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc, nsc);
     411                 :         10 :     fprintf(out->fp, "\n");
     412                 :         10 : }
     413                 :            : 
     414                 :         10 : int fb_gen_common_c_header(fb_output_t *out)
     415                 :            : {
     416                 :         10 :     const char *nscup = out->nscup;
     417                 :            : 
     418                 :         10 :     fprintf(out->fp,
     419                 :            :         "#ifndef %s_COMMON_READER_H\n"
     420                 :            :         "#define %s_COMMON_READER_H\n",
     421                 :            :         nscup, nscup);
     422                 :         10 :     fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n");
     423                 :         10 :     fprintf(out->fp, "/* Common FlatBuffers read functionality for C. */\n\n");
     424         [ -  + ]:         10 :     if (!out->opts->cgen_sort) {
     425                 :          0 :         fprintf(out->fp,
     426                 :            :                 "/*"
     427                 :            :                 " * This code is generated without support for vector sort operations\n"
     428                 :            :                 " * but find operations are supported on pre-sorted vectors.\n"
     429                 :            :                 " */\n");
     430                 :            :     }
     431                 :            :     gen_pragma_push(out);
     432                 :         10 :     gen_helpers(out);
     433                 :            :     gen_pragma_pop(out);
     434                 :         10 :     fprintf(out->fp,
     435                 :            :         "#endif /* %s_COMMON_H */\n",
     436                 :            :         nscup);
     437                 :         10 :     return 0;
     438                 :            : }
     439                 :            : 
     440                 :         24 : static void gen_pretext(fb_output_t *out)
     441                 :            : {
     442                 :         24 :     const char *nsc = out->nsc;
     443                 :         24 :     const char *nscup = out->nscup;
     444                 :            : 
     445                 :         24 :     int do_pad = out->opts->cgen_pad;
     446                 :            : 
     447                 :         24 :     fprintf(out->fp,
     448                 :            :         "#ifndef %s_READER_H\n"
     449                 :            :         "#define %s_READER_H\n",
     450                 :         24 :         out->S->basenameup, out->S->basenameup);
     451                 :            : 
     452                 :         24 :     fprintf(out->fp, "\n/* " FLATCC_GENERATED_BY " */\n\n");
     453         [ -  + ]:         24 :     if (do_pad) {
     454                 :          0 :         fprintf(out->fp,
     455                 :            :         "/*\n"
     456                 :            :         " * Generated with 'pad' option which expects #pragma pack(1) and\n"
     457                 :            :         " * #pragma pack() to be supported, and which adds extra padding\n"
     458                 :            :         " * fields to structs.\n"
     459                 :            :         " *\n"
     460                 :            :         " * This is mostly relevant for some micro controller platforms, but\n"
     461                 :            :         " * may also be needed with 'force_align' attributes > 16.\n"
     462                 :            :         " *\n"
     463                 :            :         " * The default output uses C11 <stdalign.h> alignas(n) which can be\n"
     464                 :            :         " * defined as `__attribute__((aligned (n)))` or similar on many\n"
     465                 :            :         " * older platforms.\n"
     466                 :            :         " */\n"
     467                 :            :         "\n");
     468                 :            :     }
     469                 :            : 
     470                 :         24 :     fprintf(out->fp,
     471                 :            :             "#ifndef %s_COMMON_READER_H\n"
     472                 :            :             "#include \"%scommon_reader.h\"\n"
     473                 :            :             "#endif\n",
     474                 :            :             nscup, nsc);
     475                 :         24 :     fb_gen_c_includes(out, "_reader.h", "_READER_H");
     476                 :            : 
     477         [ +  - ]:         24 :     if (!do_pad) {
     478                 :         24 :         fprintf(out->fp,
     479                 :            :                 "#ifndef alignas\n"
     480                 :            :                 "#include <stdalign.h>\n"
     481                 :            :                 "#endif\n");
     482                 :            :     }
     483                 :            :     gen_pragma_push(out);
     484         [ +  + ]:         24 :     if (out->S->file_identifier.type == vt_string) {
     485                 :          8 :         fprintf(out->fp,
     486                 :            :             "#undef %sidentifier\n"
     487                 :            :             "#define %sidentifier \"%.*s\"\n",
     488                 :            :             nsc,
     489                 :            :             nsc, out->S->file_identifier.s.len, out->S->file_identifier.s.s);
     490                 :            :     } else {
     491                 :         16 :         fprintf(out->fp,
     492                 :            :             "#ifndef %sidentifier\n"
     493                 :            :             "#define %sidentifier 0\n"
     494                 :            :             "#endif\n",
     495                 :            :             nsc, nsc);
     496                 :            :     }
     497         [ +  + ]:         24 :     if (out->S->file_extension.type == vt_string) {
     498                 :          8 :         fprintf(out->fp,
     499                 :            :             "#undef %sextension\n"
     500                 :            :             "#define %sextension \".%.*s\"\n",
     501                 :            :             nsc,
     502                 :            :             nsc, out->S->file_extension.s.len, out->S->file_extension.s.s);
     503                 :            :     } else {
     504                 :         16 :         fprintf(out->fp,
     505                 :            :             /* Configured extensions include dot, schema does not. */
     506                 :            :             "#ifndef %sextension\n"
     507                 :            :             "#define %sextension \"%s\"\n"
     508                 :            :             "#endif\n",
     509                 :         16 :             nsc, nsc, out->opts->default_bin_ext);
     510                 :            :     }
     511                 :         24 :     fprintf(out->fp, "\n");
     512                 :         24 : }
     513                 :            : 
     514                 :         24 : static void gen_footer(fb_output_t *out)
     515                 :            : {
     516                 :            :     gen_pragma_pop(out);
     517                 :         24 :     fprintf(out->fp, "#endif /* %s_READER_H */\n", out->S->basenameup);
     518                 :         24 : }
     519                 :            : 
     520                 :        105 : static void gen_forward_decl(fb_output_t *out, fb_compound_type_t *ct)
     521                 :            : {
     522                 :            :     fb_scoped_name_t snt;
     523                 :        105 :     const char *nsc = out->nsc;
     524                 :            : 
     525                 :        105 :     fb_clear(snt);
     526                 :            : 
     527                 :            :     assert(ct->symbol.kind == fb_is_struct || ct->symbol.kind == fb_is_table);
     528                 :            : 
     529                 :            :     fb_compound_name(ct, &snt);
     530         [ +  + ]:        105 :     if (ct->symbol.kind == fb_is_struct) {
     531         [ +  + ]:         42 :         if (ct->size == 0) {
     532                 :         21 :             fprintf(out->fp, "typedef void %s_t; /* empty struct */\n",
     533                 :            :                     snt.text);
     534                 :            :         } else {
     535                 :         21 :             fprintf(out->fp, "typedef struct %s %s_t;\n",
     536                 :            :                     snt.text, snt.text);
     537                 :            :         }
     538                 :         42 :         fprintf(out->fp, "typedef const %s_t *%s_struct_t;\n",
     539                 :            :                 snt.text, snt.text);
     540                 :         42 :         fprintf(out->fp, "typedef %s_t *%s_mutable_struct_t;\n",
     541                 :            :                 snt.text, snt.text);
     542                 :         42 :         fprintf(out->fp, "typedef const %s_t *%s_vec_t;\n",
     543                 :            :                 snt.text, snt.text);
     544                 :         42 :         fprintf(out->fp, "typedef %s_t *%s_mutable_vec_t;\n",
     545                 :            :                 snt.text, snt.text);
     546                 :            :     } else {
     547                 :         63 :         fprintf(out->fp, "typedef const struct %s_table *%s_table_t;\n",
     548                 :            :                 snt.text, snt.text);
     549                 :         63 :         fprintf(out->fp, "typedef const %suoffset_t *%s_vec_t;\n", nsc, snt.text);
     550                 :         63 :         fprintf(out->fp, "typedef %suoffset_t *%s_mutable_vec_t;\n", nsc, snt.text);
     551                 :            :     }
     552                 :        105 : }
     553                 :            : 
     554                 :       1306 : static inline void print_doc(fb_output_t *out, const char *indent, fb_doc_t *doc)
     555                 :            : {
     556                 :            :     long ln = 0;
     557                 :            :     int first = 1;
     558         [ +  + ]:        653 :     if (doc == 0) {
     559                 :            :         return;
     560                 :            :     }
     561         [ +  + ]:         58 :     while (doc) {
     562         [ +  + ]:         45 :         if (ln != doc->ident->linenum) {
     563         [ +  + ]:         23 :             if (first) {
     564                 :            :                 /* Not all C compilers understand // comments. */
     565                 :         13 :                 fprintf(out->fp, "%s/**", indent);
     566                 :            :                 ln = doc->ident->linenum;
     567                 :            :             } else {
     568                 :         10 :                 fprintf(out->fp, "\n%s * ", indent);
     569                 :            :             }
     570                 :            :         }
     571                 :            :         first = 0;
     572                 :         45 :         fprintf(out->fp, "%.*s", (int)doc->ident->len, doc->ident->text);
     573                 :         45 :         ln = doc->ident->linenum;
     574                 :         45 :         doc = doc->link;
     575                 :            :     }
     576                 :         13 :     fprintf(out->fp, " */\n");
     577                 :            : }
     578                 :            : 
     579                 :         42 : static void gen_struct(fb_output_t *out, fb_compound_type_t *ct)
     580                 :            : {
     581                 :            :     fb_member_t *member;
     582                 :            :     fb_symbol_t *sym;
     583                 :            :     unsigned align;
     584                 :            :     size_t offset = 0;
     585                 :            :     const char *tname, *tname_ns, *tname_prefix;
     586                 :            :     int n;
     587                 :            :     const char *s;
     588                 :            :     unsigned pad_index = 0, deprecated_index = 0, pad;
     589                 :            :     const char *kind;
     590                 :         42 :     int do_pad = out->opts->cgen_pad;
     591                 :            :     int current_key_processed, already_has_key;
     592                 :         42 :     const char *nsc = out->nsc;
     593                 :            : 
     594                 :            :     fb_scoped_name_t snt;
     595                 :            :     fb_scoped_name_t snref;
     596                 :            : 
     597                 :         42 :     fb_clear(snt);
     598                 :         42 :     fb_clear(snref);
     599                 :            : 
     600                 :            :     assert(ct->symbol.kind == fb_is_struct);
     601                 :            :     assert(ct->align > 0 || ct->count == 0);
     602                 :            :     assert(ct->size > 0 || ct->count == 0);
     603                 :            : 
     604                 :            :     fb_compound_name(ct, &snt);
     605                 :         42 :     print_doc(out, "", ct->doc);
     606         [ +  + ]:         42 :     if (ct->size == 0) {
     607                 :            :         /*
     608                 :            :          * This implies that sizeof(typename) is not valid, where
     609                 :            :          * non-std gcc extension might return 0, or 1 of an empty
     610                 :            :          * struct. All copy_from/to etc. operations on this type
     611                 :            :          * just returns a pointer without using sizeof.
     612                 :            :          *
     613                 :            :          * We ought to define size as a define so it can be used in a
     614                 :            :          * switch, but that does not mesth with flatcc_accessors.h
     615                 :            :          * macros, so we use an inline function. Users would normally
     616                 :            :          * use sizeof which will break for empty which is ok, and
     617                 :            :          * internal operations can use size() where generic behavior is
     618                 :            :          * required.
     619                 :            :          */
     620                 :         21 :         fprintf(out->fp, "/* empty struct already typedef'ed as void since this not permitted in std. C: struct %s {}; */\n", snt.text);
     621                 :         21 :         fprintf(out->fp,
     622                 :            :                 "static inline const %s_t *%s__const_ptr_add(const %s_t *p, size_t i) { return p; }\n", snt.text, snt.text, snt.text);
     623                 :         21 :         fprintf(out->fp,
     624                 :            :                 "static inline %s_t *%s__ptr_add(%s_t *p, size_t i) { return p; }\n", snt.text, snt.text, snt.text);
     625                 :         21 :         fprintf(out->fp,
     626                 :            :                 "static inline %s_struct_t %s_vec_at(%s_vec_t vec, size_t i) { return vec; }\n", snt.text, snt.text, snt.text);
     627                 :            :     } else {
     628         [ -  + ]:         21 :         if (do_pad) {
     629                 :          0 :             fprintf(out->fp, "#pragma pack(1)\n");
     630                 :            :         }
     631                 :            :         /*
     632                 :            :          * Unfortunately the following is not valid in C11:
     633                 :            :          *
     634                 :            :          *      struct alignas(4) mystruct { ... };
     635                 :            :          *
     636                 :            :          * we can only use alignas on members (unlike C++, and unlike
     637                 :            :          * non-portable C compiler variants).
     638                 :            :          *
     639                 :            :          * By padding the first element to the struct size we get around
     640                 :            :          * this problem. It shouldn't strictly be necessary to add padding
     641                 :            :          * fields, but compilers might not support padding above 16 bytes,
     642                 :            :          * so we do that as a precaution with an optional compiler flag.
     643                 :            :          *
     644                 :            :          * It is unclear how to align empty structs without padding but it
     645                 :            :          * shouldn't really matter since not field is accessed then.
     646                 :            :          */
     647                 :         21 :         fprintf(out->fp, "struct %s {\n", snt.text);
     648                 :            :         already_has_key = 0;
     649         [ +  + ]:         95 :         for (sym = ct->members; sym; sym = sym->link) {
     650                 :            :             current_key_processed = 0;
     651                 :            :             member = (fb_member_t *)sym;
     652                 :         74 :             print_doc(out, "    ", member->doc);
     653                 :            :             symbol_name(sym, &n, &s);
     654         [ +  + ]:         74 :             align = offset == 0 ? ct->align : member->align;
     655 [ -  + ][ #  # ]:         74 :             if (do_pad && (pad = (unsigned)(member->offset - offset))) {
     656                 :          0 :                 fprintf(out->fp, "    uint8_t __padding%u[%u];\n",
     657                 :            :                         pad_index++, pad);
     658                 :            :             }
     659         [ +  + ]:         74 :             if (member->metadata_flags & fb_f_deprecated) {
     660                 :          1 :                 pad = (unsigned)member->size;
     661         [ -  + ]:          1 :                 if (do_pad) {
     662                 :          0 :                     fprintf(out->fp, "    uint8_t __deprecated%u[%u]; /* was: '%.*s' */\n",
     663                 :            :                             deprecated_index++, pad, n, s);
     664                 :            :                 } else {
     665                 :          1 :                     fprintf(out->fp, "    alignas(%u) uint8_t __deprecated%u[%u]; /* was: '%.*s' */\n",
     666                 :            :                             align, deprecated_index++, pad, n, s);
     667                 :            :                 }
     668                 :          1 :                 offset = (unsigned)(member->offset + member->size);
     669                 :          1 :                 continue;
     670                 :            :             }
     671      [ +  +  - ]:         73 :             switch (member->type.type) {
     672                 :            :             case vt_scalar_type:
     673                 :         53 :                 tname_ns = scalar_type_ns(member->type.st, nsc);
     674                 :         53 :                 tname = scalar_type_name(member->type.st);
     675         [ -  + ]:         53 :                 if (do_pad) {
     676                 :          0 :                     fprintf(out->fp, "    %s%s ", tname_ns, tname);
     677                 :            :                 } else {
     678                 :         53 :                     fprintf(out->fp, "    alignas(%u) %s%s ", align, tname_ns, tname);
     679                 :            :                 }
     680                 :            :                 break;
     681                 :            :             case vt_compound_type_ref:
     682                 :            :                 assert(member->type.ct->symbol.kind == fb_is_struct || member->type.ct->symbol.kind == fb_is_enum);
     683         [ +  + ]:         20 :                 kind = member->type.ct->symbol.kind == fb_is_struct ? "" : "enum_";
     684                 :            :                 fb_compound_name(member->type.ct, &snref);
     685         [ -  + ]:         20 :                 if (do_pad) {
     686                 :          0 :                     fprintf(out->fp, "    %s_%st ", snref.text, kind);
     687                 :            :                 } else {
     688                 :         20 :                     fprintf(out->fp, "    alignas(%u) %s_%st ", align, snref.text, kind);
     689                 :            :                 }
     690                 :            :                 break;
     691                 :            :             default:
     692                 :          0 :                 fprintf(out->fp, "    %s ", __FLATCC_ERROR_TYPE);
     693                 :          0 :                 gen_panic(out, "internal error: unexpected type during code generation");
     694                 :            :                 break;
     695                 :            :             }
     696                 :         73 :             fprintf(out->fp, "%.*s;\n", n, s);
     697                 :         73 :             offset = (unsigned)(member->offset + member->size);
     698                 :            :         }
     699 [ -  + ][ #  # ]:         21 :         if (do_pad && (pad = (unsigned)(ct->size - offset))) {
     700                 :          0 :             fprintf(out->fp, "    uint8_t __padding%u[%u];\n",
     701                 :            :                     pad_index, pad);
     702                 :            :         }
     703                 :         21 :         fprintf(out->fp, "};\n");
     704         [ -  + ]:         21 :         if (do_pad) {
     705                 :          0 :             fprintf(out->fp, "#pragma pack()\n");
     706                 :            :         }
     707                 :         21 :         fprintf(out->fp,
     708                 :            :                 "static_assert(sizeof(%s_t) == %llu, \"struct size mismatch\");\n\n",
     709                 :         21 :                 snt.text, llu(ct->size));
     710                 :         21 :         fprintf(out->fp,
     711                 :            :                 "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);
     712                 :         21 :         fprintf(out->fp,
     713                 :            :                 "static inline %s_t *%s__ptr_add(%s_t *p, size_t i) { return p + i; }\n", snt.text, snt.text, snt.text);
     714                 :         21 :         fprintf(out->fp,
     715                 :            :                 "static inline %s_struct_t %s_vec_at(%s_vec_t vec, size_t i)\n"
     716                 :            :                 "__%sstruct_vec_at(vec, i)\n",
     717                 :            :                 snt.text, snt.text, snt.text,
     718                 :            :                 nsc);
     719                 :            :     }
     720                 :         42 :     fprintf(out->fp, "static inline size_t %s__size() { return %llu; }\n",
     721                 :         42 :             snt.text, llu(ct->size));
     722                 :         42 :     print_type_identifier(out, snt.text, ct->type_hash);
     723                 :         42 :     fprintf(out->fp,
     724                 :            :             "static inline size_t %s_vec_len(%s_vec_t vec)\n"
     725                 :            :             "__%svec_len(vec)\n",
     726                 :            :             snt.text, snt.text, nsc);
     727                 :         42 :     fprintf(out->fp,
     728                 :            :             "__%sstruct_as_root(%s)\n",
     729                 :            :             nsc, snt.text);
     730                 :         42 :     fprintf(out->fp, "\n");
     731                 :            : 
     732                 :            :     /* Create accessors which respect endianness and which return 0 on null struct access. */
     733         [ +  + ]:        116 :     for (sym = ct->members; sym; sym = sym->link) {
     734                 :            :         member = (fb_member_t *)sym;
     735         [ +  + ]:         74 :         if (member->metadata_flags & fb_f_deprecated) {
     736                 :          1 :             continue;
     737                 :            :         }
     738                 :            :         symbol_name(&member->symbol, &n, &s);
     739      [ +  +  - ]:         73 :         switch (member->type.type) {
     740                 :            :         case vt_scalar_type:
     741                 :         53 :             tname_ns = scalar_type_ns(member->type.st, nsc);
     742                 :         53 :             tname = scalar_type_name(member->type.st);
     743                 :         53 :             tname_prefix = scalar_type_prefix(member->type.st);
     744                 :         53 :             fprintf(out->fp,
     745                 :            :                 "static inline %s%s %s_%.*s(%s_struct_t t)\n"
     746                 :            :                 "__%sstruct_scalar_field(t, %.*s, %s%s)\n",
     747                 :            :                 tname_ns, tname, snt.text, n, s, snt.text,
     748                 :            :                 nsc, n, s, nsc, tname_prefix);
     749         [ +  + ]:         53 :             if (member->metadata_flags & fb_f_key) {
     750         [ -  + ]:          2 :                 if (already_has_key) {
     751                 :          0 :                     fprintf(out->fp, "/* Note: this is not the first field with a key on this struct. */\n");
     752                 :            :                 }
     753                 :          2 :                 fprintf(out->fp,     "/* Note: find only works on vectors sorted by this field. */\n");
     754                 :          2 :                 fprintf(out->fp,
     755                 :            :                         "__%sdefine_find_by_scalar_field(%s, %.*s, %s%s)\n",
     756                 :            :                         nsc, snt.text, n, s, tname_ns, tname);
     757         [ +  - ]:          2 :                 if (out->opts->cgen_sort) {
     758                 :          2 :                     fprintf(out->fp,
     759                 :            :                         "__%sdefine_sort_by_scalar_field(%s, %.*s, %s%s, %s_t)\n",
     760                 :            :                         nsc, snt.text, n, s, tname_ns, tname, snt.text);
     761                 :            :                 }
     762         [ +  - ]:          2 :                 if (!already_has_key) {
     763                 :          2 :                     fprintf(out->fp,
     764                 :            :                         "#define %s_vec_find %s_vec_find_by_%.*s\n",
     765                 :            :                         snt.text, snt.text, n, s);
     766         [ +  - ]:          2 :                     if (out->opts->cgen_sort) {
     767                 :          2 :                         fprintf(out->fp,
     768                 :            :                             "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
     769                 :            :                             snt.text, snt.text, n, s);
     770                 :            :                     }
     771                 :            :                     already_has_key = 1;
     772                 :            :                 }
     773                 :            :                 current_key_processed = 1;
     774                 :            :             }
     775                 :            :             break;
     776                 :            :         case vt_compound_type_ref:
     777                 :         20 :             fb_compound_name(member->type.ct, &snref);
     778      [ +  +  - ]:         20 :             switch (member->type.ct->symbol.kind) {
     779                 :            :             case fb_is_enum:
     780                 :         10 :                 tname_prefix = scalar_type_prefix(member->type.ct->type.st);
     781                 :         10 :                 fprintf(out->fp,
     782                 :            :                     "static inline %s_enum_t %s_%.*s(%s_struct_t t)\n"
     783                 :            :                     "__%sstruct_scalar_field(t, %.*s, %s%s)\n",
     784                 :            :                     snref.text, snt.text, n, s, snt.text,
     785                 :            :                     nsc, n, s, nsc, tname_prefix);
     786         [ +  + ]:         10 :                 if (member->metadata_flags & fb_f_key) {
     787         [ -  + ]:          1 :                     if (already_has_key) {
     788                 :          0 :                         fprintf(out->fp, "/* Note: this is not the first field with a key on this table. */\n");
     789                 :            :                     }
     790                 :          1 :                     fprintf(out->fp,     "/* Note: find only works on vectors sorted by this field. */\n");
     791                 :          1 :                     fprintf(out->fp,
     792                 :            :                             "__%sdefine_find_by_scalar_field(%s, %.*s, %s_enum_t)\n",
     793                 :            :                             nsc, snt.text, n, s, snref.text);
     794         [ +  - ]:          1 :                     if (out->opts->cgen_sort) {
     795                 :          1 :                         fprintf(out->fp,
     796                 :            :                             "__%sdefine_sort_by_scalar_field(%s, %.*s, %s_enum_t, %s_t)\n",
     797                 :            :                             nsc, snt.text, n, s, snref.text, snt.text);
     798                 :            :                     }
     799         [ +  - ]:          1 :                     if (!already_has_key) {
     800                 :          1 :                         fprintf(out->fp,
     801                 :            :                             "#define %s_vec_find %s_vec_find_by_%.*s\n",
     802                 :            :                             snt.text, snt.text, n, s);
     803         [ +  - ]:          1 :                         if (out->opts->cgen_sort) {
     804                 :          1 :                             fprintf(out->fp,
     805                 :            :                                 "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
     806                 :            :                                 snt.text, snt.text, n, s);
     807                 :            :                         }
     808                 :            :                         already_has_key = 1;
     809                 :            :                     }
     810                 :            :                     current_key_processed = 1;
     811                 :            :                 }
     812                 :            :                 break;
     813                 :            :             case fb_is_struct:
     814                 :            :                 /*
     815                 :            :                  * For completeness provide an accessor which returns member pointer
     816                 :            :                  * or null if container struct is null.
     817                 :            :                  */
     818                 :         10 :                 fprintf(out->fp,
     819                 :            :                     "static inline %s_struct_t %s_%.*s(%s_struct_t t)\n"
     820                 :            :                     "__%sstruct_struct_field(t, %.*s)\n",
     821                 :            :                     snref.text, snt.text, n, s, snt.text,
     822                 :            :                     nsc, n, s);
     823                 :         10 :                 break;
     824                 :            :             }
     825                 :            :         }
     826 [ +  + ][ -  + ]:         73 :         if ((member->metadata_flags & fb_f_key) && !current_key_processed) {
     827                 :          0 :             fprintf(out->fp,
     828                 :            :                 "/* Note: field has key, but there is no support for find by fields of this type. */\n");
     829                 :            :             /*
     830                 :            :              * If the first key already exists, but was for an unsupported
     831                 :            :              * type, we do not map the next possible key to generic find.
     832                 :            :              */
     833                 :            :             already_has_key = 1;
     834                 :            :         }
     835                 :         73 :         fprintf(out->fp, "\n");
     836                 :            :     }
     837                 :         42 : }
     838                 :            : 
     839                 :            : /*
     840                 :            :  * Enums are integers, but we cannot control the size.
     841                 :            :  * To produce a typesafe and portable result, we generate constants
     842                 :            :  * instead.
     843                 :            :  */
     844                 :         36 : static void gen_enum(fb_output_t *out, fb_compound_type_t *ct)
     845                 :            : {
     846                 :            :     fb_member_t *member;
     847                 :            :     fb_symbol_t *sym;
     848                 :            :     const char *tname, *tname_ns, *suffix, *s, *kind;
     849                 :            :     int n, w;
     850                 :            :     int is_union;
     851                 :            :     fb_scoped_name_t snt;
     852                 :         36 :     const char *nsc = out->nsc;
     853                 :            : 
     854                 :         36 :     fb_clear(snt);
     855                 :            : 
     856                 :            :     assert(ct->symbol.kind == fb_is_enum || ct->symbol.kind == fb_is_union);
     857                 :            :     assert(ct->type.type == vt_scalar_type);
     858                 :            : 
     859                 :         36 :     tname_ns = scalar_type_ns(ct->type.st, nsc);
     860                 :         36 :     tname = scalar_type_name(ct->type.st);
     861                 :         36 :     suffix = scalar_suffix(ct->type.st);
     862                 :            : 
     863                 :         36 :     w = (int)ct->size * 8;
     864                 :            : 
     865                 :         36 :     is_union = ct->symbol.kind != fb_is_enum;
     866         [ +  + ]:         36 :     kind = is_union ? "union_type" : "enum";
     867                 :            :     fb_compound_name(ct, &snt);
     868                 :         36 :     print_doc(out, "", ct->doc);
     869                 :         36 :     fprintf(out->fp,
     870                 :            :             "typedef %s%s %s_%s_t;\n",
     871                 :            :             tname_ns, tname, snt.text, kind);
     872                 :         36 :         fprintf(out->fp,
     873                 :            :                 "__%sdefine_integer_type(%s, %s_%s_t, %u)\n",
     874                 :            :                 nsc, snt.text, snt.text, kind, w);
     875         [ +  + ]:        129 :     for (sym = ct->members; sym; sym = sym->link) {
     876                 :            :         member = (fb_member_t *)sym;
     877                 :         93 :         print_doc(out, "", member->doc);
     878                 :            :         symbol_name(&member->symbol, &n, &s);
     879                 :            :         /*
     880                 :            :          * This must be a define, not a static const integer, otherwise it
     881                 :            :          * won't work in switch statements - except with GNU extensions.
     882                 :            :          */
     883   [ +  +  +  - ]:         93 :         switch (member->value.type) {
     884                 :            :         case vt_uint:
     885                 :         34 :             fprintf(out->fp,
     886                 :            :                     "#define %s_%.*s ((%s_%s_t)%llu%s)\n",
     887                 :         34 :                     snt.text, n, s, snt.text, kind, llu(member->value.u), suffix);
     888                 :         34 :             break;
     889                 :            :         case vt_int:
     890                 :         57 :             fprintf(out->fp,
     891                 :            :                     "#define %s_%.*s ((%s_%s_t)%lld%s)\n",
     892                 :         57 :                     snt.text, n, s, snt.text, kind, llu(member->value.i), suffix);
     893                 :         57 :             break;
     894                 :            :         case vt_bool:
     895                 :          2 :             fprintf(out->fp,
     896                 :            :                     "#define %s_%.*s ((%s_%s_t)%u)\n",
     897                 :          2 :                     snt.text, n, s, snt.text, kind, member->value.b);
     898                 :          2 :             break;
     899                 :            :         default:
     900                 :          0 :             gen_panic(out, "internal error: unexpected value type in enum");
     901                 :            :             break;
     902                 :            :         }
     903                 :            :     }
     904                 :         36 :     fprintf(out->fp, "\n");
     905                 :            : 
     906         [ +  + ]:         36 :     if (is_union) {
     907                 :          9 :         fprintf(out->fp, "static inline const char *%s_type_name(%s_union_type_t type)\n"
     908                 :            :                 "{\n",
     909                 :            :                 snt.text, snt.text);
     910                 :            :     } else {
     911                 :         27 :         fprintf(out->fp, "static inline const char *%s_name(%s_enum_t value)\n"
     912                 :            :                 "{\n",
     913                 :            :                 snt.text, snt.text);
     914                 :            :     }
     915                 :            : 
     916         [ +  + ]:         36 :     if (is_union) {
     917                 :          9 :         fprintf(out->fp, "    switch (type) {\n");
     918                 :            :     } else {
     919                 :         27 :         fprintf(out->fp, "    switch (value) {\n");
     920                 :            :     }
     921         [ +  + ]:        129 :     for (sym = ct->members; sym; sym = sym->link) {
     922                 :            :         member = (fb_member_t *)sym;
     923                 :            :         symbol_name(&member->symbol, &n, &s);
     924         [ -  + ]:         93 :         if (sym->flags & fb_duplicate) {
     925                 :          0 :             fprintf(out->fp,
     926                 :            :                     "    /* case %s_%.*s: return \"%.*s\"; (duplicate) */\n",
     927                 :            :                     snt.text, n, s, n, s);
     928                 :            :         } else {
     929                 :         93 :             fprintf(out->fp,
     930                 :            :                     "    case %s_%.*s: return \"%.*s\";\n",
     931                 :            :                     snt.text, n, s, n, s);
     932                 :            :         }
     933                 :            :     }
     934                 :         36 :     fprintf(out->fp,
     935                 :            :             "    default: return \"\";\n"
     936                 :            :             "    }\n"
     937                 :            :             "}\n");
     938                 :         36 :     fprintf(out->fp, "\n");
     939                 :         36 : }
     940                 :            : 
     941                 :          9 : static void gen_nested_root(fb_output_t *out, fb_symbol_t *root_type, fb_symbol_t *container, fb_symbol_t *member)
     942                 :            : {
     943                 :            :     const char *s;
     944                 :            :     int n;
     945                 :            :     const char *kind;
     946                 :          9 :     const char *nsc = out->nsc;
     947                 :            :     fb_scoped_name_t snt;
     948                 :            :     fb_scoped_name_t snc;
     949                 :            : 
     950                 :          9 :     fb_clear(snt);
     951                 :          9 :     fb_clear(snc);
     952         [ +  - ]:          9 :     if (!root_type) {
     953                 :          0 :         return;
     954                 :            :     }
     955                 :            :     /*
     956                 :            :      * Current flatc compiler only accepts tables, but here we support
     957                 :            :      * both tables and structs in so far the parser and analyzer
     958                 :            :      * allows for it.
     959                 :            :      */
     960      [ +  -  + ]:          9 :     switch (root_type->kind) {
     961                 :            :     case fb_is_table:
     962                 :            :         kind = "table_";
     963                 :            :         break;
     964                 :            :     case fb_is_struct:
     965                 :            :         kind = "struct_";
     966                 :          1 :         break;
     967                 :            :     default:
     968                 :          0 :         gen_panic(out, "internal error: roots can only be structs or tables");
     969                 :            :         return;
     970                 :            :     }
     971                 :            :     fb_compound_name((fb_compound_type_t *)root_type, &snt);
     972                 :            :     assert(container->kind == fb_is_table);
     973                 :            :     fb_compound_name((fb_compound_type_t *)container, &snc);
     974                 :            :     symbol_name(member, &n, &s);
     975                 :          9 :     fprintf(out->fp, "__%snested_buffer_as_root(%s, %.*s, %s, %s)\n", nsc, snc.text, n, s, snt.text, kind);
     976                 :            : }
     977                 :            : 
     978                 :         63 : static void gen_table(fb_output_t *out, fb_compound_type_t *ct)
     979                 :            : {
     980                 :            :     fb_member_t *member;
     981                 :            :     fb_symbol_t *sym;
     982                 :            :     const char *s, *tname, *tname_ns, *tname_prefix;
     983                 :            :     int n, r;
     984                 :            :     int already_has_key, current_key_processed;
     985                 :         63 :     const char *nsc = out->nsc;
     986                 :            :     fb_scoped_name_t snt;
     987                 :            :     fb_scoped_name_t snref;
     988                 :            :     uint64_t present_id;
     989                 :            : 
     990                 :            :     assert(ct->symbol.kind == fb_is_table);
     991                 :            : 
     992                 :         63 :     fb_clear(snt);
     993                 :         63 :     fb_clear(snref);
     994                 :            : 
     995                 :         63 :     fprintf(out->fp, "\n");
     996                 :            :     fb_compound_name(ct, &snt);
     997                 :         63 :     print_doc(out, "", ct->doc);
     998                 :         63 :     fprintf(out->fp,
     999                 :            :             /*
    1000                 :            :              * We don't really need the struct, but it provides better
    1001                 :            :              * type safety than a typedef void *.
    1002                 :            :              */
    1003                 :            :             "struct %s_table { uint8_t unused__; };\n"
    1004                 :            :             "\n",
    1005                 :            :             snt.text);
    1006                 :         63 :     print_type_identifier(out, snt.text, ct->type_hash);
    1007                 :         63 :     fprintf(out->fp,
    1008                 :            :             "static inline size_t %s_vec_len(%s_vec_t vec)\n"
    1009                 :            :             "__%svec_len(vec)\n",
    1010                 :            :             snt.text, snt.text, nsc);
    1011                 :         63 :     fprintf(out->fp,
    1012                 :            :             "static inline %s_table_t %s_vec_at(%s_vec_t vec, size_t i)\n"
    1013                 :            :             "__%soffset_vec_at(%s_table_t, vec, i, 0)\n",
    1014                 :            :             snt.text, snt.text, snt.text, nsc, snt.text);
    1015                 :         63 :     fprintf(out->fp,
    1016                 :            :             "__%stable_as_root(%s)\n",
    1017                 :            :             nsc, snt.text);
    1018                 :         63 :     fprintf(out->fp, "\n");
    1019                 :            : 
    1020                 :            :     already_has_key = 0;
    1021         [ +  + ]:        408 :     for (sym = ct->members; sym; sym = sym->link) {
    1022                 :            :         current_key_processed = 0;
    1023                 :            :         member = (fb_member_t *)sym;
    1024                 :        345 :         present_id = member->id;
    1025                 :        345 :         print_doc(out, "", member->doc);
    1026                 :            :         /*
    1027                 :            :          * In flatc, there can at most one key field, and it should be
    1028                 :            :          * scalar or string. Here we export all keys using the
    1029                 :            :          * <table>_vec_find_by_<fieldname> convention and let the parser deal with
    1030                 :            :          * semantics. Keys on unsupported fields are ignored. The first
    1031                 :            :          * valid find operation is also mapped to just <table>_vec_find.
    1032                 :            :          */
    1033                 :            :         symbol_name(&member->symbol, &n, &s);
    1034         [ +  + ]:        345 :         if (member->metadata_flags & fb_f_deprecated) {
    1035                 :          9 :             fprintf(out->fp, "/* Skipping deprecated field: '%s_%.*s' */\n\n", snt.text, n, s);
    1036                 :          9 :             continue;
    1037                 :            :         }
    1038                 :        336 :         r = (member->metadata_flags & fb_f_required) != 0;
    1039   [ +  +  +  +  :        336 :         switch (member->type.type) {
                +  +  - ]
    1040                 :            :         case vt_scalar_type:
    1041                 :        147 :             tname_ns = scalar_type_ns(member->type.st, nsc);
    1042                 :        147 :             tname = scalar_type_name(member->type.st);
    1043                 :        147 :             tname_prefix = scalar_type_prefix(member->type.st);
    1044   [ +  +  +  +  :        147 :             switch (member->value.type) {
                      - ]
    1045                 :            :             case vt_uint:
    1046                 :         65 :                 fprintf(out->fp,
    1047                 :            :                     "static inline %s%s %s_%.*s(%s_table_t t)\n"
    1048                 :            :                     "__%sscalar_field(%s%s, %llu, %llu, t)\n",
    1049                 :            :                     tname_ns, tname, snt.text, n, s, snt.text,
    1050                 :         65 :                     nsc, nsc, tname_prefix, llu(member->id), llu(member->value.u));
    1051                 :         65 :                 break;
    1052                 :            :             case vt_int:
    1053                 :         75 :                 fprintf(out->fp,
    1054                 :            :                     "static inline %s%s %s_%.*s(%s_table_t t)\n"
    1055                 :            :                     "__%sscalar_field(%s%s, %llu, %lld, t)\n",
    1056                 :            :                     tname_ns, tname, snt.text, n, s, snt.text,
    1057                 :         75 :                     nsc, nsc, tname_prefix, llu(member->id), lld(member->value.i));
    1058                 :         75 :                 break;
    1059                 :            :             case vt_bool:
    1060                 :          2 :                 fprintf(out->fp,
    1061                 :            :                     "static inline %s%s %s_%.*s(%s_table_t t)\n"
    1062                 :            :                     "__%sscalar_field(%s%s, %llu, %u, t)\n",
    1063                 :            :                     tname_ns, tname, snt.text, n, s, snt.text,
    1064                 :          4 :                     nsc, nsc, tname_prefix, llu(member->id), member->value.b);
    1065                 :          2 :                 break;
    1066                 :            :             case vt_float:
    1067                 :          5 :                 fprintf(out->fp,
    1068                 :            :                     "static inline %s%s %s_%.*s(%s_table_t t)\n"
    1069                 :            :                     "__%sscalar_field(%s%s, %llu, %lf, t)\n",
    1070                 :            :                     tname_ns, tname, snt.text, n, s, snt.text,
    1071                 :          5 :                     nsc, nsc, tname_prefix, llu(member->id), member->value.f);
    1072                 :          5 :                 break;
    1073                 :            :             default:
    1074                 :          0 :                 gen_panic(out, "internal error: unexpected scalar table default value");
    1075                 :            :                 continue;
    1076                 :            :             }
    1077         [ +  + ]:        147 :             if (member->metadata_flags & fb_f_key) {
    1078         [ +  + ]:          2 :                 if (already_has_key) {
    1079                 :          1 :                     fprintf(out->fp, "/* Note: this is not the first field with a key on this table. */\n");
    1080                 :            :                 }
    1081                 :          2 :                 fprintf(out->fp,     "/* Note: find only works on vectors sorted by this field. */\n");
    1082                 :          2 :                 fprintf(out->fp,
    1083                 :            :                         "__%sdefine_find_by_scalar_field(%s, %.*s, %s%s)\n",
    1084                 :            :                         nsc, snt.text, n, s, tname_ns, tname);
    1085         [ +  - ]:          2 :                 if (out->opts->cgen_sort) {
    1086                 :          2 :                     fprintf(out->fp,
    1087                 :            :                         "__%sdefine_sort_by_scalar_field(%s, %.*s, %s%s, %suoffset_t)\n",
    1088                 :            :                         nsc, snt.text, n, s, tname_ns, tname, nsc);
    1089                 :            :                 }
    1090         [ +  + ]:          2 :                 if (!already_has_key) {
    1091                 :          1 :                     fprintf(out->fp,
    1092                 :            :                         "#define %s_vec_find %s_vec_find_by_%.*s\n",
    1093                 :            :                         snt.text, snt.text, n, s);
    1094         [ +  - ]:          1 :                     if (out->opts->cgen_sort) {
    1095                 :          1 :                         fprintf(out->fp,
    1096                 :            :                             "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
    1097                 :            :                             snt.text, snt.text, n, s);
    1098                 :            :                     }
    1099                 :            :                     already_has_key = 1;
    1100                 :            :                 }
    1101                 :            :                 current_key_processed = 1;
    1102                 :            :             }
    1103                 :            :             break;
    1104                 :            :         case vt_vector_type:
    1105                 :            :             /* They all use a namespace. */
    1106                 :         25 :             tname = scalar_vector_type_name(member->type.st);
    1107                 :            :             tname_ns = nsc;
    1108                 :         25 :             fprintf(out->fp,
    1109                 :            :                 "static inline %s%s %s_%.*s(%s_table_t t)\n"
    1110                 :            :                 "__%svector_field(%s%s, %llu, t, %u)\n",
    1111                 :            :                 tname_ns, tname, snt.text, n, s, snt.text,
    1112                 :         25 :                 nsc, tname_ns, tname, llu(member->id), r);
    1113         [ +  + ]:         25 :             if (member->nest) {
    1114                 :          9 :                 gen_nested_root(out, &member->nest->symbol, &ct->symbol, &member->symbol);
    1115                 :            :             }
    1116                 :            :             break;
    1117                 :            :         case vt_string_type:
    1118                 :         27 :             fprintf(out->fp,
    1119                 :            :                 "static inline %sstring_t %s_%.*s(%s_table_t t)\n"
    1120                 :            :                 "__%svector_field(%sstring_t, %llu, t, %u)\n",
    1121                 :            :                 nsc, snt.text, n, s, snt.text,
    1122                 :         27 :                 nsc, nsc, llu(member->id), r);
    1123         [ +  + ]:         27 :             if (member->metadata_flags & fb_f_key) {
    1124         [ -  + ]:          8 :                 if (already_has_key) {
    1125                 :          0 :                     fprintf(out->fp, "/* Note: this is not the first field with a key on this table. */\n");
    1126                 :            :                 }
    1127                 :          8 :                 fprintf(out->fp,     "/* Note: find only works on vectors sorted by this field. */\n");
    1128                 :          8 :                 fprintf(out->fp,
    1129                 :            :                     "static inline size_t %s_vec_find_by_%.*s(%s_vec_t vec, const char *s)\n"
    1130                 :            :                     "__%sfind_by_string_field(%s_%.*s, vec, %s_vec_at, %s_vec_len, s)\n",
    1131                 :            :                     snt.text, n, s, snt.text, nsc, snt.text, n, s, snt.text, snt.text);
    1132                 :          8 :                 fprintf(out->fp,
    1133                 :            :                     "static inline size_t %s_vec_find_n_by_%.*s(%s_vec_t vec, const char *s, int n)\n"
    1134                 :            :                     "__%sfind_by_string_n_field(%s_%.*s, vec, %s_vec_at, %s_vec_len, s, n)\n",
    1135                 :            :                     snt.text, n, s, snt.text, nsc, snt.text, n, s, snt.text, snt.text);
    1136         [ +  - ]:          8 :                 if (out->opts->cgen_sort) {
    1137                 :          8 :                     fprintf(out->fp,
    1138                 :            :                         "__%sdefine_sort_by_string_field(%s, %.*s)\n",
    1139                 :            :                         nsc, snt.text, n, s);
    1140                 :            :                 }
    1141         [ +  - ]:          8 :                 if (!already_has_key) {
    1142                 :          8 :                     fprintf(out->fp,
    1143                 :            :                         "#define %s_vec_find %s_vec_find_by_%.*s\n"
    1144                 :            :                         "#define %s_vec_find_n %s_vec_find_n_by_%.*s\n",
    1145                 :            :                         snt.text, snt.text, n, s,
    1146                 :            :                         snt.text, snt.text, n, s);
    1147         [ +  - ]:          8 :                     if (out->opts->cgen_sort) {
    1148                 :          8 :                         fprintf(out->fp,
    1149                 :            :                                 "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
    1150                 :            :                                 snt.text, snt.text, n, s);
    1151                 :            :                     }
    1152                 :            :                     already_has_key = 1;
    1153                 :            :                 }
    1154                 :            :                 current_key_processed = 1;
    1155                 :            :             }
    1156                 :            :             break;
    1157                 :            :         case vt_vector_string_type:
    1158                 :         10 :             fprintf(out->fp,
    1159                 :            :                 "static inline %sstring_vec_t %s_%.*s(%s_table_t t)\n"
    1160                 :            :                 "__%svector_field(%sstring_vec_t, %llu, t, %u)\n",
    1161                 :            :                 nsc, snt.text, n, s, snt.text,
    1162                 :         10 :                 nsc, nsc, llu(member->id), r);
    1163                 :         10 :             break;
    1164                 :            :         case vt_compound_type_ref:
    1165                 :        109 :             fb_compound_name(member->type.ct, &snref);
    1166   [ +  +  +  +  :        109 :             switch (member->type.ct->symbol.kind) {
                      - ]
    1167                 :            :             case fb_is_struct:
    1168                 :         27 :                 fprintf(out->fp,
    1169                 :            :                     "static inline %s_struct_t %s_%.*s(%s_table_t t)\n"
    1170                 :            :                     "__%sstruct_field(%s_struct_t, %llu, t, %u)\n",
    1171                 :            :                     snref.text, snt.text, n, s, snt.text,
    1172                 :         27 :                     nsc, snref.text, llu(member->id), r);
    1173                 :         27 :                 break;
    1174                 :            :             case fb_is_table:
    1175                 :         23 :                 fprintf(out->fp,
    1176                 :            :                     "static inline %s_table_t %s_%.*s(%s_table_t t)\n"
    1177                 :            :                     "__%stable_field(%s_table_t, %llu, t, %u)\n",
    1178                 :            :                     snref.text, snt.text, n, s, snt.text,
    1179                 :         23 :                     nsc, snref.text, llu(member->id), r);
    1180                 :         23 :                 break;
    1181                 :            :             case fb_is_enum:
    1182   [ +  +  -  - ]:         48 :                 switch (member->value.type) {
    1183                 :            :                 case vt_uint:
    1184                 :          2 :                     fprintf(out->fp,
    1185                 :            :                         "static inline %s_enum_t %s_%.*s(%s_table_t t)\n"
    1186                 :            :                         "__%sscalar_field(%s, %llu, %llu, t)\n",
    1187                 :            :                         snref.text, snt.text, n, s, snt.text,
    1188                 :          2 :                         nsc, snref.text, llu(member->id), llu(member->value.u));
    1189                 :          2 :                     break;
    1190                 :            :                 case vt_int:
    1191                 :         46 :                     fprintf(out->fp,
    1192                 :            :                         "static inline %s_enum_t %s_%.*s(%s_table_t t)\n"
    1193                 :            :                         "__%sscalar_field(%s, %llu, %lld, t)\n",
    1194                 :            :                         snref.text, snt.text, n, s, snt.text,
    1195                 :         46 :                         nsc, snref.text, llu(member->id), lld(member->value.i));
    1196                 :         46 :                     break;
    1197                 :            :                 case vt_bool:
    1198                 :          0 :                     fprintf(out->fp,
    1199                 :            :                         "static inline %s_enum_t %s_%.*s(%s_table_t t)\n"
    1200                 :            :                         "__%sscalar_field(%s, %llu, %u, t)\n",
    1201                 :            :                         snref.text, snt.text, n, s, snt.text,
    1202                 :          0 :                         nsc, snref.text, llu(member->id), member->value.b);
    1203                 :          0 :                     break;
    1204                 :            :                 default:
    1205                 :          0 :                     gen_panic(out, "internal error: unexpected enum type referenced by table");
    1206                 :            :                     continue;
    1207                 :            :                 }
    1208         [ +  + ]:         48 :                 if (member->metadata_flags & fb_f_key) {
    1209         [ -  + ]:          1 :                     if (already_has_key) {
    1210                 :          0 :                         fprintf(out->fp, "/* Note: this is not the first field with a key on this table. */\n");
    1211                 :            :                     }
    1212                 :          1 :                     fprintf(out->fp,     "/* Note: find only works on vectors sorted by this field. */\n");
    1213                 :          1 :                     fprintf(out->fp,
    1214                 :            :                             "__%sdefine_find_by_scalar_field(%s, %.*s, %s_enum_t)\n",
    1215                 :            :                             nsc, snt.text, n, s, snref.text);
    1216         [ +  - ]:          1 :                     if (out->opts->cgen_sort) {
    1217                 :          1 :                         fprintf(out->fp,
    1218                 :            :                                 "__%sdefine_sort_by_scalar_field(%s, %.*s, %s_enum_t, %suoffset_t)\n",
    1219                 :            :                                 nsc, snt.text, n, s, snref.text, nsc);
    1220                 :            :                     }
    1221         [ +  - ]:          1 :                     if (!already_has_key) {
    1222                 :          1 :                         fprintf(out->fp,
    1223                 :            :                             "#define %s_vec_find %s_vec_find_by_%.*s\n",
    1224                 :            :                             snt.text, snt.text, n, s);
    1225         [ +  - ]:          1 :                         if (out->opts->cgen_sort) {
    1226                 :          1 :                             fprintf(out->fp,
    1227                 :            :                                     "#define %s_vec_sort %s_vec_sort_by_%.*s\n",
    1228                 :            :                                     snt.text, snt.text, n, s);
    1229                 :            :                         }
    1230                 :            :                         already_has_key = 1;
    1231                 :            :                     }
    1232                 :            :                     current_key_processed = 1;
    1233                 :            :                 }
    1234                 :            :                 break;
    1235                 :            :             case fb_is_union:
    1236                 :         11 :                 present_id--;
    1237                 :         11 :                 fprintf(out->fp,
    1238                 :            :                     "static inline %s_union_type_t %s_%.*s_type(%s_table_t t)\n"
    1239                 :            :                     "__%sscalar_field(%s, %llu, 0, t)\n",
    1240                 :            :                     snref.text, snt.text, n, s, snt.text,
    1241                 :         11 :                     nsc, snref.text, llu(member->id) - 1);
    1242                 :         11 :                 fprintf(out->fp,
    1243                 :            :                     "static inline %sgeneric_table_t %s_%.*s(%s_table_t t)\n"
    1244                 :            :                     "__%stable_field(%sgeneric_table_t, %llu, t, %u)\n",
    1245                 :            :                     nsc, snt.text, n, s, snt.text,
    1246                 :         11 :                     nsc, nsc, llu(member->id), r);
    1247                 :         11 :                     break;
    1248                 :            :             default:
    1249                 :          0 :                 gen_panic(out, "internal error: unexpected compound type in table during code generation");
    1250                 :            :                 break;
    1251                 :            :             }
    1252                 :            :             break;
    1253                 :            :         case vt_vector_compound_type_ref:
    1254                 :         18 :             fb_compound_name(member->type.ct, &snref);
    1255   [ +  +  +  -  :         18 :             switch (member->type.ct->symbol.kind) {
                      - ]
    1256                 :            :             case fb_is_struct:
    1257                 :          8 :                 fprintf(out->fp,
    1258                 :            :                     "static inline %s_vec_t %s_%.*s(%s_table_t t)\n"
    1259                 :            :                     "__%svector_field(%s_vec_t, %llu, t, %u)\n",
    1260                 :            :                     snref.text, snt.text, n, s, snt.text,
    1261                 :          8 :                     nsc, snref.text, llu(member->id), r);
    1262                 :          8 :                 break;
    1263                 :            :             case fb_is_table:
    1264                 :          9 :                 fprintf(out->fp,
    1265                 :            :                     "static inline %s_vec_t %s_%.*s(%s_table_t t)\n"
    1266                 :            :                     "__%svector_field(%s_vec_t, %llu, t, %u)\n",
    1267                 :            :                     snref.text, snt.text, n, s, snt.text,
    1268                 :          9 :                     nsc, snref.text, llu(member->id), r);
    1269                 :          9 :                 break;
    1270                 :            :             case fb_is_enum:
    1271                 :          1 :                 fprintf(out->fp,
    1272                 :            :                     "static inline %s_vec_t %s_%.*s(%s_table_t t)\n"
    1273                 :            :                     "__%svector_field(%s_vec_t, %llu, t, %u)\n",
    1274                 :            :                     snref.text, snt.text, n, s, snt.text,
    1275                 :          1 :                     nsc, snref.text, llu(member->id), r);
    1276                 :          1 :                 break;
    1277                 :            :             case fb_is_union:
    1278                 :          0 :                 gen_panic(out, "internal error: unexpected vector of union present in table");
    1279                 :            :                 break;
    1280                 :            :             default:
    1281                 :          0 :                 gen_panic(out, "internal error: unexpected vector compound type in table during code generation");
    1282                 :            :                 break;
    1283                 :            :             }
    1284                 :            :             break;
    1285                 :            :         default:
    1286                 :          0 :             gen_panic(out, "internal error: unexpected table member type during code generation");
    1287                 :            :             break;
    1288                 :            :         }
    1289                 :        336 :         fprintf(out->fp,
    1290                 :            :                 "static inline int %s_%.*s_is_present(%s_table_t t)\n"
    1291                 :            :                 "__%sfield_present(%llu, t)\n",
    1292                 :            :                 snt.text, n, s, snt.text, nsc, llu(present_id));
    1293 [ +  + ][ -  + ]:        336 :         if ((member->metadata_flags & fb_f_key) && !current_key_processed) {
    1294                 :          0 :             fprintf(out->fp,
    1295                 :            :                 "/* Note: field has key, but there is no support for find by fields of this type. */\n");
    1296                 :            :             /*
    1297                 :            :              * If the first key already exists, but was for an unsupported
    1298                 :            :              * type, we do not map the next possible key to generic find.
    1299                 :            :              */
    1300                 :            :             already_has_key = 1;
    1301                 :            :         }
    1302                 :        336 :         fprintf(out->fp, "\n");
    1303                 :            :     }
    1304                 :         63 : }
    1305                 :            : 
    1306                 :         24 : int fb_gen_c_reader(fb_output_t *out)
    1307                 :            : {
    1308                 :            :     fb_symbol_t *sym;
    1309                 :            :     fb_compound_type_t *ct;
    1310                 :            : 
    1311                 :         24 :     gen_pretext(out);
    1312                 :            : 
    1313         [ +  + ]:         66 :     for (ct = out->S->ordered_structs; ct; ct = ct->order) {
    1314                 :         42 :         gen_forward_decl(out, ct);
    1315                 :            :     }
    1316                 :         24 :     fprintf(out->fp, "\n");
    1317         [ +  + ]:        166 :     for (sym = out->S->symbols; sym; sym = sym->link) {
    1318         [ +  + ]:        142 :         switch (sym->kind) {
    1319                 :            :         case fb_is_table:
    1320                 :         63 :             gen_forward_decl(out, (fb_compound_type_t *)sym);
    1321                 :         63 :             break;
    1322                 :            :         }
    1323                 :            :     }
    1324                 :         24 :     fprintf(out->fp, "\n");
    1325         [ +  + ]:        166 :     for (sym = out->S->symbols; sym; sym = sym->link) {
    1326         [ +  + ]:        142 :         switch (sym->kind) {
    1327                 :            :          /* Enums must come before structs in case they are referenced. */
    1328                 :            :         case fb_is_enum:
    1329                 :         27 :             gen_enum(out, (fb_compound_type_t *)sym);
    1330                 :         27 :             break;
    1331                 :            :         }
    1332                 :            :     }
    1333                 :         24 :     fprintf(out->fp, "\n");
    1334                 :            :     /* Generate structs in topologically sorted order. */
    1335         [ +  + ]:         66 :     for (ct = out->S->ordered_structs; ct; ct = ct->order) {
    1336                 :         42 :             gen_struct(out, ct);
    1337                 :            :     }
    1338         [ +  + ]:        166 :     for (sym = out->S->symbols; sym; sym = sym->link) {
    1339   [ +  +  -  + ]:        142 :         switch (sym->kind) {
    1340                 :            :         case fb_is_enum:
    1341                 :            :         case fb_is_struct:
    1342                 :            :             /* Already generated. */
    1343                 :            :             break;
    1344                 :            :         case fb_is_union:
    1345                 :          9 :             gen_enum(out, (fb_compound_type_t *)sym);
    1346                 :          9 :             break;
    1347                 :            :         case fb_is_table:
    1348                 :         63 :             gen_table(out, (fb_compound_type_t *)sym);
    1349                 :         63 :             break;
    1350                 :            :         case fb_is_rpc_service:
    1351                 :            :             /* Ignore. */
    1352                 :            :             break;
    1353                 :            :         default:
    1354                 :          0 :             gen_panic(out, "internal error: unexpected schema component");
    1355                 :            :             break;
    1356                 :            :         }
    1357                 :            :     }
    1358                 :         24 :     fprintf(out->fp, "\n");
    1359                 :         24 :     gen_footer(out);
    1360                 :         24 :     return 0;
    1361                 :            : }

Generated by: LCOV version 1.12