From nobody Sun Feb 8 23:05:11 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1510682760506262.5699229994842; Tue, 14 Nov 2017 10:06:00 -0800 (PST) Received: from localhost ([::1]:32989 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eEfak-0003FY-Ej for importer@patchew.org; Tue, 14 Nov 2017 13:05:46 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42061) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eEfX0-0000QE-1Q for qemu-devel@nongnu.org; Tue, 14 Nov 2017 13:02:00 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eEfWw-0003Eo-T6 for qemu-devel@nongnu.org; Tue, 14 Nov 2017 13:01:54 -0500 Received: from mx1.redhat.com ([209.132.183.28]:52032) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eEfWm-00039R-Hc; Tue, 14 Nov 2017 13:01:40 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 91BE2C04AC53; Tue, 14 Nov 2017 18:01:39 +0000 (UTC) Received: from localhost (unknown [10.40.205.72]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 81821953A8; Tue, 14 Nov 2017 18:01:38 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Tue, 14 Nov 2017 19:01:25 +0100 Message-Id: <20171114180128.17076-4-mreitz@redhat.com> In-Reply-To: <20171114180128.17076-1-mreitz@redhat.com> References: <20171114180128.17076-1-mreitz@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 14 Nov 2017 18:01:39 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH for-2.11? v7 3/6] qapi: Add qobject_is_equal() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Markus Armbruster , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This generic function (along with its implementations for different types) determines whether two QObjects are equal. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Alberto Garcia Reviewed-by: Markus Armbruster --- include/qapi/qmp/qbool.h | 1 + include/qapi/qmp/qdict.h | 1 + include/qapi/qmp/qlist.h | 1 + include/qapi/qmp/qnull.h | 2 ++ include/qapi/qmp/qnum.h | 1 + include/qapi/qmp/qobject.h | 9 ++++++++ include/qapi/qmp/qstring.h | 1 + qobject/qbool.c | 8 +++++++ qobject/qdict.c | 29 +++++++++++++++++++++++++ qobject/qlist.c | 32 +++++++++++++++++++++++++++ qobject/qnull.c | 9 ++++++++ qobject/qnum.c | 54 ++++++++++++++++++++++++++++++++++++++++++= ++++ qobject/qobject.c | 29 +++++++++++++++++++++++++ qobject/qstring.c | 9 ++++++++ 14 files changed, 186 insertions(+) diff --git a/include/qapi/qmp/qbool.h b/include/qapi/qmp/qbool.h index a41111c309..f77ea86c4e 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); =20 #endif /* QBOOL_H */ diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h index 7ea5120c4a..fc218e7be6 100644 --- a/include/qapi/qmp/qdict.h +++ b/include/qapi/qmp/qdict.h @@ -43,6 +43,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/qlist.h b/include/qapi/qmp/qlist.h index 59d209bbae..ec3fcc1a4c 100644 --- a/include/qapi/qmp/qlist.h +++ b/include/qapi/qmp/qlist.h @@ -61,6 +61,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); =20 static inline const QListEntry *qlist_first(const QList *qlist) diff --git a/include/qapi/qmp/qnull.h b/include/qapi/qmp/qnull.h index d075549283..c992ee2ae1 100644 --- a/include/qapi/qmp/qnull.h +++ b/include/qapi/qmp/qnull.h @@ -27,4 +27,6 @@ static inline QNull *qnull(void) return &qnull_; } =20 +bool qnull_is_equal(const QObject *x, const QObject *y); + #endif /* QNULL_H */ diff --git a/include/qapi/qmp/qnum.h b/include/qapi/qmp/qnum.h index d6b0791139..c3d86794bb 100644 --- a/include/qapi/qmp/qnum.h +++ b/include/qapi/qmp/qnum.h @@ -69,6 +69,7 @@ double qnum_get_double(QNum *qn); char *qnum_to_string(QNum *qn); =20 QNum *qobject_to_qnum(const QObject *obj); +bool qnum_is_equal(const QObject *x, const QObject *y); void qnum_destroy_obj(QObject *obj); =20 #endif /* QNUM_H */ diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h index ef1d1a9237..38ac68845c 100644 --- a/include/qapi/qmp/qobject.h +++ b/include/qapi/qmp/qobject.h @@ -68,6 +68,15 @@ static inline void qobject_incref(QObject *obj) } =20 /** + * 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 */ void qobject_destroy(QObject *obj); diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index 10076b7c8c..65c05a9be5 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); =20 #endif /* QSTRING_H */ diff --git a/qobject/qbool.c b/qobject/qbool.c index 0606bbd2a3..ac825fc5a2 100644 --- a/qobject/qbool.c +++ b/qobject/qbool.c @@ -52,6 +52,14 @@ QBool *qobject_to_qbool(const QObject *obj) } =20 /** + * 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 =3D=3D 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 576018e531..e8f15f1132 100644 --- a/qobject/qdict.c +++ b/qobject/qdict.c @@ -403,6 +403,35 @@ void qdict_del(QDict *qdict, const char *key) } =20 /** + * 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 =3D qobject_to_qdict(x); + const QDict *dict_y =3D qobject_to_qdict(y); + const QDictEntry *e; + + if (qdict_size(dict_x) !=3D qdict_size(dict_y)) { + return false; + } + + for (e =3D qdict_first(dict_x); e; e =3D qdict_next(dict_x, e)) { + const QObject *obj_x =3D qdict_entry_value(e); + const QObject *obj_y =3D 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/qlist.c b/qobject/qlist.c index 86b60cb88c..3ef57d31d1 100644 --- a/qobject/qlist.c +++ b/qobject/qlist.c @@ -140,6 +140,38 @@ QList *qobject_to_qlist(const QObject *obj) } =20 /** + * 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 =3D qobject_to_qlist(x); + const QList *list_y =3D qobject_to_qlist(y); + const QListEntry *entry_x, *entry_y; + + entry_x =3D qlist_first(list_x); + entry_y =3D 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 =3D qlist_next(entry_x); + entry_y =3D 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 bc9fd31626..f6f55f11ea 100644 --- a/qobject/qnull.c +++ b/qobject/qnull.c @@ -20,3 +20,12 @@ QNull qnull_ =3D { .refcnt =3D 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/qobject/qnum.c b/qobject/qnum.c index 476e81c93b..410686a611 100644 --- a/qobject/qnum.c +++ b/qobject/qnum.c @@ -213,6 +213,60 @@ QNum *qobject_to_qnum(const QObject *obj) } =20 /** + * 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 =3D qobject_to_qnum(x); + QNum *num_y =3D 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 =3D=3D 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 >=3D 0 && num_x->u.i64 =3D=3D 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 =3D=3D 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 =3D=3D num_y->u.dbl; + } + abort(); + } + + abort(); +} + +/** * qnum_destroy_obj(): Free all memory allocated by a * QNum object */ diff --git a/qobject/qobject.c b/qobject/qobject.c index b0cafb66f1..b2a536041d 100644 --- a/qobject/qobject.c +++ b/qobject/qobject.c @@ -27,3 +27,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 *) =3D= { + [QTYPE_NONE] =3D NULL, /* No such object exists */ + [QTYPE_QNULL] =3D qnull_is_equal, + [QTYPE_QNUM] =3D qnum_is_equal, + [QTYPE_QSTRING] =3D qstring_is_equal, + [QTYPE_QDICT] =3D qdict_is_equal, + [QTYPE_QLIST] =3D qlist_is_equal, + [QTYPE_QBOOL] =3D qbool_is_equal, +}; + +bool qobject_is_equal(const QObject *x, const QObject *y) +{ + /* We cannot test x =3D=3D 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 !=3D 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 5da7b5f37c..74182a1c02 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -129,6 +129,15 @@ const char *qstring_get_str(const QString *qstring) } =20 /** + * 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 */ --=20 2.13.6