Ignore:
Timestamp:
Dec 15, 2012, 12:01:59 AM (9 years ago)
Author:
jordan
Message:

(trunk, libT) faster JSON parsing for tr_variant. This mostly helps the Qt client, which makes heavy use of the JSON-based RPC calls.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/variant-json.c

    r13669 r13672  
    4444  bool has_content;
    4545  tr_variant * top;
    46   char * key;
     46  const char * key;
     47  size_t keylen;
     48  struct evbuffer * keybuf;
     49  struct evbuffer * strbuf;
    4750  const char * source;
    4851  tr_ptrArray stack;
     
    7073  else if (tr_variantIsDict (parent) && (data->key!=NULL))
    7174    {
    72       node = tr_variantDictAdd (parent, data->key);
    73       tr_free (data->key);
     75      node = tr_variantDictAdd (parent, data->key, data->keylen);
     76
    7477      data->key = NULL;
     78      data->keylen = 0;
    7579    }
    7680
     
    168172
    169173static char*
    170 extract_string (jsonsl_t jsn, struct jsonsl_state_st * state, size_t * len)
    171 {
    172   const char * in_begin;
    173   const char * in_end;
    174   const char * in_it;
    175   size_t out_buflen;
    176   char * out_buf;
    177   char * out_it;
    178 
    179   in_begin = jsn->base + state->pos_begin;
    180   if (*in_begin == '"')
    181     in_begin++;
    182   in_end = jsn->base + state->pos_cur;
    183 
    184   out_buflen = (in_end-in_begin)*3 + 1;
    185   out_buf = tr_new0 (char, out_buflen);
    186   out_it = out_buf;
    187 
    188   for (in_it=in_begin; in_it!=in_end;)
     174extract_escaped_string (const char * in, size_t in_len, size_t * len, struct evbuffer * buf)
     175{
     176  const char * const in_end = in + in_len;
     177
     178  evbuffer_drain (buf, evbuffer_get_length (buf));
     179
     180  while (in < in_end)
    189181    {
    190182      bool unescaped = false;
    191183
    192       if (*in_it=='\\' && in_end-in_it>=2)
    193         {
    194           switch (in_it[1])
     184      if (*in=='\\' && in_end-in>=2)
     185        {
     186          switch (in[1])
    195187            {
    196               case 'b' : *out_it++ = '\b'; in_it+=2; unescaped = true; break;
    197               case 'f' : *out_it++ = '\f'; in_it+=2; unescaped = true; break;
    198               case 'n' : *out_it++ = '\n'; in_it+=2; unescaped = true; break;
    199               case 'r' : *out_it++ = '\r'; in_it+=2; unescaped = true; break;
    200               case 't' : *out_it++ = '\t'; in_it+=2; unescaped = true; break;
    201               case '/' : *out_it++ = '/' ; in_it+=2; unescaped = true; break;
    202               case '"' : *out_it++ = '"' ; in_it+=2; unescaped = true; break;
    203               case '\\': *out_it++ = '\\'; in_it+=2; unescaped = true; break;
     188              case 'b' : evbuffer_add (buf, "\b", 1); in+=2; unescaped = true; break;
     189              case 'f' : evbuffer_add (buf, "\f", 1); in+=2; unescaped = true; break;
     190              case 'n' : evbuffer_add (buf, "\n", 1); in+=2; unescaped = true; break;
     191              case 'r' : evbuffer_add (buf, "\r", 1); in+=2; unescaped = true; break;
     192              case 't' : evbuffer_add (buf, "\t", 1); in+=2; unescaped = true; break;
     193              case '/' : evbuffer_add (buf, "/" , 1); in+=2; unescaped = true; break;
     194              case '"' : evbuffer_add (buf, "\"" , 1); in+=2; unescaped = true; break;
     195              case '\\': evbuffer_add (buf, "\\", 1); in+=2; unescaped = true; break;
    204196              case 'u':
    205197                {
    206                   if (in_end - in_it >= 6)
     198                  if (in_end - in >= 6)
    207199                    {
    208200                      unsigned int val = 0;
    209                       if (decode_hex_string (in_it, &val))
     201
     202                      if (decode_hex_string (in, &val))
    210203                        {
    211204                          UTF32 str32_buf[2] = { val, 0 };
     
    215208                          UTF8 * str8_walk = str8_buf;
    216209                          UTF8 * str8_end = str8_buf + 8;
    217 
     210   
    218211                          if (ConvertUTF32toUTF8 (&str32_walk, str32_end, &str8_walk, str8_end, 0) == 0)
    219212                            {
    220213                              const size_t len = str8_walk - str8_buf;
    221                               memcpy (out_it, str8_buf, len);
    222                               out_it += len;
     214                              evbuffer_add (buf, str8_buf, len);
    223215                              unescaped = true;
    224216                            }
    225 
    226                           in_it += 6;
     217   
     218                          in += 6;
    227219                          break;
    228220                        }
     
    233225
    234226      if (!unescaped)
    235         *out_it++ = *in_it++;
    236     }
    237 
    238   if (len != NULL)
    239     *len = out_it - out_buf;
    240 
    241   return out_buf;
     227        {
     228          evbuffer_add (buf, in, 1);
     229          ++in;
     230        }
     231    }
     232
     233  *len = evbuffer_get_length (buf);
     234  return (char*) evbuffer_pullup (buf, -1);
     235}
     236
     237static const char*
     238extract_string (jsonsl_t jsn, struct jsonsl_state_st * state, size_t * len, struct evbuffer * buf)
     239{
     240  const char * ret;
     241  const char * in_begin;
     242  const char * in_end;
     243  size_t in_len;
     244
     245  /* figure out where the string is */
     246  in_begin = jsn->base + state->pos_begin;
     247  if (*in_begin == '"')
     248    in_begin++;
     249  in_end = jsn->base + state->pos_cur;
     250  in_len = in_end - in_begin;
     251
     252  if (memchr (in_begin, '\\', in_len) == NULL)
     253    {
     254      /* it's not escaped */
     255      ret = in_begin;
     256      *len = in_len;
     257    }
     258  else
     259    {
     260      ret = extract_escaped_string (in_begin, in_len, len, buf);
     261    }
     262
     263  return ret;
    242264}
    243265
     
    252274  if (state->type == JSONSL_T_STRING)
    253275    {
    254       size_t len = 0;
    255       char * str = extract_string (jsn, state, &len);
     276      size_t len;
     277      const char * str = extract_string (jsn, state, &len, data->strbuf);
    256278      tr_variantInitStr (get_node (jsn), str, len);
    257279      data->has_content = true;
    258       tr_free (str);
    259280    }
    260281  else if (state->type == JSONSL_T_HKEY)
    261282    {
    262       char * str = extract_string (jsn, state, NULL);
    263283      data->has_content = true;
    264       data->key = str;
     284      data->key = extract_string (jsn, state, &data->keylen, data->keybuf);
    265285    }
    266286  else if ((state->type == JSONSL_T_LIST) || (state->type == JSONSL_T_OBJECT))
     
    320340  data.stack = TR_PTR_ARRAY_INIT;
    321341  data.source = source;
     342  data.keybuf = evbuffer_new ();
     343  data.strbuf = evbuffer_new ();
    322344
    323345  /* parse it */
     
    334356  /* cleanup */
    335357  error = data.error;
     358  evbuffer_free (data.keybuf);
     359  evbuffer_free (data.strbuf);
    336360  tr_ptrArrayDestruct (&data.stack, NULL);
    337361  jsonsl_destroy (jsn);
Note: See TracChangeset for help on using the changeset viewer.