[PATCH for-5.1 4/5] qobject: Eliminate qdict_iter(), use qdict_first(), qdict_next()

Markus Armbruster posted 5 patches 5 years, 9 months ago
Maintainers: Markus Armbruster <armbru@redhat.com>, Michael Roth <mdroth@linux.vnet.ibm.com>
[PATCH for-5.1 4/5] qobject: Eliminate qdict_iter(), use qdict_first(), qdict_next()
Posted by Markus Armbruster 5 years, 9 months ago
qdict_iter() has just three uses and no test coverage.  Replace by
qdict_first(), qdict_next() for more concise code and less type
punning.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 include/qapi/qmp/qdict.h     |  3 --
 qapi/qobject-input-visitor.c | 21 +++++++-------
 qobject/qdict.c              | 19 -------------
 qobject/qjson.c              | 54 +++++++++++++-----------------------
 util/qemu-option.c           | 10 ++++++-
 5 files changed, 40 insertions(+), 67 deletions(-)

diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index 7f3ec10a10..da942347a7 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -40,9 +40,6 @@ void qdict_del(QDict *qdict, const char *key);
 int qdict_haskey(const QDict *qdict, const char *key);
 QObject *qdict_get(const QDict *qdict, const char *key);
 bool qdict_is_equal(const QObject *x, const QObject *y);
-void qdict_iter(const QDict *qdict,
-                void (*iter)(const char *key, QObject *obj, void *opaque),
-                void *opaque);
 const QDictEntry *qdict_first(const QDict *qdict);
 const QDictEntry *qdict_next(const QDict *qdict, const QDictEntry *entry);
 void qdict_destroy_obj(QObject *obj);
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 32236cbcb1..5ce3ec2e5f 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -203,31 +203,32 @@ static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv,
     return qstring_get_str(qstr);
 }
 
-static void qdict_add_key(const char *key, QObject *obj, void *opaque)
-{
-    GHashTable *h = opaque;
-    g_hash_table_insert(h, (gpointer) key, NULL);
-}
-
 static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
                                             const char *name,
                                             QObject *obj, void *qapi)
 {
     GHashTable *h;
     StackObject *tos = g_new0(StackObject, 1);
+    QDict *qdict = qobject_to(QDict, obj);
+    QList *qlist = qobject_to(QList, obj);
+    const QDictEntry *entry;
 
     assert(obj);
     tos->name = name;
     tos->obj = obj;
     tos->qapi = qapi;
 
-    if (qobject_type(obj) == QTYPE_QDICT) {
+    if (qdict) {
         h = g_hash_table_new(g_str_hash, g_str_equal);
-        qdict_iter(qobject_to(QDict, obj), qdict_add_key, h);
+        for (entry = qdict_first(qdict);
+             entry;
+             entry = qdict_next(qdict, entry)) {
+            g_hash_table_insert(h, (void *)qdict_entry_key(entry), NULL);
+        }
         tos->h = h;
     } else {
-        assert(qobject_type(obj) == QTYPE_QLIST);
-        tos->entry = qlist_first(qobject_to(QList, obj));
+        assert(qlist);
+        tos->entry = qlist_first(qlist);
         tos->index = -1;
     }
 
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 3d8c2f7bbc..526de54ceb 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -298,25 +298,6 @@ const char *qdict_get_try_str(const QDict *qdict, const char *key)
     return qstr ? qstring_get_str(qstr) : NULL;
 }
 
-/**
- * qdict_iter(): Iterate over all the dictionary's stored values.
- *
- * This function allows the user to provide an iterator, which will be
- * called for each stored value in the dictionary.
- */
-void qdict_iter(const QDict *qdict,
-                void (*iter)(const char *key, QObject *obj, void *opaque),
-                void *opaque)
-{
-    int i;
-    QDictEntry *entry;
-
-    for (i = 0; i < QDICT_BUCKET_MAX; i++) {
-        QLIST_FOREACH(entry, &qdict->table[i], next)
-            iter(entry->key, entry->value, opaque);
-    }
-}
-
 static QDictEntry *qdict_next_entry(const QDict *qdict, int first_bucket)
 {
     int i;
diff --git a/qobject/qjson.c b/qobject/qjson.c
index 10050354a0..2a3336e459 100644
--- a/qobject/qjson.c
+++ b/qobject/qjson.c
@@ -149,14 +149,6 @@ QDict *qdict_from_jsonf_nofail(const char *string, ...)
     return qdict;
 }
 
-typedef struct ToJsonIterState
-{
-    int indent;
-    int pretty;
-    int count;
-    QString *str;
-} ToJsonIterState;
-
 static void to_json(const QObject *obj, QString *str, int pretty, int indent);
 
 static void json_pretty_newline(QString *str, bool pretty, int indent)
@@ -171,26 +163,6 @@ static void json_pretty_newline(QString *str, bool pretty, int indent)
     }
 }
 
