1
2
3
4
5
6
7
8
9
10
11
12
13#include "qapi/qmp/qint.h"
14#include "qapi/qmp/qfloat.h"
15#include "qapi/qmp/qdict.h"
16#include "qapi/qmp/qbool.h"
17#include "qapi/qmp/qstring.h"
18#include "qapi/qmp/qobject.h"
19#include "qemu/queue.h"
20#include "qemu-common.h"
21
22static void qdict_destroy_obj(QObject *obj);
23
24static const QType qdict_type = {
25 .code = QTYPE_QDICT,
26 .destroy = qdict_destroy_obj,
27};
28
29
30
31
32
33
34QDict *qdict_new(void)
35{
36 QDict *qdict;
37
38 qdict = g_malloc0(sizeof(*qdict));
39 QOBJECT_INIT(qdict, &qdict_type);
40
41 return qdict;
42}
43
44
45
46
47QDict *qobject_to_qdict(const QObject *obj)
48{
49 if (qobject_type(obj) != QTYPE_QDICT)
50 return NULL;
51
52 return container_of(obj, QDict, base);
53}
54
55
56
57
58
59static unsigned int tdb_hash(const char *name)
60{
61 unsigned value;
62 unsigned i;
63
64
65 for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
66 value = (value + (((const unsigned char *)name)[i] << (i*5 % 24)));
67
68 return (1103515243 * value + 12345);
69}
70
71
72
73
74static QDictEntry *alloc_entry(const char *key, QObject *value)
75{
76 QDictEntry *entry;
77
78 entry = g_malloc0(sizeof(*entry));
79 entry->key = g_strdup(key);
80 entry->value = value;
81
82 return entry;
83}
84
85
86
87
88
89
90QObject *qdict_entry_value(const QDictEntry *entry)
91{
92 return entry->value;
93}
94
95
96
97
98
99
100
101const char *qdict_entry_key(const QDictEntry *entry)
102{
103 return entry->key;
104}
105
106
107
108
109static QDictEntry *qdict_find(const QDict *qdict,
110 const char *key, unsigned int bucket)
111{
112 QDictEntry *entry;
113
114 QLIST_FOREACH(entry, &qdict->table[bucket], next)
115 if (!strcmp(entry->key, key))
116 return entry;
117
118 return NULL;
119}
120
121
122
123
124
125
126
127
128
129
130
131
132void qdict_put_obj(QDict *qdict, const char *key, QObject *value)
133{
134 unsigned int bucket;
135 QDictEntry *entry;
136
137 bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
138 entry = qdict_find(qdict, key, bucket);
139 if (entry) {
140
141 qobject_decref(entry->value);
142 entry->value = value;
143 } else {
144
145 entry = alloc_entry(key, value);
146 QLIST_INSERT_HEAD(&qdict->table[bucket], entry, next);
147 qdict->size++;
148 }
149}
150
151
152
153
154
155
156
157QObject *qdict_get(const QDict *qdict, const char *key)
158{
159 QDictEntry *entry;
160
161 entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
162 return (entry == NULL ? NULL : entry->value);
163}
164
165
166
167
168
169
170int qdict_haskey(const QDict *qdict, const char *key)
171{
172 unsigned int bucket = tdb_hash(key) % QDICT_BUCKET_MAX;
173 return (qdict_find(qdict, key, bucket) == NULL ? 0 : 1);
174}
175
176
177
178
179size_t qdict_size(const QDict *qdict)
180{
181 return qdict->size;
182}
183
184
185
186
187static QObject *qdict_get_obj(const QDict *qdict, const char *key,
188 qtype_code type)
189{
190 QObject *obj;
191
192 obj = qdict_get(qdict, key);
193 assert(obj != NULL);
194 assert(qobject_type(obj) == type);
195
196 return obj;
197}
198
199
200
201
202
203
204
205
206
207double qdict_get_double(const QDict *qdict, const char *key)
208{
209 QObject *obj = qdict_get(qdict, key);
210
211 assert(obj);
212 switch (qobject_type(obj)) {
213 case QTYPE_QFLOAT:
214 return qfloat_get_double(qobject_to_qfloat(obj));
215 case QTYPE_QINT:
216 return qint_get_int(qobject_to_qint(obj));
217 default:
218 abort();
219 }
220}
221
222
223
224
225
226
227
228
229
230int64_t qdict_get_int(const QDict *qdict, const char *key)
231{
232 QObject *obj = qdict_get_obj(qdict, key, QTYPE_QINT);
233 return qint_get_int(qobject_to_qint(obj));
234}
235
236
237
238
239
240
241
242
243
244int qdict_get_bool(const QDict *qdict, const char *key)
245{
246 QObject *obj = qdict_get_obj(qdict, key, QTYPE_QBOOL);
247 return qbool_get_int(qobject_to_qbool(obj));
248}
249
250
251
252
253
254
255
256
257
258QList *qdict_get_qlist(const QDict *qdict, const char *key)
259{
260 return qobject_to_qlist(qdict_get_obj(qdict, key, QTYPE_QLIST));
261}
262
263
264
265
266
267
268
269
270
271QDict *qdict_get_qdict(const QDict *qdict, const char *key)
272{
273 return qobject_to_qdict(qdict_get_obj(qdict, key, QTYPE_QDICT));
274}
275
276
277
278
279
280
281
282
283
284
285const char *qdict_get_str(const QDict *qdict, const char *key)
286{
287 QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING);
288 return qstring_get_str(qobject_to_qstring(obj));
289}
290
291
292
293
294
295
296
297
298int64_t qdict_get_try_int(const QDict *qdict, const char *key,
299 int64_t def_value)
300{
301 QObject *obj;
302
303 obj = qdict_get(qdict, key);
304 if (!obj || qobject_type(obj) != QTYPE_QINT)
305 return def_value;
306
307 return qint_get_int(qobject_to_qint(obj));
308}
309
310
311
312
313
314
315
316
317int qdict_get_try_bool(const QDict *qdict, const char *key, int def_value)
318{
319 QObject *obj;
320
321 obj = qdict_get(qdict, key);
322 if (!obj || qobject_type(obj) != QTYPE_QBOOL)
323 return def_value;
324
325 return qbool_get_int(qobject_to_qbool(obj));
326}
327
328
329
330
331
332
333
334
335
336const char *qdict_get_try_str(const QDict *qdict, const char *key)
337{
338 QObject *obj;
339
340 obj = qdict_get(qdict, key);
341 if (!obj || qobject_type(obj) != QTYPE_QSTRING)
342 return NULL;
343
344 return qstring_get_str(qobject_to_qstring(obj));
345}
346
347
348
349
350
351
352
353void qdict_iter(const QDict *qdict,
354 void (*iter)(const char *key, QObject *obj, void *opaque),
355 void *opaque)
356{
357 int i;
358 QDictEntry *entry;
359
360 for (i = 0; i < QDICT_BUCKET_MAX; i++) {
361 QLIST_FOREACH(entry, &qdict->table[i], next)
362 iter(entry->key, entry->value, opaque);
363 }
364}
365
366static QDictEntry *qdict_next_entry(const QDict *qdict, int first_bucket)
367{
368 int i;
369
370 for (i = first_bucket; i < QDICT_BUCKET_MAX; i++) {
371 if (!QLIST_EMPTY(&qdict->table[i])) {
372 return QLIST_FIRST(&qdict->table[i]);
373 }
374 }
375
376 return NULL;
377}
378
379
380
381
382const QDictEntry *qdict_first(const QDict *qdict)
383{
384 return qdict_next_entry(qdict, 0);
385}
386
387
388
389
390const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry)
391{
392 QDictEntry *ret;
393
394 ret = QLIST_NEXT(entry, next);
395 if (!ret) {
396 unsigned int bucket = tdb_hash(entry->key) % QDICT_BUCKET_MAX;
397 ret = qdict_next_entry(qdict, bucket + 1);
398 }
399
400 return ret;
401}
402
403
404
405
406
407QDict *qdict_clone_shallow(const QDict *src)
408{
409 QDict *dest;
410 QDictEntry *entry;
411 int i;
412
413 dest = qdict_new();
414
415 for (i = 0; i < QDICT_BUCKET_MAX; i++) {
416 QLIST_FOREACH(entry, &src->table[i], next) {
417 qobject_incref(entry->value);
418 qdict_put_obj(dest, entry->key, entry->value);
419 }
420 }
421
422 return dest;
423}
424
425
426
427
428static void qentry_destroy(QDictEntry *e)
429{
430 assert(e != NULL);
431 assert(e->key != NULL);
432 assert(e->value != NULL);
433
434 qobject_decref(e->value);
435 g_free(e->key);
436 g_free(e);
437}
438
439
440
441
442
443
444void qdict_del(QDict *qdict, const char *key)
445{
446 QDictEntry *entry;
447
448 entry = qdict_find(qdict, key, tdb_hash(key) % QDICT_BUCKET_MAX);
449 if (entry) {
450 QLIST_REMOVE(entry, next);
451 qentry_destroy(entry);
452 qdict->size--;
453 }
454}
455
456
457
458
459static void qdict_destroy_obj(QObject *obj)
460{
461 int i;
462 QDict *qdict;
463
464 assert(obj != NULL);
465 qdict = qobject_to_qdict(obj);
466
467 for (i = 0; i < QDICT_BUCKET_MAX; i++) {
468 QDictEntry *entry = QLIST_FIRST(&qdict->table[i]);
469 while (entry) {
470 QDictEntry *tmp = QLIST_NEXT(entry, next);
471 QLIST_REMOVE(entry, next);
472 qentry_destroy(entry);
473 entry = tmp;
474 }
475 }
476
477 g_free(qdict);
478}
479