github.com/cloudwego/frugal@v0.1.15/native/skipping.c (about)

     1  #include <stdint.h>
     2  
     3  #define ETAG        -1
     4  #define EEOF        -2
     5  #define ESTACK      -3
     6  #define MAX_STACK   1024
     7  
     8  #define T_bool      2
     9  #define T_i8        3
    10  #define T_double    4
    11  #define T_i16       6
    12  #define T_i32       8
    13  #define T_i64       10
    14  #define T_string    11
    15  #define T_struct    12
    16  #define T_map       13
    17  #define T_set       14
    18  #define T_list      15
    19  #define T_list_elem 0xfe
    20  #define T_map_pair  0xff
    21  
    22  typedef struct {
    23      uint8_t  t;
    24      uint8_t  k;
    25      uint8_t  v;
    26      uint32_t n;
    27  } skipbuf_t;
    28  
    29  static const char WireTags[256] = {
    30      [T_bool  ] = 1,
    31      [T_i8    ] = 1,
    32      [T_double] = 1,
    33      [T_i16   ] = 1,
    34      [T_i32   ] = 1,
    35      [T_i64   ] = 1,
    36      [T_string] = 1,
    37      [T_struct] = 1,
    38      [T_map   ] = 1,
    39      [T_set   ] = 1,
    40      [T_list  ] = 1,
    41  };
    42  
    43  static const int8_t SkipSizeFixed[256] = {
    44      [T_bool  ] = 1,
    45      [T_i8    ] = 1,
    46      [T_double] = 8,
    47      [T_i16   ] = 2,
    48      [T_i32   ] = 4,
    49      [T_i64   ] = 8,
    50  };
    51  
    52  static inline int64_t u32be(const char *s) {
    53      return __builtin_bswap32(*(const uint32_t *)s);
    54  }
    55  
    56  static inline char stpop(skipbuf_t *s, int64_t *p) {
    57      if (s[*p].n == 0) {
    58          (*p)--;
    59          return 1;
    60      } else {
    61          s[*p].n--;
    62          return 0;
    63      }
    64  }
    65  
    66  static inline char stadd(skipbuf_t *s, int64_t *p, uint8_t t) {
    67      if (++*p >= MAX_STACK) {
    68          return 0;
    69      } else {
    70          s[*p].t = t;
    71          s[*p].n = 0;
    72          return 1;
    73      }
    74  }
    75  
    76  static inline void mvbuf(const char **s, int64_t *n, int64_t *r, int64_t nb) {
    77      *n -= nb;
    78      *r += nb;
    79      *s += nb;
    80  }
    81  
    82  int64_t do_skip(skipbuf_t *st, const char *s, int64_t n, uint8_t t) {
    83      int64_t nb;
    84      int64_t rv = 0;
    85      int64_t sp = 0;
    86  
    87      /* initialize the stack */
    88      st->n = 0;
    89      st->t = t;
    90  
    91      /* run until drain */
    92      while (sp >= 0) {
    93          switch (st[sp].t) {
    94              default: {
    95                  return ETAG;
    96              }
    97  
    98              /* simple fixed types */
    99              case T_bool   :
   100              case T_i8     :
   101              case T_double :
   102              case T_i16    :
   103              case T_i32    :
   104              case T_i64    : {
   105                  if ((nb = SkipSizeFixed[st[sp].t]) > n) {
   106                      return EEOF;
   107                  } else {
   108                      stpop(st, &sp);
   109                      mvbuf(&s, &n, &rv, nb);
   110                      break;
   111                  }
   112              }
   113  
   114              /* strings & binaries */
   115              case T_string: {
   116                  if (n < 4) {
   117                      return EEOF;
   118                  } else if ((nb = u32be(s) + 4) > n) {
   119                      return EEOF;
   120                  } else {
   121                      stpop(st, &sp);
   122                      mvbuf(&s, &n, &rv, nb);
   123                      break;
   124                  }
   125              }
   126  
   127              /* structs */
   128              case T_struct: {
   129                  int64_t nf;
   130                  uint8_t vt;
   131  
   132                  /* must have at least 1 byte */
   133                  if (n < 1) {
   134                      return EEOF;
   135                  }
   136  
   137                  /* check for end of tag */
   138                  if ((vt = *s) == 0) {
   139                      stpop(st, &sp);
   140                      mvbuf(&s, &n, &rv, 1);
   141                      continue;
   142                  }
   143  
   144                  /* check for tag value */
   145                  if (!(WireTags[vt])) {
   146                      return ETAG;
   147                  }
   148  
   149                  /* fast-path for primitive fields */
   150                  if ((nf = SkipSizeFixed[vt]) != 0) {
   151                      if (n < nf + 3) {
   152                          return EEOF;
   153                      } else {
   154                          mvbuf(&s, &n, &rv, nf + 3);
   155                          continue;
   156                      }
   157                  }
   158  
   159                  /* must have more than 3 bytes (fields cannot have a size of zero),
   160                   * also skip the field ID because we don't care */
   161                  if (n <= 3) {
   162                      return EEOF;
   163                  } else if (!stadd(st, &sp, vt)) {
   164                      return ESTACK;
   165                  } else {
   166                      mvbuf(&s, &n, &rv, 3);
   167                      break;
   168                  }
   169              }
   170  
   171              /* maps */
   172              case T_map: {
   173                  int64_t np;
   174                  uint8_t kt;
   175                  uint8_t vt;
   176  
   177                  /* must have at least 6 bytes */
   178                  if (n < 6) {
   179                      return EEOF;
   180                  }
   181  
   182                  /* get the element type and count */
   183                  kt = s[0];
   184                  vt = s[1];
   185                  np = u32be(s + 2);
   186  
   187                  /* check for tag value */
   188                  if (!(WireTags[kt] && WireTags[vt])) {
   189                      return ETAG;
   190                  }
   191  
   192                  /* empty map */
   193                  if (np == 0) {
   194                      stpop(st, &sp);
   195                      mvbuf(&s, &n, &rv, 6);
   196                      continue;
   197                  }
   198  
   199                  /* check for fixed key and value */
   200                  int64_t nk = SkipSizeFixed[kt];
   201                  int64_t nv = SkipSizeFixed[vt];
   202  
   203                  /* fast path for fixed key and value */
   204                  if (nk != 0 && nv != 0) {
   205                      if ((nb = np * (nk + nv) + 6) > n) {
   206                          return EEOF;
   207                      } else {
   208                          stpop(st, &sp);
   209                          mvbuf(&s, &n, &rv, nb);
   210                          continue;
   211                      }
   212                  }
   213  
   214                  /* set to parse the map pairs */
   215                  st[sp].k = kt;
   216                  st[sp].v = vt;
   217                  st[sp].t = T_map_pair;
   218                  st[sp].n = np * 2 - 1;
   219                  mvbuf(&s, &n, &rv, 6);
   220                  break;
   221              }
   222  
   223              /* map pairs */
   224              case T_map_pair: {
   225                  uint8_t kt = st[sp].k;
   226                  uint8_t vt = st[sp].v;
   227  
   228                  /* there are keys pending */
   229                  if (!stpop(st, &sp) && (st[sp].n & 1) == 0) {
   230                      vt = kt;
   231                  }
   232  
   233                  /* push the element onto stack */
   234                  if (stadd(st, &sp, vt)) {
   235                      break;
   236                  } else {
   237                      return ESTACK;
   238                  }
   239              }
   240  
   241              /* sets and lists */
   242              case T_set  :
   243              case T_list : {
   244                  int64_t nv;
   245                  int64_t nt;
   246                  uint8_t et;
   247  
   248                  /* must have at least 5 bytes */
   249                  if (n < 5) {
   250                      return EEOF;
   251                  }
   252  
   253                  /* get the element type and count */
   254                  et = s[0];
   255                  nv = u32be(s + 1);
   256  
   257                  /* check for tag value */
   258                  if (!(WireTags[et])) {
   259                      return ETAG;
   260                  }
   261  
   262                  /* empty sequence */
   263                  if (nv == 0) {
   264                      stpop(st, &sp);
   265                      mvbuf(&s, &n, &rv, 5);
   266                      continue;
   267                  }
   268  
   269                  /* fast path for fixed types */
   270                  if ((nt = SkipSizeFixed[et]) != 0) {
   271                      if ((nb = nv * nt + 5) > n) {
   272                          return EEOF;
   273                      } else {
   274                          stpop(st, &sp);
   275                          mvbuf(&s, &n, &rv, nb);
   276                          continue;
   277                      }
   278                  }
   279  
   280                  /* set to parse the elements */
   281                  st[sp].t = T_list_elem;
   282                  st[sp].v = et;
   283                  st[sp].n = nv - 1;
   284                  mvbuf(&s, &n, &rv, 5);
   285                  break;
   286              }
   287  
   288              /* list elements */
   289              case T_list_elem: {
   290                  uint8_t et = st[sp].v;
   291                  stpop(st, &sp);
   292  
   293                  /* push the element onto stack */
   294                  if (stadd(st, &sp, et)) {
   295                      break;
   296                  } else {
   297                      return ESTACK;
   298                  }
   299              }
   300          }
   301      }
   302  
   303      /* all done */
   304      return rv;
   305  }