diff --git a/qemu/include/qapi/qmp/qbool.h b/qemu/include/qapi/qmp/qbool.h index 914e17c4..a958ddbf 100644 --- a/qemu/include/qapi/qmp/qbool.h +++ b/qemu/include/qapi/qmp/qbool.h @@ -25,6 +25,7 @@ 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/qemu/include/qapi/qmp/qdict.h b/qemu/include/qapi/qmp/qdict.h index 14b01933..0538318f 100644 --- a/qemu/include/qapi/qmp/qdict.h +++ b/qemu/include/qapi/qmp/qdict.h @@ -42,6 +42,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/qemu/include/qapi/qmp/qlist.h b/qemu/include/qapi/qmp/qlist.h index ec2dd961..c5705b51 100644 --- a/qemu/include/qapi/qmp/qlist.h +++ b/qemu/include/qapi/qmp/qlist.h @@ -54,6 +54,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/qemu/include/qapi/qmp/qnull.h b/qemu/include/qapi/qmp/qnull.h index d0755492..c992ee2a 100644 --- a/qemu/include/qapi/qmp/qnull.h +++ b/qemu/include/qapi/qmp/qnull.h @@ -27,4 +27,6 @@ static inline QNull *qnull(void) return &qnull_; } +bool qnull_is_equal(const QObject *x, const QObject *y); + #endif /* QNULL_H */ diff --git a/qemu/include/qapi/qmp/qnum.h b/qemu/include/qapi/qmp/qnum.h index 94b5f853..15e3971c 100644 --- a/qemu/include/qapi/qmp/qnum.h +++ b/qemu/include/qapi/qmp/qnum.h @@ -69,6 +69,7 @@ double qnum_get_double(QNum *qn); char *qnum_to_string(QNum *qn); QNum *qobject_to_qnum(const QObject *obj); +bool qnum_is_equal(const QObject *x, const QObject *y); void qnum_destroy_obj(QObject *obj); #endif /* QNUM_H */ diff --git a/qemu/include/qapi/qmp/qobject.h b/qemu/include/qapi/qmp/qobject.h index de0daf0f..029e6e81 100644 --- a/qemu/include/qapi/qmp/qobject.h +++ b/qemu/include/qapi/qmp/qobject.h @@ -73,6 +73,15 @@ static inline void qobject_incref(QObject *obj) obj->refcnt++; } +/** + * qobject_is_equal(): Return whether the two objects are equal. + * + * Any of the pointers may be NULL; return true if both are. 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 */ diff --git a/qemu/include/qapi/qmp/qstring.h b/qemu/include/qapi/qmp/qstring.h index ee037bbd..a3b9ba0a 100644 --- a/qemu/include/qapi/qmp/qstring.h +++ b/qemu/include/qapi/qmp/qstring.h @@ -32,6 +32,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/qemu/qobject/qbool.c b/qemu/qobject/qbool.c index 0606bbd2..ac825fc5 100644 --- a/qemu/qobject/qbool.c +++ b/qemu/qobject/qbool.c @@ -51,6 +51,14 @@ QBool *qobject_to_qbool(const QObject *obj) return container_of(obj, QBool, base); } +/** + * qbool_is_equal(): Test 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/qemu/qobject/qdict.c b/qemu/qobject/qdict.c index 04604c8f..ef0cd17c 100644 --- a/qemu/qobject/qdict.c +++ b/qemu/qobject/qdict.c @@ -423,6 +423,35 @@ void qdict_del(QDict *qdict, const char *key) } } +/** + * qdict_is_equal(): Test 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); + 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 */ diff --git a/qemu/qobject/qlist.c b/qemu/qobject/qlist.c index b9972d4b..46dde3c7 100644 --- a/qemu/qobject/qlist.c +++ b/qemu/qobject/qlist.c @@ -166,6 +166,38 @@ QList *qobject_to_qlist(const QObject *obj) return container_of(obj, QList, base); } +/** + * qlist_is_equal(): Test 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); + const QList *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 */ diff --git a/qemu/qobject/qnull.c b/qemu/qobject/qnull.c index a651ba8e..3cb2b1c7 100644 --- a/qemu/qobject/qnull.c +++ b/qemu/qobject/qnull.c @@ -19,3 +19,12 @@ QNull qnull_ = { 1, } }; + +/** + * qnull_is_equal(): Always return true because any two QNull objects + * are equal. + */ +bool qnull_is_equal(const QObject *x, const QObject *y) +{ + return true; +} diff --git a/qemu/qobject/qnum.c b/qemu/qobject/qnum.c index 8e2188db..517610d9 100644 --- a/qemu/qobject/qnum.c +++ b/qemu/qobject/qnum.c @@ -211,6 +211,60 @@ QNum *qobject_to_qnum(const QObject *obj) return container_of(obj, QNum, base); } +/** + * qnum_is_equal(): Test whether the two QNums are equal + * + * Negative integers are never considered equal to unsigned integers, + * but positive integers in the range [0, INT64_MAX] are considered + * equal independently of whether the QNum's kind is i64 or u64. + * + * Doubles are never considered equal to integers. + */ +bool qnum_is_equal(const QObject *x, const QObject *y) +{ + QNum *num_x = qobject_to_qnum(x); + QNum *num_y = qobject_to_qnum(y); + + switch (num_x->kind) { + case QNUM_I64: + switch (num_y->kind) { + case QNUM_I64: + /* Comparison in native int64_t type */ + return num_x->u.i64 == num_y->u.i64; + case QNUM_U64: + /* Implicit conversion of x to uin64_t, so we have to + * check its sign before */ + return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64; + case QNUM_DOUBLE: + return false; + } + abort(); + case QNUM_U64: + switch (num_y->kind) { + case QNUM_I64: + return qnum_is_equal(y, x); + case QNUM_U64: + /* Comparison in native uint64_t type */ + return num_x->u.u64 == num_y->u.u64; + case QNUM_DOUBLE: + return false; + } + abort(); + case QNUM_DOUBLE: + switch (num_y->kind) { + case QNUM_I64: + case QNUM_U64: + return false; + case QNUM_DOUBLE: + /* Comparison in native double type */ + return num_x->u.dbl == num_y->u.dbl; + } + abort(); + } + + abort(); +} + /** * qnum_destroy_obj(): Free all memory allocated by a * QNum object diff --git a/qemu/qobject/qobject.c b/qemu/qobject/qobject.c index d1fbe2f8..6edaacb9 100644 --- a/qemu/qobject/qobject.c +++ b/qemu/qobject/qobject.c @@ -31,3 +31,32 @@ 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 *) = { + NULL, /* No such object exists */ + qnull_is_equal, + qnum_is_equal, + qstring_is_equal, + qdict_is_equal, + qlist_is_equal, + 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/qemu/qobject/qstring.c b/qemu/qobject/qstring.c index f1469dfe..940b2c8d 100644 --- a/qemu/qobject/qstring.c +++ b/qemu/qobject/qstring.c @@ -127,6 +127,15 @@ const char *qstring_get_str(const QString *qstring) return qstring->string; } +/** + * qstring_is_equal(): Test 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