This generic function (along with its implementations for different
types) determines whether two QObjects are equal.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
include/qapi/qmp/qbool.h | 1 +
include/qapi/qmp/qdict.h | 1 +
include/qapi/qmp/qfloat.h | 1 +
include/qapi/qmp/qint.h | 1 +
include/qapi/qmp/qlist.h | 1 +
include/qapi/qmp/qnull.h | 2 ++
include/qapi/qmp/qobject.h | 9 +++++++++
include/qapi/qmp/qstring.h | 1 +
qobject/qbool.c | 8 ++++++++
qobject/qdict.c | 28 ++++++++++++++++++++++++++++
qobject/qfloat.c | 8 ++++++++
qobject/qint.c | 8 ++++++++
qobject/qlist.c | 30 ++++++++++++++++++++++++++++++
qobject/qnull.c | 5 +++++
qobject/qobject.c | 30 ++++++++++++++++++++++++++++++
qobject/qstring.c | 9 +++++++++
16 files changed, 143 insertions(+)
diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h
index a41111c..f77ea86 100644
--- a/include/qapi/qmp/qbool.h
+++ b/include/qapi/qmp/qbool.h
@@ -24,6 +24,7 @@ typedef struct QBool {
QBool *qbool_from_bool(bool value);
bool qbool_get_bool(const QBool *qb);
QBool *qobject_to_qbool(const QObject *obj);
+bool qbool_is_equal(const QObject *x, const QObject *y);
void qbool_destroy_obj(QObject *obj);
#endif /* QBOOL_H */
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index 188440a..134a526 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -41,6 +41,7 @@ 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);
QDict *qobject_to_qdict(const QObject *obj);
+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);
diff --git a/include/qapi/qmp/qfloat.h b/include/qapi/qmp/qfloat.h
index b5d1583..318e91e 100644
--- a/include/qapi/qmp/qfloat.h
+++ b/include/qapi/qmp/qfloat.h
@@ -24,6 +24,7 @@ typedef struct QFloat {
QFloat *qfloat_from_double(double value);
double qfloat_get_double(const QFloat *qi);
QFloat *qobject_to_qfloat(const QObject *obj);
+bool qfloat_is_equal(const QObject *x, const QObject *y);
void qfloat_destroy_obj(QObject *obj);
#endif /* QFLOAT_H */
diff --git a/include/qapi/qmp/qint.h b/include/qapi/qmp/qint.h
index 3aaff76..20975da 100644
--- a/include/qapi/qmp/qint.h
+++ b/include/qapi/qmp/qint.h
@@ -23,6 +23,7 @@ typedef struct QInt {
QInt *qint_from_int(int64_t value);
int64_t qint_get_int(const QInt *qi);
QInt *qobject_to_qint(const QObject *obj);
+bool qint_is_equal(const QObject *x, const QObject *y);
void qint_destroy_obj(QObject *obj);
#endif /* QINT_H */
diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h
index 5dc4ed9..4380a5b 100644
--- a/include/qapi/qmp/qlist.h
+++ b/include/qapi/qmp/qlist.h
@@ -57,6 +57,7 @@ QObject *qlist_peek(QList *qlist);
int qlist_empty(const QList *qlist);
size_t qlist_size(const QList *qlist);
QList *qobject_to_qlist(const QObject *obj);
+bool qlist_is_equal(const QObject *x, const QObject *y);
void qlist_destroy_obj(QObject *obj);
static inline const QListEntry *qlist_first(const QList *qlist)
diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h
index 69555ac..9299683 100644
--- a/include/qapi/qmp/qnull.h
+++ b/include/qapi/qmp/qnull.h
@@ -23,4 +23,6 @@ static inline QObject *qnull(void)
return &qnull_;
}
+bool qnull_is_equal(const QObject *x, const QObject *y);
+
#endif /* QNULL_H */
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
index ef1d1a9..cac72e3 100644
--- a/include/qapi/qmp/qobject.h
+++ b/include/qapi/qmp/qobject.h
@@ -68,6 +68,15 @@ static inline void qobject_incref(QObject *obj)
}
/**
+ * qobject_is_equal(): Returns whether the two objects are equal.
+ *
+ * Any of the pointers may be NULL; will return true if both are. Will always
+ * return false if only one is (therefore a QNull object is not considered equal
+ * to a NULL pointer).
+ */
+bool qobject_is_equal(const QObject *x, const QObject *y);
+
+/**
* qobject_destroy(): Free resources used by the object
*/
void qobject_destroy(QObject *obj);
diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h
index 10076b7..65c05a9 100644
--- a/include/qapi/qmp/qstring.h
+++ b/include/qapi/qmp/qstring.h
@@ -31,6 +31,7 @@ void qstring_append_int(QString *qstring, int64_t value);
void qstring_append(QString *qstring, const char *str);
void qstring_append_chr(QString *qstring, int c);
QString *qobject_to_qstring(const QObject *obj);
+bool qstring_is_equal(const QObject *x, const QObject *y);
void qstring_destroy_obj(QObject *obj);
#endif /* QSTRING_H */
diff --git a/qobject/qbool.c b/qobject/qbool.c
index 0606bbd..f1d1719 100644
--- a/qobject/qbool.c
+++ b/qobject/qbool.c
@@ -52,6 +52,14 @@ QBool *qobject_to_qbool(const QObject *obj)
}
/**
+ * qbool_is_equal(): Tests whether the two QBools are equal
+ */
+bool qbool_is_equal(const QObject *x, const QObject *y)
+{
+ return qobject_to_qbool(x)->value == qobject_to_qbool(y)->value;
+}
+
+/**
* qbool_destroy_obj(): Free all memory allocated by a
* QBool object
*/
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 88e2ecd..ca919bc 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -410,6 +410,34 @@ void qdict_del(QDict *qdict, const char *key)
}
/**
+ * qdict_is_equal(): Tests whether the two QDicts are equal
+ *
+ * Here, equality means whether they contain the same keys and whether the
+ * respective values are in turn equal (i.e. invoking qobject_is_equal() on them
+ * yields true).
+ */
+bool qdict_is_equal(const QObject *x, const QObject *y)
+{
+ const QDict *dict_x = qobject_to_qdict(x), *dict_y = qobject_to_qdict(y);
+ const QDictEntry *e;
+
+ if (qdict_size(dict_x) != qdict_size(dict_y)) {
+ return false;
+ }
+
+ for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) {
+ const QObject *obj_x = qdict_entry_value(e);
+ const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e));
+
+ if (!qobject_is_equal(obj_x, obj_y)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
* qdict_destroy_obj(): Free all the memory allocated by a QDict
*/
void qdict_destroy_obj(QObject *obj)
diff --git a/qobject/qfloat.c b/qobject/qfloat.c
index d5da847..291ecc4 100644
--- a/qobject/qfloat.c
+++ b/qobject/qfloat.c
@@ -52,6 +52,14 @@ QFloat *qobject_to_qfloat(const QObject *obj)
}
/**
+ * qfloat_is_equal(): Tests whether the two QFloats are equal
+ */
+bool qfloat_is_equal(const QObject *x, const QObject *y)
+{
+ return qobject_to_qfloat(x)->value == qobject_to_qfloat(y)->value;
+}
+
+/**
* qfloat_destroy_obj(): Free all memory allocated by a
* QFloat object
*/
diff --git a/qobject/qint.c b/qobject/qint.c
index d7d1b30..f638cb7 100644
--- a/qobject/qint.c
+++ b/qobject/qint.c
@@ -51,6 +51,14 @@ QInt *qobject_to_qint(const QObject *obj)
}
/**
+ * qint_is_equal(): Tests whether the two QInts are equal
+ */
+bool qint_is_equal(const QObject *x, const QObject *y)
+{
+ return qobject_to_qint(x)->value == qobject_to_qint(y)->value;
+}
+
+/**
* qint_destroy_obj(): Free all memory allocated by a
* QInt object
*/
diff --git a/qobject/qlist.c b/qobject/qlist.c
index 86b60cb..652fc53 100644
--- a/qobject/qlist.c
+++ b/qobject/qlist.c
@@ -140,6 +140,36 @@ QList *qobject_to_qlist(const QObject *obj)
}
/**
+ * qlist_is_equal(): Tests whether the two QLists are equal
+ *
+ * In order to be considered equal, the respective two objects at each index of
+ * the two lists have to compare equal (regarding qobject_is_equal()), and both
+ * lists have to have the same number of elements.
+ * That means, both lists have to contain equal objects in equal order.
+ */
+bool qlist_is_equal(const QObject *x, const QObject *y)
+{
+ const QList *list_x = qobject_to_qlist(x), *list_y = qobject_to_qlist(y);
+ const QListEntry *entry_x, *entry_y;
+
+ entry_x = qlist_first(list_x);
+ entry_y = qlist_first(list_y);
+
+ while (entry_x && entry_y) {
+ if (!qobject_is_equal(qlist_entry_obj(entry_x),
+ qlist_entry_obj(entry_y)))
+ {
+ return false;
+ }
+
+ entry_x = qlist_next(entry_x);
+ entry_y = qlist_next(entry_y);
+ }
+
+ return !entry_x && !entry_y;
+}
+
+/**
* qlist_destroy_obj(): Free all the memory allocated by a QList
*/
void qlist_destroy_obj(QObject *obj)
diff --git a/qobject/qnull.c b/qobject/qnull.c
index b3cc85e..af5453d 100644
--- a/qobject/qnull.c
+++ b/qobject/qnull.c
@@ -19,3 +19,8 @@ QObject qnull_ = {
.type = QTYPE_QNULL,
.refcnt = 1,
};
+
+bool qnull_is_equal(const QObject *x, const QObject *y)
+{
+ return true;
+}
diff --git a/qobject/qobject.c b/qobject/qobject.c
index fe4fa10..af2869a 100644
--- a/qobject/qobject.c
+++ b/qobject/qobject.c
@@ -28,3 +28,33 @@ void qobject_destroy(QObject *obj)
assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
qdestroy[obj->type](obj);
}
+
+
+static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) = {
+ [QTYPE_NONE] = NULL, /* No such object exists */
+ [QTYPE_QNULL] = qnull_is_equal,
+ [QTYPE_QINT] = qint_is_equal,
+ [QTYPE_QSTRING] = qstring_is_equal,
+ [QTYPE_QDICT] = qdict_is_equal,
+ [QTYPE_QLIST] = qlist_is_equal,
+ [QTYPE_QFLOAT] = qfloat_is_equal,
+ [QTYPE_QBOOL] = qbool_is_equal,
+};
+
+bool qobject_is_equal(const QObject *x, const QObject *y)
+{
+ /* We cannot test x == y because an object does not need to be equal to
+ * itself (e.g. NaN floats are not). */
+
+ if (!x && !y) {
+ return true;
+ }
+
+ if (!x || !y || x->type != y->type) {
+ return false;
+ }
+
+ assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX);
+
+ return qis_equal[x->type](x, y);
+}
diff --git a/qobject/qstring.c b/qobject/qstring.c
index 5da7b5f..a2b51fa 100644
--- a/qobject/qstring.c
+++ b/qobject/qstring.c
@@ -129,6 +129,15 @@ const char *qstring_get_str(const QString *qstring)
}
/**
+ * qstring_is_equal(): Tests whether the two QStrings are equal
+ */
+bool qstring_is_equal(const QObject *x, const QObject *y)
+{
+ return !strcmp(qobject_to_qstring(x)->string,
+ qobject_to_qstring(y)->string);
+}
+
+/**
* qstring_destroy_obj(): Free all memory allocated by a QString
* object
*/
--
2.9.4
Max Reitz <mreitz@redhat.com> writes:
> This generic function (along with its implementations for different
> types) determines whether two QObjects are equal.
>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
> include/qapi/qmp/qbool.h | 1 +
> include/qapi/qmp/qdict.h | 1 +
> include/qapi/qmp/qfloat.h | 1 +
> include/qapi/qmp/qint.h | 1 +
> include/qapi/qmp/qlist.h | 1 +
> include/qapi/qmp/qnull.h | 2 ++
> include/qapi/qmp/qobject.h | 9 +++++++++
> include/qapi/qmp/qstring.h | 1 +
> qobject/qbool.c | 8 ++++++++
> qobject/qdict.c | 28 ++++++++++++++++++++++++++++
> qobject/qfloat.c | 8 ++++++++
> qobject/qint.c | 8 ++++++++
> qobject/qlist.c | 30 ++++++++++++++++++++++++++++++
> qobject/qnull.c | 5 +++++
> qobject/qobject.c | 30 ++++++++++++++++++++++++++++++
> qobject/qstring.c | 9 +++++++++
> 16 files changed, 143 insertions(+)
No unit test?
> diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h
> index a41111c..f77ea86 100644
> --- a/include/qapi/qmp/qbool.h
> +++ b/include/qapi/qmp/qbool.h
> @@ -24,6 +24,7 @@ typedef struct QBool {
> QBool *qbool_from_bool(bool value);
> bool qbool_get_bool(const QBool *qb);
> QBool *qobject_to_qbool(const QObject *obj);
> +bool qbool_is_equal(const QObject *x, const QObject *y);
> void qbool_destroy_obj(QObject *obj);
>
> #endif /* QBOOL_H */
> diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
> index 188440a..134a526 100644
> --- a/include/qapi/qmp/qdict.h
> +++ b/include/qapi/qmp/qdict.h
> @@ -41,6 +41,7 @@ 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);
> QDict *qobject_to_qdict(const QObject *obj);
> +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);
> diff --git a/include/qapi/qmp/qfloat.h b/include/qapi/qmp/qfloat.h
> index b5d1583..318e91e 100644
> --- a/include/qapi/qmp/qfloat.h
> +++ b/include/qapi/qmp/qfloat.h
> @@ -24,6 +24,7 @@ typedef struct QFloat {
> QFloat *qfloat_from_double(double value);
> double qfloat_get_double(const QFloat *qi);
> QFloat *qobject_to_qfloat(const QObject *obj);
> +bool qfloat_is_equal(const QObject *x, const QObject *y);
> void qfloat_destroy_obj(QObject *obj);
>
> #endif /* QFLOAT_H */
> diff --git a/include/qapi/qmp/qint.h b/include/qapi/qmp/qint.h
> index 3aaff76..20975da 100644
> --- a/include/qapi/qmp/qint.h
> +++ b/include/qapi/qmp/qint.h
> @@ -23,6 +23,7 @@ typedef struct QInt {
> QInt *qint_from_int(int64_t value);
> int64_t qint_get_int(const QInt *qi);
> QInt *qobject_to_qint(const QObject *obj);
> +bool qint_is_equal(const QObject *x, const QObject *y);
> void qint_destroy_obj(QObject *obj);
>
> #endif /* QINT_H */
> diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h
> index 5dc4ed9..4380a5b 100644
> --- a/include/qapi/qmp/qlist.h
> +++ b/include/qapi/qmp/qlist.h
> @@ -57,6 +57,7 @@ QObject *qlist_peek(QList *qlist);
> int qlist_empty(const QList *qlist);
> size_t qlist_size(const QList *qlist);
> QList *qobject_to_qlist(const QObject *obj);
> +bool qlist_is_equal(const QObject *x, const QObject *y);
> void qlist_destroy_obj(QObject *obj);
>
> static inline const QListEntry *qlist_first(const QList *qlist)
> diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h
> index 69555ac..9299683 100644
> --- a/include/qapi/qmp/qnull.h
> +++ b/include/qapi/qmp/qnull.h
> @@ -23,4 +23,6 @@ static inline QObject *qnull(void)
> return &qnull_;
> }
>
> +bool qnull_is_equal(const QObject *x, const QObject *y);
> +
> #endif /* QNULL_H */
> diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
> index ef1d1a9..cac72e3 100644
> --- a/include/qapi/qmp/qobject.h
> +++ b/include/qapi/qmp/qobject.h
> @@ -68,6 +68,15 @@ static inline void qobject_incref(QObject *obj)
> }
>
> /**
> + * qobject_is_equal(): Returns whether the two objects are equal.
Imperative mood, please: Return whether...
> + *
> + * Any of the pointers may be NULL; will return true if both are. Will always
> + * return false if only one is (therefore a QNull object is not considered equal
> + * to a NULL pointer).
> + */
Humor me: wrap comment lines around column 70, and put two spaces
between sentences.
Same for the other function comments.
> +bool qobject_is_equal(const QObject *x, const QObject *y);
> +
> +/**
> * qobject_destroy(): Free resources used by the object
> */
> void qobject_destroy(QObject *obj);
> diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h
> index 10076b7..65c05a9 100644
> --- a/include/qapi/qmp/qstring.h
> +++ b/include/qapi/qmp/qstring.h
> @@ -31,6 +31,7 @@ void qstring_append_int(QString *qstring, int64_t value);
> void qstring_append(QString *qstring, const char *str);
> void qstring_append_chr(QString *qstring, int c);
> QString *qobject_to_qstring(const QObject *obj);
> +bool qstring_is_equal(const QObject *x, const QObject *y);
> void qstring_destroy_obj(QObject *obj);
>
> #endif /* QSTRING_H */
> diff --git a/qobject/qbool.c b/qobject/qbool.c
> index 0606bbd..f1d1719 100644
> --- a/qobject/qbool.c
> +++ b/qobject/qbool.c
> @@ -52,6 +52,14 @@ QBool *qobject_to_qbool(const QObject *obj)
> }
>
> /**
> + * qbool_is_equal(): Tests whether the two QBools are equal
Return whether ...
> + */
> +bool qbool_is_equal(const QObject *x, const QObject *y)
> +{
> + return qobject_to_qbool(x)->value == qobject_to_qbool(y)->value;
> +}
> +
> +/**
> * qbool_destroy_obj(): Free all memory allocated by a
> * QBool object
> */
> diff --git a/qobject/qdict.c b/qobject/qdict.c
> index 88e2ecd..ca919bc 100644
> --- a/qobject/qdict.c
> +++ b/qobject/qdict.c
> @@ -410,6 +410,34 @@ void qdict_del(QDict *qdict, const char *key)
> }
>
> /**
> + * qdict_is_equal(): Tests whether the two QDicts are equal
> + *
> + * Here, equality means whether they contain the same keys and whether the
> + * respective values are in turn equal (i.e. invoking qobject_is_equal() on them
> + * yields true).
> + */
> +bool qdict_is_equal(const QObject *x, const QObject *y)
> +{
> + const QDict *dict_x = qobject_to_qdict(x), *dict_y = qobject_to_qdict(y);
I'm fine with multiple initializers in one declaration, but I think this
one would look tidier as
const QDict *dict_x = qobject_to_qdict(x);
const QDict *dict_y = qobject_to_qdict(y);
> + const QDictEntry *e;
> +
> + if (qdict_size(dict_x) != qdict_size(dict_y)) {
> + return false;
> + }
> +
> + for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) {
> + const QObject *obj_x = qdict_entry_value(e);
> + const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e));
> +
> + if (!qobject_is_equal(obj_x, obj_y)) {
> + return false;
> + }
> + }
> +
> + return true;
> +}
> +
> +/**
> * qdict_destroy_obj(): Free all the memory allocated by a QDict
> */
> void qdict_destroy_obj(QObject *obj)
> diff --git a/qobject/qfloat.c b/qobject/qfloat.c
> index d5da847..291ecc4 100644
> --- a/qobject/qfloat.c
> +++ b/qobject/qfloat.c
> @@ -52,6 +52,14 @@ QFloat *qobject_to_qfloat(const QObject *obj)
> }
>
> /**
> + * qfloat_is_equal(): Tests whether the two QFloats are equal
> + */
> +bool qfloat_is_equal(const QObject *x, const QObject *y)
> +{
> + return qobject_to_qfloat(x)->value == qobject_to_qfloat(y)->value;
> +}
> +
> +/**
> * qfloat_destroy_obj(): Free all memory allocated by a
> * QFloat object
> */
> diff --git a/qobject/qint.c b/qobject/qint.c
> index d7d1b30..f638cb7 100644
> --- a/qobject/qint.c
> +++ b/qobject/qint.c
> @@ -51,6 +51,14 @@ QInt *qobject_to_qint(const QObject *obj)
> }
>
> /**
> + * qint_is_equal(): Tests whether the two QInts are equal
> + */
> +bool qint_is_equal(const QObject *x, const QObject *y)
> +{
> + return qobject_to_qint(x)->value == qobject_to_qint(y)->value;
> +}
> +
> +/**
> * qint_destroy_obj(): Free all memory allocated by a
> * QInt object
> */
> diff --git a/qobject/qlist.c b/qobject/qlist.c
> index 86b60cb..652fc53 100644
> --- a/qobject/qlist.c
> +++ b/qobject/qlist.c
> @@ -140,6 +140,36 @@ QList *qobject_to_qlist(const QObject *obj)
> }
>
> /**
> + * qlist_is_equal(): Tests whether the two QLists are equal
> + *
> + * In order to be considered equal, the respective two objects at each index of
> + * the two lists have to compare equal (regarding qobject_is_equal()), and both
> + * lists have to have the same number of elements.
> + * That means, both lists have to contain equal objects in equal order.
> + */
> +bool qlist_is_equal(const QObject *x, const QObject *y)
> +{
> + const QList *list_x = qobject_to_qlist(x), *list_y = qobject_to_qlist(y);
> + const QListEntry *entry_x, *entry_y;
> +
> + entry_x = qlist_first(list_x);
> + entry_y = qlist_first(list_y);
> +
> + while (entry_x && entry_y) {
> + if (!qobject_is_equal(qlist_entry_obj(entry_x),
> + qlist_entry_obj(entry_y)))
> + {
> + return false;
> + }
> +
> + entry_x = qlist_next(entry_x);
> + entry_y = qlist_next(entry_y);
> + }
> +
> + return !entry_x && !entry_y;
> +}
> +
> +/**
> * qlist_destroy_obj(): Free all the memory allocated by a QList
> */
> void qlist_destroy_obj(QObject *obj)
> diff --git a/qobject/qnull.c b/qobject/qnull.c
> index b3cc85e..af5453d 100644
> --- a/qobject/qnull.c
> +++ b/qobject/qnull.c
> @@ -19,3 +19,8 @@ QObject qnull_ = {
> .type = QTYPE_QNULL,
> .refcnt = 1,
> };
> +
> +bool qnull_is_equal(const QObject *x, const QObject *y)
> +{
> + return true;
> +}
> diff --git a/qobject/qobject.c b/qobject/qobject.c
> index fe4fa10..af2869a 100644
> --- a/qobject/qobject.c
> +++ b/qobject/qobject.c
> @@ -28,3 +28,33 @@ void qobject_destroy(QObject *obj)
> assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
> qdestroy[obj->type](obj);
> }
> +
> +
> +static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) = {
> + [QTYPE_NONE] = NULL, /* No such object exists */
> + [QTYPE_QNULL] = qnull_is_equal,
> + [QTYPE_QINT] = qint_is_equal,
> + [QTYPE_QSTRING] = qstring_is_equal,
> + [QTYPE_QDICT] = qdict_is_equal,
> + [QTYPE_QLIST] = qlist_is_equal,
> + [QTYPE_QFLOAT] = qfloat_is_equal,
> + [QTYPE_QBOOL] = qbool_is_equal,
> +};
> +
> +bool qobject_is_equal(const QObject *x, const QObject *y)
> +{
> + /* We cannot test x == y because an object does not need to be equal to
> + * itself (e.g. NaN floats are not). */
> +
> + if (!x && !y) {
> + return true;
> + }
> +
> + if (!x || !y || x->type != y->type) {
> + return false;
> + }
> +
> + assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX);
> +
> + return qis_equal[x->type](x, y);
> +}
> diff --git a/qobject/qstring.c b/qobject/qstring.c
> index 5da7b5f..a2b51fa 100644
> --- a/qobject/qstring.c
> +++ b/qobject/qstring.c
> @@ -129,6 +129,15 @@ const char *qstring_get_str(const QString *qstring)
> }
>
> /**
> + * qstring_is_equal(): Tests whether the two QStrings are equal
> + */
> +bool qstring_is_equal(const QObject *x, const QObject *y)
> +{
> + return !strcmp(qobject_to_qstring(x)->string,
> + qobject_to_qstring(y)->string);
> +}
> +
> +/**
> * qstring_destroy_obj(): Free all memory allocated by a QString
> * object
> */
Address my nitpicks, and either provide a unit test or convince me it's
not worth the trouble, and you may add
Reviewed-by: Markus Armbruster <armbru@redhat.com>
On 2017-06-21 18:43, Markus Armbruster wrote:
> Max Reitz <mreitz@redhat.com> writes:
>
>> This generic function (along with its implementations for different
>> types) determines whether two QObjects are equal.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>> include/qapi/qmp/qbool.h | 1 +
>> include/qapi/qmp/qdict.h | 1 +
>> include/qapi/qmp/qfloat.h | 1 +
>> include/qapi/qmp/qint.h | 1 +
>> include/qapi/qmp/qlist.h | 1 +
>> include/qapi/qmp/qnull.h | 2 ++
>> include/qapi/qmp/qobject.h | 9 +++++++++
>> include/qapi/qmp/qstring.h | 1 +
>> qobject/qbool.c | 8 ++++++++
>> qobject/qdict.c | 28 ++++++++++++++++++++++++++++
>> qobject/qfloat.c | 8 ++++++++
>> qobject/qint.c | 8 ++++++++
>> qobject/qlist.c | 30 ++++++++++++++++++++++++++++++
>> qobject/qnull.c | 5 +++++
>> qobject/qobject.c | 30 ++++++++++++++++++++++++++++++
>> qobject/qstring.c | 9 +++++++++
>> 16 files changed, 143 insertions(+)
>
> No unit test?
*cough*
>> diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h
>> index a41111c..f77ea86 100644
>> --- a/include/qapi/qmp/qbool.h
>> +++ b/include/qapi/qmp/qbool.h
>> @@ -24,6 +24,7 @@ typedef struct QBool {
>> QBool *qbool_from_bool(bool value);
>> bool qbool_get_bool(const QBool *qb);
>> QBool *qobject_to_qbool(const QObject *obj);
>> +bool qbool_is_equal(const QObject *x, const QObject *y);
>> void qbool_destroy_obj(QObject *obj);
>>
>> #endif /* QBOOL_H */
>> diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
>> index 188440a..134a526 100644
>> --- a/include/qapi/qmp/qdict.h
>> +++ b/include/qapi/qmp/qdict.h
>> @@ -41,6 +41,7 @@ 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);
>> QDict *qobject_to_qdict(const QObject *obj);
>> +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);
>> diff --git a/include/qapi/qmp/qfloat.h b/include/qapi/qmp/qfloat.h
>> index b5d1583..318e91e 100644
>> --- a/include/qapi/qmp/qfloat.h
>> +++ b/include/qapi/qmp/qfloat.h
>> @@ -24,6 +24,7 @@ typedef struct QFloat {
>> QFloat *qfloat_from_double(double value);
>> double qfloat_get_double(const QFloat *qi);
>> QFloat *qobject_to_qfloat(const QObject *obj);
>> +bool qfloat_is_equal(const QObject *x, const QObject *y);
>> void qfloat_destroy_obj(QObject *obj);
>>
>> #endif /* QFLOAT_H */
>> diff --git a/include/qapi/qmp/qint.h b/include/qapi/qmp/qint.h
>> index 3aaff76..20975da 100644
>> --- a/include/qapi/qmp/qint.h
>> +++ b/include/qapi/qmp/qint.h
>> @@ -23,6 +23,7 @@ typedef struct QInt {
>> QInt *qint_from_int(int64_t value);
>> int64_t qint_get_int(const QInt *qi);
>> QInt *qobject_to_qint(const QObject *obj);
>> +bool qint_is_equal(const QObject *x, const QObject *y);
>> void qint_destroy_obj(QObject *obj);
>>
>> #endif /* QINT_H */
>> diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h
>> index 5dc4ed9..4380a5b 100644
>> --- a/include/qapi/qmp/qlist.h
>> +++ b/include/qapi/qmp/qlist.h
>> @@ -57,6 +57,7 @@ QObject *qlist_peek(QList *qlist);
>> int qlist_empty(const QList *qlist);
>> size_t qlist_size(const QList *qlist);
>> QList *qobject_to_qlist(const QObject *obj);
>> +bool qlist_is_equal(const QObject *x, const QObject *y);
>> void qlist_destroy_obj(QObject *obj);
>>
>> static inline const QListEntry *qlist_first(const QList *qlist)
>> diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h
>> index 69555ac..9299683 100644
>> --- a/include/qapi/qmp/qnull.h
>> +++ b/include/qapi/qmp/qnull.h
>> @@ -23,4 +23,6 @@ static inline QObject *qnull(void)
>> return &qnull_;
>> }
>>
>> +bool qnull_is_equal(const QObject *x, const QObject *y);
>> +
>> #endif /* QNULL_H */
>> diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
>> index ef1d1a9..cac72e3 100644
>> --- a/include/qapi/qmp/qobject.h
>> +++ b/include/qapi/qmp/qobject.h
>> @@ -68,6 +68,15 @@ static inline void qobject_incref(QObject *obj)
>> }
>>
>> /**
>> + * qobject_is_equal(): Returns whether the two objects are equal.
>
> Imperative mood, please: Return whether...
OK, will do here and everywhere else.
>> + *
>> + * Any of the pointers may be NULL; will return true if both are. Will always
>> + * return false if only one is (therefore a QNull object is not considered equal
>> + * to a NULL pointer).
>> + */
>
> Humor me: wrap comment lines around column 70, and put two spaces
> between sentences.
Do I hear "one checkpatch.pl per subsystem"?
Yes, I know, there's no point to. Why should anyone not break comments
after 70 lines and not use two spaces after full stops? O:-)
> Same for the other function comments.
Sure, will do.
>> +bool qobject_is_equal(const QObject *x, const QObject *y);
>> +
>> +/**
>> * qobject_destroy(): Free resources used by the object
>> */
>> void qobject_destroy(QObject *obj);
>> diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h
>> index 10076b7..65c05a9 100644
>> --- a/include/qapi/qmp/qstring.h
>> +++ b/include/qapi/qmp/qstring.h
>> @@ -31,6 +31,7 @@ void qstring_append_int(QString *qstring, int64_t value);
>> void qstring_append(QString *qstring, const char *str);
>> void qstring_append_chr(QString *qstring, int c);
>> QString *qobject_to_qstring(const QObject *obj);
>> +bool qstring_is_equal(const QObject *x, const QObject *y);
>> void qstring_destroy_obj(QObject *obj);
>>
>> #endif /* QSTRING_H */
>> diff --git a/qobject/qbool.c b/qobject/qbool.c
>> index 0606bbd..f1d1719 100644
>> --- a/qobject/qbool.c
>> +++ b/qobject/qbool.c
>> @@ -52,6 +52,14 @@ QBool *qobject_to_qbool(const QObject *obj)
>> }
>>
>> /**
>> + * qbool_is_equal(): Tests whether the two QBools are equal
>
> Return whether ...
>
>> + */
>> +bool qbool_is_equal(const QObject *x, const QObject *y)
>> +{
>> + return qobject_to_qbool(x)->value == qobject_to_qbool(y)->value;
>> +}
>> +
>> +/**
>> * qbool_destroy_obj(): Free all memory allocated by a
>> * QBool object
>> */
>> diff --git a/qobject/qdict.c b/qobject/qdict.c
>> index 88e2ecd..ca919bc 100644
>> --- a/qobject/qdict.c
>> +++ b/qobject/qdict.c
>> @@ -410,6 +410,34 @@ void qdict_del(QDict *qdict, const char *key)
>> }
>>
>> /**
>> + * qdict_is_equal(): Tests whether the two QDicts are equal
>> + *
>> + * Here, equality means whether they contain the same keys and whether the
>> + * respective values are in turn equal (i.e. invoking qobject_is_equal() on them
>> + * yields true).
>> + */
>> +bool qdict_is_equal(const QObject *x, const QObject *y)
>> +{
>> + const QDict *dict_x = qobject_to_qdict(x), *dict_y = qobject_to_qdict(y);
>
> I'm fine with multiple initializers in one declaration, but I think this
> one would look tidier as
>
> const QDict *dict_x = qobject_to_qdict(x);
> const QDict *dict_y = qobject_to_qdict(y);
I don't mind.
>> + const QDictEntry *e;
>> +
>> + if (qdict_size(dict_x) != qdict_size(dict_y)) {
>> + return false;
>> + }
>> +
>> + for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) {
>> + const QObject *obj_x = qdict_entry_value(e);
>> + const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e));
>> +
>> + if (!qobject_is_equal(obj_x, obj_y)) {
>> + return false;
>> + }
>> + }
>> +
>> + return true;
>> +}
>> +
>> +/**
>> * qdict_destroy_obj(): Free all the memory allocated by a QDict
>> */
>> void qdict_destroy_obj(QObject *obj)
>> diff --git a/qobject/qfloat.c b/qobject/qfloat.c
>> index d5da847..291ecc4 100644
>> --- a/qobject/qfloat.c
>> +++ b/qobject/qfloat.c
>> @@ -52,6 +52,14 @@ QFloat *qobject_to_qfloat(const QObject *obj)
>> }
>>
>> /**
>> + * qfloat_is_equal(): Tests whether the two QFloats are equal
>> + */
>> +bool qfloat_is_equal(const QObject *x, const QObject *y)
>> +{
>> + return qobject_to_qfloat(x)->value == qobject_to_qfloat(y)->value;
>> +}
>> +
>> +/**
>> * qfloat_destroy_obj(): Free all memory allocated by a
>> * QFloat object
>> */
>> diff --git a/qobject/qint.c b/qobject/qint.c
>> index d7d1b30..f638cb7 100644
>> --- a/qobject/qint.c
>> +++ b/qobject/qint.c
>> @@ -51,6 +51,14 @@ QInt *qobject_to_qint(const QObject *obj)
>> }
>>
>> /**
>> + * qint_is_equal(): Tests whether the two QInts are equal
>> + */
>> +bool qint_is_equal(const QObject *x, const QObject *y)
>> +{
>> + return qobject_to_qint(x)->value == qobject_to_qint(y)->value;
>> +}
>> +
>> +/**
>> * qint_destroy_obj(): Free all memory allocated by a
>> * QInt object
>> */
>> diff --git a/qobject/qlist.c b/qobject/qlist.c
>> index 86b60cb..652fc53 100644
>> --- a/qobject/qlist.c
>> +++ b/qobject/qlist.c
>> @@ -140,6 +140,36 @@ QList *qobject_to_qlist(const QObject *obj)
>> }
>>
>> /**
>> + * qlist_is_equal(): Tests whether the two QLists are equal
>> + *
>> + * In order to be considered equal, the respective two objects at each index of
>> + * the two lists have to compare equal (regarding qobject_is_equal()), and both
>> + * lists have to have the same number of elements.
>> + * That means, both lists have to contain equal objects in equal order.
>> + */
>> +bool qlist_is_equal(const QObject *x, const QObject *y)
>> +{
>> + const QList *list_x = qobject_to_qlist(x), *list_y = qobject_to_qlist(y);
>> + const QListEntry *entry_x, *entry_y;
>> +
>> + entry_x = qlist_first(list_x);
>> + entry_y = qlist_first(list_y);
>> +
>> + while (entry_x && entry_y) {
>> + if (!qobject_is_equal(qlist_entry_obj(entry_x),
>> + qlist_entry_obj(entry_y)))
>> + {
>> + return false;
>> + }
>> +
>> + entry_x = qlist_next(entry_x);
>> + entry_y = qlist_next(entry_y);
>> + }
>> +
>> + return !entry_x && !entry_y;
>> +}
>> +
>> +/**
>> * qlist_destroy_obj(): Free all the memory allocated by a QList
>> */
>> void qlist_destroy_obj(QObject *obj)
>> diff --git a/qobject/qnull.c b/qobject/qnull.c
>> index b3cc85e..af5453d 100644
>> --- a/qobject/qnull.c
>> +++ b/qobject/qnull.c
>> @@ -19,3 +19,8 @@ QObject qnull_ = {
>> .type = QTYPE_QNULL,
>> .refcnt = 1,
>> };
>> +
>> +bool qnull_is_equal(const QObject *x, const QObject *y)
>> +{
>> + return true;
>> +}
>> diff --git a/qobject/qobject.c b/qobject/qobject.c
>> index fe4fa10..af2869a 100644
>> --- a/qobject/qobject.c
>> +++ b/qobject/qobject.c
>> @@ -28,3 +28,33 @@ void qobject_destroy(QObject *obj)
>> assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
>> qdestroy[obj->type](obj);
>> }
>> +
>> +
>> +static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) = {
>> + [QTYPE_NONE] = NULL, /* No such object exists */
>> + [QTYPE_QNULL] = qnull_is_equal,
>> + [QTYPE_QINT] = qint_is_equal,
>> + [QTYPE_QSTRING] = qstring_is_equal,
>> + [QTYPE_QDICT] = qdict_is_equal,
>> + [QTYPE_QLIST] = qlist_is_equal,
>> + [QTYPE_QFLOAT] = qfloat_is_equal,
>> + [QTYPE_QBOOL] = qbool_is_equal,
>> +};
>> +
>> +bool qobject_is_equal(const QObject *x, const QObject *y)
>> +{
>> + /* We cannot test x == y because an object does not need to be equal to
>> + * itself (e.g. NaN floats are not). */
>> +
>> + if (!x && !y) {
>> + return true;
>> + }
>> +
>> + if (!x || !y || x->type != y->type) {
>> + return false;
>> + }
>> +
>> + assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX);
>> +
>> + return qis_equal[x->type](x, y);
>> +}
>> diff --git a/qobject/qstring.c b/qobject/qstring.c
>> index 5da7b5f..a2b51fa 100644
>> --- a/qobject/qstring.c
>> +++ b/qobject/qstring.c
>> @@ -129,6 +129,15 @@ const char *qstring_get_str(const QString *qstring)
>> }
>>
>> /**
>> + * qstring_is_equal(): Tests whether the two QStrings are equal
>> + */
>> +bool qstring_is_equal(const QObject *x, const QObject *y)
>> +{
>> + return !strcmp(qobject_to_qstring(x)->string,
>> + qobject_to_qstring(y)->string);
>> +}
>> +
>> +/**
>> * qstring_destroy_obj(): Free all memory allocated by a QString
>> * object
>> */
>
> Address my nitpicks, and either provide a unit test or convince me it's
> not worth the trouble, and you may add
Unfortunately (for me), it's always worth the trouble.
> Reviewed-by: Markus Armbruster <armbru@redhat.com>
Thanks again!
Max
Max Reitz <mreitz@redhat.com> writes:
> On 2017-06-21 18:43, Markus Armbruster wrote:
>> Max Reitz <mreitz@redhat.com> writes:
>>
>>> This generic function (along with its implementations for different
>>> types) determines whether two QObjects are equal.
>>>
>>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>>> ---
>>> include/qapi/qmp/qbool.h | 1 +
>>> include/qapi/qmp/qdict.h | 1 +
>>> include/qapi/qmp/qfloat.h | 1 +
>>> include/qapi/qmp/qint.h | 1 +
>>> include/qapi/qmp/qlist.h | 1 +
>>> include/qapi/qmp/qnull.h | 2 ++
>>> include/qapi/qmp/qobject.h | 9 +++++++++
>>> include/qapi/qmp/qstring.h | 1 +
>>> qobject/qbool.c | 8 ++++++++
>>> qobject/qdict.c | 28 ++++++++++++++++++++++++++++
>>> qobject/qfloat.c | 8 ++++++++
>>> qobject/qint.c | 8 ++++++++
>>> qobject/qlist.c | 30 ++++++++++++++++++++++++++++++
>>> qobject/qnull.c | 5 +++++
>>> qobject/qobject.c | 30 ++++++++++++++++++++++++++++++
>>> qobject/qstring.c | 9 +++++++++
>>> 16 files changed, 143 insertions(+)
>>
>> No unit test?
>
> *cough*
>
>>> diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h
>>> index a41111c..f77ea86 100644
>>> --- a/include/qapi/qmp/qbool.h
>>> +++ b/include/qapi/qmp/qbool.h
>>> @@ -24,6 +24,7 @@ typedef struct QBool {
>>> QBool *qbool_from_bool(bool value);
>>> bool qbool_get_bool(const QBool *qb);
>>> QBool *qobject_to_qbool(const QObject *obj);
>>> +bool qbool_is_equal(const QObject *x, const QObject *y);
>>> void qbool_destroy_obj(QObject *obj);
>>>
>>> #endif /* QBOOL_H */
>>> diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
>>> index 188440a..134a526 100644
>>> --- a/include/qapi/qmp/qdict.h
>>> +++ b/include/qapi/qmp/qdict.h
>>> @@ -41,6 +41,7 @@ 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);
>>> QDict *qobject_to_qdict(const QObject *obj);
>>> +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);
>>> diff --git a/include/qapi/qmp/qfloat.h b/include/qapi/qmp/qfloat.h
>>> index b5d1583..318e91e 100644
>>> --- a/include/qapi/qmp/qfloat.h
>>> +++ b/include/qapi/qmp/qfloat.h
>>> @@ -24,6 +24,7 @@ typedef struct QFloat {
>>> QFloat *qfloat_from_double(double value);
>>> double qfloat_get_double(const QFloat *qi);
>>> QFloat *qobject_to_qfloat(const QObject *obj);
>>> +bool qfloat_is_equal(const QObject *x, const QObject *y);
>>> void qfloat_destroy_obj(QObject *obj);
>>>
>>> #endif /* QFLOAT_H */
>>> diff --git a/include/qapi/qmp/qint.h b/include/qapi/qmp/qint.h
>>> index 3aaff76..20975da 100644
>>> --- a/include/qapi/qmp/qint.h
>>> +++ b/include/qapi/qmp/qint.h
>>> @@ -23,6 +23,7 @@ typedef struct QInt {
>>> QInt *qint_from_int(int64_t value);
>>> int64_t qint_get_int(const QInt *qi);
>>> QInt *qobject_to_qint(const QObject *obj);
>>> +bool qint_is_equal(const QObject *x, const QObject *y);
>>> void qint_destroy_obj(QObject *obj);
>>>
>>> #endif /* QINT_H */
>>> diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h
>>> index 5dc4ed9..4380a5b 100644
>>> --- a/include/qapi/qmp/qlist.h
>>> +++ b/include/qapi/qmp/qlist.h
>>> @@ -57,6 +57,7 @@ QObject *qlist_peek(QList *qlist);
>>> int qlist_empty(const QList *qlist);
>>> size_t qlist_size(const QList *qlist);
>>> QList *qobject_to_qlist(const QObject *obj);
>>> +bool qlist_is_equal(const QObject *x, const QObject *y);
>>> void qlist_destroy_obj(QObject *obj);
>>>
>>> static inline const QListEntry *qlist_first(const QList *qlist)
>>> diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h
>>> index 69555ac..9299683 100644
>>> --- a/include/qapi/qmp/qnull.h
>>> +++ b/include/qapi/qmp/qnull.h
>>> @@ -23,4 +23,6 @@ static inline QObject *qnull(void)
>>> return &qnull_;
>>> }
>>>
>>> +bool qnull_is_equal(const QObject *x, const QObject *y);
>>> +
>>> #endif /* QNULL_H */
>>> diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
>>> index ef1d1a9..cac72e3 100644
>>> --- a/include/qapi/qmp/qobject.h
>>> +++ b/include/qapi/qmp/qobject.h
>>> @@ -68,6 +68,15 @@ static inline void qobject_incref(QObject *obj)
>>> }
>>>
>>> /**
>>> + * qobject_is_equal(): Returns whether the two objects are equal.
>>
>> Imperative mood, please: Return whether...
>
> OK, will do here and everywhere else.
>
>>> + *
>>> + * Any of the pointers may be NULL; will return true if both are. Will always
>>> + * return false if only one is (therefore a QNull object is not considered equal
>>> + * to a NULL pointer).
>>> + */
>>
>> Humor me: wrap comment lines around column 70, and put two spaces
>> between sentences.
>
> Do I hear "one checkpatch.pl per subsystem"?
Nah, you hear "would you mind doing me a favor if I ask nicely?"
> Yes, I know, there's no point to. Why should anyone not break comments
> after 70 lines and not use two spaces after full stops? O:-)
That too ;)
>> Same for the other function comments.
>
> Sure, will do.
>
>>> +bool qobject_is_equal(const QObject *x, const QObject *y);
>>> +
>>> +/**
>>> * qobject_destroy(): Free resources used by the object
>>> */
>>> void qobject_destroy(QObject *obj);
>>> diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h
>>> index 10076b7..65c05a9 100644
>>> --- a/include/qapi/qmp/qstring.h
>>> +++ b/include/qapi/qmp/qstring.h
>>> @@ -31,6 +31,7 @@ void qstring_append_int(QString *qstring, int64_t value);
>>> void qstring_append(QString *qstring, const char *str);
>>> void qstring_append_chr(QString *qstring, int c);
>>> QString *qobject_to_qstring(const QObject *obj);
>>> +bool qstring_is_equal(const QObject *x, const QObject *y);
>>> void qstring_destroy_obj(QObject *obj);
>>>
>>> #endif /* QSTRING_H */
>>> diff --git a/qobject/qbool.c b/qobject/qbool.c
>>> index 0606bbd..f1d1719 100644
>>> --- a/qobject/qbool.c
>>> +++ b/qobject/qbool.c
>>> @@ -52,6 +52,14 @@ QBool *qobject_to_qbool(const QObject *obj)
>>> }
>>>
>>> /**
>>> + * qbool_is_equal(): Tests whether the two QBools are equal
>>
>> Return whether ...
>>
>>> + */
>>> +bool qbool_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + return qobject_to_qbool(x)->value == qobject_to_qbool(y)->value;
>>> +}
>>> +
>>> +/**
>>> * qbool_destroy_obj(): Free all memory allocated by a
>>> * QBool object
>>> */
>>> diff --git a/qobject/qdict.c b/qobject/qdict.c
>>> index 88e2ecd..ca919bc 100644
>>> --- a/qobject/qdict.c
>>> +++ b/qobject/qdict.c
>>> @@ -410,6 +410,34 @@ void qdict_del(QDict *qdict, const char *key)
>>> }
>>>
>>> /**
>>> + * qdict_is_equal(): Tests whether the two QDicts are equal
>>> + *
>>> + * Here, equality means whether they contain the same keys and whether the
>>> + * respective values are in turn equal (i.e. invoking qobject_is_equal() on them
>>> + * yields true).
>>> + */
>>> +bool qdict_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + const QDict *dict_x = qobject_to_qdict(x), *dict_y = qobject_to_qdict(y);
>>
>> I'm fine with multiple initializers in one declaration, but I think this
>> one would look tidier as
>>
>> const QDict *dict_x = qobject_to_qdict(x);
>> const QDict *dict_y = qobject_to_qdict(y);
>
> I don't mind.
>
>>> + const QDictEntry *e;
>>> +
>>> + if (qdict_size(dict_x) != qdict_size(dict_y)) {
>>> + return false;
>>> + }
>>> +
>>> + for (e = qdict_first(dict_x); e; e = qdict_next(dict_x, e)) {
>>> + const QObject *obj_x = qdict_entry_value(e);
>>> + const QObject *obj_y = qdict_get(dict_y, qdict_entry_key(e));
>>> +
>>> + if (!qobject_is_equal(obj_x, obj_y)) {
>>> + return false;
>>> + }
>>> + }
>>> +
>>> + return true;
>>> +}
>>> +
>>> +/**
>>> * qdict_destroy_obj(): Free all the memory allocated by a QDict
>>> */
>>> void qdict_destroy_obj(QObject *obj)
>>> diff --git a/qobject/qfloat.c b/qobject/qfloat.c
>>> index d5da847..291ecc4 100644
>>> --- a/qobject/qfloat.c
>>> +++ b/qobject/qfloat.c
>>> @@ -52,6 +52,14 @@ QFloat *qobject_to_qfloat(const QObject *obj)
>>> }
>>>
>>> /**
>>> + * qfloat_is_equal(): Tests whether the two QFloats are equal
>>> + */
>>> +bool qfloat_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + return qobject_to_qfloat(x)->value == qobject_to_qfloat(y)->value;
>>> +}
>>> +
>>> +/**
>>> * qfloat_destroy_obj(): Free all memory allocated by a
>>> * QFloat object
>>> */
>>> diff --git a/qobject/qint.c b/qobject/qint.c
>>> index d7d1b30..f638cb7 100644
>>> --- a/qobject/qint.c
>>> +++ b/qobject/qint.c
>>> @@ -51,6 +51,14 @@ QInt *qobject_to_qint(const QObject *obj)
>>> }
>>>
>>> /**
>>> + * qint_is_equal(): Tests whether the two QInts are equal
>>> + */
>>> +bool qint_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + return qobject_to_qint(x)->value == qobject_to_qint(y)->value;
>>> +}
>>> +
>>> +/**
>>> * qint_destroy_obj(): Free all memory allocated by a
>>> * QInt object
>>> */
>>> diff --git a/qobject/qlist.c b/qobject/qlist.c
>>> index 86b60cb..652fc53 100644
>>> --- a/qobject/qlist.c
>>> +++ b/qobject/qlist.c
>>> @@ -140,6 +140,36 @@ QList *qobject_to_qlist(const QObject *obj)
>>> }
>>>
>>> /**
>>> + * qlist_is_equal(): Tests whether the two QLists are equal
>>> + *
>>> + * In order to be considered equal, the respective two objects at each index of
>>> + * the two lists have to compare equal (regarding qobject_is_equal()), and both
>>> + * lists have to have the same number of elements.
>>> + * That means, both lists have to contain equal objects in equal order.
>>> + */
>>> +bool qlist_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + const QList *list_x = qobject_to_qlist(x), *list_y = qobject_to_qlist(y);
>>> + const QListEntry *entry_x, *entry_y;
>>> +
>>> + entry_x = qlist_first(list_x);
>>> + entry_y = qlist_first(list_y);
>>> +
>>> + while (entry_x && entry_y) {
>>> + if (!qobject_is_equal(qlist_entry_obj(entry_x),
>>> + qlist_entry_obj(entry_y)))
>>> + {
>>> + return false;
>>> + }
>>> +
>>> + entry_x = qlist_next(entry_x);
>>> + entry_y = qlist_next(entry_y);
>>> + }
>>> +
>>> + return !entry_x && !entry_y;
>>> +}
>>> +
>>> +/**
>>> * qlist_destroy_obj(): Free all the memory allocated by a QList
>>> */
>>> void qlist_destroy_obj(QObject *obj)
>>> diff --git a/qobject/qnull.c b/qobject/qnull.c
>>> index b3cc85e..af5453d 100644
>>> --- a/qobject/qnull.c
>>> +++ b/qobject/qnull.c
>>> @@ -19,3 +19,8 @@ QObject qnull_ = {
>>> .type = QTYPE_QNULL,
>>> .refcnt = 1,
>>> };
>>> +
>>> +bool qnull_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + return true;
>>> +}
>>> diff --git a/qobject/qobject.c b/qobject/qobject.c
>>> index fe4fa10..af2869a 100644
>>> --- a/qobject/qobject.c
>>> +++ b/qobject/qobject.c
>>> @@ -28,3 +28,33 @@ void qobject_destroy(QObject *obj)
>>> assert(QTYPE_QNULL < obj->type && obj->type < QTYPE__MAX);
>>> qdestroy[obj->type](obj);
>>> }
>>> +
>>> +
>>> +static bool (*qis_equal[QTYPE__MAX])(const QObject *, const QObject *) = {
>>> + [QTYPE_NONE] = NULL, /* No such object exists */
>>> + [QTYPE_QNULL] = qnull_is_equal,
>>> + [QTYPE_QINT] = qint_is_equal,
>>> + [QTYPE_QSTRING] = qstring_is_equal,
>>> + [QTYPE_QDICT] = qdict_is_equal,
>>> + [QTYPE_QLIST] = qlist_is_equal,
>>> + [QTYPE_QFLOAT] = qfloat_is_equal,
>>> + [QTYPE_QBOOL] = qbool_is_equal,
>>> +};
>>> +
>>> +bool qobject_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + /* We cannot test x == y because an object does not need to be equal to
>>> + * itself (e.g. NaN floats are not). */
>>> +
>>> + if (!x && !y) {
>>> + return true;
>>> + }
>>> +
>>> + if (!x || !y || x->type != y->type) {
>>> + return false;
>>> + }
>>> +
>>> + assert(QTYPE_NONE < x->type && x->type < QTYPE__MAX);
>>> +
>>> + return qis_equal[x->type](x, y);
>>> +}
>>> diff --git a/qobject/qstring.c b/qobject/qstring.c
>>> index 5da7b5f..a2b51fa 100644
>>> --- a/qobject/qstring.c
>>> +++ b/qobject/qstring.c
>>> @@ -129,6 +129,15 @@ const char *qstring_get_str(const QString *qstring)
>>> }
>>>
>>> /**
>>> + * qstring_is_equal(): Tests whether the two QStrings are equal
>>> + */
>>> +bool qstring_is_equal(const QObject *x, const QObject *y)
>>> +{
>>> + return !strcmp(qobject_to_qstring(x)->string,
>>> + qobject_to_qstring(y)->string);
>>> +}
>>> +
>>> +/**
>>> * qstring_destroy_obj(): Free all memory allocated by a QString
>>> * object
>>> */
>>
>> Address my nitpicks, and either provide a unit test or convince me it's
>> not worth the trouble, and you may add
>
> Unfortunately (for me), it's always worth the trouble.
Awesome!
>> Reviewed-by: Markus Armbruster <armbru@redhat.com>
>
> Thanks again!
>
> Max
© 2016 - 2026 Red Hat, Inc.