qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qdict.c (10661B)


      1 /*
      2  * QDict Module
      3  *
      4  * Copyright (C) 2009 Red Hat Inc.
      5  *
      6  * Authors:
      7  *  Luiz Capitulino <lcapitulino@redhat.com>
      8  *
      9  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
     10  * See the COPYING.LIB file in the top-level directory.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "qapi/qmp/qnum.h"
     15 #include "qapi/qmp/qdict.h"
     16 #include "qapi/qmp/qbool.h"
     17 #include "qapi/qmp/qnull.h"
     18 #include "qapi/qmp/qstring.h"
     19 #include "qobject-internal.h"
     20 
     21 /**
     22  * qdict_new(): Create a new QDict
     23  *
     24  * Return strong reference.
     25  */
     26 QDict *qdict_new(void)
     27 {
     28     QDict *qdict;
     29 
     30     qdict = g_malloc0(sizeof(*qdict));
     31     qobject_init(QOBJECT(qdict), QTYPE_QDICT);
     32 
     33     return qdict;
     34 }
     35 
     36 /**
     37  * tdb_hash(): based on the hash algorithm from gdbm, via tdb
     38  * (from module-init-tools)
     39  */
     40 static unsigned int tdb_hash(const char *name)
     41 {
     42     unsigned value;    /* Used to compute the hash value.  */
     43     unsigned   i;      /* Used to cycle through random values. */
     44 
     45     /* Set the initial value from the key size. */
     46     for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) {
     47         value = (value + (((const unsigned char *)name)[i] << (i * 5 % 24)));
     48     }
     49 
     50     return (1103515243 * value + 12345);
     51 }
     52 
     53 /**
     54  * alloc_entry(): allocate a new QDictEntry
     55  */
     56 static QDictEntry *alloc_entry(const char *key, QObject *value)
     57 {
     58     QDictEntry *entry;
     59 
     60     entry = g_malloc0(sizeof(*entry));
     61     entry->key = g_strdup(key);
     62     entry->value = value;
     63 
     64     return entry;
     65 }
     66 
     67 /**
     68  * qdict_entry_value(): Return qdict entry value
     69  *
     70  * Return weak reference.
     71  */
     72 QObject *qdict_entry_value(const QDictEntry *entry)
     73 {
     74     return entry->value;
     75 }
     76 
     77 /**
     78  * qdict_entry_key(): Return qdict entry key
     79  *
     80  * Return a *pointer* to the string, it has to be duplicated before being
     81  * stored.
     82  */
     83 const char *qdict_entry_key(const QDictEntry *entry)
     84 {
     85     return entry->key;
     86 }
     87 
     88 /**
     89  * qdict_find(): List lookup function
     90  */
     91 static QDictEntry *qdict_find(const QDict *qdict,
     92                               const char *key, unsigned int bucket)
     93 {
     94     QDictEntry *entry;
     95 
     96     QLIST_FOREACH(entry, &qdict->table[bucket], next)
     97         if (!strcmp(entry->key, key)) {
     98             return entry;
     99         }
    100 
    101     return NULL;
    102 }
    103 
    104 /**
    105  * qdict_put_obj(): Put a new QObject into the dictionary
    106  *
    107  * Insert the pair 'key:value' into 'qdict', if 'key' already exists
    108  * its 'value' will be replaced.
    109  *
    110  * This is done by freeing the reference to the stored QObject and
    111  * storing the new one in the same entry.
    112  *
    113  * NOTE: ownership of 'value' is transferred to the QDict
    114  */
    115 void qdict_put_obj(QDict *qdict, const char *key, QObject *value)
    116 {
    117     unsigned int bucket;
    118     QDictEntry *entry;
    119 
    120     bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
    121     entry = qdict_find(qdict, key, bucket);
    122     if (entry) {
    123         /* replace key's value */
    124         qobject_unref(entry->value);
    125         entry->value = value;
    126     } else {
    127         /* allocate a new entry */
    128         entry = alloc_entry(key, value);
    129         QLIST_INSERT_HEAD(&qdict->table[bucket], entry, next);
    130         qdict->size++;
    131     }
    132 }
    133 
    134 void qdict_put_int(QDict *qdict, const char *key, int64_t value)
    135 {
    136     qdict_put(qdict, key, qnum_from_int(value));
    137 }
    138 
    139 void qdict_put_bool(QDict *qdict, const char *key, bool value)
    140 {
    141     qdict_put(qdict, key, qbool_from_bool(value));
    142 }
    143 
    144 void qdict_put_str(QDict *qdict, const char *key, const char *value)
    145 {
    146     qdict_put(qdict, key, qstring_from_str(value));
    147 }
    148 
    149 void qdict_put_null(QDict *qdict, const char *key)
    150 {
    151     qdict_put(qdict, key, qnull());
    152 }
    153 
    154 /**
    155  * qdict_get(): Lookup for a given 'key'
    156  *
    157  * Return a weak reference to the QObject associated with 'key' if
    158  * 'key' is present in the dictionary, NULL otherwise.
    159  */
    160 QObject *qdict_get(const QDict *qdict, const char *key)
    161 {
    162     QDictEntry *entry;
    163 
    164     entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
    165     return (entry == NULL ? NULL : entry->value);
    166 }
    167 
    168 /**
    169  * qdict_haskey(): Check if 'key' exists
    170  *
    171  * Return 1 if 'key' exists in the dict, 0 otherwise
    172  */
    173 int qdict_haskey(const QDict *qdict, const char *key)
    174 {
    175     unsigned int bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
    176     return (qdict_find(qdict, key, bucket) == NULL ? 0 : 1);
    177 }
    178 
    179 /**
    180  * qdict_size(): Return the size of the dictionary
    181  */
    182 size_t qdict_size(const QDict *qdict)
    183 {
    184     return qdict->size;
    185 }
    186 
    187 /**
    188  * qdict_get_double(): Get an number mapped by 'key'
    189  *
    190  * This function assumes that 'key' exists and it stores a QNum.
    191  *
    192  * Return number mapped by 'key'.
    193  */
    194 double qdict_get_double(const QDict *qdict, const char *key)
    195 {
    196     return qnum_get_double(qobject_to(QNum, qdict_get(qdict, key)));
    197 }
    198 
    199 /**
    200  * qdict_get_int(): Get an integer mapped by 'key'
    201  *
    202  * This function assumes that 'key' exists and it stores a
    203  * QNum representable as int.
    204  *
    205  * Return integer mapped by 'key'.
    206  */
    207 int64_t qdict_get_int(const QDict *qdict, const char *key)
    208 {
    209     return qnum_get_int(qobject_to(QNum, qdict_get(qdict, key)));
    210 }
    211 
    212 /**
    213  * qdict_get_bool(): Get a bool mapped by 'key'
    214  *
    215  * This function assumes that 'key' exists and it stores a
    216  * QBool object.
    217  *
    218  * Return bool mapped by 'key'.
    219  */
    220 bool qdict_get_bool(const QDict *qdict, const char *key)
    221 {
    222     return qbool_get_bool(qobject_to(QBool, qdict_get(qdict, key)));
    223 }
    224 
    225 /**
    226  * qdict_get_qlist(): If @qdict maps @key to a QList, return it, else NULL.
    227  */
    228 QList *qdict_get_qlist(const QDict *qdict, const char *key)
    229 {
    230     return qobject_to(QList, qdict_get(qdict, key));
    231 }
    232 
    233 /**
    234  * qdict_get_qdict(): If @qdict maps @key to a QDict, return it, else NULL.
    235  */
    236 QDict *qdict_get_qdict(const QDict *qdict, const char *key)
    237 {
    238     return qobject_to(QDict, qdict_get(qdict, key));
    239 }
    240 
    241 /**
    242  * qdict_get_str(): Get a pointer to the stored string mapped
    243  * by 'key'
    244  *
    245  * This function assumes that 'key' exists and it stores a
    246  * QString object.
    247  *
    248  * Return pointer to the string mapped by 'key'.
    249  */
    250 const char *qdict_get_str(const QDict *qdict, const char *key)
    251 {
    252     return qstring_get_str(qobject_to(QString, qdict_get(qdict, key)));
    253 }
    254 
    255 /**
    256  * qdict_get_try_int(): Try to get integer mapped by 'key'
    257  *
    258  * Return integer mapped by 'key', if it is not present in the
    259  * dictionary or if the stored object is not a QNum representing an
    260  * integer, 'def_value' will be returned.
    261  */
    262 int64_t qdict_get_try_int(const QDict *qdict, const char *key,
    263                           int64_t def_value)
    264 {
    265     QNum *qnum = qobject_to(QNum, qdict_get(qdict, key));
    266     int64_t val;
    267 
    268     if (!qnum || !qnum_get_try_int(qnum, &val)) {
    269         return def_value;
    270     }
    271 
    272     return val;
    273 }
    274 
    275 /**
    276  * qdict_get_try_bool(): Try to get a bool mapped by 'key'
    277  *
    278  * Return bool mapped by 'key', if it is not present in the
    279  * dictionary or if the stored object is not of QBool type
    280  * 'def_value' will be returned.
    281  */
    282 bool qdict_get_try_bool(const QDict *qdict, const char *key, bool def_value)
    283 {
    284     QBool *qbool = qobject_to(QBool, qdict_get(qdict, key));
    285 
    286     return qbool ? qbool_get_bool(qbool) : def_value;
    287 }
    288 
    289 /**
    290  * qdict_get_try_str(): Try to get a pointer to the stored string
    291  * mapped by 'key'
    292  *
    293  * Return a pointer to the string mapped by 'key', if it is not present
    294  * in the dictionary or if the stored object is not of QString type
    295  * NULL will be returned.
    296  */
    297 const char *qdict_get_try_str(const QDict *qdict, const char *key)
    298 {
    299     QString *qstr = qobject_to(QString, qdict_get(qdict, key));
    300 
    301     return qstr ? qstring_get_str(qstr) : NULL;
    302 }
    303 
    304 static QDictEntry *qdict_next_entry(const QDict *qdict, int first_bucket)
    305 {
    306     int i;
    307 
    308     for (i = first_bucket; i < QDICT_BUCKET_MAX; i++) {
    309         if (!QLIST_EMPTY(&qdict->table[i])) {
    310             return QLIST_FIRST(&qdict->table[i]);
    311         }
    312     }
    313 
    314     return NULL;
    315 }
    316 
    317 /**
    318  * qdict_first(): Return first qdict entry for iteration.
    319  */
    320 const QDictEntry *qdict_first(const QDict *qdict)
    321 {
    322     return qdict_next_entry(qdict, 0);
    323 }
    324 
    325 /**
    326  * qdict_next(): Return next qdict entry in an iteration.
    327  */
    328 const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry)
    329 {
    330     QDictEntry *ret;
    331 
    332     ret = QLIST_NEXT(entry, next);
    333     if (!ret) {
    334         unsigned int bucket = tdb_hash(entry->key) % QDICT_BUCKET_MAX;
    335         ret = qdict_next_entry(qdict, bucket + 1);
    336     }
    337 
    338     return ret;
    339 }
    340 
    341 /**
    342  * qdict_clone_shallow(): Clones a given QDict. Its entries are not copied, but
    343  * another reference is added.
    344  */
    345 QDict *qdict_clone_shallow(const QDict *src)
    346 {
    347     QDict *dest;
    348     QDictEntry *entry;
    349     int i;
    350 
    351     dest = qdict_new();
    352 
    353     for (i = 0; i < QDICT_BUCKET_MAX; i++) {
    354         QLIST_FOREACH(entry, &src->table[i], next) {
    355             qdict_put_obj(dest, entry->key, qobject_ref(entry->value));
    356         }
    357     }
    358 
    359     return dest;
    360 }
    361 
    362 /**
    363  * qentry_destroy(): Free all the memory allocated by a QDictEntry
    364  */
    365 static void qentry_destroy(QDictEntry *e)
    366 {
    367     assert(e != NULL);
    368     assert(e->key != NULL);
    369     assert(e->value != NULL);
    370 
    371     qobject_unref(e->value);
    372     g_free(e->key);
    373     g_free(e);
    374 }
    375 
    376 /**
    377  * qdict_del(): Delete a 'key:value' pair from the dictionary
    378  *
    379  * This will destroy all data allocated by this entry.
    380  */
    381 void qdict_del(QDict *qdict, const char *key)
    382 {
    383     QDictEntry *entry;
    384 
    385     entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
    386     if (entry) {
    387         QLIST_REMOVE(entry, next);
    388         qentry_destroy(entry);
    389         qdict->size--;
    390     }
    391 }
    392 
    393 /**
    394  * qdict_is_equal(): Test whether the two QDicts are equal
    395  *
    396  * Here, equality means whether they contain the same keys and whether
    397  * the respective values are in turn equal (i.e. invoking
    398  * qobject_is_equal() on them yields true).
    399  */
    400 bool qdict_is_equal(const QObject *x, const QObject *y)
    401 {
    402     const QDict *dict_x = qobject_to(QDict, x);
    403     const QDict *dict_y = qobject_to(QDict, y);
    404     const QDictEntry *e;
    405 
    406     if (qdict_size(dict_x) != qdict_size(dict_y)) {
    407         return false;
    408     }
    409 
    410     for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) {
    411         const QObject *obj_x = qdict_entry_value(e);
    412         const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e));
    413 
    414         if (!qobject_is_equal(obj_x, obj_y)) {
    415             return false;
    416         }
    417     }
    418 
    419     return true;
    420 }
    421 
    422 /**
    423  * qdict_destroy_obj(): Free all the memory allocated by a QDict
    424  */
    425 void qdict_destroy_obj(QObject *obj)
    426 {
    427     int i;
    428     QDict *qdict;
    429 
    430     assert(obj != NULL);
    431     qdict = qobject_to(QDict, obj);
    432 
    433     for (i = 0; i < QDICT_BUCKET_MAX; i++) {
    434         QDictEntry *entry = QLIST_FIRST(&qdict->table[i]);
    435         while (entry) {
    436             QDictEntry *tmp = QLIST_NEXT(entry, next);
    437             QLIST_REMOVE(entry, next);
    438             qentry_destroy(entry);
    439             entry = tmp;
    440         }
    441     }
    442 
    443     g_free(qdict);
    444 }
    445 
    446 void qdict_unref(QDict *q)
    447 {
    448     qobject_unref(q);
    449 }