-static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
-{
-    ToJsonIterState *s = opaque;
-    QString *qkey;
-
-    if (s->count) {
-        qstring_append(s->str, s->pretty ? "," : ", ");
-    }
-
-    json_pretty_newline(s->str, s->pretty, s->indent);
-
-    qkey = qstring_from_str(key);
-    to_json(QOBJECT(qkey), s->str, s->pretty, s->indent);
-    qobject_unref(qkey);
-
-    qstring_append(s->str, ": ");
-    to_json(obj, s->str, s->pretty, s->indent);
-    s->count++;
-}
-
 static void to_json(const QObject *obj, QString *str, int pretty, int indent)
 {
     switch (qobject_type(obj)) {
@@ -261,15 +233,29 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent)
         break;
     }
     case QTYPE_QDICT: {
-        ToJsonIterState s;
         QDict *val = qobject_to(QDict, obj);
+        const char *comma = pretty ? "," : ", ";
+        const char *sep = "";
+        const QDictEntry *entry;
+        QString *qkey;
 
-        s.count = 0;
-        s.str = str;
-        s.indent = indent + 1;
-        s.pretty = pretty;
         qstring_append(str, "{");
-        qdict_iter(val, to_json_dict_iter, &s);
+
+        for (entry = qdict_first(val);
+             entry;
+             entry = qdict_next(val, entry)) {
+            qstring_append(str, sep);
+            json_pretty_newline(str, pretty, indent + 1);
+
+            qkey = qstring_from_str(qdict_entry_key(entry));
+            to_json(QOBJECT(qkey), str, pretty, indent + 1);
+            qobject_unref(qkey);
+
+            qstring_append(str, ": ");
+            to_json(qdict_entry_value(entry), str, pretty, indent + 1);
+            sep = comma;
+        }
+
         json_pretty_newline(str, pretty, indent);
         qstring_append(str, "}");
         break;
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 97172b5eaa..3fabfd157d 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1015,6 +1015,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
     OptsFromQDictState state;
     Error *local_err = NULL;
     QemuOpts *opts;
+    const QDictEntry *entry;
 
     opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1,
                             &local_err);
@@ -1027,7 +1028,14 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
 
     state.errp = &local_err;
     state.opts = opts;
-    qdict_iter(qdict, qemu_opts_from_qdict_1, &state);
+
+    for (entry = qdict_first(qdict);
+         entry;
+         entry = qdict_next(qdict, entry)) {
+        qemu_opts_from_qdict_1(qdict_entry_key(entry),
+                               qdict_entry_value(entry),
+                               &state);
+    }
     if (local_err) {
         error_propagate(errp, local_err);
         qemu_opts_del(opts);
-- 
2.21.1


Re: [PATCH for-5.1 4/5] qobject: Eliminate qdict_iter(), use qdict_first(), qdict_next()
Posted by Eric Blake 5 years, 9 months ago
On 4/15/20 3:30 AM, Markus Armbruster wrote:
> qdict_iter() has just three uses and no test coverage.  Replace by
> qdict_first(), qdict_next() for more concise code and less type
> punning.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>   include/qapi/qmp/qdict.h     |  3 --
>   qapi/qobject-input-visitor.c | 21 +++++++-------
>   qobject/qdict.c              | 19 -------------
>   qobject/qjson.c              | 54 +++++++++++++-----------------------
>   util/qemu-option.c           | 10 ++++++-
>   5 files changed, 40 insertions(+), 67 deletions(-)
> 

>   static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
>                                               const char *name,
>                                               QObject *obj, void *qapi)
>   {
>       GHashTable *h;
>       StackObject *tos = g_new0(StackObject, 1);
> +    QDict *qdict = qobject_to(QDict, obj);
> +    QList *qlist = qobject_to(QList, obj);
> +    const QDictEntry *entry;
>   
>       assert(obj);
>       tos->name = name;
>       tos->obj = obj;
>       tos->qapi = qapi;
>   
> -    if (qobject_type(obj) == QTYPE_QDICT) {
> +    if (qdict) {
>           h = g_hash_table_new(g_str_hash, g_str_equal);
> -        qdict_iter(qobject_to(QDict, obj), qdict_add_key, h);
> +        for (entry = qdict_first(qdict);
> +             entry;
> +             entry = qdict_next(qdict, entry)) {
> +            g_hash_table_insert(h, (void *)qdict_entry_key(entry), NULL);

Is the cast to void* necessary?

Otherwise,
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org


Re: [PATCH for-5.1 4/5] qobject: Eliminate qdict_iter(), use qdict_first(), qdict_next()
Posted by Markus Armbruster 5 years, 9 months ago
Eric Blake <eblake@redhat.com> writes:

> On 4/15/20 3:30 AM, Markus Armbruster wrote:
>> qdict_iter() has just three uses and no test coverage.  Replace by
>> qdict_first(), qdict_next() for more concise code and less type
>> punning.
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>   include/qapi/qmp/qdict.h     |  3 --
>>   qapi/qobject-input-visitor.c | 21 +++++++-------
>>   qobject/qdict.c              | 19 -------------
>>   qobject/qjson.c              | 54 +++++++++++++-----------------------
>>   util/qemu-option.c           | 10 ++++++-
>>   5 files changed, 40 insertions(+), 67 deletions(-)
>>
>
>>   static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
>>                                               const char *name,
>>                                               QObject *obj, void *qapi)
>>   {
>>       GHashTable *h;
>>       StackObject *tos = g_new0(StackObject, 1);
>> +    QDict *qdict = qobject_to(QDict, obj);
>> +    QList *qlist = qobject_to(QList, obj);
>> +    const QDictEntry *entry;
>>         assert(obj);
>>       tos->name = name;
>>       tos->obj = obj;
>>       tos->qapi = qapi;
>>   -    if (qobject_type(obj) == QTYPE_QDICT) {
>> +    if (qdict) {
>>           h = g_hash_table_new(g_str_hash, g_str_equal);
>> -        qdict_iter(qobject_to(QDict, obj), qdict_add_key, h);
>> +        for (entry = qdict_first(qdict);
>> +             entry;
>> +             entry = qdict_next(qdict, entry)) {
>> +            g_hash_table_insert(h, (void *)qdict_entry_key(entry), NULL);
>
> Is the cast to void* necessary?

It casts away const.

> Otherwise,
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!