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