Changeset 13687


Ignore:
Timestamp:
Dec 24, 2012, 10:38:41 PM (8 years ago)
Author:
jordan
Message:

(trunk, libT) more tr_variant revision: faster serialization, dictionaries use less space

Location:
trunk
Files:
6 edited

Legend:

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

    r13683 r13687  
    1212
    1313#include <assert.h>
    14 #include <ctype.h> /* isdigit () */
     14#include <ctype.h> /* isdigit() */
    1515#include <errno.h>
    16 #include <stdlib.h> /* strtoul (), strtod (), realloc (), qsort (), mkstemp () */
    17 #include <string.h> /* strlen (), memchr () */
    18 
    19 #include <locale.h> /* setlocale () */
     16#include <stdlib.h> /* strtoul(), strtod(), realloc(), qsort(), mkstemp() */
     17#include <string.h> /* strlen(), memchr() */
    2018
    2119#include <event2/buffer.h>
     
    2624#include "transmission.h"
    2725#include "ptrarray.h"
    28 #include "utils.h" /* tr_strlcpy () */
     26#include "utils.h" /* tr_snprintf() */
    2927#include "variant.h"
    3028#include "variant-common.h"
    3129
    3230/***
    33 ****  tr_variantParse ()
    34 ****  tr_variantLoad ()
     31****  tr_variantParse()
     32****  tr_variantLoad()
    3533***/
    3634
     
    118116}
    119117
    120 static int
    121 makeroom (tr_variant * container, size_t count)
    122 {
    123   const size_t needed = container->val.l.count + count;
    124 
    125   assert (tr_variantIsContainer (container));
    126 
    127   if (needed > container->val.l.alloc)
     118static tr_variant*
     119get_node (tr_ptrArray * stack, tr_quark * key, tr_variant * top, int * err)
     120{
     121  tr_variant * node = NULL;
     122
     123  if (tr_ptrArrayEmpty (stack))
    128124    {
    129       size_t n;
    130       void * tmp;
    131 
    132       /* scale the alloc size in powers-of-2 */
    133       n = container->val.l.alloc ? container->val.l.alloc : 8;
    134       while (n < needed)
    135         n *= 2u;
    136 
    137       tmp = realloc (container->val.l.vals, n * sizeof (tr_variant));
    138       if (tmp == NULL)
    139         return 1;
    140 
    141       container->val.l.alloc = n;
    142       container->val.l.vals = tmp;
     125      node = top;
    143126    }
    144 
    145   return 0;
    146 }
    147 
    148 static inline bool
    149 isReadyForDictKey (tr_ptrArray * parentStack)
    150 {
    151   tr_variant * parent = tr_ptrArrayBack (parentStack);
    152 
    153   return (parent != NULL)
    154       && (tr_variantIsDict(parent))
    155       && ((parent->val.l.count%2)==0);
    156 }
    157 
    158 static tr_variant*
    159 getNode (tr_variant  * top,
    160          tr_ptrArray * parentStack,
    161          int           type)
    162 {
    163   tr_variant * parent;
    164 
    165   assert (top);
    166   assert (parentStack);
    167 
    168   if (tr_ptrArrayEmpty (parentStack))
    169     return top;
    170 
    171   parent = tr_ptrArrayBack (parentStack);
    172   assert (parent);
    173 
    174   /* dictionary keys must be strings */
    175   if ((parent->type == TR_VARIANT_TYPE_DICT)
    176       && (type != TR_VARIANT_TYPE_STR)
    177       && (! (parent->val.l.count % 2)))
    178     return NULL;
    179 
    180   makeroom (parent, 1);
    181   return parent->val.l.vals + parent->val.l.count++;
     127  else
     128    {
     129      tr_variant * parent = tr_ptrArrayBack (stack);
     130
     131      if (tr_variantIsList (parent))
     132        {
     133          node = tr_variantListAdd (parent);
     134        }
     135      else if (*key && tr_variantIsDict (parent))
     136        {
     137          node = tr_variantDictAdd (parent, *key);
     138          *key = 0;
     139        }
     140      else
     141        {
     142          *err = EILSEQ;
     143        }
     144    }
     145
     146  return node;
    182147}
    183148
     
    187152 * attack via maliciously-crafted bencoded data. (#667)
    188153 */
    189 static int
    190 tr_variantParseImpl (const void    * buf_in,
     154int
     155tr_variantParseBenc (const void    * buf_in,
    191156                     const void    * bufend_in,
    192157                     tr_variant    * top,
    193                      tr_ptrArray   * parentStack,
    194158                     const char   ** setme_end)
    195159{
    196   int err;
     160  int err = 0;
    197161  const uint8_t * buf = buf_in;
    198162  const uint8_t * bufend = bufend_in;
     163  tr_ptrArray stack = TR_PTR_ARRAY_INIT;
     164  tr_quark key = 0;
    199165
    200166  tr_variantInit (top, 0);
     
    203169    {
    204170      if (buf > bufend) /* no more text to parse... */
    205         return 1;
     171        err = EILSEQ;
     172
     173      if (err)
     174        break;
    206175
    207176      if (*buf == 'i') /* int */
     
    209178          int64_t val;
    210179          const uint8_t * end;
    211           tr_variant * node;
     180          tr_variant * v;
    212181
    213182          if ((err = tr_bencParseInt (buf, bufend, &end, &val)))
    214             return err;
    215 
    216           node = getNode (top, parentStack, TR_VARIANT_TYPE_INT);
    217           if (!node)
    218             return EILSEQ;
    219 
    220           tr_variantInitInt (node, val);
     183            break;
    221184          buf = end;
    222185
    223           if (tr_ptrArrayEmpty (parentStack))
    224             break;
     186          if ((v = get_node (&stack, &key, top, &err)))
     187            tr_variantInitInt (v, val);
    225188        }
    226189      else if (*buf == 'l') /* list */
    227190        {
    228           tr_variant * node = getNode (top, parentStack, TR_VARIANT_TYPE_LIST);
    229           if (!node)
    230             return EILSEQ;
    231 
    232           tr_variantInit (node, TR_VARIANT_TYPE_LIST);
    233           tr_ptrArrayAppend (parentStack, node);
     191          tr_variant * v;
     192
    234193          ++buf;
     194
     195          if ((v = get_node (&stack, &key, top, &err)))
     196            {
     197              tr_variantInitList (v, 0);
     198              tr_ptrArrayAppend (&stack, v);
     199            }
    235200        }
    236201      else if (*buf == 'd') /* dict */
    237202        {
    238           tr_variant * node = getNode (top, parentStack, TR_VARIANT_TYPE_DICT);
    239           if (!node)
    240             return EILSEQ;
    241 
    242           tr_variantInit (node, TR_VARIANT_TYPE_DICT);
    243           tr_ptrArrayAppend (parentStack, node);
     203          tr_variant * v;
     204
    244205          ++buf;
     206
     207          if ((v = get_node (&stack, &key, top, &err)))
     208            {
     209              tr_variantInitDict (v, 0);
     210              tr_ptrArrayAppend (&stack, v);
     211            }
    245212        }
    246213      else if (*buf == 'e') /* end of list or dict */
    247214        {
    248           tr_variant * node;
    249215          ++buf;
    250           if (tr_ptrArrayEmpty (parentStack))
    251               return EILSEQ;
    252 
    253           node = tr_ptrArrayBack (parentStack);
    254           if (tr_variantIsDict (node) && (node->val.l.count % 2))
     216
     217          if (tr_ptrArrayEmpty (&stack) || (key != 0))
    255218            {
    256               /* odd # of children in dict */
    257               tr_variantFree (&node->val.l.vals[--node->val.l.count]);
    258               return EILSEQ;
     219              err = EILSEQ;
     220              break;
    259221            }
    260 
    261           tr_ptrArrayPop (parentStack);
    262           if (tr_ptrArrayEmpty (parentStack))
    263             break;
     222          else
     223            {
     224              tr_ptrArrayPop (&stack);
     225              if (tr_ptrArrayEmpty (&stack))
     226                break;
     227            }
    264228        }
    265229      else if (isdigit (*buf)) /* string? */
    266230        {
     231          tr_variant * v;
    267232          const uint8_t * end;
    268233          const uint8_t * str;
    269234          size_t str_len;
    270           tr_variant * node;
    271           const bool is_key = isReadyForDictKey (parentStack);
    272235
    273236          if ((err = tr_bencParseStr (buf, bufend, &end, &str, &str_len)))
    274             return err;
    275 
    276           node = getNode (top, parentStack, TR_VARIANT_TYPE_STR);
    277           if (!node)
    278             return EILSEQ;
    279 
    280           if (is_key)
    281             tr_variantInitQuark (node, tr_quark_new (str, str_len));
    282           else
    283             tr_variantInitStr (node, str, str_len);
    284 
     237            break;
    285238          buf = end;
    286239
    287           if (tr_ptrArrayEmpty (parentStack))
    288             break;
     240          if (!key && !tr_ptrArrayEmpty(&stack) && tr_variantIsDict(tr_ptrArrayBack(&stack)))
     241            key = tr_quark_new (str, str_len);
     242          else if ((v = get_node (&stack, &key, top, &err)))
     243            tr_variantInitStr (v, str, str_len);
    289244        }
    290245      else /* invalid bencoded text... march past it */
     
    292247          ++buf;
    293248        }
     249
     250      if (tr_ptrArrayEmpty (&stack))
     251        break;
    294252    }
    295253
    296   err = !tr_variantIsSomething (top) || !tr_ptrArrayEmpty (parentStack);
     254  if (!err)
     255    err = !top->type || !tr_ptrArrayEmpty(&stack);
    297256
    298257  if (!err && setme_end)
    299258    *setme_end = (const char*) buf;
    300259
    301   return err;
    302 }
    303 
    304 
    305 int
    306 tr_variantParseBenc (const void     * buf,
    307                      const void     * end,
    308                      tr_variant     * top,
    309                      const char    ** setme_end)
    310 {
    311   int err;
    312   tr_ptrArray parentStack = TR_PTR_ARRAY_INIT;
    313 
    314   top->type = 0; /* set to `uninitialized' */
    315   err = tr_variantParseImpl (buf, end, top, &parentStack, setme_end);
    316   if (err)
    317     tr_variantFree (top);
    318 
    319   tr_ptrArrayDestruct (&parentStack, NULL);
     260  tr_ptrArrayDestruct (&stack, NULL);
    320261  return err;
    321262}
     
    343284saveRealFunc (const tr_variant * val, void * evbuf)
    344285{
     286  int len;
    345287  char buf[128];
    346   char locale[128];
    347   size_t len;
    348 
    349   /* always use a '.' decimal point s.t. locale-hopping doesn't bite us */
    350   tr_strlcpy (locale, setlocale (LC_NUMERIC, NULL), sizeof (locale));
    351   setlocale (LC_NUMERIC, "POSIX");
    352   tr_snprintf (buf, sizeof (buf), "%f", val->val.d);
    353   setlocale (LC_NUMERIC, locale);
    354 
    355   len = strlen (buf);
    356   evbuffer_add_printf (evbuf, "%lu:", (unsigned long)len);
     288
     289  len = tr_snprintf (buf, sizeof (buf), "%f", val->val.d);
     290  evbuffer_add_printf (evbuf, "%d:", len);
    357291  evbuffer_add (evbuf, buf, len);
    358292}
  • trunk/libtransmission/variant-common.h

    r13667 r13687  
    4141void tr_variantToBufBenc (const tr_variant * top, struct evbuffer * buf);
    4242
    43 bool tr_variantIsSomething (const tr_variant * v);
    44 
    45 bool tr_variantIsContainer (const tr_variant * v);
    46 
    4743void tr_variantInit (tr_variant * v, char type);
    4844
  • trunk/libtransmission/variant-json.c

    r13683 r13687  
    1717#include <string.h>
    1818#include <errno.h> /* EILSEQ, EINVAL */
    19 
    20 #include <locale.h> /* setlocale() */
    2119
    2220#include <event2/buffer.h> /* evbuffer_add() */
     
    390388jsonIndent (struct jsonWalk * data)
    391389{
     390  static char buf[1024] = { '\0' };
     391  if (!*buf)
     392    {
     393      memset (buf, ' ', sizeof(buf));
     394      buf[0] = '\n';
     395    }
     396
    392397  if (data->doIndent)
    393     {
    394       char buf[1024];
    395       const int width = tr_list_size (data->parents) * 4;
    396 
    397       buf[0] = '\n';
    398       memset (buf+1, ' ', width);
    399       evbuffer_add (data->out, buf, 1+width);
    400     }
     398    evbuffer_add (data->out, buf, tr_list_size(data->parents)*4 + 1);
    401399}
    402400
     
    456454  pstate->childIndex = 0;
    457455  pstate->childCount = v->val.l.count;
     456  if (tr_variantIsDict (v))
     457    pstate->childCount *= 2;
     458
    458459  tr_list_prepend (&data->parents, pstate);
    459460}
     
    621622tr_variantToBufJson (const tr_variant * top, struct evbuffer * buf, bool lean)
    622623{
    623   char lc_numeric[128];
    624624  struct jsonWalk data;
    625625
     
    628628  data.parents = NULL;
    629629
    630   /* json requires a '.' decimal point regardless of locale */
    631   tr_strlcpy (lc_numeric, setlocale (LC_NUMERIC, NULL), sizeof (lc_numeric));
    632   setlocale (LC_NUMERIC, "POSIX");
    633630  tr_variantWalk (top, &walk_funcs, &data, true);
    634   setlocale (LC_NUMERIC, lc_numeric);
    635631
    636632  if (evbuffer_get_length (buf))
  • trunk/libtransmission/variant.c

    r13683 r13687  
    1313#include <assert.h>
    1414#include <errno.h>
    15 #include <stdio.h> /* rename () */
    16 #include <stdlib.h> /* strtoul (), strtod (), realloc (), qsort (), mkstemp () */
     15#include <stdio.h> /* rename() */
     16#include <stdlib.h> /* strtoul(), strtod(), realloc(), qsort(), mkstemp() */
    1717#include <string.h>
    1818
    19 #ifdef WIN32 /* tr_mkstemp () */
     19#ifdef WIN32 /* tr_mkstemp() */
    2020 #include <fcntl.h>
    2121 #define _S_IREAD 256
     
    2323#endif
    2424
    25 #include <locale.h> /* setlocale () */
    26 #include <unistd.h> /* write (), unlink () */
     25#include <locale.h> /* setlocale() */
     26#include <unistd.h> /* write(), unlink() */
    2727
    2828#include <event2/buffer.h>
     
    3131#include "transmission.h"
    3232#include "ConvertUTF.h" 
    33 #include "fdlimit.h" /* tr_close_file () */
     33#include "fdlimit.h" /* tr_close_file() */
    3434#include "platform.h" /* TR_PATH_MAX */
    35 #include "utils.h" /* tr_new (), tr_free () */
     35#include "utils.h" /* tr_new(), tr_free() */
    3636#include "variant.h"
    3737#include "variant-common.h"
     
    4141**/
    4242
    43 bool
     43static bool
    4444tr_variantIsContainer (const tr_variant * v)
    4545{
     
    4747}
    4848
    49 bool
     49static bool
    5050tr_variantIsSomething (const tr_variant * v)
    5151{
     
    6060tr_variantInit (tr_variant * v, char type)
    6161{
    62   memset (v, 0, sizeof (*v));
    6362  v->type = type;
     63  memset (&v->val, 0, sizeof(v->val));
    6464}
    6565
     
    6767****
    6868***/
    69 
    70 /*
    71 zzz
    72 
    73 typedef enum
    74 {
    75   TR_STRING_TYPE_KEY,
    76   TR_STRING_TYPE_HEAP,
    77   TR_STRING_TYPE_BUF
    78 }
    79 tr_string_type;
    80 
    81 struct tr_variant_string
    82 {
    83   tr_key key;
    84   tr_string_type type;
    85   size_t len;
    86   union { char buf[8]; char * ptr; } str;
    87 };
    88 */
    8969
    9070static const struct tr_variant_string STRING_INIT =
     
    123103
    124104static void
    125 tr_variant_string_set_quark (struct tr_variant_string * str, const tr_quark quark)
     105tr_variant_string_set_quark (struct tr_variant_string  * str,
     106                             const tr_quark              quark)
    126107{
    127108  tr_variant_string_clear (str);
     
    133114
    134115static void
    135 tr_variant_string_set_string (struct tr_variant_string * str, const char * bytes, int len)
     116tr_variant_string_set_string (struct tr_variant_string  * str,
     117                              const char                * bytes,
     118                              int                         len)
    136119{
    137120  tr_quark quark;
     
    189172      const tr_variant * const end = begin + dict->val.l.count;
    190173
    191       for (walk=begin; walk!=end; walk+=2)
    192       {
    193         assert (walk->type == TR_VARIANT_TYPE_STR);
    194         assert (walk->val.s.type == TR_STRING_TYPE_QUARK);
    195 
    196         if (walk->val.s.quark == key)
     174      for (walk=begin; walk!=end; ++walk)
     175        if (walk->key == key)
    197176          return walk - begin;
    198       }
    199177    }
    200178
     
    207185  const int i = dictIndexOf (dict, key);
    208186
    209   return i < 0 ? NULL : &dict->val.l.vals[i + 1];
     187  return i < 0 ? NULL : dict->val.l.vals+i;
    210188}
    211189
     
    226204
    227205tr_variant*
    228 tr_variantListChild (tr_variant * val,
    229                   size_t    i)
     206tr_variantListChild (tr_variant * v,
     207                     size_t    i)
    230208{
    231209  tr_variant * ret = NULL;
    232210
    233   if (tr_variantIsList (val) && (i < val->val.l.count))
    234     ret = val->val.l.vals + i;
     211  if (tr_variantIsList (v) && (i < v->val.l.count))
     212    ret = v->val.l.vals + i;
    235213
    236214  return ret;
    237215}
    238216
    239 int
     217bool
    240218tr_variantListRemove (tr_variant * list, size_t i)
    241219{
     220  bool removed = false;
     221
    242222  if (tr_variantIsList (list) && (i < list->val.l.count))
    243223    {
     224      removed = true;
    244225      tr_variantFree (&list->val.l.vals[i]);
    245226      tr_removeElementFromArray (list->val.l.vals, i,
    246227                                 sizeof (tr_variant),
    247228                                 list->val.l.count--);
    248       return 1;
    249     }
    250 
    251   return 0;
    252 }
    253 
    254 static void
    255 tr_variant_warning (const char * err)
    256 {
    257   fprintf (stderr, "warning: %s\n", err);
    258 }
    259 
    260 bool
    261 tr_variantGetInt (const tr_variant  * val,
     229    }
     230
     231  return removed;
     232}
     233
     234bool
     235tr_variantGetInt (const tr_variant  * v,
    262236                  int64_t           * setme)
    263237{
    264238  bool success = false;
    265239
    266   if (!success && ((success = tr_variantIsInt (val))))
     240  if (!success && ((success = tr_variantIsInt (v))))
    267241    if (setme)
    268       *setme = val->val.i;
    269 
    270   if (!success && ((success = tr_variantIsBool (val))))
    271     {
    272       tr_variant_warning ("reading bool as an int");
    273       if (setme)
    274         *setme = val->val.b ? 1 : 0;
    275     }
     242      *setme = v->val.i;
     243
     244  if (!success && ((success = tr_variantIsBool (v))))
     245    if (setme)
     246      *setme = v->val.b ? 1 : 0;
    276247
    277248  return success;
     
    279250
    280251bool
    281 tr_variantGetStr (const tr_variant   * val,
     252tr_variantGetStr (const tr_variant   * v,
    282253                  const char        ** setme,
    283254                  size_t             * len)
    284255{
    285   const bool success = tr_variantIsString (val);
     256  const bool success = tr_variantIsString (v);
    286257
    287258  if (success)
    288     *setme = getStr (val);
     259    *setme = getStr (v);
    289260
    290261  if (len != NULL)
    291     *len = success ? val->val.s.len : 0;
     262    *len = success ? v->val.s.len : 0;
    292263
    293264  return success;
     
    295266
    296267bool
    297 tr_variantGetRaw (const tr_variant   * val,
     268tr_variantGetRaw (const tr_variant   * v,
    298269                  const uint8_t     ** setme_raw,
    299270                  size_t             * setme_len)
    300271{
    301   const bool success = tr_variantIsString (val);
     272  const bool success = tr_variantIsString (v);
    302273
    303274  if (success)
    304275    {
    305       *setme_raw = (uint8_t*) getStr (val);
    306       *setme_len = val->val.s.len;
     276      *setme_raw = (uint8_t*) getStr (v);
     277      *setme_len = v->val.s.len;
    307278    }
    308279
     
    311282
    312283bool
    313 tr_variantGetBool (const tr_variant * val, bool * setme)
     284tr_variantGetBool (const tr_variant * v, bool * setme)
    314285{
    315286  const char * str;
    316287  bool success = false;
    317288
    318   if ((success = tr_variantIsBool (val)))
    319     *setme = val->val.b;
    320 
    321   if (!success && tr_variantIsInt (val))
    322     if ((success = (val->val.i==0 || val->val.i==1)))
    323       *setme = val->val.i!=0;
    324 
    325   if (!success && tr_variantGetStr (val, &str, NULL))
     289  if ((success = tr_variantIsBool (v)))
     290    *setme = v->val.b;
     291
     292  if (!success && tr_variantIsInt (v))
     293    if ((success = (v->val.i==0 || v->val.i==1)))
     294      *setme = v->val.i!=0;
     295
     296  if (!success && tr_variantGetStr (v, &str, NULL))
    326297    if ((success = (!strcmp (str,"true") || !strcmp (str,"false"))))
    327298      *setme = !strcmp (str,"true");
     
    331302
    332303bool
    333 tr_variantGetReal (const tr_variant * val, double * setme)
     304tr_variantGetReal (const tr_variant * v, double * setme)
    334305{
    335306  bool success = false;
    336307
    337   if (!success && ((success = tr_variantIsReal (val))))
    338     *setme = val->val.d;
    339 
    340   if (!success && ((success = tr_variantIsInt (val))))
    341     *setme = val->val.i;
    342 
    343   if (!success && tr_variantIsString (val))
     308  if (!success && ((success = tr_variantIsReal (v))))
     309    *setme = v->val.d;
     310
     311  if (!success && ((success = tr_variantIsInt (v))))
     312    *setme = v->val.i;
     313
     314  if (!success && tr_variantIsString (v))
    344315    {
    345316      char * endptr;
     
    350321      tr_strlcpy (locale, setlocale (LC_NUMERIC, NULL), sizeof (locale));
    351322      setlocale (LC_NUMERIC, "POSIX");
    352       d  = strtod (getStr (val), &endptr);
     323      d  = strtod (getStr (v), &endptr);
    353324      setlocale (LC_NUMERIC, locale);
    354325
    355       if ((success = (getStr (val) != endptr) && !*endptr))
     326      if ((success = (getStr (v) != endptr) && !*endptr))
    356327        *setme = d;
    357328    }
     
    402373                        tr_variant      ** setme)
    403374{
    404   return tr_variantDictFindType (dict,
    405                                  key,
    406                                  TR_VARIANT_TYPE_LIST,
    407                                  setme);
     375  return tr_variantDictFindType (dict, key, TR_VARIANT_TYPE_LIST, setme);
    408376}
    409377
     
    413381                        tr_variant      ** setme)
    414382{
    415   return tr_variantDictFindType (dict,
    416                                  key,
    417                                  TR_VARIANT_TYPE_DICT,
    418                                  setme);
     383  return tr_variantDictFindType (dict, key, TR_VARIANT_TYPE_DICT, setme);
    419384}
    420385
     
    455420
    456421void
    457 tr_variantInitBool (tr_variant * variant, bool value)
    458 {
    459   tr_variantInit (variant, TR_VARIANT_TYPE_BOOL);
    460   variant->val.b = value != 0;
    461 }
    462 
    463 void
    464 tr_variantInitReal (tr_variant * b, double value)
    465 {
    466   tr_variantInit (b, TR_VARIANT_TYPE_REAL);
    467   b->val.d = value;
    468 }
    469 
    470 void
    471 tr_variantInitInt (tr_variant * variant, int64_t value)
    472 {
    473   tr_variantInit (variant, TR_VARIANT_TYPE_INT);
    474   variant->val.i = value;
    475 }
    476 
    477 int
    478 tr_variantInitList (tr_variant * variant, size_t reserve_count)
    479 {
    480   tr_variantInit (variant, TR_VARIANT_TYPE_LIST);
    481   return tr_variantListReserve (variant, reserve_count);
    482 }
    483 
    484 static int
    485 containerReserve (tr_variant * container, size_t count)
    486 {
    487   const size_t needed = container->val.l.count + count;
    488 
    489   assert (tr_variantIsContainer (container));
    490 
    491   if (needed > container->val.l.alloc)
    492     {
    493       size_t n;
    494       void * tmp;
    495 
     422tr_variantInitBool (tr_variant * v, bool value)
     423{
     424  tr_variantInit (v, TR_VARIANT_TYPE_BOOL);
     425  v->val.b = value != 0;
     426}
     427
     428void
     429tr_variantInitReal (tr_variant * v, double value)
     430{
     431  tr_variantInit (v, TR_VARIANT_TYPE_REAL);
     432  v->val.d = value;
     433}
     434
     435void
     436tr_variantInitInt (tr_variant * v, int64_t value)
     437{
     438  tr_variantInit (v, TR_VARIANT_TYPE_INT);
     439  v->val.i = value;
     440}
     441
     442void
     443tr_variantInitList (tr_variant * v, size_t reserve_count)
     444{
     445  tr_variantInit (v, TR_VARIANT_TYPE_LIST);
     446  tr_variantListReserve (v, reserve_count);
     447}
     448
     449static void
     450containerReserve (tr_variant * v, size_t count)
     451{
     452  const size_t needed = v->val.l.count + count;
     453
     454  assert (tr_variantIsContainer (v));
     455
     456  if (needed > v->val.l.alloc)
     457    {
    496458      /* scale the alloc size in powers-of-2 */
    497       n = container->val.l.alloc ? container->val.l.alloc : 8;
     459      size_t n = v->val.l.alloc ? v->val.l.alloc : 8;
    498460      while (n < needed)
    499461        n *= 2u;
    500462
    501       tmp = tr_renew (tr_variant, container->val.l.vals, n);
    502       if (tmp == NULL)
    503         return 1;
    504 
    505       container->val.l.alloc = n;
    506       container->val.l.vals = tmp;
    507     }
    508 
    509   return 0;
    510 }
    511 
    512 int
     463      v->val.l.vals = tr_renew (tr_variant, v->val.l.vals, n);
     464      v->val.l.alloc = n;
     465    }
     466}
     467
     468void
    513469tr_variantListReserve (tr_variant * list, size_t count)
    514470{
    515471  assert (tr_variantIsList (list));
    516   return containerReserve (list, count);
    517 }
    518 
    519 int
    520 tr_variantInitDict (tr_variant * variant, size_t reserve_count)
    521 {
    522   tr_variantInit (variant, TR_VARIANT_TYPE_DICT);
    523   return tr_variantDictReserve (variant, reserve_count);
    524 }
    525 
    526 int
     472  containerReserve (list, count);
     473}
     474
     475void
     476tr_variantInitDict (tr_variant * v, size_t reserve_count)
     477{
     478  tr_variantInit (v, TR_VARIANT_TYPE_DICT);
     479  tr_variantDictReserve (v, reserve_count);
     480}
     481
     482void
    527483tr_variantDictReserve (tr_variant  * dict,
    528484                       size_t        reserve_count)
    529485{
    530486  assert (tr_variantIsDict (dict));
    531   return containerReserve (dict, reserve_count * 2);
     487  containerReserve (dict, reserve_count);
    532488}
    533489
     
    541497  containerReserve (list, 1);
    542498  child = &list->val.l.vals[list->val.l.count++];
     499  child->key = 0;
    543500  tr_variantInit (child, TR_VARIANT_TYPE_INT);
    544501
     
    623580                   const tr_quark    key)
    624581{
    625   tr_variant * child_key;
    626   tr_variant * child_val;
     582  tr_variant * val;
    627583
    628584  assert (tr_variantIsDict (dict));
    629585
    630   containerReserve (dict, 2);
    631 
    632   child_key = dict->val.l.vals + dict->val.l.count++;
    633   tr_variantInitQuark (child_key, key);
    634 
    635   child_val = dict->val.l.vals + dict->val.l.count++;
    636   tr_variantInit (child_val, TR_VARIANT_TYPE_INT);
    637   return child_val;
     586  containerReserve (dict, 1);
     587
     588  val = dict->val.l.vals + dict->val.l.count++;
     589  tr_variantInit (val, TR_VARIANT_TYPE_INT);
     590  val->key = key;
     591  return val;
    638592}
    639593
     
    675629
    676630tr_variant*
    677 tr_variantDictAddBool (tr_variant * dict, const tr_quark key, bool val)
     631tr_variantDictAddBool (tr_variant      * dict,
     632                       const tr_quark    key,
     633                       bool              val)
    678634{
    679635  tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_BOOL);
     
    683639
    684640tr_variant*
    685 tr_variantDictAddReal (tr_variant * dict, const tr_quark key, double val)
     641tr_variantDictAddReal (tr_variant      * dict,
     642                       const tr_quark    key,
     643                       double            val)
    686644{
    687645  tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_REAL);
     
    691649
    692650tr_variant*
    693 tr_variantDictAddQuark (tr_variant * dict, const tr_quark key, const tr_quark val)
     651tr_variantDictAddQuark (tr_variant      * dict,
     652                        const tr_quark    key,
     653                        const tr_quark    val)
    694654{
    695655  tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_STR);
     
    699659
    700660tr_variant*
    701 tr_variantDictAddStr (tr_variant * dict, const tr_quark key, const char * val)
     661tr_variantDictAddStr (tr_variant      * dict,
     662                      const tr_quark    key,
     663                      const char      * val)
    702664{
    703665  tr_variant * child = dictFindOrAdd (dict, key, TR_VARIANT_TYPE_STR);
     
    737699}
    738700
    739 int
     701bool
    740702tr_variantDictRemove (tr_variant     * dict,
    741703                      const tr_quark   key)
    742704{
     705  bool removed = false;
    743706  const int i = dictIndexOf (dict, key);
    744707
    745708  if (i >= 0)
    746709    {
    747       const int n = dict->val.l.count;
     710      const int last = dict->val.l.count - 1;
     711
    748712      tr_variantFree (&dict->val.l.vals[i]);
    749       tr_variantFree (&dict->val.l.vals[i + 1]);
    750       if (i + 2 < n)
    751         {
    752           dict->val.l.vals[i]   = dict->val.l.vals[n - 2];
    753           dict->val.l.vals[i + 1] = dict->val.l.vals[n - 1];
    754         }
    755       dict->val.l.count -= 2;
    756     }
    757 
    758   return i >= 0; /* return true if found */
     713
     714      if (i != last)
     715        dict->val.l.vals[i] = dict->val.l.vals[last];
     716
     717      --dict->val.l.count;
     718
     719       removed = true;
     720    }
     721
     722  return removed;
    759723}
    760724
     
    765729struct KeyIndex
    766730{
    767   const char *  key;
    768   int           index;
     731  const char * keystr;
     732  tr_variant * val;
    769733};
    770734
     
    775739  const struct KeyIndex * b = vb;
    776740
    777   return strcmp (a->key, b->key);
     741  return strcmp (a->keystr, b->keystr);
    778742}
    779743
    780744struct SaveNode
    781745{
    782   const tr_variant * val;
    783   int valIsVisited;
    784   int childCount;
    785   int childIndex;
    786   int * children;
     746  const tr_variant * v;
     747  tr_variant sorted;
     748  size_t childIndex;
     749  bool isVisited;
    787750};
    788751
    789752static void
    790 nodeInitDict (struct SaveNode   * node,
    791               const tr_variant  * val,
    792               bool                sort_dicts)
    793 {
    794   const int n = val->val.l.count;
    795   const int nKeys = n / 2;
    796 
    797   assert (tr_variantIsDict (val));
    798 
    799   node->val = val;
    800   node->children = tr_new0 (int, n);
    801 
    802   if (sort_dicts)
    803     {
    804       int i, j;
    805       struct KeyIndex * indices = tr_new (struct KeyIndex, nKeys);
    806 
    807       for (i=j=0; i<n; i+=2, ++j)
     753nodeConstruct (struct SaveNode   * node,
     754               const tr_variant  * v,
     755               bool                sort_dicts)
     756{
     757  node->isVisited = false;
     758  node->childIndex = 0;
     759
     760  if (sort_dicts && tr_variantIsDict(v))
     761    {
     762      /* make node->sorted a sorted version of this dictionary */
     763
     764      size_t i;
     765      const size_t n = v->val.l.count;
     766      struct KeyIndex * tmp = tr_new (struct KeyIndex, n);
     767
     768      for (i=0; i<n; i++)
    808769        {
    809           indices[j].key = getStr (&val->val.l.vals[i]);
    810           indices[j].index = i;
     770          tmp[i].val = v->val.l.vals+i;
     771          tmp[i].keystr = tr_quark_get_string (tmp[i].val->key, NULL);
    811772        }
    812773
    813       qsort (indices, j, sizeof (struct KeyIndex), compareKeyIndex);
    814 
    815       for (i=0; i<j; ++i)
    816         {
    817           const int index = indices[i].index;
    818           node->children[node->childCount++] = index;
    819           node->children[node->childCount++] = index + 1;
    820         }
    821 
    822       tr_free (indices);
     774      qsort (tmp, n, sizeof (struct KeyIndex), compareKeyIndex);
     775
     776      tr_variantInitDict (&node->sorted, n);
     777      for (i=0; i<n; ++i)
     778        node->sorted.val.l.vals[i] = *tmp[i].val;
     779      node->sorted.val.l.count = n;
     780
     781      tr_free (tmp);
     782
     783      node->v = &node->sorted;
    823784    }
    824785  else
    825786    {
    826       int i;
    827 
    828       for (i=0; i<n; ++i)
    829         node->children[node->childCount++] = i;
    830     }
    831 
    832   assert (node->childCount == n);
     787      node->v = v;
     788    }
    833789}
    834790
    835791static void
    836 nodeInitList (struct SaveNode   * node,
    837               const tr_variant  * val)
    838 {
    839   int i;
    840   int n;
    841 
    842   assert (tr_variantIsList (val));
    843 
    844   n = val->val.l.count;
    845   node->val = val;
    846   node->childCount = n;
    847   node->children = tr_new0 (int, n);
    848   for (i=0; i<n; ++i) /* a list's children don't need to be reordered */
    849     node->children[i] = i;
    850 }
    851 
    852 static void
    853 nodeInitLeaf (struct SaveNode   * node,
    854               const tr_variant  * variant)
    855 {
    856   assert (!tr_variantIsContainer (variant));
    857 
    858   node->val = variant;
    859 }
    860 
    861 static void
    862 nodeInit (struct SaveNode   * node,
    863           const tr_variant  * variant,
    864           bool                sort_dicts)
    865 {
    866   static const struct SaveNode INIT_NODE = { NULL, 0, 0, 0, NULL };
    867 
    868   *node = INIT_NODE;
    869 
    870   if (tr_variantIsList (variant))
    871     nodeInitList (node, variant);
    872   else if (tr_variantIsDict (variant))
    873     nodeInitDict (node, variant, sort_dicts);
    874   else
    875     nodeInitLeaf (node, variant);
     792nodeDestruct (struct SaveNode * node)
     793{
     794  if (node->v == &node->sorted)
     795    tr_free (node->sorted.val.l.vals);
    876796}
    877797
     
    882802 */
    883803void
    884 tr_variantWalk (const tr_variant               * top,
     804tr_variantWalk (const tr_variant               * v,
    885805                const struct VariantWalkFuncs  * walkFuncs,
    886806                void                           * user_data,
     
    889809  int stackSize = 0;
    890810  int stackAlloc = 64;
     811  char lc_numeric[128];
    891812  struct SaveNode * stack = tr_new (struct SaveNode, stackAlloc);
    892813
    893   nodeInit (&stack[stackSize++], top, sort_dicts);
     814  /* always use a '.' decimal point s.t. locale-hopping doesn't bite us */
     815  tr_strlcpy (lc_numeric, setlocale (LC_NUMERIC, NULL), sizeof (lc_numeric));
     816  setlocale (LC_NUMERIC, "POSIX");
     817
     818  nodeConstruct (&stack[stackSize++], v, sort_dicts);
    894819
    895820  while (stackSize > 0)
    896821    {
    897822      struct SaveNode * node = &stack[stackSize-1];
    898       const tr_variant * val;
    899 
    900       if (!node->valIsVisited)
     823      const tr_variant * v;
     824
     825      if (!node->isVisited)
    901826        {
    902             val = node->val;
    903             node->valIsVisited = true;
     827          v = node->v;
     828          node->isVisited = true;
    904829        }
    905       else if (node->childIndex < node->childCount)
     830      else if (tr_variantIsContainer(node->v) && (node->childIndex < node->v->val.l.count))
    906831        {
    907             const int index = node->children[node->childIndex++];
    908             val = node->val->val.l.vals +  index;
     832          const int index = node->childIndex++;
     833          v = node->v->val.l.vals + index;
     834
     835          if (tr_variantIsDict (node->v))
     836            {
     837              tr_variant tmp;
     838              tr_variantInitQuark (&tmp, v->key);
     839              walkFuncs->stringFunc (&tmp, user_data);
     840            }
    909841        }
    910842      else /* done with this node */
    911843        {
    912             if (tr_variantIsContainer (node->val))
    913                 walkFuncs->containerEndFunc (node->val, user_data);
    914             --stackSize;
    915             tr_free (node->children);
    916             continue;
     844          if (tr_variantIsContainer (node->v))
     845            walkFuncs->containerEndFunc (node->v, user_data);
     846          --stackSize;
     847          nodeDestruct (node);
     848          continue;
    917849        }
    918850
    919       if (val) switch (val->type)
     851      if (v) switch (v->type)
    920852        {
    921853          case TR_VARIANT_TYPE_INT:
    922             walkFuncs->intFunc (val, user_data);
     854            walkFuncs->intFunc (v, user_data);
    923855            break;
    924856
    925857          case TR_VARIANT_TYPE_BOOL:
    926             walkFuncs->boolFunc (val, user_data);
     858            walkFuncs->boolFunc (v, user_data);
    927859            break;
    928860
    929861          case TR_VARIANT_TYPE_REAL:
    930             walkFuncs->realFunc (val, user_data);
     862            walkFuncs->realFunc (v, user_data);
    931863            break;
    932864
    933865          case TR_VARIANT_TYPE_STR:
    934             walkFuncs->stringFunc (val, user_data);
     866            walkFuncs->stringFunc (v, user_data);
    935867            break;
    936868
    937869          case TR_VARIANT_TYPE_LIST:
    938             if (val == node->val)
     870            if (v == node->v)
    939871              {
    940                 walkFuncs->listBeginFunc (val, user_data);
     872                walkFuncs->listBeginFunc (v, user_data);
    941873              }
    942874            else
     
    947879                    stack = tr_renew (struct SaveNode, stack, stackAlloc);
    948880                  }
    949                 nodeInit (&stack[stackSize++], val, sort_dicts);
     881                nodeConstruct (&stack[stackSize++], v, sort_dicts);
    950882              }
    951883            break;
    952884
    953885          case TR_VARIANT_TYPE_DICT:
    954             if (val == node->val)
     886            if (v == node->v)
    955887              {
    956                 walkFuncs->dictBeginFunc (val, user_data);
     888                walkFuncs->dictBeginFunc (v, user_data);
    957889              }
    958890            else
     
    963895                    stack = tr_renew (struct SaveNode, stack, stackAlloc);
    964896                  }
    965                 nodeInit (&stack[stackSize++], val, sort_dicts);
     897                nodeConstruct (&stack[stackSize++], v, sort_dicts);
    966898              }
    967899            break;
     
    973905        }
    974906    }
     907
     908  /* restore the locale... */
     909  setlocale (LC_NUMERIC, lc_numeric);
    975910
    976911  tr_free (stack);
     
    10671002tr_variantDictSize (const tr_variant * dict)
    10681003{
    1069   size_t count = 0;
    1070 
    1071   if (tr_variantIsDict (dict))
    1072     count = dict->val.l.count / 2;
    1073 
    1074   return count;
     1004  return tr_variantIsDict (dict) ? dict->val.l.count : 0;
    10751005}
    10761006
     
    10851015  assert (tr_variantIsDict (dict));
    10861016
    1087   if (tr_variantIsDict (dict) && (n*2)+1 <= dict->val.l.count)
    1088     {
    1089       tr_variant * k = dict->val.l.vals + (n*2);
    1090       tr_variant * v = dict->val.l.vals + (n*2) + 1;
    1091       if ((k->val.s.type == TR_STRING_TYPE_QUARK) && tr_variantIsSomething (v))
    1092         {
    1093           *key = k->val.s.quark;
    1094           *val = v;
    1095           success = true;
    1096         }
     1017  if (tr_variantIsDict (dict) && (n<dict->val.l.count))
     1018    {
     1019      *key = dict->val.l.vals[n].key;
     1020      *val = dict->val.l.vals+n;
     1021      success = true;
    10971022    }
    10981023
     
    11761101
    11771102struct evbuffer *
    1178 tr_variantToBuf (const tr_variant * top, tr_variant_fmt fmt)
    1179 {
    1180   struct evbuffer * buf = evbuffer_new ();
     1103tr_variantToBuf (const tr_variant * v, tr_variant_fmt fmt)
     1104{
     1105  struct evbuffer * buf = evbuffer_new();
    11811106
    11821107  evbuffer_expand (buf, 4096); /* alloc a little memory to start off with */
     
    11851110    {
    11861111      case TR_VARIANT_FMT_BENC:
    1187         tr_variantToBufBenc (top, buf);
     1112        tr_variantToBufBenc (v, buf);
    11881113        break;
    11891114
    11901115      case TR_VARIANT_FMT_JSON:
    1191         tr_variantToBufJson (top, buf, false);
     1116        tr_variantToBufJson (v, buf, false);
    11921117        break;
    11931118
    11941119      case TR_VARIANT_FMT_JSON_LEAN:
    1195         tr_variantToBufJson (top, buf, true);
     1120        tr_variantToBufJson (v, buf, true);
    11961121        break;
    11971122    }
     
    12011126
    12021127char*
    1203 tr_variantToStr (const tr_variant * top, tr_variant_fmt fmt, int * len)
    1204 {
    1205   struct evbuffer * buf = tr_variantToBuf (top, fmt);
     1128tr_variantToStr (const tr_variant * v, tr_variant_fmt fmt, int * len)
     1129{
     1130  struct evbuffer * buf = tr_variantToBuf (v, fmt);
    12061131  const size_t n = evbuffer_get_length (buf);
    12071132  char * ret = evbuffer_free_to_str (buf);
     
    12111136}
    12121137
    1213 /* portability wrapper for mkstemp (). */
     1138/* portability wrapper for mkstemp(). */
    12141139static int
    12151140tr_mkstemp (char * template)
     
    12261151
    12271152int
    1228 tr_variantToFile (const tr_variant  * top,
     1153tr_variantToFile (const tr_variant  * v,
    12291154                  tr_variant_fmt      fmt,
    12301155                  const char        * filename)
     
    12361161
    12371162  /* follow symlinks to find the "real" file, to make sure the temporary
    1238    * we build with tr_mkstemp () is created on the right partition */
     1163   * we build with tr_mkstemp() is created on the right partition */
    12391164  if (tr_realpath (filename, buf) != NULL)
    12401165    filename = buf;
     
    12501175      /* save the variant to a temporary file */
    12511176      {
    1252         struct evbuffer * buf = tr_variantToBuf (top, fmt);
     1177        struct evbuffer * buf = tr_variantToBuf (v, fmt);
    12531178        const char * walk = (const char *) evbuffer_pullup (buf, -1);
    12541179        nleft = evbuffer_get_length (buf);
  • trunk/libtransmission/variant.h

    r13685 r13687  
    7575  char type;
    7676
     77  tr_quark key;
     78
    7779  union
    7880    {
     
    8789      struct
    8890        {
    89           struct tr_variant * vals; /* nodes */
    90           size_t alloc; /* nodes allocated */
    91           size_t count; /* nodes used */
     91          size_t alloc;
     92          size_t count;
     93          struct tr_variant * vals;
    9294        } l;
    9395    }
     
    276278}
    277279
    278 int          tr_variantInitList        (tr_variant       * list,
    279                                         size_t             reserve_count);
    280 
    281 int          tr_variantListReserve     (tr_variant       * list,
     280void         tr_variantInitList        (tr_variant       * list,
     281                                        size_t             reserve_count);
     282
     283void         tr_variantListReserve     (tr_variant       * list,
    282284                                        size_t             reserve_count);
    283285
     
    312314                                        size_t             pos);
    313315
    314 int          tr_variantListRemove      (tr_variant       * list,
     316bool         tr_variantListRemove      (tr_variant       * list,
    315317                                        size_t             pos);
    316318
     
    328330}
    329331
    330 int          tr_variantInitDict        (tr_variant       * initme,
    331                                         size_t             reserve_count);
    332 
    333 int          tr_variantDictReserve     (tr_variant       * dict,
    334                                         size_t             reserve_count);
    335 
    336 int          tr_variantDictRemove      (tr_variant       * dict,
     332void         tr_variantInitDict        (tr_variant       * initme,
     333                                        size_t             reserve_count);
     334
     335void         tr_variantDictReserve     (tr_variant       * dict,
     336                                        size_t             reserve_count);
     337
     338bool         tr_variantDictRemove      (tr_variant       * dict,
    337339                                        const tr_quark     key);
    338340
  • trunk/qt/my-valgrind.sh

    r13667 r13687  
    11#/bin/sh
    2 valgrind --tool=cachegrind ./transmission-qt
     2valgrind --tool=cachegrind ./transmission-qt 2>&1 | tee runlog
     3#valgrind --tool=memcheck --leak-check=full --leak-resolution=high --num-callers=48 --log-file=x-valgrind --show-reachable=no ./transmission-qt 2>&1 | tee runlog
Note: See TracChangeset for help on using the changeset viewer.